hal: Branch 'master'

David Zeuthen david at kemper.freedesktop.org
Sun Sep 10 08:09:34 PDT 2006


 Makefile.am                        |    2 
 configure.in                       |   19 
 doc/api/tmpl/hal-unused.sgml       |  299 ++++++
 doc/api/tmpl/libhal-storage.sgml   |  324 ------
 doc/spec/hal-spec-properties.xml   |  208 +++-
 doc/spec/hal-spec.html             | 1145 ++++++++++++++++++++---
 hald/linux/addons/addon-storage.c  |    9 
 hald/linux/blockdev.c              |    2 
 hald/linux/probing/Makefile.am     |    4 
 hald/linux/probing/probe-storage.c |  182 ++-
 hald/linux/probing/probe-volume.c  |  439 +++------
 libhal-storage/libhal-storage.c    |   59 +
 libhal-storage/libhal-storage.h    |   64 -
 libhal/libhal.h                    |    7 
 partutil/Makefile.am               |   11 
 partutil/partutil.c                | 1791 +++++++++++++++++++++++++++++++++++++
 partutil/partutil.h                |  412 ++++++++
 17 files changed, 4152 insertions(+), 825 deletions(-)

New commits:
diff-tree 989e1bcc472cd7c130ae828e7d5d2ca81ee300db (from 853115cf6749087546671c92fc64d51ec01e68ac)
Author: David Zeuthen <davidz at redhat.com>
Date:   Sun Sep 10 11:08:41 2006 -0400

    add new partition probing code and adapt hal code to use it
    
    Added a new static library in partutil/ that serves two purposes
    
     1. Probe for partition tables and the entries in them. This is
        done without any new dependencies and is in general efficient.
        Right now we understand Master Boot Record (and Extended MBR),
        GUID Partitioning Tables and Apple Partition Map. The interface
        is generic enough to add support for other disk labels too
        should the need arise.
    
     2. Create partition tables, add partition table entries, alter
        partition table entries, delete partition table entries. This
        is done using libparted to ensure maximal robustness and
        correctness.
    
    Beware that libparted is kinda silly in a few ways, it probes all
    drives (even when asked to only look at one drive - the audicity!),
    and we have to poke at the internals to get/set vital raw
    properties. As such, we only officially support libparted 1.7.1 at
    this point. If you use anything else but that, you are on your own.
    We should start a dialouge with the libparted guys to make them
    export official API suitable for our needs.
    
    configure now takes a new --enable-parted and by default (for
    the upcoming 0.5.8 release), this is set to "no". As such, the
    upcoming 0.5.8 release will not depend on libparted.
    
    Also we now use this infrastructure in probe-volume and probe-storage
    to export the following new properties
    
     storage.partitioning_scheme (string)
    
    on storage devices and
    
     volume.partition.scheme (string)
     volume.partition.type (string)
     volume.partition.label (string)
     volume.partition.uuid (string)
     volume.partition.flags (strlist)
    
    on volumes. These new properties are also now exported through
    libhal-storage.
    
    Also moves some more code over to using LibHalChangeSet for nicer
    and much more efficient handling.

diff --git a/Makefile.am b/Makefile.am
index d083870..16968d2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,6 +1,6 @@
 ## Process this file with automake to produce Makefile.in
 
-SUBDIRS = libhal libhal-storage hald hald-runner tools \
+SUBDIRS = libhal libhal-storage partutil  hald hald-runner tools \
           fdi doc po privileges
 
 pkgconfigdir = $(libdir)/pkgconfig
diff --git a/configure.in b/configure.in
index 42b0cf9..cedcb22 100644
--- a/configure.in
+++ b/configure.in
@@ -100,6 +100,21 @@ fi
 AC_SUBST(ACPI_PROC)
 AM_CONDITIONAL(ACPI_PROC, test x$acpi_proc = xyes)
 
+
+dnl libparted
+AC_ARG_ENABLE([parted], AC_HELP_STRING([--enable-parted], [Use libparted]), [use_parted=$enableval], [use_parted=no])
+if test "x$use_parted" = "xyes" ; then
+   USE_PARTED=yes
+   AC_DEFINE(USE_PARTED,1,[Whether libparted is to be used])
+   PARTED_CHECK_LIBPARTED(1.7.1, ,
+	[AC_MSG_ERROR([*** libparted >= 1.7.1 not installed - please install first ***])])
+else
+   USE_PARTED=no
+fi
+AC_SUBST(USE_PARTED)
+AM_CONDITIONAL(USE_PARTED, test x$use_parted == xyes)
+
+
 #### gcc warning flags
 
 if test "x$GCC" = "xyes"; then
@@ -184,7 +199,7 @@ AM_CONDITIONAL(GCOV, test x$enable_gcov 
 
 
 EXPAT_LIB=""
-AC_ARG_WITH(expat, [  --with-expat=<dir>      ese expat from here],
+AC_ARG_WITH(expat, [  --with-expat=<dir>      Use expat from here],
                       [
                       expat=$withval
                       CPPFLAGS="$CPPFLAGS -I$withval/include"
@@ -457,6 +472,7 @@ tools/linux/Makefile
 tools/device-manager/hal-device-manager
 tools/device-manager/Makefile
 tools/device-manager/Const.py
+partutil/Makefile
 privileges/Makefile
 fdi/Makefile
 fdi/preprobe/Makefile
@@ -510,6 +526,7 @@ echo "
         use acpid interface:        ${acpi_acpid}
         use libusb:                 ${USE_LIBUSB}
         use libpci:                 ${USE_LIBPCI}
+        use libparted:              ${USE_PARTED}
 
         use PolicyKit:              ${msg_polkit}
 
diff --git a/doc/api/tmpl/hal-unused.sgml b/doc/api/tmpl/hal-unused.sgml
index 0f22ab2..6fb25b0 100644
--- a/doc/api/tmpl/hal-unused.sgml
+++ b/doc/api/tmpl/hal-unused.sgml
@@ -370,6 +370,61 @@ sysfs
 </para>
 
 
+<!-- ##### ENUM LibHalDriveBus ##### -->
+<para>
+
+</para>
+
+ at LIBHAL_DRIVE_BUS_UNKNOWN: 
+ at LIBHAL_DRIVE_BUS_IDE: 
+ at LIBHAL_DRIVE_BUS_SCSI: 
+ at LIBHAL_DRIVE_BUS_USB: 
+ at LIBHAL_DRIVE_BUS_IEEE1394: 
+ at LIBHAL_DRIVE_BUS_CCW: 
+
+<!-- ##### ENUM LibHalDriveCdromCaps ##### -->
+<para>
+
+</para>
+
+ at LIBHAL_DRIVE_CDROM_CAPS_CDROM: 
+ at LIBHAL_DRIVE_CDROM_CAPS_CDR: 
+ at LIBHAL_DRIVE_CDROM_CAPS_CDRW: 
+ at LIBHAL_DRIVE_CDROM_CAPS_DVDRAM: 
+ at LIBHAL_DRIVE_CDROM_CAPS_DVDROM: 
+ at LIBHAL_DRIVE_CDROM_CAPS_DVDR: 
+ at LIBHAL_DRIVE_CDROM_CAPS_DVDRW: 
+ at LIBHAL_DRIVE_CDROM_CAPS_DVDPLUSR: 
+ at LIBHAL_DRIVE_CDROM_CAPS_DVDPLUSRW: 
+ at LIBHAL_DRIVE_CDROM_CAPS_DVDPLUSRDL: 
+ at LIBHAL_DRIVE_CDROM_CAPS_DVDPLUSRWDL: 
+ at LIBHAL_DRIVE_CDROM_CAPS_BDROM: 
+ at LIBHAL_DRIVE_CDROM_CAPS_BDR: 
+ at LIBHAL_DRIVE_CDROM_CAPS_BDRE: 
+ at LIBHAL_DRIVE_CDROM_CAPS_HDDVDROM: 
+ at LIBHAL_DRIVE_CDROM_CAPS_HDDVDR: 
+ at LIBHAL_DRIVE_CDROM_CAPS_HDDVDRW: 
+
+<!-- ##### ENUM LibHalDriveType ##### -->
+<para>
+
+</para>
+
+ at LIBHAL_DRIVE_TYPE_REMOVABLE_DISK: 
+ at LIBHAL_DRIVE_TYPE_DISK: 
+ at LIBHAL_DRIVE_TYPE_CDROM: 
+ at LIBHAL_DRIVE_TYPE_FLOPPY: 
+ at LIBHAL_DRIVE_TYPE_TAPE: 
+ at LIBHAL_DRIVE_TYPE_COMPACT_FLASH: 
+ at LIBHAL_DRIVE_TYPE_MEMORY_STICK: 
+ at LIBHAL_DRIVE_TYPE_SMART_MEDIA: 
+ at LIBHAL_DRIVE_TYPE_SD_MMC: 
+ at LIBHAL_DRIVE_TYPE_CAMERA: 
+ at LIBHAL_DRIVE_TYPE_PORTABLE_AUDIO_PLAYER: 
+ at LIBHAL_DRIVE_TYPE_ZIP: 
+ at LIBHAL_DRIVE_TYPE_JAZ: 
+ at LIBHAL_DRIVE_TYPE_FLASHKEY: 
+
 <!-- ##### TYPEDEF LibHalPolicyContext ##### -->
 <para>
 
@@ -413,6 +468,40 @@ sysfs
 @LIBHAL_POLICY_RESULT_PERMISSON_DENIED: 
 @LIBHAL_POLICY_RESULT_NO_SUCH_POLICY: 
 
+<!-- ##### ENUM LibHalVolumeDiscType ##### -->
+<para>
+
+</para>
+
+ at LIBHAL_VOLUME_DISC_TYPE_CDROM: 
+ at LIBHAL_VOLUME_DISC_TYPE_CDR: 
+ at LIBHAL_VOLUME_DISC_TYPE_CDRW: 
+ at LIBHAL_VOLUME_DISC_TYPE_DVDROM: 
+ at LIBHAL_VOLUME_DISC_TYPE_DVDRAM: 
+ at LIBHAL_VOLUME_DISC_TYPE_DVDR: 
+ at LIBHAL_VOLUME_DISC_TYPE_DVDRW: 
+ at LIBHAL_VOLUME_DISC_TYPE_DVDPLUSR: 
+ at LIBHAL_VOLUME_DISC_TYPE_DVDPLUSRW: 
+ at LIBHAL_VOLUME_DISC_TYPE_DVDPLUSR_DL: 
+ at LIBHAL_VOLUME_DISC_TYPE_BDROM: 
+ at LIBHAL_VOLUME_DISC_TYPE_BDR: 
+ at LIBHAL_VOLUME_DISC_TYPE_BDRE: 
+ at LIBHAL_VOLUME_DISC_TYPE_HDDVDROM: 
+ at LIBHAL_VOLUME_DISC_TYPE_HDDVDR: 
+ at LIBHAL_VOLUME_DISC_TYPE_HDDVDRW: 
+
+<!-- ##### ENUM LibHalVolumeUsage ##### -->
+<para>
+
+</para>
+
+ at LIBHAL_VOLUME_USAGE_MOUNTABLE_FILESYSTEM: 
+ at LIBHAL_VOLUME_USAGE_PARTITION_TABLE: 
+ at LIBHAL_VOLUME_USAGE_RAID_MEMBER: 
+ at LIBHAL_VOLUME_USAGE_CRYPTO: 
+ at LIBHAL_VOLUME_USAGE_UNKNOWN: 
+ at LIBHAL_VOLUME_USAGE_OTHER: 
+
 <!-- ##### MACRO SB_BUFFER_SIZE ##### -->
 <para>
 
@@ -975,6 +1064,95 @@ sysfs
 
 @x: 
 
+<!-- ##### FUNCTION libhal_drive_find_all_volumes ##### -->
+<para>
+
+</para>
+
+ at hal_ctx: 
+ at drive: 
+ at num_volumes: 
+ at Returns: 
+
+<!-- ##### FUNCTION libhal_drive_from_udi ##### -->
+<para>
+
+</para>
+
+ at hal_ctx: 
+ at udi: 
+ at Returns: 
+
+<!-- ##### FUNCTION libhal_drive_policy_compute_icon_name ##### -->
+<para>
+
+</para>
+
+ at drive: 
+ at volume: 
+ at policy: 
+ at Returns: 
+
+<!-- ##### FUNCTION libhal_drive_policy_default_get_managed_keyword_primary ##### -->
+<para>
+
+</para>
+
+ at hal_ctx: 
+ at Returns: 
+
+<!-- ##### FUNCTION libhal_drive_policy_default_get_managed_keyword_secondary ##### -->
+<para>
+
+</para>
+
+ at hal_ctx: 
+ at Returns: 
+
+<!-- ##### FUNCTION libhal_drive_policy_default_use_managed_keyword ##### -->
+<para>
+
+</para>
+
+ at hal_ctx: 
+ at Returns: 
+
+<!-- ##### FUNCTION libhal_drive_policy_get_desired_mount_point ##### -->
+<para>
+
+</para>
+
+ at drive: 
+ at policy: 
+ at Returns: 
+
+<!-- ##### FUNCTION libhal_drive_policy_get_mount_fs ##### -->
+<para>
+
+</para>
+
+ at drive: 
+ at policy: 
+ at Returns: 
+
+<!-- ##### FUNCTION libhal_drive_policy_get_mount_options ##### -->
+<para>
+
+</para>
+
+ at drive: 
+ at policy: 
+ at Returns: 
+
+<!-- ##### FUNCTION libhal_drive_policy_is_mountable ##### -->
+<para>
+
+</para>
+
+ at drive: 
+ at policy: 
+ at Returns: 
+
 <!-- ##### FUNCTION libhal_policy_context_set_txt_source ##### -->
 <para>
 
@@ -1238,6 +1416,127 @@ sysfs
 @default_gid: 
 @Returns: 
 
+<!-- ##### FUNCTION libhal_storage_policy_free ##### -->
+<para>
+
+</para>
+
+ at policy: 
+
+<!-- ##### FUNCTION libhal_storage_policy_lookup_icon ##### -->
+<para>
+
+</para>
+
+ at policy: 
+ at icon: 
+ at Returns: 
+
+<!-- ##### FUNCTION libhal_storage_policy_set_icon_mapping ##### -->
+<para>
+
+</para>
+
+ at policy: 
+ at pairs: 
+
+<!-- ##### FUNCTION libhal_storage_policy_set_icon_path ##### -->
+<para>
+
+</para>
+
+ at policy: 
+ at icon: 
+ at path: 
+
+<!-- ##### FUNCTION libhal_volume_from_udi ##### -->
+<para>
+
+</para>
+
+ at hal_ctx: 
+ at udi: 
+ at Returns: 
+
+<!-- ##### FUNCTION libhal_volume_policy_compute_display_name ##### -->
+<para>
+
+</para>
+
+ at drive: 
+ at volume: 
+ at policy: 
+ at Returns: 
+
+<!-- ##### FUNCTION libhal_volume_policy_compute_icon_name ##### -->
+<para>
+
+</para>
+
+ at drive: 
+ at volume: 
+ at policy: 
+ at Returns: 
+
+<!-- ##### FUNCTION libhal_volume_policy_compute_size_as_string ##### -->
+<para>
+
+</para>
+
+ at volume: 
+ at Returns: 
+
+<!-- ##### FUNCTION libhal_volume_policy_get_desired_mount_point ##### -->
+<para>
+
+</para>
+
+ at drive: 
+ at volume: 
+ at policy: 
+ at Returns: 
+
+<!-- ##### FUNCTION libhal_volume_policy_get_mount_fs ##### -->
+<para>
+
+</para>
+
+ at drive: 
+ at volume: 
+ at policy: 
+ at Returns: 
+
+<!-- ##### FUNCTION libhal_volume_policy_get_mount_options ##### -->
+<para>
+
+</para>
+
+ at drive: 
+ at volume: 
+ at policy: 
+ at Returns: 
+
+<!-- ##### FUNCTION libhal_volume_policy_is_mountable ##### -->
+<para>
+
+</para>
+
+ at drive: 
+ at volume: 
+ at policy: 
+ at Returns: 
+
+<!-- ##### FUNCTION libhal_volume_policy_should_be_visible ##### -->
+<para>
+
+</para>
+
+ at drive: 
+ at volume: 
+ at policy: 
+ at target_mount_point: 
+ at Returns: 
+
 <!-- ##### FUNCTION lstat ##### -->
 <para>
 
diff --git a/doc/api/tmpl/libhal-storage.sgml b/doc/api/tmpl/libhal-storage.sgml
index ae28039..c99e3c2 100644
--- a/doc/api/tmpl/libhal-storage.sgml
+++ b/doc/api/tmpl/libhal-storage.sgml
@@ -151,108 +151,6 @@ libhal-storage
 @Returns: 
 
 
-<!-- ##### FUNCTION libhal_storage_policy_free ##### -->
-<para>
-
-</para>
-
- at policy: 
-
-
-<!-- ##### FUNCTION libhal_storage_policy_set_icon_path ##### -->
-<para>
-
-</para>
-
- at policy: 
- at icon: 
- at path: 
-
-
-<!-- ##### FUNCTION libhal_storage_policy_set_icon_mapping ##### -->
-<para>
-
-</para>
-
- at policy: 
- at pairs: 
-
-
-<!-- ##### FUNCTION libhal_storage_policy_lookup_icon ##### -->
-<para>
-
-</para>
-
- at policy: 
- at icon: 
- at Returns: 
-
-
-<!-- ##### ENUM LibHalDriveBus ##### -->
-<para>
-
-</para>
-
- at LIBHAL_DRIVE_BUS_UNKNOWN: 
- at LIBHAL_DRIVE_BUS_IDE: 
- at LIBHAL_DRIVE_BUS_SCSI: 
- at LIBHAL_DRIVE_BUS_USB: 
- at LIBHAL_DRIVE_BUS_IEEE1394: 
- at LIBHAL_DRIVE_BUS_CCW: 
-
-<!-- ##### ENUM LibHalDriveType ##### -->
-<para>
-
-</para>
-
- at LIBHAL_DRIVE_TYPE_REMOVABLE_DISK: 
- at LIBHAL_DRIVE_TYPE_DISK: 
- at LIBHAL_DRIVE_TYPE_CDROM: 
- at LIBHAL_DRIVE_TYPE_FLOPPY: 
- at LIBHAL_DRIVE_TYPE_TAPE: 
- at LIBHAL_DRIVE_TYPE_COMPACT_FLASH: 
- at LIBHAL_DRIVE_TYPE_MEMORY_STICK: 
- at LIBHAL_DRIVE_TYPE_SMART_MEDIA: 
- at LIBHAL_DRIVE_TYPE_SD_MMC: 
- at LIBHAL_DRIVE_TYPE_CAMERA: 
- at LIBHAL_DRIVE_TYPE_PORTABLE_AUDIO_PLAYER: 
- at LIBHAL_DRIVE_TYPE_ZIP: 
- at LIBHAL_DRIVE_TYPE_JAZ: 
- at LIBHAL_DRIVE_TYPE_FLASHKEY: 
-
-<!-- ##### ENUM LibHalDriveCdromCaps ##### -->
-<para>
-
-</para>
-
- at LIBHAL_DRIVE_CDROM_CAPS_CDROM: 
- at LIBHAL_DRIVE_CDROM_CAPS_CDR: 
- at LIBHAL_DRIVE_CDROM_CAPS_CDRW: 
- at LIBHAL_DRIVE_CDROM_CAPS_DVDRAM: 
- at LIBHAL_DRIVE_CDROM_CAPS_DVDROM: 
- at LIBHAL_DRIVE_CDROM_CAPS_DVDR: 
- at LIBHAL_DRIVE_CDROM_CAPS_DVDRW: 
- at LIBHAL_DRIVE_CDROM_CAPS_DVDPLUSR: 
- at LIBHAL_DRIVE_CDROM_CAPS_DVDPLUSRW: 
- at LIBHAL_DRIVE_CDROM_CAPS_DVDPLUSRDL: 
- at LIBHAL_DRIVE_CDROM_CAPS_DVDPLUSRWDL: 
- at LIBHAL_DRIVE_CDROM_CAPS_BDROM: 
- at LIBHAL_DRIVE_CDROM_CAPS_BDR: 
- at LIBHAL_DRIVE_CDROM_CAPS_BDRE: 
- at LIBHAL_DRIVE_CDROM_CAPS_HDDVDROM: 
- at LIBHAL_DRIVE_CDROM_CAPS_HDDVDR: 
- at LIBHAL_DRIVE_CDROM_CAPS_HDDVDRW: 
-
-<!-- ##### FUNCTION libhal_drive_from_udi ##### -->
-<para>
-
-</para>
-
- at hal_ctx: 
- at udi: 
- at Returns: 
-
-
 <!-- ##### FUNCTION libhal_drive_from_device_file ##### -->
 <para>
 
@@ -476,69 +374,6 @@ libhal-storage
 
 @drive: 
 @volume: 
- at policy: 
- at Returns: 
-
-
-<!-- ##### FUNCTION libhal_drive_policy_compute_icon_name ##### -->
-<para>
-
-</para>
-
- at drive: 
- at volume: 
- at policy: 
- at Returns: 
-
-
-<!-- ##### FUNCTION libhal_drive_policy_is_mountable ##### -->
-<para>
-
-</para>
-
- at drive: 
- at policy: 
- at Returns: 
-
-
-<!-- ##### FUNCTION libhal_drive_policy_get_desired_mount_point ##### -->
-<para>
-
-</para>
-
- at drive: 
- at policy: 
- at Returns: 
-
-
-<!-- ##### FUNCTION libhal_drive_policy_get_mount_options ##### -->
-<para>
-
-</para>
-
- at drive: 
- at policy: 
- at Returns: 
-
-
-<!-- ##### FUNCTION libhal_drive_policy_get_mount_fs ##### -->
-<para>
-
-</para>
-
- at drive: 
- at policy: 
- at Returns: 
-
-
-<!-- ##### FUNCTION libhal_drive_find_all_volumes ##### -->
-<para>
-
-</para>
-
- at hal_ctx: 
- at drive: 
- at num_volumes: 
 @Returns: 
 
 
@@ -547,78 +382,6 @@ libhal-storage
 
 </para>
 
- at hal_ctx: 
- at Returns: 
-
-
-<!-- ##### FUNCTION libhal_drive_policy_default_use_managed_keyword ##### -->
-<para>
-
-</para>
-
- at hal_ctx: 
- at Returns: 
-
-
-<!-- ##### FUNCTION libhal_drive_policy_default_get_managed_keyword_primary ##### -->
-<para>
-
-</para>
-
- at hal_ctx: 
- at Returns: 
-
-
-<!-- ##### FUNCTION libhal_drive_policy_default_get_managed_keyword_secondary ##### -->
-<para>
-
-</para>
-
- at hal_ctx: 
- at Returns: 
-
-
-<!-- ##### ENUM LibHalVolumeUsage ##### -->
-<para>
-
-</para>
-
- at LIBHAL_VOLUME_USAGE_MOUNTABLE_FILESYSTEM: 
- at LIBHAL_VOLUME_USAGE_PARTITION_TABLE: 
- at LIBHAL_VOLUME_USAGE_RAID_MEMBER: 
- at LIBHAL_VOLUME_USAGE_CRYPTO: 
- at LIBHAL_VOLUME_USAGE_UNKNOWN: 
- at LIBHAL_VOLUME_USAGE_OTHER: 
-
-<!-- ##### ENUM LibHalVolumeDiscType ##### -->
-<para>
-
-</para>
-
- at LIBHAL_VOLUME_DISC_TYPE_CDROM: 
- at LIBHAL_VOLUME_DISC_TYPE_CDR: 
- at LIBHAL_VOLUME_DISC_TYPE_CDRW: 
- at LIBHAL_VOLUME_DISC_TYPE_DVDROM: 
- at LIBHAL_VOLUME_DISC_TYPE_DVDRAM: 
- at LIBHAL_VOLUME_DISC_TYPE_DVDR: 
- at LIBHAL_VOLUME_DISC_TYPE_DVDRW: 
- at LIBHAL_VOLUME_DISC_TYPE_DVDPLUSR: 
- at LIBHAL_VOLUME_DISC_TYPE_DVDPLUSRW: 
- at LIBHAL_VOLUME_DISC_TYPE_DVDPLUSR_DL: 
- at LIBHAL_VOLUME_DISC_TYPE_BDROM: 
- at LIBHAL_VOLUME_DISC_TYPE_BDR: 
- at LIBHAL_VOLUME_DISC_TYPE_BDRE: 
- at LIBHAL_VOLUME_DISC_TYPE_HDDVDROM: 
- at LIBHAL_VOLUME_DISC_TYPE_HDDVDR: 
- at LIBHAL_VOLUME_DISC_TYPE_HDDVDRW: 
-
-<!-- ##### FUNCTION libhal_volume_from_udi ##### -->
-<para>
-
-</para>
-
- at hal_ctx: 
- at udi: 
 @Returns: 
 
 
@@ -929,90 +692,3 @@ libhal-storage
 @Returns: 
 
 
-<!-- ##### FUNCTION libhal_volume_policy_compute_size_as_string ##### -->
-<para>
-
-</para>
-
- at volume: 
- at Returns: 
-
-
-<!-- ##### FUNCTION libhal_volume_policy_compute_display_name ##### -->
-<para>
-
-</para>
-
- at drive: 
- at volume: 
- at policy: 
- at Returns: 
-
-
-<!-- ##### FUNCTION libhal_volume_policy_compute_icon_name ##### -->
-<para>
-
-</para>
-
- at drive: 
- at volume: 
- at policy: 
- at Returns: 
-
-
-<!-- ##### FUNCTION libhal_volume_policy_should_be_visible ##### -->
-<para>
-
-</para>
-
- at drive: 
- at volume: 
- at policy: 
- at target_mount_point: 
- at Returns: 
-
-
-<!-- ##### FUNCTION libhal_volume_policy_is_mountable ##### -->
-<para>
-
-</para>
-
- at drive: 
- at volume: 
- at policy: 
- at Returns: 
-
-
-<!-- ##### FUNCTION libhal_volume_policy_get_desired_mount_point ##### -->
-<para>
-
-</para>
-
- at drive: 
- at volume: 
- at policy: 
- at Returns: 
-
-
-<!-- ##### FUNCTION libhal_volume_policy_get_mount_options ##### -->
-<para>
-
-</para>
-
- at drive: 
- at volume: 
- at policy: 
- at Returns: 
-
-
-<!-- ##### FUNCTION libhal_volume_policy_get_mount_fs ##### -->
-<para>
-
-</para>
-
- at drive: 
- at volume: 
- at policy: 
- at Returns: 
-
-
diff --git a/doc/spec/hal-spec-properties.xml b/doc/spec/hal-spec-properties.xml
index c3ff522..77fac0b 100644
--- a/doc/spec/hal-spec-properties.xml
+++ b/doc/spec/hal-spec-properties.xml
@@ -2288,9 +2288,7 @@
               <entry>partitiontable</entry>
               <entry></entry>
               <entry>
-	        The volume contains a partitiontable. If an MS-DOS extended
-		partition table is found, then <literal>volume.fstype</literal> 
-		will be <literal>msdos_extended_partitiontable</literal>.
+	        The volume contains a partitiontable.
 	      </entry>
             </row>
             <row>
@@ -2315,7 +2313,7 @@
               <entry>
                 <literal>volume.fstype</literal> (string)
               </entry>
-              <entry>examples: ext3, vfat, msdos_extended_partitiontable</entry>
+              <entry>examples: ext3, vfat</entry>
               <entry>Yes (is blank if the type is unknown)</entry>
               <entry>The specific type of either the file system or what the volume is used for, cf. volume.fsusage</entry>
             </row>
@@ -2405,6 +2403,7 @@
                 If the volume stems from the Linux Device Mapper this property is set to <literal>TRUE</literal>.
               </entry>
             </row>
+
             <row>
               <entry>
                 <literal>volume.partition.number</literal> (int)
@@ -2418,53 +2417,188 @@
                 The number of the partition.
               </entry>
             </row>
+
+
             <row>
               <entry>
-                <literal>volume.partition.msdos_part_table_type</literal> (int)
+                <literal>volume.partition.label</literal> (string)
               </entry>
-              <entry>examples: 0x83, 0xfd, 0x8e</entry>
+              <entry></entry>
               <entry>
-                No
+                If, and only if, <literal>volume.is_partition</literal>
+                is set to <literal>TRUE</literal>.
               </entry>
               <entry>
-                If available, this is the partition type if the disk for which
-                this volume stems from is using an MS-DOS-style partition table.
+	        Label of partition. Only available for "apm" and "gpt"
+		partition tables. Note that this is not the same as the
+		file system label defined in <literal>volume.label</literal>.
               </entry>
             </row>
             <row>
               <entry>
-                <literal>volume.partition.msdos_part_table_start</literal> (uint64)
+                <literal>volume.partition.uuid</literal> (string)
               </entry>
               <entry></entry>
               <entry>
-                No
+                If, and only if, <literal>volume.is_partition</literal>
+                is set to <literal>TRUE</literal>.
               </entry>
               <entry>
-                If available, this is the partition start offset if the disk for which
-                this volume stems from is using an MS-DOS-style partition table.
+                The UUID or GUID of the partition table entry. Only available for
+		"gpt" partition tables.
               </entry>
             </row>
+
             <row>
               <entry>
-                <literal>volume.partition.msdos_part_table_size</literal> (uint64)
+                <literal>volume.partition.scheme</literal> (string)
               </entry>
               <entry></entry>
               <entry>
-                No
+                If, and only if, <literal>volume.is_partition</literal>
+                is set to <literal>TRUE</literal>.
               </entry>
               <entry>
-                If available, this is the partition size if the disk for which
-                this volume stems from is using an MS-DOS-style partition table.
-		This information is derived from the partition table so it might
-		not be reliable and match e.g. <literal>volume.size</literal>.
-		Specifically, for MS-DOS extended partition tables, this number
-		will be larger as the actual volume is only e.g. 1 kilobyte
-		(e.g. <literal>volume.size</literal>) while 
-		<literal>volume.partition.msdos_part_table_size</literal>
-		will be the size enclosing all the logical partitions.
+                The scheme of the partition table this entry is part of.
+		Note that this is not necessarily the same as 
+		<literal>storage.partitioning_scheme</literal> as 
+		some partition tables can embed other partition tables.
               </entry>
             </row>
             <row>
+              <entry></entry>
+              <entry>mbr</entry>
+              <entry></entry>
+              <entry>
+                Master Boot Record
+              </entry>
+            </row>
+            <row>
+              <entry></entry>
+              <entry>embr</entry>
+              <entry></entry>
+              <entry>
+                Extended Master Boot Record
+              </entry>
+            </row>
+            <row>
+              <entry></entry>
+              <entry>gpt</entry>
+              <entry></entry>
+              <entry>
+                GUID Partition Table as defined by EFI
+              </entry>
+            </row>
+            <row>
+              <entry></entry>
+              <entry>apm</entry>
+              <entry></entry>
+              <entry>
+                Apple Partition Map
+              </entry>
+            </row>
+
+            <row>
+              <entry>
+                <literal>volume.partition.type</literal> (string)
+              </entry>
+              <entry></entry>
+              <entry>
+                If, and only if, <literal>volume.is_partition</literal>
+                is set to <literal>TRUE</literal>.
+              </entry>
+              <entry>
+                The type of the partition table entry. Depends on 
+		<literal>volume.partition.scheme</literal>.
+              </entry>
+            </row>
+            <row>
+              <entry></entry>
+              <entry><literal>mbr</literal> and <literal>embr</literal> entries</entry>
+              <entry></entry>
+              <entry>
+	        The hexadecimal encoding of the 8-bit partition type, see 
+		http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
+		for a list. For example the Linux partition type is represented
+		as the string "0x83".
+              </entry>
+            </row>
+            <row>
+              <entry></entry>
+              <entry><literal>gpt</literal> entries</entry>
+              <entry></entry>
+              <entry>
+	        The GUID encoded as a string. See http://en.wikipedia.org/wiki/GUID_Partition_Table
+		for a list of well-known GUID's.
+              </entry>
+            </row>
+            <row>
+              <entry></entry>
+              <entry><literal>apm</literal> entries</entry>
+              <entry></entry>
+              <entry>
+	        Defined in http://developer.apple.com/documentation/mac/Devices/Devices-126.html.
+		Also note that for FAT file systems, it appears that "DOS_FAT_32", "DOS_FAT_16" 
+		and "DOS_FAT_12" are also recognized under Mac OS X (I've tested this too) cf. 
+		http://lists.apple.com/archives/Darwin-drivers/2003/May/msg00021.html
+              </entry>
+            </row>
+
+            <row>
+              <entry>
+                <literal>volume.partition.flags</literal> (strlist)
+              </entry>
+              <entry></entry>
+              <entry>
+                If, and only if, <literal>volume.is_partition</literal>
+                is set to <literal>TRUE</literal>.
+              </entry>
+              <entry>
+	        Flags conveying specific information about the partition
+		entry. Dependent on the partitioning scheme.
+              </entry>
+            </row>
+            <row>
+              <entry></entry>
+              <entry><literal>mbr</literal> and <literal>embr</literal> entries</entry>
+              <entry></entry>
+              <entry>
+	        Only one flag, "boot", is defined. This is used by some BIOS'es and
+		boot loaders to populate a boot menu. It means that a partition is
+		bootable.
+              </entry>
+            </row>
+            <row>
+              <entry></entry>
+              <entry><literal>gpt</literal> entries</entry>
+              <entry></entry>
+              <entry>
+	        Only the flag "required" is recognized. This corresponds to
+		bit 0 of the attibutes (at offset 48), meaning 
+		"Required for the platform to function. The system cannot 
+		function normally if this partition is removed. This
+		partition should be considered as part of the hardware of the
+		system, and if it is removed the system may not boot. It may
+		contain diagnostics, recovery tools, or other code or data that is
+		critical to the functioning of a system independent of any OS."
+              </entry>
+            </row>
+            <row>
+              <entry></entry>
+              <entry><literal>apm</literal> entries</entry>
+              <entry></entry>
+              <entry>
+	        The following flags are recognized: 
+		"allocated" if the partition is already allocated; and
+		"in_use" if the partition is in use; may be cleared after a system reset; and
+		"boot" if partition contains valid boot information; and
+		"allow_read" if partition allows reading; and
+		"allow_write"; if partition allows writing; and
+		"boot_code_is_pic"; if boot code is position independent
+              </entry>
+            </row>
+
+            <row>
               <entry>
                 <literal>volume.partition.media_size</literal> (uint64)
               </entry>
@@ -3026,6 +3160,32 @@
             </row>
             <row>
               <entry>
+	        <literal>storage.partitioning_scheme</literal> (string)
+              </entry>
+              <entry></entry>
+              <entry>Only when media is inserted and is partitioned</entry>
+              <entry>The partitioning scheme of the media.</entry>
+            </row>
+            <row>
+              <entry></entry>
+              <entry>mbr</entry>
+              <entry></entry>
+              <entry>Master Boot Record partitioning scheme used in most PC's</entry>
+            </row>
+            <row>
+              <entry></entry>
+              <entry>gpt</entry>
+              <entry></entry>
+              <entry>GUID Partitioning Table as defined by UEFI</entry>
+            </row>
+            <row>
+              <entry></entry>
+              <entry>apm</entry>
+              <entry></entry>
+              <entry>Apple Partition Map, used in non-Intel Apple computers</entry>
+            </row>
+            <row>
+              <entry>
 	        <literal>storage.size</literal> (uint64)
               </entry>
               <entry></entry>
diff --git a/doc/spec/hal-spec.html b/doc/spec/hal-spec.html
index e77fde1..561d03e 100644
--- a/doc/spec/hal-spec.html
+++ b/doc/spec/hal-spec.html
@@ -609,14 +609,24 @@ HREF="#dbus-api"
 ><DL
 ><DT
 ><A
-HREF="#AEN4036"
+HREF="#AEN4328"
 >Interface org.freedesktop.Hal.Manager</A
 ></DT
 ><DT
 ><A
-HREF="#AEN4055"
+HREF="#AEN4347"
 >Interface org.freedesktop.Hal.Device</A
 ></DT
+><DT
+><A
+HREF="#AEN4356"
+>Interface org.freedesktop.Hal.Device.Volume</A
+></DT
+><DT
+><A
+HREF="#AEN4360"
+>Interface org.freedesktop.Hal.Device.Storage</A
+></DT
 ></DL
 ></DD
 ><DT
@@ -3159,6 +3169,120 @@ CLASS="literal"
 ><TD
 >SCSI Logical Unit Number</TD
 ></TR
+><TR
+><TD
+>&#13;                <TT
+CLASS="literal"
+>scsi.type</TT
+> (string)
+              </TD
+><TD
+>Example: disk</TD
+><TD
+>Yes</TD
+><TD
+>SCSI device type</TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+>cdrom</TD
+><TD
+>&nbsp;</TD
+><TD
+>This is a SCSI cdrom device.</TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+>comm</TD
+><TD
+>&nbsp;</TD
+><TD
+>This is a SCSI communication device.</TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+>disk</TD
+><TD
+>&nbsp;</TD
+><TD
+>This is a SCSI disk device.</TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+>medium_changer</TD
+><TD
+>&nbsp;</TD
+><TD
+>This is a SCSI media changer (e.g. for CD/Tape).</TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+>printer</TD
+><TD
+>&nbsp;</TD
+><TD
+>This is a SCSI printer.</TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+>processor</TD
+><TD
+>&nbsp;</TD
+><TD
+>This is a SCSI processor device.</TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+>raid</TD
+><TD
+>&nbsp;</TD
+><TD
+>This is a SCSI raid device.</TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+>scanner</TD
+><TD
+>&nbsp;</TD
+><TD
+>This is a SCSI scanner.</TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+>tape</TD
+><TD
+>&nbsp;</TD
+><TD
+>This is a SCSI tape device.</TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+>unknown</TD
+><TD
+>&nbsp;</TD
+><TD
+>The type of this SCSI device is unknwon.</TD
+></TR
 ></TBODY
 ></TABLE
 ><P
@@ -3193,7 +3317,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN804"
+NAME="AEN860"
 ></A
 ><TABLE
 BORDER="1"
@@ -3318,7 +3442,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN849"
+NAME="AEN905"
 ></A
 ><TABLE
 BORDER="1"
@@ -3442,7 +3566,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN894"
+NAME="AEN950"
 ></A
 ><TABLE
 BORDER="1"
@@ -3511,7 +3635,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN915"
+NAME="AEN971"
 ></A
 ><TABLE
 BORDER="1"
@@ -3580,7 +3704,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN936"
+NAME="AEN992"
 ></A
 ><TABLE
 BORDER="1"
@@ -3763,7 +3887,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN1005"
+NAME="AEN1061"
 ></A
 ><TABLE
 BORDER="1"
@@ -3953,7 +4077,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN1079"
+NAME="AEN1135"
 ></A
 ><TABLE
 BORDER="1"
@@ -4045,7 +4169,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN1111"
+NAME="AEN1167"
 ></A
 ><TABLE
 BORDER="1"
@@ -4119,7 +4243,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN1136"
+NAME="AEN1192"
 ></A
 ><TABLE
 BORDER="1"
@@ -4230,7 +4354,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN1175"
+NAME="AEN1231"
 ></A
 ><TABLE
 BORDER="1"
@@ -4330,7 +4454,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN1209"
+NAME="AEN1265"
 ></A
 ><TABLE
 BORDER="1"
@@ -4402,7 +4526,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN1234"
+NAME="AEN1290"
 ></A
 ><TABLE
 BORDER="1"
@@ -4687,7 +4811,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN1343"
+NAME="AEN1399"
 ></A
 ><TABLE
 BORDER="1"
@@ -4773,7 +4897,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN1374"
+NAME="AEN1430"
 ></A
 ><TABLE
 BORDER="1"
@@ -4859,7 +4983,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN1405"
+NAME="AEN1461"
 ></A
 ><TABLE
 BORDER="1"
@@ -5016,7 +5140,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN1465"
+NAME="AEN1521"
 ></A
 ><TABLE
 BORDER="1"
@@ -5074,7 +5198,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN1484"
+NAME="AEN1540"
 ></A
 ><TABLE
 BORDER="1"
@@ -5160,7 +5284,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN1512"
+NAME="AEN1568"
 ></A
 ><TABLE
 BORDER="1"
@@ -5339,7 +5463,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN1568"
+NAME="AEN1624"
 ></A
 ><TABLE
 BORDER="1"
@@ -5460,7 +5584,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN1606"
+NAME="AEN1662"
 ></A
 ><TABLE
 BORDER="1"
@@ -5579,15 +5703,7 @@ CLASS="literal"
 ><TD
 >&nbsp;</TD
 ><TD
->&#13;	        The volume contains a partitiontable. If an MS-DOS extended
-		partition table is found, then <TT
-CLASS="literal"
->volume.fstype</TT
-> 
-		will be <TT
-CLASS="literal"
->msdos_extended_partitiontable</TT
->.
+>&#13;	        The volume contains a partitiontable.
 	      </TD
 ></TR
 ><TR
@@ -5628,7 +5744,7 @@ CLASS="literal"
 > (string)
               </TD
 ><TD
->examples: ext3, vfat, msdos_extended_partitiontable</TD
+>examples: ext3, vfat</TD
 ><TD
 >Yes (is blank if the type is unknown)</TD
 ><TD
@@ -5805,78 +5921,136 @@ CLASS="literal"
 ><TD
 >&#13;                <TT
 CLASS="literal"
->volume.partition.msdos_part_table_type</TT
-> (int)
+>volume.partition.label</TT
+> (string)
               </TD
 ><TD
->examples: 0x83, 0xfd, 0x8e</TD
+>&nbsp;</TD
 ><TD
->&#13;                No
+>&#13;                If, and only if, <TT
+CLASS="literal"
+>volume.is_partition</TT
+>
+                is set to <TT
+CLASS="literal"
+>TRUE</TT
+>.
               </TD
 ><TD
->&#13;                If available, this is the partition type if the disk for which
-                this volume stems from is using an MS-DOS-style partition table.
+>&#13;	        Label of partition. Only available for "apm" and "gpt"
+		partition tables. Note that this is not the same as the
+		file system label defined in <TT
+CLASS="literal"
+>volume.label</TT
+>.
               </TD
 ></TR
 ><TR
 ><TD
 >&#13;                <TT
 CLASS="literal"
->volume.partition.msdos_part_table_start</TT
-> (uint64)
+>volume.partition.uuid</TT
+> (string)
               </TD
 ><TD
 >&nbsp;</TD
 ><TD
->&#13;                No
+>&#13;                If, and only if, <TT
+CLASS="literal"
+>volume.is_partition</TT
+>
+                is set to <TT
+CLASS="literal"
+>TRUE</TT
+>.
               </TD
 ><TD
->&#13;                If available, this is the partition start offset if the disk for which
-                this volume stems from is using an MS-DOS-style partition table.
+>&#13;                The UUID or GUID of the partition table entry. Only available for
+		"gpt" partition tables.
               </TD
 ></TR
 ><TR
 ><TD
 >&#13;                <TT
 CLASS="literal"
->volume.partition.msdos_part_table_size</TT
-> (uint64)
+>volume.partition.scheme</TT
+> (string)
               </TD
 ><TD
 >&nbsp;</TD
 ><TD
->&#13;                No
-              </TD
-><TD
->&#13;                If available, this is the partition size if the disk for which
-                this volume stems from is using an MS-DOS-style partition table.
-		This information is derived from the partition table so it might
-		not be reliable and match e.g. <TT
+>&#13;                If, and only if, <TT
 CLASS="literal"
->volume.size</TT
->.
-		Specifically, for MS-DOS extended partition tables, this number
-		will be larger as the actual volume is only e.g. 1 kilobyte
-		(e.g. <TT
+>volume.is_partition</TT
+>
+                is set to <TT
 CLASS="literal"
->volume.size</TT
->) while 
+>TRUE</TT
+>.
+              </TD
+><TD
+>&#13;                The scheme of the partition table this entry is part of.
+		Note that this is not necessarily the same as 
 		<TT
 CLASS="literal"
->volume.partition.msdos_part_table_size</TT
->
-		will be the size enclosing all the logical partitions.
+>storage.partitioning_scheme</TT
+> as 
+		some partition tables can embed other partition tables.
+              </TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+>mbr</TD
+><TD
+>&nbsp;</TD
+><TD
+>&#13;                Master Boot Record
+              </TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+>embr</TD
+><TD
+>&nbsp;</TD
+><TD
+>&#13;                Extended Master Boot Record
+              </TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+>gpt</TD
+><TD
+>&nbsp;</TD
+><TD
+>&#13;                GUID Partition Table as defined by EFI
+              </TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+>apm</TD
+><TD
+>&nbsp;</TD
+><TD
+>&#13;                Apple Partition Map
               </TD
 ></TR
 ><TR
 ><TD
 >&#13;                <TT
 CLASS="literal"
->volume.partition.media_size</TT
-> (uint64)
+>volume.partition.type</TT
+> (string)
               </TD
 ><TD
->example: 500107862016</TD
+>&nbsp;</TD
 ><TD
 >&#13;                If, and only if, <TT
 CLASS="literal"
@@ -5888,18 +6062,74 @@ CLASS="literal"
 >.
               </TD
 ><TD
->&#13;                If available, size of the current media or the fixed disk in the storage device.
+>&#13;                The type of the partition table entry. Depends on 
+		<TT
+CLASS="literal"
+>volume.partition.scheme</TT
+>.
+              </TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+><TT
+CLASS="literal"
+>mbr</TT
+> and <TT
+CLASS="literal"
+>embr</TT
+> entries</TD
+><TD
+>&nbsp;</TD
+><TD
+>&#13;	        The hexadecimal encoding of the 8-bit partition type, see 
+		http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
+		for a list. For example the Linux partition type is represented
+		as the string "0x83".
+              </TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+><TT
+CLASS="literal"
+>gpt</TT
+> entries</TD
+><TD
+>&nbsp;</TD
+><TD
+>&#13;	        The GUID encoded as a string. See http://en.wikipedia.org/wiki/GUID_Partition_Table
+		for a list of well-known GUID's.
+              </TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+><TT
+CLASS="literal"
+>apm</TT
+> entries</TD
+><TD
+>&nbsp;</TD
+><TD
+>&#13;	        Defined in http://developer.apple.com/documentation/mac/Devices/Devices-126.html.
+		Also note that for FAT file systems, it appears that "DOS_FAT_32", "DOS_FAT_16" 
+		and "DOS_FAT_12" are also recognized under Mac OS X (I've tested this too) cf. 
+		http://lists.apple.com/archives/Darwin-drivers/2003/May/msg00021.html
               </TD
 ></TR
 ><TR
 ><TD
 >&#13;                <TT
 CLASS="literal"
->volume.partition.start</TT
-> (uint64)
+>volume.partition.flags</TT
+> (strlist)
               </TD
 ><TD
->example: 32256</TD
+>&nbsp;</TD
 ><TD
 >&#13;                If, and only if, <TT
 CLASS="literal"
@@ -5911,31 +6141,138 @@ CLASS="literal"
 >.
               </TD
 ><TD
->&#13;                If available, the offset where the physical partition starts on the media or the fixed disk in the storage device.
+>&#13;	        Flags conveying specific information about the partition
+		entry. Dependent on the partitioning scheme.
               </TD
 ></TR
-></TBODY
-></TABLE
-><P
-></P
-></DIV
-><P
->&#13;        Device objects with this capability may emit the following
-        device conditions
-      </P
-><DIV
-CLASS="informaltable"
-><P
-></P
-><A
-NAME="AEN1781"
-></A
-><TABLE
-BORDER="1"
-BGCOLOR="#E0E0E0"
-CELLSPACING="0"
-CELLPADDING="4"
-CLASS="CALSTABLE"
+><TR
+><TD
+>&nbsp;</TD
+><TD
+><TT
+CLASS="literal"
+>mbr</TT
+> and <TT
+CLASS="literal"
+>embr</TT
+> entries</TD
+><TD
+>&nbsp;</TD
+><TD
+>&#13;	        Only one flag, "boot", is defined. This is used by some BIOS'es and
+		boot loaders to populate a boot menu. It means that a partition is
+		bootable.
+              </TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+><TT
+CLASS="literal"
+>gpt</TT
+> entries</TD
+><TD
+>&nbsp;</TD
+><TD
+>&#13;	        Only the flag "required" is recognized. This corresponds to
+		bit 0 of the attibutes (at offset 48), meaning 
+		"Required for the platform to function. The system cannot 
+		function normally if this partition is removed. This
+		partition should be considered as part of the hardware of the
+		system, and if it is removed the system may not boot. It may
+		contain diagnostics, recovery tools, or other code or data that is
+		critical to the functioning of a system independent of any OS."
+              </TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+><TT
+CLASS="literal"
+>apm</TT
+> entries</TD
+><TD
+>&nbsp;</TD
+><TD
+>&#13;	        The following flags are recognized: 
+		"allocated" if the partition is already allocated; and
+		"in_use" if the partition is in use; may be cleared after a system reset; and
+		"boot" if partition contains valid boot information; and
+		"allow_read" if partition allows reading; and
+		"allow_write"; if partition allows writing; and
+		"boot_code_is_pic"; if boot code is position independent
+              </TD
+></TR
+><TR
+><TD
+>&#13;                <TT
+CLASS="literal"
+>volume.partition.media_size</TT
+> (uint64)
+              </TD
+><TD
+>example: 500107862016</TD
+><TD
+>&#13;                If, and only if, <TT
+CLASS="literal"
+>volume.is_partition</TT
+>
+                is set to <TT
+CLASS="literal"
+>TRUE</TT
+>.
+              </TD
+><TD
+>&#13;                If available, size of the current media or the fixed disk in the storage device.
+              </TD
+></TR
+><TR
+><TD
+>&#13;                <TT
+CLASS="literal"
+>volume.partition.start</TT
+> (uint64)
+              </TD
+><TD
+>example: 32256</TD
+><TD
+>&#13;                If, and only if, <TT
+CLASS="literal"
+>volume.is_partition</TT
+>
+                is set to <TT
+CLASS="literal"
+>TRUE</TT
+>.
+              </TD
+><TD
+>&#13;                If available, the offset where the physical partition starts on the media or the fixed disk in the storage device.
+              </TD
+></TR
+></TBODY
+></TABLE
+><P
+></P
+></DIV
+><P
+>&#13;        Device objects with this capability may emit the following
+        device conditions
+      </P
+><DIV
+CLASS="informaltable"
+><P
+></P
+><A
+NAME="AEN1915"
+></A
+><TABLE
+BORDER="1"
+BGCOLOR="#E0E0E0"
+CELLSPACING="0"
+CELLPADDING="4"
+CLASS="CALSTABLE"
 ><THEAD
 ><TR
 ><TH
@@ -6068,7 +6405,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN1824"
+NAME="AEN1958"
 ></A
 ><TABLE
 BORDER="1"
@@ -6242,7 +6579,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN1882"
+NAME="AEN2016"
 ></A
 ><TABLE
 BORDER="1"
@@ -6624,7 +6961,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN2043"
+NAME="AEN2177"
 ></A
 ><TABLE
 BORDER="1"
@@ -6874,6 +7211,64 @@ CLASS="literal"
 ><TD
 >&#13;	        <TT
 CLASS="literal"
+>storage.removable.media_size</TT
+> (uint64)
+              </TD
+><TD
+>&nbsp;</TD
+><TD
+>Yes</TD
+><TD
+>Size of media in storage device. Available only if media have been detected in storage device.</TD
+></TR
+><TR
+><TD
+>&#13;	        <TT
+CLASS="literal"
+>storage.partitioning_scheme</TT
+> (string)
+              </TD
+><TD
+>&nbsp;</TD
+><TD
+>Only when media is inserted and is partitioned</TD
+><TD
+>The partitioning scheme of the media.</TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+>mbr</TD
+><TD
+>&nbsp;</TD
+><TD
+>Master Boot Record partitioning scheme used in most PC's</TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+>gpt</TD
+><TD
+>&nbsp;</TD
+><TD
+>GUID Partitioning Table as defined by UEFI</TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+>apm</TD
+><TD
+>&nbsp;</TD
+><TD
+>Apple Partition Map, used in non-Intel Apple computers</TD
+></TR
+><TR
+><TD
+>&#13;	        <TT
+CLASS="literal"
 >storage.size</TT
 > (uint64)
               </TD
@@ -7153,7 +7548,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN2249"
+NAME="AEN2410"
 ></A
 ><TABLE
 BORDER="1"
@@ -7487,7 +7882,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN2383"
+NAME="AEN2544"
 ></A
 ><TABLE
 BORDER="1"
@@ -7647,7 +8042,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN2441"
+NAME="AEN2602"
 ></A
 ><TABLE
 BORDER="1"
@@ -7783,7 +8178,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN2483"
+NAME="AEN2644"
 ></A
 ><TABLE
 BORDER="1"
@@ -7855,7 +8250,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN2505"
+NAME="AEN2666"
 ></A
 ><TABLE
 BORDER="1"
@@ -7921,7 +8316,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN2525"
+NAME="AEN2686"
 ></A
 ><TABLE
 BORDER="1"
@@ -7985,7 +8380,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN2545"
+NAME="AEN2706"
 ></A
 ><TABLE
 BORDER="1"
@@ -8129,7 +8524,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN2595"
+NAME="AEN2756"
 ></A
 ><TABLE
 BORDER="1"
@@ -8344,7 +8739,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN2667"
+NAME="AEN2828"
 ></A
 ><TABLE
 BORDER="1"
@@ -8455,6 +8850,89 @@ CLASS="literal"
 ><TD
 >&#13;                <TT
 CLASS="literal"
+>alsa.device_pcm_class</TT
+> (string)
+              </TD
+><TD
+>&nbsp;</TD
+><TD
+>Yes</TD
+><TD
+>&#13;                The PCM class of the device.
+              </TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+>generic</TD
+><TD
+>&nbsp;</TD
+><TD
+>&#13;                A standard PCM sound device (SND_PCM_CLASS_GENERIC).
+              </TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+>multi</TD
+><TD
+>&nbsp;</TD
+><TD
+>&#13;                A multichannel device PCM sound device (SND_PCM_CLASS_MULTI) which 
+		e.g. contains a generic and a modem device.
+              </TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+>digitizer</TD
+><TD
+>&nbsp;</TD
+><TD
+>&#13;                A PCM digitizer device (SND_PCM_CLASS_DIGITIZER).
+              </TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+>modem</TD
+><TD
+>&nbsp;</TD
+><TD
+>&#13;                A PCM modem device (SND_PCM_CLASS_MODEM).
+              </TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+>unknown</TD
+><TD
+>&nbsp;</TD
+><TD
+>&#13;                The value is 'unknown' if the kernel provide no information about the 
+		PCM device class of the device (e.g. the file pcm_class is missing).
+              </TD
+></TR
+><TR
+><TD
+>&nbsp;</TD
+><TD
+>none</TD
+><TD
+>&nbsp;</TD
+><TD
+>&#13;                The value is 'none' if this there is no PCM class for this device.
+              </TD
+></TR
+><TR
+><TD
+>&#13;                <TT
+CLASS="literal"
 >alsa.physical_device</TT
 > (string)
               </TD
@@ -8608,7 +9086,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN2763"
+NAME="AEN2960"
 ></A
 ><TABLE
 BORDER="1"
@@ -8860,7 +9338,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN2852"
+NAME="AEN3049"
 ></A
 ><TABLE
 BORDER="1"
@@ -8981,7 +9459,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN2894"
+NAME="AEN3091"
 ></A
 ><TABLE
 BORDER="1"
@@ -9069,7 +9547,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN2923"
+NAME="AEN3120"
 ></A
 ><TABLE
 BORDER="1"
@@ -9166,7 +9644,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN2951"
+NAME="AEN3148"
 ></A
 ><TABLE
 BORDER="1"
@@ -9316,7 +9794,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN3010"
+NAME="AEN3207"
 ></A
 ><TABLE
 BORDER="1"
@@ -9396,7 +9874,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN3036"
+NAME="AEN3233"
 ></A
 ><TABLE
 BORDER="1"
@@ -9463,7 +9941,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN3056"
+NAME="AEN3253"
 ></A
 ><TABLE
 BORDER="1"
@@ -10325,7 +10803,7 @@ CLASS="literal"
 ><TD
 >&#13;                <TT
 CLASS="literal"
->battery.technology</TT
+>battery.reporting.technology</TT
 > (string)
               </TD
 ><TD
@@ -10333,7 +10811,30 @@ CLASS="literal"
 ><TD
 >No</TD
 ><TD
->&#13;                The technology of the battery.
+>&#13;                The technology of the battery as reported by the hardware.
+              </TD
+></TR
+><TR
+><TD
+>&#13;                <TT
+CLASS="literal"
+>battery.technology</TT
+> (string)
+              </TD
+><TD
+>&#13;                lead-acid, lithium-ion, lithium-polymer,
+                nickel-metal-hydride, unknown
+              </TD
+><TD
+>No</TD
+><TD
+>&#13;                The technology of the battery processed to a few standard types.
+                This key is needed as the hardware often does not specify the
+                description text for a battery, and so we have to calculate it
+                from the output of <TT
+CLASS="literal"
+>battery.reporting.technology</TT
+>.
               </TD
 ></TR
 ><TR
@@ -10381,7 +10882,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN3374"
+NAME="AEN3578"
 ></A
 ><TABLE
 BORDER="1"
@@ -10496,7 +10997,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN3418"
+NAME="AEN3622"
 ></A
 ><TABLE
 BORDER="1"
@@ -10564,7 +11065,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN3439"
+NAME="AEN3643"
 ></A
 ><TABLE
 BORDER="1"
@@ -10659,7 +11160,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN3471"
+NAME="AEN3675"
 ></A
 ><TABLE
 BORDER="1"
@@ -10771,7 +11272,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN3513"
+NAME="AEN3717"
 ></A
 ><TABLE
 BORDER="1"
@@ -10910,7 +11411,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN3569"
+NAME="AEN3773"
 ></A
 ><TABLE
 BORDER="1"
@@ -11048,7 +11549,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN3613"
+NAME="AEN3817"
 ></A
 ><TABLE
 BORDER="1"
@@ -11112,6 +11613,277 @@ CLASS="literal"
 ><P
 ></P
 ></DIV
+><P
+>&#13;        The following methods exist on the interface
+        <TT
+CLASS="literal"
+>org.freedesktop.Hal.Device.CPUFreq</TT
+>.
+      </P
+><DIV
+CLASS="informaltable"
+><P
+></P
+><A
+NAME="AEN3840"
+></A
+><TABLE
+BORDER="1"
+BGCOLOR="#E0E0E0"
+CELLSPACING="0"
+CELLPADDING="4"
+CLASS="CALSTABLE"
+><THEAD
+><TR
+><TH
+>Method (parameter types)</TH
+><TH
+>Parameters</TH
+><TH
+>Mandatory</TH
+><TH
+>Description</TH
+></TR
+></THEAD
+><TBODY
+><TR
+><TD
+>&#13;                <TT
+CLASS="literal"
+>SetCPUFreqGovernor</TT
+> (string)
+              </TD
+><TD
+>&#13;	        The name of the governor to set. Get a list of available governors
+		with the GetCPUFreqAvailableGovernors method.
+              </TD
+><TD
+>No</TD
+><TD
+>&#13;	        Sets a CPU frequency scaling governor for all CPUFreq
+		interfaces the kernel provides. If the userspace governor
+		is set, this interface also contains a proper scaling
+		mechanism. The default performance is set to 50.
+              </TD
+></TR
+><TR
+><TD
+>&#13;                <TT
+CLASS="literal"
+>SetCPUFreqPerformance</TT
+> (integer)
+              </TD
+><TD
+>&#13;	        The performance between 1 and 100 to set in dynamic scaling modes.
+              </TD
+><TD
+>No</TD
+><TD
+>&#13;	        Sets the performance of the dynamic scaling mechanism. This method
+		summarizes and abstracts all the different settings which can be taken
+		for dynamic frequency adjustments, like at which load to switch up
+		frequency or how many steps the mechanism should traverse until
+		reaching the maximum frequency. The higher the value, the more
+		performance you get. Respectively, the higher the value, the sooner
+		and the more often the frequency is switched up.
+              </TD
+></TR
+><TR
+><TD
+>&#13;                <TT
+CLASS="literal"
+>SetCPUFreqConsiderNice</TT
+> (boolean)
+              </TD
+><TD
+>&#13;	        Whether or not niced processes should be considered on CPU
+		load calculation.
+              </TD
+><TD
+>No</TD
+><TD
+>&#13;	        Whether or not niced processes should be considered on CPU
+		load calculation. If niced processes are considered, they can cause a
+		frequency increment although their absolute load percentage wouldn't
+		trigger the scaling mechanism to switch up the frequency. The default
+		setting is 'false'.
+              </TD
+></TR
+><TR
+><TD
+>&#13;                <TT
+CLASS="literal"
+>GetCPUFreqGovernor</TT
+> (void)
+              </TD
+><TD
+>&nbsp;</TD
+><TD
+>No</TD
+><TD
+>&#13;	        Get the current active governor for all CPU frequency interfaces (string).
+              </TD
+></TR
+><TR
+><TD
+>&#13;                <TT
+CLASS="literal"
+>GetCPUFreqPerformance</TT
+> (void)
+              </TD
+><TD
+>&nbsp;</TD
+><TD
+>No</TD
+><TD
+>&#13;	        Get the current active performance setting if a dynamic scaling
+		mechanism is in use (integer between 1 and 100).
+              </TD
+></TR
+><TR
+><TD
+>&#13;                <TT
+CLASS="literal"
+>GetCPUFreqConsiderNice</TT
+> (void)
+              </TD
+><TD
+>&nbsp;</TD
+><TD
+>No</TD
+><TD
+>&#13;	        Returns whether niced processed are considered during CPU load
+		calculation or not (returns boolean).
+              </TD
+></TR
+><TR
+><TD
+>&#13;                <TT
+CLASS="literal"
+>GetCPUFreqAvailableGovernors</TT
+> (void)
+              </TD
+><TD
+>&nbsp;</TD
+><TD
+>No</TD
+><TD
+>&#13;	        Returns a list of strings of all available governors which
+		could be set with the SetCPUFreqGovernor method.
+              </TD
+></TR
+></TBODY
+></TABLE
+><P
+></P
+></DIV
+><P
+>&#13;        The following errors maybe raised on the interface
+        <TT
+CLASS="literal"
+>org.freedesktop.Hal.Device.CPUFreq</TT
+>.
+      </P
+><DIV
+CLASS="informaltable"
+><P
+></P
+><A
+NAME="AEN3893"
+></A
+><TABLE
+BORDER="1"
+BGCOLOR="#E0E0E0"
+CELLSPACING="0"
+CELLPADDING="4"
+CLASS="CALSTABLE"
+><THEAD
+><TR
+><TH
+>Error</TH
+><TH
+>Description</TH
+><TH
+>Detail field</TH
+></TR
+></THEAD
+><TBODY
+><TR
+><TD
+>&#13;                <TT
+CLASS="literal"
+>GeneralError</TT
+>
+              </TD
+><TD
+>&#13;	        A general error occured.
+              </TD
+><TD
+>&#13;	        The exact error.
+	      </TD
+></TR
+><TR
+><TD
+>&#13;                <TT
+CLASS="literal"
+>UnknownGovernor</TT
+>
+              </TD
+><TD
+>&#13;	        The governor which was tried to be set doesn't exist.
+              </TD
+><TD
+>&#13;	        The governor which was tried be to set.
+	      </TD
+></TR
+><TR
+><TD
+>&#13;                <TT
+CLASS="literal"
+>PermissionDenied</TT
+>
+              </TD
+><TD
+>&#13;	        The caller doesn't have the privilege to execute this
+		method.
+              </TD
+><TD
+>&#13;	        The privilege the caller needs to execute the method.
+	      </TD
+></TR
+><TR
+><TD
+>&#13;                <TT
+CLASS="literal"
+>NoSuitableGovernor</TT
+>
+              </TD
+><TD
+>&#13;	        The method executed doesn't exist for the current active governor.
+              </TD
+><TD
+>&#13;	        The method which was tried to be executed.
+	      </TD
+></TR
+><TR
+><TD
+>&#13;                <TT
+CLASS="literal"
+>GovernorInitFailed</TT
+>
+              </TD
+><TD
+>&#13;	        The initialization of the governor failed.
+              </TD
+><TD
+>&#13;	        The reason for the failure.
+	      </TD
+></TR
+></TBODY
+></TABLE
+><P
+></P
+></DIV
 ></DIV
 ><DIV
 CLASS="sect2"
@@ -11136,7 +11908,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN3639"
+NAME="AEN3931"
 ></A
 ><TABLE
 BORDER="1"
@@ -11229,7 +12001,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN3667"
+NAME="AEN3959"
 ></A
 ><TABLE
 BORDER="1"
@@ -11397,7 +12169,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN3719"
+NAME="AEN4011"
 ></A
 ><TABLE
 BORDER="1"
@@ -11532,7 +12304,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN3760"
+NAME="AEN4052"
 ></A
 ><TABLE
 BORDER="1"
@@ -11795,7 +12567,7 @@ CLASS="literal"
 >&#13;          <TT
 CLASS="literal"
 >empty</TT
-> - can only be used on string properties
+> - can only be used on string or strlist properties
           with 'true' and 'false'.
           The semantics for 'true' is to match only when the string is non-empty.
         </P
@@ -12014,7 +12786,7 @@ CLASS="literal"
     string list. For example to remove item 'bla' from property 'foo.bar':
     <TT
 CLASS="literal"
->&#60;remove key="foo.bar" type="strlist"&#62;bla&#60;/merge&#62;</TT
+>&#60;remove key="foo.bar" type="strlist"&#62;bla&#60;/remove&#62;</TT
 >
   </P
 ><P
@@ -12178,7 +12950,7 @@ WIDTH="100%"
 ><TD
 ><PRE
 CLASS="programlisting"
->&#13;        &#60;?xml version="1.0" encoding="ISO-8859-1"?&#62; &#60;!-- -*- SGML -*- --&#62; 
+>&#13;        &#60;?xml version="1.0" encoding="UTF-8"?&#62;
 
 &#60;!-- Example: This device information file matches an USB Mass Storage based MP3 player 
               by the matching on the USB vendor and product identifiers. --&#62;
@@ -12226,7 +12998,7 @@ WIDTH="100%"
 ><TD
 ><PRE
 CLASS="programlisting"
->&#13;        &#60;?xml version="1.0" encoding="ISO-8859-1"?&#62; &#60;!-- -*- SGML -*- --&#62; 
+>&#13;        &#60;?xml version="1.0" encoding="UTF-8"?&#62;
 
 &#60;!-- Example: This device information file matches a Sony digital still 
               camera by matching on the USB vendor and product identifers.  --&#62;
@@ -12272,7 +13044,7 @@ WIDTH="100%"
 ><TD
 ><PRE
 CLASS="programlisting"
->&#13;        &#60;?xml version="1.0" encoding="ISO-8859-1"?&#62; &#60;!-- -*- SGML -*- --&#62; 
+>&#13;        &#60;?xml version="1.0" encoding="UTF-8"?&#62;
 
 &#60;!-- Example: This device information file matches a memory card reader with 
               multiple storage ports that can be active at the same time. --&#62;
@@ -12393,7 +13165,7 @@ WIDTH="100%"
 ><TD
 ><PRE
 CLASS="programlisting"
->&#13;        &#60;?xml version="1.0" encoding="ISO-8859-1"?&#62; &#60;!-- -*- SGML -*- --&#62; 
+>&#13;        &#60;?xml version="1.0" encoding="UTF-8"?&#62;
 
 &#60;deviceinfo version="0.2"&#62;
 
@@ -12477,7 +13249,7 @@ CLASS="informaltable"
 ><P
 ></P
 ><A
-NAME="AEN3994"
+NAME="AEN4286"
 ></A
 ><TABLE
 BORDER="1"
@@ -12640,7 +13412,7 @@ CLASS="sect2"
 ><HR><H3
 CLASS="sect2"
 ><A
-NAME="AEN4036"
+NAME="AEN4328"
 >Interface org.freedesktop.Hal.Manager</A
 ></H3
 ><P
@@ -12744,7 +13516,7 @@ CLASS="sect3"
 ><HR><H4
 CLASS="sect3"
 ><A
-NAME="AEN4047"
+NAME="AEN4339"
 >Example</A
 ></H4
 ><P
@@ -12853,7 +13625,7 @@ CLASS="sect2"
 ><HR><H3
 CLASS="sect2"
 ><A
-NAME="AEN4055"
+NAME="AEN4347"
 >Interface org.freedesktop.Hal.Device</A
 ></H3
 ><P
@@ -12999,6 +13771,109 @@ void Condition(string condition, ...)
         signals for only a subset of the devices available.
       </P
 ></DIV
+><DIV
+CLASS="sect2"
+><HR><H3
+CLASS="sect2"
+><A
+NAME="AEN4356"
+>Interface org.freedesktop.Hal.Device.Volume</A
+></H3
+><P
+>&#13;        The org.freedesktop.Hal.Device.Volume interface is used on objects
+        with the "volume" capability. This interface has the following methods.
+      </P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="programlisting"
+>&#13;# Mount volume
+#
+# @param  mountpoint            Desired mount point. If NULL, will be generated based on label.
+# @param  fstype                Filesystem type
+# @param  options               Mount options
+# @raises                       org.freedesktop.Hal.Device.Volume.NoSuchDevice
+#                               org.freedesktop.Hal.Device.Volume.PermissionDenied
+#                               org.freedesktop.Hal.Device.Volume.AlreadyMounted
+#                               org.freedesktop.Hal.Device.Volume.InvalidMountOption
+#                               org.freedesktop.Hal.Device.Volume.UnknownFilesystemType
+#                               org.freedesktop.Hal.Device.Volume.InvalidMountpoint
+#                               org.freedesktop.Hal.Device.Volume.MountPointNotAvailable
+#                               org.freedesktop.Hal.Device.Volume.PermissionDeniedByPolicy
+#
+void Mount(string mountpoint, string fstype, array{string} options)
+# Unmount volume
+#
+# @param  options               Unmount options
+# @raises                       org.freedesktop.Hal.Device.Volume.NoSuchDevice
+#                               org.freedesktop.Hal.Device.Volume.PermissionDenied
+#                               org.freedesktop.Hal.Device.Volume.InvalidUnmountOption
+#                               org.freedesktop.Hal.Device.Volume.InvalidMountpoint
+#                               org.freedesktop.Hal.Device.Volume.MountPointNotAvailable
+#                               org.freedesktop.Hal.Device.Volume.PermissionDeniedByPolicy
+#
+void Unmount(array{string} options)
+# Eject volume
+#
+# @param  ejectoptions          Eject options
+# @raises                       org.freedesktop.Hal.Device.Volume.NoSuchDevice
+#                               org.freedesktop.Hal.Device.Volume.PermissionDenied
+#                               org.freedesktop.Hal.Device.Volume.InvalidEjectOption
+#                               org.freedesktop.Hal.Device.Volume.PermissionDeniedByPolicy
+#
+void Eject(array{string} options)
+      </PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="sect2"
+><HR><H3
+CLASS="sect2"
+><A
+NAME="AEN4360"
+>Interface org.freedesktop.Hal.Device.Storage</A
+></H3
+><P
+>&#13;        The org.freedesktop.Hal.Device.Storage interface is used on objects
+        with the "storage" capability. This interface has the following methods.
+      </P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="programlisting"
+>&#13;# Eject media
+#
+# @param  ejectoptions          Eject options
+# @raises                       org.freedesktop.Hal.Device.Storage.NoSuchDevice
+#                               org.freedesktop.Hal.Device.Storage.PermissionDenied
+#                               org.freedesktop.Hal.Device.Storage.InvalidEjectOption
+#                               org.freedesktop.Hal.Device.Storage.PermissionDeniedByPolicy
+#
+void Eject(array{string} options)
+# Close media tray
+#
+# @param  closetrayoptions      Close tray options
+# @raises                       org.freedesktop.Hal.Device.Storage.NoSuchDevice
+#                               org.freedesktop.Hal.Device.Storage.PermissionDenied
+#                               org.freedesktop.Hal.Device.Storage.InvalidCloseTrayOption
+#                               org.freedesktop.Hal.Device.Storage.PermissionDeniedByPolicy
+#
+void CloseTray(array{string} options)
+      </PRE
+></TD
+></TR
+></TABLE
+></DIV
 ></DIV
 ><DIV
 CLASS="sect1"
diff --git a/hald/linux/addons/addon-storage.c b/hald/linux/addons/addon-storage.c
index 1660abc..5d848c5 100644
--- a/hald/linux/addons/addon-storage.c
+++ b/hald/linux/addons/addon-storage.c
@@ -427,7 +427,9 @@ main (int argc, char *argv[])
 				DBusError error;
 				
 				HAL_DEBUG (("Media removal detected on %s", device_file));
-				libhal_device_set_property_bool (ctx, udi, "storage.removable.media_available", FALSE, &error);
+				libhal_device_set_property_bool (ctx, udi, "storage.removable.media_available", FALSE, NULL);
+				libhal_device_set_property_string (ctx, udi, "storage.partitioning_scheme", "", NULL);
+
 				
 				/* attempt to unmount all childs */
 				unmount_childs (ctx, udi);
@@ -449,7 +451,10 @@ main (int argc, char *argv[])
 				DBusError error;
 
 				HAL_DEBUG (("Media insertion detected on %s", device_file));
-				libhal_device_set_property_bool (ctx, udi, "storage.removable.media_available", TRUE, &error);				/* our probe will trigger the appropriate hotplug events */
+
+				/* our probe will trigger the appropriate hotplug events */
+				libhal_device_set_property_bool (
+					ctx, udi, "storage.removable.media_available", TRUE, NULL);
 
 				/* could have a fs on the main block device; do a rescan to add it */
 				dbus_error_init (&error);
diff --git a/hald/linux/blockdev.c b/hald/linux/blockdev.c
index 8fbe084..3061424 100644
--- a/hald/linux/blockdev.c
+++ b/hald/linux/blockdev.c
@@ -780,7 +780,6 @@ hotplug_event_begin_add_blockdev (const 
 		hal_device_property_set_string (d, "storage.physical_device", parent->udi);
 		hal_device_property_set_bool (d, "storage.removable", TRUE);
 		hal_device_property_set_bool (d, "storage.removable.media_available", FALSE);
-		hal_device_property_set_uint64 (d, "storage.removable.media_size", 0);
 		hal_device_property_set_bool (d, "storage.hotpluggable", FALSE);
 		hal_device_property_set_bool (d, "storage.requires_eject", FALSE);
 		hal_device_property_set_uint64 (d, "storage.size", 0);
@@ -924,7 +923,6 @@ hotplug_event_begin_add_blockdev (const 
 		}
 
 		hal_device_property_set_bool (d, "storage.removable.media_available", FALSE);
-		hal_device_property_set_uint64 (d, "storage.removable.media_size", 0);
 		hal_device_property_set_bool (d, "storage.removable", is_removable);
 		/* set storage.size only if we have fixed media */
 		if (!is_removable) {
diff --git a/hald/linux/probing/Makefile.am b/hald/linux/probing/Makefile.am
index a66d858..5b2d3c2 100644
--- a/hald/linux/probing/Makefile.am
+++ b/hald/linux/probing/Makefile.am
@@ -30,10 +30,10 @@ hald_probe_serial_SOURCES = probe-serial
 hald_probe_serial_LDADD = $(top_builddir)/libhal/libhal.la
 
 hald_probe_storage_SOURCES = probe-storage.c linux_dvd_rw_utils.c linux_dvd_rw_utils.h ../../logger.c
-hald_probe_storage_LDADD = $(top_builddir)/libhal/libhal.la @GLIB_LIBS@ @VOLUME_ID_LIBS@
+hald_probe_storage_LDADD = $(top_builddir)/libhal/libhal.la $(top_builddir)/partutil/libpartutil.la @GLIB_LIBS@ @VOLUME_ID_LIBS@
 
 hald_probe_pc_floppy_SOURCES = probe-pc-floppy.c ../../logger.c
 
 hald_probe_volume_SOURCES = probe-volume.c linux_dvd_rw_utils.c ../../logger.c 
-hald_probe_volume_LDADD = $(top_builddir)/libhal/libhal.la @GLIB_LIBS@ @VOLUME_ID_LIBS@
+hald_probe_volume_LDADD = $(top_builddir)/libhal/libhal.la $(top_builddir)/partutil/libpartutil.la @GLIB_LIBS@ @VOLUME_ID_LIBS@
 
diff --git a/hald/linux/probing/probe-storage.c b/hald/linux/probing/probe-storage.c
index 7b84a64..9a6b860 100644
--- a/hald/linux/probing/probe-storage.c
+++ b/hald/linux/probing/probe-storage.c
@@ -46,6 +46,7 @@
 #include <libvolume_id.h>
 
 #include "libhal/libhal.h"
+#include "partutil/partutil.h"
 #include "linux_dvd_rw_utils.h"
 
 #include "../../logger.h"
@@ -57,7 +58,7 @@ static void vid_log(int priority, const 
 
 	va_start(args, format);
 	vsnprintf(log_str, sizeof(log_str), format, args);
-	logger_forward_debug("%s:%i %s", file, line, log_str);
+	logger_forward_debug("%s:%i %s\n", file, line, log_str);
 	va_end(args);
 }
 
@@ -95,6 +96,62 @@ out:
 	return rc;
 }
 
+#define BSIZE 0x200
+#define MSDOS_MAGIC			"\x55\xaa"
+#define MSDOS_SIG_OFF			0x01fe
+#define MSDOS_PARTTABLE_OFFSET		0x01be
+
+#define MAC_MAGIC                       "\x45\x52"
+#define MAC_SIG_OFF                     0x0000
+
+enum {
+	PART_TABLE_UNKNOWN,
+	PART_TABLE_MBR,
+	PART_TABLE_APM,
+	PART_TABLE_GPT
+};
+
+/* Detect partition table scheme */
+static int
+probe_for_part_scheme (LibHalChangeSet *changeset, int fd)
+{
+	int res;
+	const uint8_t buf[BSIZE];
+
+	res = PART_TABLE_UNKNOWN;
+
+	if (lseek(fd, 0, SEEK_SET) < 0) {
+		dbg("lseek failed (%s)", strerror(errno));
+		goto out;
+	}
+	if (read(fd, &buf, BSIZE) < BSIZE) {
+		dbg("read failed (%s)", strerror(errno));
+		goto out;
+	}
+
+	if (memcmp(&buf[MSDOS_SIG_OFF], MSDOS_MAGIC, 2) == 0) {
+		/* if the first partition have type 0xee, it's a GUID Partitioning Table */
+		if (buf[MSDOS_PARTTABLE_OFFSET + 4] == 0xee) {
+			dbg("foo1");
+			res = PART_TABLE_GPT;
+		} else {
+			dbg("foo2");
+			res = PART_TABLE_MBR;
+		}
+		goto out;
+	}
+
+	if (memcmp(&buf[MAC_SIG_OFF], MAC_MAGIC, 2) == 0) {
+		dbg("foo3");
+		res = PART_TABLE_APM;
+		goto out;
+	}
+
+
+out:
+	return res;
+}
+
 int 
 main (int argc, char *argv[])
 {
@@ -108,6 +165,8 @@ main (int argc, char *argv[])
 	char *drive_type;
 	char *sysfs_path;
 	dbus_bool_t only_check_for_fs;
+	LibHalChangeSet *cs;
+
 
 	fd = -1;
 
@@ -139,6 +198,12 @@ main (int argc, char *argv[])
 	if ((ctx = libhal_ctx_init_direct (&error)) == NULL)
 		goto out;
 
+	cs = libhal_device_new_changeset (udi);
+	if (cs == NULL) {
+		HAL_DEBUG(("Cannot initialize changeset"));
+		goto out;
+	}
+
 	HAL_DEBUG (("Doing probe-storage for %s (bus %s) (drive_type %s) (udi=%s) (--only-check-for-fs==%d)", 
 	     device_file, bus, drive_type, udi, only_check_for_fs));
 
@@ -169,83 +234,85 @@ main (int argc, char *argv[])
 				goto out;
 			}
 			
-			libhal_device_set_property_bool (ctx, udi, "storage.cdrom.cdr", FALSE, &error);
-			libhal_device_set_property_bool (ctx, udi, "storage.cdrom.cdrw", FALSE, &error);
-			libhal_device_set_property_bool (ctx, udi, "storage.cdrom.dvd", FALSE, &error);
-			libhal_device_set_property_bool (ctx, udi, "storage.cdrom.dvdr", FALSE, &error);
-			libhal_device_set_property_bool (ctx, udi, "storage.cdrom.dvdrw", FALSE, &error);
-			libhal_device_set_property_bool (ctx, udi, "storage.cdrom.dvdram", FALSE, &error);
-			libhal_device_set_property_bool (ctx, udi, "storage.cdrom.dvdplusr", FALSE, &error);
-			libhal_device_set_property_bool (ctx, udi, "storage.cdrom.dvdplusrw", FALSE, &error);
-			libhal_device_set_property_bool (ctx, udi, "storage.cdrom.dvdplusrwdl", FALSE, &error);
-			libhal_device_set_property_bool (ctx, udi, "storage.cdrom.dvdplusrdl", FALSE, &error);
-			libhal_device_set_property_bool (ctx, udi, "storage.cdrom.bd", FALSE, &error);
-			libhal_device_set_property_bool (ctx, udi, "storage.cdrom.bdr", FALSE, &error);
-			libhal_device_set_property_bool (ctx, udi, "storage.cdrom.bdre", FALSE, &error);
-			libhal_device_set_property_bool (ctx, udi, "storage.cdrom.hddvd", FALSE, &error);
-			libhal_device_set_property_bool (ctx, udi, "storage.cdrom.hddvdr", FALSE, &error);
-			libhal_device_set_property_bool (ctx, udi, "storage.cdrom.hddvdrw", FALSE, &error);
+			libhal_changeset_set_property_bool (cs, "storage.cdrom.cdr", FALSE);
+			libhal_changeset_set_property_bool (cs, "storage.cdrom.cdrw", FALSE);
+			libhal_changeset_set_property_bool (cs, "storage.cdrom.dvd", FALSE);
+			libhal_changeset_set_property_bool (cs, "storage.cdrom.dvdr", FALSE);
+			libhal_changeset_set_property_bool (cs, "storage.cdrom.dvdrw", FALSE);
+			libhal_changeset_set_property_bool (cs, "storage.cdrom.dvdram", FALSE);
+			libhal_changeset_set_property_bool (cs, "storage.cdrom.dvdplusr", FALSE);
+			libhal_changeset_set_property_bool (cs, "storage.cdrom.dvdplusrw", FALSE);
+			libhal_changeset_set_property_bool (cs, "storage.cdrom.dvdplusrwdl", FALSE);
+			libhal_changeset_set_property_bool (cs, "storage.cdrom.dvdplusrdl", FALSE);
+			libhal_changeset_set_property_bool (cs, "storage.cdrom.bd", FALSE);
+			libhal_changeset_set_property_bool (cs, "storage.cdrom.bdr", FALSE);
+			libhal_changeset_set_property_bool (cs, "storage.cdrom.bdre", FALSE);
+			libhal_changeset_set_property_bool (cs, "storage.cdrom.hddvd", FALSE);
+			libhal_changeset_set_property_bool (cs, "storage.cdrom.hddvdr", FALSE);
+			libhal_changeset_set_property_bool (cs, "storage.cdrom.hddvdrw", FALSE);
 			
 			if (capabilities & CDC_CD_R) {
-				libhal_device_set_property_bool (ctx, udi, "storage.cdrom.cdr", TRUE, &error);
+				libhal_changeset_set_property_bool (cs, "storage.cdrom.cdr", TRUE);
 			}
 			
 			if (capabilities & CDC_CD_RW) {
-				libhal_device_set_property_bool (ctx, udi, "storage.cdrom.cdrw", TRUE, &error);
+				libhal_changeset_set_property_bool (cs, "storage.cdrom.cdrw", TRUE);
 			}
 			if (capabilities & CDC_DVD) {
 				int profile;
 				
-				libhal_device_set_property_bool (ctx, udi, "storage.cdrom.dvd", TRUE, &error);
+				libhal_changeset_set_property_bool (cs, "storage.cdrom.dvd", TRUE);
 
 				profile = get_dvd_r_rw_profile (fd);
 				HAL_DEBUG (("get_dvd_r_rw_profile returned: %d", profile));
 
 				if (profile & DRIVE_CDROM_CAPS_DVDRW)
-					libhal_device_set_property_bool (ctx, udi, "storage.cdrom.dvdrw", TRUE, &error);
+					libhal_changeset_set_property_bool (cs, "storage.cdrom.dvdrw", TRUE);
 				if (profile & DRIVE_CDROM_CAPS_DVDPLUSR)
-					libhal_device_set_property_bool(ctx, udi, "storage.cdrom.dvdplusr", TRUE, &error);
+					libhal_changeset_set_property_bool(cs, "storage.cdrom.dvdplusr", TRUE);
 				if (profile & DRIVE_CDROM_CAPS_DVDPLUSRW)
-					libhal_device_set_property_bool (ctx, udi, "storage.cdrom.dvdplusrw", TRUE, &error);
+					libhal_changeset_set_property_bool (cs, "storage.cdrom.dvdplusrw", TRUE);
 				if (profile & DRIVE_CDROM_CAPS_DVDPLUSRWDL)
-					libhal_device_set_property_bool (ctx, udi, "storage.cdrom.dvdplusrwdl", TRUE, &error);
+					libhal_changeset_set_property_bool (cs, "storage.cdrom.dvdplusrwdl", TRUE);
 				if (profile & DRIVE_CDROM_CAPS_DVDPLUSRDL)
-                                        libhal_device_set_property_bool (ctx, udi, "storage.cdrom.dvdplusrdl", TRUE, &error);
+                                        libhal_changeset_set_property_bool (cs, "storage.cdrom.dvdplusrdl", TRUE);
 			}
 			if (capabilities & CDC_DVD_R) {
-				libhal_device_set_property_bool (ctx, udi, "storage.cdrom.dvdr", TRUE, &error);
+				libhal_changeset_set_property_bool (cs, "storage.cdrom.dvdr", TRUE);
 			}
 			if (capabilities & CDC_DVD_RAM) {
-				libhal_device_set_property_bool (ctx, udi, "storage.cdrom.dvdram", TRUE, &error);
+				libhal_changeset_set_property_bool (cs, "storage.cdrom.dvdram", TRUE);
 			}
 			
 			/* while we're at it, check if we support media changed */
 			if (capabilities & CDC_MEDIA_CHANGED) {
-				libhal_device_set_property_bool (ctx, udi, "storage.cdrom.support_media_changed", TRUE, &error);
+				libhal_changeset_set_property_bool (cs, "storage.cdrom.support_media_changed", TRUE);
 			} else {
-				libhal_device_set_property_bool (ctx, udi, "storage.cdrom.support_media_changed", FALSE, &error);
+				libhal_changeset_set_property_bool (cs, "storage.cdrom.support_media_changed", FALSE);
 			}
 			
 			if (get_read_write_speed(fd, &read_speed, &write_speed, &write_speeds) >= 0) {
-				libhal_device_set_property_int (ctx, udi, "storage.cdrom.read_speed", read_speed, &error);
+				libhal_changeset_set_property_int (cs, "storage.cdrom.read_speed", read_speed);
 				if (write_speed > 0) {
-					libhal_device_set_property_int (ctx, udi, "storage.cdrom.write_speed", write_speed, &error);
+					libhal_changeset_set_property_int (
+						cs, "storage.cdrom.write_speed", write_speed);
+					
 					if (write_speeds != NULL)
 					{
 						gchar **wspeeds;
-						int i;
-						wspeeds = g_strsplit_set (write_speeds, ",", -1);
-						for (i = 0 ; wspeeds[i] != NULL; i++) {
-					                if (strlen (wspeeds[i]) > 0)
-								libhal_device_property_strlist_append (ctx, udi, "storage.cdrom.write_speeds", wspeeds[i], &error);
-						}
+ 						wspeeds = g_strsplit_set (write_speeds, ",", -1);
+						libhal_changeset_set_property_strlist (cs, 
+										       "storage.cdrom.write_speeds", 
+										       (const char **) wspeeds);
+						g_strfreev (wspeeds);
 						free (write_speeds);
 					}
-				}	
-				else
-					libhal_device_set_property_int (ctx, udi, "storage.cdrom.write_speed", 0, &error);
+				} else {
+					libhal_changeset_set_property_int (cs, "storage.cdrom.write_speed", 0);
+					libhal_changeset_set_property_strlist (cs, "storage.cdrom.write_speeds", NULL);
+				}
 			}
-
+			
 			close (fd);
 		}
 		
@@ -331,13 +398,13 @@ main (int argc, char *argv[])
 		if (got_media) {
 			uint64_t size;
 			ret = 2;
-			libhal_device_set_property_bool (ctx, udi, "storage.removable.media_available", TRUE, &error);
+			libhal_changeset_set_property_bool (cs, "storage.removable.media_available", TRUE);
 			if (ioctl (fd, BLKGETSIZE64, &size) == 0) {
 				HAL_DEBUG (("media size = %llu", size));
-				libhal_device_set_property_uint64 (ctx, udi, "storage.removable.media_size", size, &error);
+				libhal_changeset_set_property_uint64 (cs, "storage.removable.media_size", size);
 			}
 		} else {
-			libhal_device_set_property_bool (ctx, udi, "storage.removable.media_available", FALSE, &error);
+			libhal_changeset_set_property_bool (cs, "storage.removable.media_available", FALSE);
 		}
 
 		close (fd);
@@ -360,18 +427,18 @@ main (int argc, char *argv[])
 		if (fd < 0) {
 			HAL_DEBUG (("Cannot open %s: %s", device_file, strerror (errno)));
 			/* no media */
-			libhal_device_set_property_bool (ctx, udi, "storage.removable.media_available", FALSE, &error);
+			libhal_changeset_set_property_bool (cs, "storage.removable.media_available", FALSE);
 			goto out;
 		}
 		HAL_DEBUG (("Returned from open(2)"));
 
 		/* if we get to here, we have media */
-		libhal_device_set_property_bool (ctx, udi, "storage.removable.media_available", TRUE, &error);
+		libhal_changeset_set_property_bool (cs, "storage.removable.media_available", TRUE);
 
 		if (ioctl (fd, BLKGETSIZE64, &size) != 0)
 			size = 0;
 		
-		libhal_device_set_property_uint64 (ctx, udi, "storage.removable.media_size", size, &error);
+		libhal_changeset_set_property_uint64 (cs, "storage.removable.media_size", size);
 
 		/* if the kernel has created partitions, we don't look for a filesystem */
 		main_device = strrchr (sysfs_path, '/');
@@ -387,13 +454,30 @@ main (int argc, char *argv[])
 		while ((partition = g_dir_read_name (dir)) != NULL) {
 			if (strncmp (main_device, partition, main_device_len) == 0 &&
 			    isdigit (partition[main_device_len])) {
+				PartitionTable *p;
+
 				HAL_DEBUG (("partition %s found, skip probing for filesystem", partition));
 				g_dir_close (dir);
+
+				/* probe for partition table type */
+				p = part_table_load_from_disk (device_file);
+				if (p != NULL) {
+
+					libhal_changeset_set_property_string (
+						cs, 
+						"storage.partitioning_scheme", 
+						part_get_scheme_name (part_table_get_scheme (p)));
+
+					part_table_free (p);
+				}
+
 				goto out;
 			}
 		}
 		g_dir_close (dir);
 
+		libhal_changeset_set_property_string (cs, "storage.partitioning_scheme", "none");
+
 		/* probe for file system */
 		vid = volume_id_open_fd (fd);
 		if (vid != NULL) {
@@ -416,6 +500,10 @@ main (int argc, char *argv[])
 	}
 	
 out:
+	if (cs != NULL) {
+		libhal_device_commit_changeset (ctx, cs, &error);
+		libhal_device_free_changeset (cs);
+	}
 
 	if (ctx != NULL) {
 		dbus_error_init (&error);
diff --git a/hald/linux/probing/probe-volume.c b/hald/linux/probing/probe-volume.c
index 8a57e52..3b6b00b 100644
--- a/hald/linux/probing/probe-volume.c
+++ b/hald/linux/probing/probe-volume.c
@@ -44,6 +44,7 @@
 #include <libvolume_id.h>
 
 #include "libhal/libhal.h"
+#include "partutil/partutil.h"
 #include "linux_dvd_rw_utils.h"
 #include "../../logger.h"
 
@@ -54,7 +55,7 @@ static void vid_log(int priority, const 
 
 	va_start(args, format);
 	vsnprintf(log_str, sizeof(log_str), format, args);
-	logger_forward_debug("%s:%i %s", file, line, log_str);
+	logger_forward_debug("%s:%i %s\n", file, line, log_str);
 	va_end(args);
 }
 
@@ -85,156 +86,9 @@ strdup_valid_utf8 (const char *str)
 	return newstr;
 }
 
-/* probe_msdos_part_table: return array of partiton type numbers */
-#define BSIZE				0x200
-#define MSDOS_MAGIC			"\x55\xaa"
-#define MSDOS_PARTTABLE_OFFSET		0x1be
-#define MSDOS_SIG_OFF			0x1fe
-#define DOS_EXTENDED_PARTITION		0x05
-#define LINUX_EXTENDED_PARTITION	0x85
-#define WIN98_EXTENDED_PARTITION	0x0f
-#define is_extended(type) \
-	(type == DOS_EXTENDED_PARTITION ||	\
-	 type == WIN98_EXTENDED_PARTITION ||	\
-	 type == LINUX_EXTENDED_PARTITION)
-
-struct msdos_part_entry {
-	uint8_t part_type;
-	uint64_t start;
-	uint64_t size;
-};
-
-static struct msdos_part_entry *
-probe_msdos_part_table(int fd)
-{
-	static struct msdos_part_entry partition_id_index[256];
-	unsigned int partition_count;
-	const uint8_t buf[BSIZE];
-	int i;
-	uint64_t poff;
-	uint64_t plen;
-	uint64_t extended = 0;
-	uint64_t next;
-	int limit;
-	int empty = 1;
-	struct msdos_partition_entry {
-		uint8_t		boot_ind;
-		uint8_t		head;
-		uint8_t		sector;
-		uint8_t		cyl;
-		uint8_t		sys_ind;
-		uint8_t		end_head;
-		uint8_t		end_sector;
-		uint8_t		end_cyl;
-		uint32_t	start_sect;
-		uint32_t	nr_sects;
-	} __attribute__((packed)) *part;
-
-	if (lseek(fd, 0, SEEK_SET) < 0) {
-		HAL_DEBUG (("lseek failed (%s)", strerror(errno)));
-		return NULL;
-	}
-	if (read(fd, &buf, BSIZE) < BSIZE) {
-		HAL_DEBUG (("read failed (%s)", strerror(errno)));
-		return NULL;
-	}
-	if (memcmp(&buf[MSDOS_SIG_OFF], MSDOS_MAGIC, 2) != 0)
-		return NULL;
-
-	part = (struct msdos_partition_entry*) &buf[MSDOS_PARTTABLE_OFFSET];
-	/* check flags on all entries for a valid partition table */
-	for (i = 0; i < 4; i++) {
-		if (part[i].boot_ind != 0 &&
-		    part[i].boot_ind != 0x80)
-			return NULL;
-
-		if (GINT32_FROM_LE(part[i].nr_sects) != 0)
-			empty = 0;
-	}
-	if (empty == 1)
-		return NULL;
-
-	memset(partition_id_index, 0x00, sizeof(partition_id_index));
-
-	for (i = 0; i < 4; i++) {
-		poff = (uint64_t) GINT32_FROM_LE(part[i].start_sect) * BSIZE;
-		plen = (uint64_t) GINT32_FROM_LE(part[i].nr_sects) * BSIZE;
-
-		if (plen == 0)
-			continue;
-
-		partition_id_index[i].part_type = part[i].sys_ind;
-		partition_id_index[i].start = poff;
-		partition_id_index[i].size = plen;
-		HAL_DEBUG (("part %d -> type=%d off=%lld size=%lld", i, part[i].sys_ind, poff, plen));
-
-		if (is_extended(part[i].sys_ind)) {
-			HAL_DEBUG (("found extended partition at 0x%llx", (unsigned long long) poff));
-			if (extended == 0)
-				extended = poff;
-		} else {
-			HAL_DEBUG (("found 0x%x primary data partition at 0x%llx, len 0x%llx",
-			    part[i].sys_ind, (unsigned long long) poff, (unsigned long long) plen));
-		}
-	}
-
-	/* follow extended partition chain and add data partitions */
-	partition_count = 4;
-	limit = 255;
-	next = extended;
-	while (next != 0) {
-		uint64_t oldnext;
-
-		if (limit-- == 0) {
-			HAL_DEBUG(("extended chain limit reached"));
-			break;
-		}
-
-		HAL_DEBUG (("read 0x%llx (%llu)", next, next));
-		if (lseek(fd, next, SEEK_SET) < 0) {
-			HAL_DEBUG(("lseek failed (%s)", strerror(errno)));
-			return NULL;
-		}
-		if (read(fd, &buf, BSIZE) < BSIZE) {
-			HAL_DEBUG(("read failed (%s)", strerror(errno)));
-			return NULL;
-		}
-		if (memcmp(&buf[MSDOS_SIG_OFF], MSDOS_MAGIC, 2) != 0)
-			break;
-
-		oldnext = next;
-		next = 0;
-
-		part = (struct msdos_partition_entry*) &buf[MSDOS_PARTTABLE_OFFSET];
-		for (i = 0; i < 4; i++) {
-			poff = (uint64_t) GINT32_FROM_LE(part[i].start_sect) * BSIZE;
-			plen = (uint64_t) GINT32_FROM_LE(part[i].nr_sects) * BSIZE;
-
-			if (plen == 0)
-				continue;
-
-			if (is_extended(part[i].sys_ind)) {
-				HAL_DEBUG(("found extended partition (chain) at 0x%llx", (unsigned long long) poff));
-				if (next == 0)
-					next = extended + poff;
-			} else {
-				HAL_DEBUG(("found 0x%x logical data partition at 0x%llx, len 0x%llx",
-					part[i].sys_ind, (unsigned long long) poff, (unsigned long long) plen));
-
-				partition_id_index[partition_count].part_type = part[i].sys_ind;
-				partition_id_index[partition_count].start = oldnext + poff;
-				partition_id_index[partition_count].size = plen;
-
-				partition_count++;
-			}
-		}
-	}
-
-	return partition_id_index;
-}
 
 static void
-set_volume_id_values (LibHalContext *ctx, const char *udi, LibHalChangeSet *changes, struct volume_id *vid)
+set_volume_id_values (LibHalContext *ctx, const char *udi, LibHalChangeSet *cs, struct volume_id *vid)
 {
 	char buf[256];
 	const char *usage;
@@ -257,47 +111,47 @@ set_volume_id_values (LibHalContext *ctx
 		usage = "crypto";
 		break;
 	case VOLUME_ID_UNUSED:
-		libhal_changeset_set_property_string (changes, "info.product", "Volume (unused)");
+		libhal_changeset_set_property_string (cs, "info.product", "Volume (unused)");
 		usage = "unused";
 		return;
 	default:
 		usage = "";
 	}
 
-	libhal_changeset_set_property_string (changes, "volume.fsusage", usage);
+	libhal_changeset_set_property_string (cs, "volume.fsusage", usage);
 	HAL_DEBUG (("volume.fsusage = '%s'", usage));
 
-	libhal_changeset_set_property_string (changes, "volume.fstype", vid->type);
+	libhal_changeset_set_property_string (cs, "volume.fstype", vid->type);
 	HAL_DEBUG(("volume.fstype = '%s'", vid->type));
 	if (vid->type_version[0] != '\0') {
-		libhal_changeset_set_property_string (changes, "volume.fsversion", vid->type_version);
+		libhal_changeset_set_property_string (cs, "volume.fsversion", vid->type_version);
 		HAL_DEBUG(("volume.fsversion = '%s'", vid->type_version));
 	}
-	libhal_changeset_set_property_string (changes, "volume.uuid", vid->uuid);
+	libhal_changeset_set_property_string (cs, "volume.uuid", vid->uuid);
 	HAL_DEBUG(("volume.uuid = '%s'", vid->uuid));
 
 	/* we need to be sure for a utf8 valid label, because dbus accept only utf8 valid strings */
 	volume_label = strdup_valid_utf8 (vid->label);
 	if( volume_label != NULL ) {
-		libhal_changeset_set_property_string (changes, "volume.label", volume_label);
+		libhal_changeset_set_property_string (cs, "volume.label", volume_label);
 		HAL_DEBUG(("volume.label = '%s'", volume_label));
 		
 		if (strlen(volume_label) > 0) {	
-			libhal_changeset_set_property_string (changes, "info.product", volume_label);
+			libhal_changeset_set_property_string (cs, "info.product", volume_label);
 		}
 		else {
 			snprintf (buf, sizeof (buf), "Volume (%s)", vid->type);
-			libhal_changeset_set_property_string (changes, "info.product", buf);
+			libhal_changeset_set_property_string (cs, "info.product", buf);
 		}
 		g_free(volume_label);
 	} else {
 		snprintf (buf, sizeof (buf), "Volume (%s)", vid->type);
-		libhal_changeset_set_property_string (changes, "info.product", buf);
+		libhal_changeset_set_property_string (cs, "info.product", buf);
 	}
 }
 
 static void
-advanced_disc_detect (LibHalContext *ctx, const char *udi, LibHalChangeSet *changes,
+advanced_disc_detect (LibHalContext *ctx, const char *udi, LibHalChangeSet *cs,
                       int fd, const char *device_file)
 {
 	/* the discs block size */
@@ -323,9 +177,9 @@ advanced_disc_detect (LibHalContext *ctx
 	dbus_error_init (&error);
 	
 	/* set defaults */
-	libhal_changeset_set_property_bool (changes, "volume.disc.is_videodvd", FALSE);
-	libhal_changeset_set_property_bool (changes, "volume.disc.is_vcd", FALSE);
-	libhal_changeset_set_property_bool (changes, "volume.disc.is_svcd", FALSE);
+	libhal_changeset_set_property_bool (cs, "volume.disc.is_videodvd", FALSE);
+	libhal_changeset_set_property_bool (cs, "volume.disc.is_vcd", FALSE);
+	libhal_changeset_set_property_bool (cs, "volume.disc.is_svcd", FALSE);
 	
 	/* read the block size */
 	lseek (fd, 0x8080, SEEK_CUR);
@@ -395,19 +249,19 @@ advanced_disc_detect (LibHalContext *ctx
 		{
 			if (!strcmp (dirname, "VIDEO_TS"))
 			{
-				libhal_changeset_set_property_bool (changes, "volume.disc.is_videodvd", TRUE);
+				libhal_changeset_set_property_bool (cs, "volume.disc.is_videodvd", TRUE);
 				HAL_DEBUG(("Disc in %s is a Video DVD", device_file));
 				break;
 			}
 			else if (!strcmp (dirname, "VCD"))
 			{
-				libhal_changeset_set_property_bool (changes, "volume.disc.is_vcd", TRUE);
+				libhal_changeset_set_property_bool (cs, "volume.disc.is_vcd", TRUE);
 				HAL_DEBUG(("Disc in %s is a Video CD", device_file));
 				break;
 			}
 			else if (!strcmp (dirname, "SVCD"))
 			{
-				libhal_changeset_set_property_bool (changes, "volume.disc.is_svcd", TRUE);
+				libhal_changeset_set_property_bool (cs, "volume.disc.is_svcd", TRUE);
 				HAL_DEBUG(("Disc in %s is a Super Video CD", device_file));
 				break;
 			}
@@ -445,19 +299,26 @@ main (int argc, char *argv[])
 	struct volume_id *vid;
 	char *stordev_dev_file;
 	char *partition_number_str;
+	char *partition_start_str;
 	char *is_disc_str;
 	dbus_bool_t is_disc;
 	unsigned int partition_number;
+	guint64 partition_start;
 	unsigned int block_size;
 	dbus_uint64_t vol_size;
 	dbus_bool_t should_probe_for_fs;
 	dbus_uint64_t vol_probe_offset = 0;
-	LibHalChangeSet *changeset;
+	LibHalChangeSet *cs;
 	fd = -1;
 
+
+	cs = NULL;
+
 	/* hook in our debug into libvolume_id */
 	volume_id_log_fn = vid_log;
 
+	setup_logger ();
+
 	/* assume failure */
 	ret = 1;
 
@@ -475,20 +336,24 @@ main (int argc, char *argv[])
 	else
 		partition_number = (unsigned int) -1;
 
+	partition_start_str = getenv ("HAL_PROP_VOLUME_PARTITION_START");
+	if (partition_start_str != NULL)
+		partition_start = (guint64) strtoll (partition_start_str, NULL, 0);
+	else
+		partition_start = (guint64) 0;
+
 	is_disc_str = getenv ("HAL_PROP_VOLUME_IS_DISC");
 	if (is_disc_str != NULL && strcmp (is_disc_str, "true") == 0)
 		is_disc = TRUE;
 	else
 		is_disc = FALSE;
 
-	setup_logger ();
-
 	dbus_error_init (&error);
 	if ((ctx = libhal_ctx_init_direct (&error)) == NULL)
 		goto out;
 
-	changeset = libhal_device_new_changeset (udi);
-	if (changeset == NULL) {
+	cs = libhal_device_new_changeset (udi);
+	if (cs == NULL) {
 		HAL_DEBUG(("Cannot initialize changeset"));
 		goto out;
 	}
@@ -502,11 +367,11 @@ main (int argc, char *argv[])
 	/* block size and total size */
 	if (ioctl (fd, BLKSSZGET, &block_size) == 0) {
 		HAL_DEBUG(("volume.block_size = %d", block_size));
-		libhal_changeset_set_property_int (changeset, "volume.block_size", block_size);
+		libhal_changeset_set_property_int (cs, "volume.block_size", block_size);
 	}
 	if (ioctl (fd, BLKGETSIZE64, &vol_size) == 0) {
 		HAL_DEBUG(("volume.size = %llu", vol_size));
-		libhal_changeset_set_property_uint64 (changeset, "volume.size", vol_size);
+		libhal_changeset_set_property_uint64 (cs, "volume.size", vol_size);
 	} else
 		vol_size = 0;
 
@@ -518,12 +383,12 @@ main (int argc, char *argv[])
 		struct cdrom_tochdr; /* toc_hdr; */
 
 		/* defaults */
-		libhal_changeset_set_property_string (changeset, "volume.disc.type", "unknown");
-		libhal_changeset_set_property_bool (changeset, "volume.disc.has_audio", FALSE);
-		libhal_changeset_set_property_bool (changeset, "volume.disc.has_data", FALSE);
-		libhal_changeset_set_property_bool (changeset, "volume.disc.is_blank", FALSE);
-		libhal_changeset_set_property_bool (changeset, "volume.disc.is_appendable", FALSE);
-		libhal_changeset_set_property_bool (changeset, "volume.disc.is_rewritable", FALSE);
+		libhal_changeset_set_property_string (cs, "volume.disc.type", "unknown");
+		libhal_changeset_set_property_bool (cs, "volume.disc.has_audio", FALSE);
+		libhal_changeset_set_property_bool (cs, "volume.disc.has_data", FALSE);
+		libhal_changeset_set_property_bool (cs, "volume.disc.is_blank", FALSE);
+		libhal_changeset_set_property_bool (cs, "volume.disc.is_appendable", FALSE);
+		libhal_changeset_set_property_bool (cs, "volume.disc.is_rewritable", FALSE);
 
 		/* Suggested by Alex Larsson to get rid of log spewage
 		 * on Alan's cd changer (RH bug 130649) */
@@ -535,33 +400,33 @@ main (int argc, char *argv[])
 		type = ioctl (fd, CDROM_DISC_STATUS, CDSL_CURRENT);
 		switch (type) {
 		case CDS_AUDIO:		/* audio CD */
-			libhal_changeset_set_property_bool (changeset, "volume.disc.has_audio", TRUE);
+			libhal_changeset_set_property_bool (cs, "volume.disc.has_audio", TRUE);
 			HAL_DEBUG(("Disc in %s has audio", device_file));
 			should_probe_for_fs = FALSE;
 			break;
 		case CDS_MIXED:		/* mixed mode CD */
-			libhal_changeset_set_property_bool (changeset, "volume.disc.has_audio", TRUE);
-			libhal_changeset_set_property_bool (changeset, "volume.disc.has_data", TRUE);
+			libhal_changeset_set_property_bool (cs, "volume.disc.has_audio", TRUE);
+			libhal_changeset_set_property_bool (cs, "volume.disc.has_data", TRUE);
 			HAL_DEBUG(("Disc in %s has audio+data", device_file));
 			break;
 		case CDS_DATA_1:	/* data CD */
 		case CDS_DATA_2:
 		case CDS_XA_2_1:
 		case CDS_XA_2_2:
-			libhal_changeset_set_property_bool (changeset, "volume.disc.has_data", TRUE);
+			libhal_changeset_set_property_bool (cs, "volume.disc.has_data", TRUE);
 			HAL_DEBUG(("Disc in %s has data", device_file));
-			advanced_disc_detect (ctx, udi, changeset, fd, device_file);
+			advanced_disc_detect (ctx, udi, cs, fd, device_file);
 			break;
 		case CDS_NO_INFO:	/* blank or invalid CD */
-			libhal_changeset_set_property_bool (changeset, "volume.disc.is_blank", TRUE);
+			libhal_changeset_set_property_bool (cs, "volume.disc.is_blank", TRUE);
 			/* set the volume size to 0 if disc is blank and not as 4 from BLKGETSIZE64 */
-			libhal_changeset_set_property_int (changeset, "volume.block_size", 0);
+			libhal_changeset_set_property_int (cs, "volume.block_size", 0);
 			HAL_DEBUG(("Disc in %s is blank", device_file));
 			should_probe_for_fs = FALSE;
 			break;
 			
 		default:		/* should never see this */
-			libhal_changeset_set_property_string (changeset, "volume.disc_type", "unknown");
+			libhal_changeset_set_property_string (cs, "volume.disc_type", "unknown");
 			HAL_DEBUG(("Disc in %s returned unknown CDROM_DISC_STATUS", device_file));
 			should_probe_for_fs = FALSE;
 			break;
@@ -575,65 +440,65 @@ main (int argc, char *argv[])
 		if (type != -1) {
 			switch (type) {
 			case 0x08: /* CD-ROM */
-				libhal_changeset_set_property_string (changeset, "volume.disc.type", "cd_rom");
+				libhal_changeset_set_property_string (cs, "volume.disc.type", "cd_rom");
 				break;
 			case 0x09: /* CD-R */
-				libhal_changeset_set_property_string (changeset, "volume.disc.type", "cd_r");
+				libhal_changeset_set_property_string (cs, "volume.disc.type", "cd_r");
 				break;
 			case 0x0a: /* CD-RW */
-				libhal_changeset_set_property_string (changeset, "volume.disc.type", "cd_rw");
-				libhal_changeset_set_property_bool (changeset, "volume.disc.is_rewritable", TRUE);
+				libhal_changeset_set_property_string (cs, "volume.disc.type", "cd_rw");
+				libhal_changeset_set_property_bool (cs, "volume.disc.is_rewritable", TRUE);
 				break;
 			case 0x10: /* DVD-ROM */
-				libhal_changeset_set_property_string (changeset, "volume.disc.type", "dvd_rom");
+				libhal_changeset_set_property_string (cs, "volume.disc.type", "dvd_rom");
 				break;
 			case 0x11: /* DVD-R Sequential */
-				libhal_changeset_set_property_string (changeset, "volume.disc.type", "dvd_r");
+				libhal_changeset_set_property_string (cs, "volume.disc.type", "dvd_r");
 				break;
 			case 0x12: /* DVD-RAM */
-				libhal_changeset_set_property_string (changeset, "volume.disc.type", "dvd_ram");
-				libhal_changeset_set_property_bool (changeset, "volume.disc.is_rewritable", TRUE);
+				libhal_changeset_set_property_string (cs, "volume.disc.type", "dvd_ram");
+				libhal_changeset_set_property_bool (cs, "volume.disc.is_rewritable", TRUE);
 				break;
 			case 0x13: /* DVD-RW Restricted Overwrite */
-				libhal_changeset_set_property_string (changeset, "volume.disc.type", "dvd_rw");
-				libhal_changeset_set_property_bool (changeset, "volume.disc.is_rewritable", TRUE);
+				libhal_changeset_set_property_string (cs, "volume.disc.type", "dvd_rw");
+				libhal_changeset_set_property_bool (cs, "volume.disc.is_rewritable", TRUE);
 				break;
 			case 0x14: /* DVD-RW Sequential */
-				libhal_changeset_set_property_string (changeset, "volume.disc.type", "dvd_rw");
-				libhal_changeset_set_property_bool (changeset, "volume.disc.is_rewritable", TRUE);
+				libhal_changeset_set_property_string (cs, "volume.disc.type", "dvd_rw");
+				libhal_changeset_set_property_bool (cs, "volume.disc.is_rewritable", TRUE);
 				break;
 			case 0x1A: /* DVD+RW */
-				libhal_changeset_set_property_string (changeset, "volume.disc.type", "dvd_plus_rw");
-				libhal_changeset_set_property_bool (changeset, "volume.disc.is_rewritable", TRUE);
+				libhal_changeset_set_property_string (cs, "volume.disc.type", "dvd_plus_rw");
+				libhal_changeset_set_property_bool (cs, "volume.disc.is_rewritable", TRUE);
 				break;
 			case 0x1B: /* DVD+R */
-				libhal_changeset_set_property_string (changeset, "volume.disc.type", "dvd_plus_r");
+				libhal_changeset_set_property_string (cs, "volume.disc.type", "dvd_plus_r");
 				break;
 			case 0x2B: /* DVD+R Double Layer */
-                          	libhal_changeset_set_property_string (changeset, "volume.disc.type", "dvd_plus_r_dl");
+                          	libhal_changeset_set_property_string (cs, "volume.disc.type", "dvd_plus_r_dl");
 				break;
 			case 0x40: /* BD-ROM  */
-                          	libhal_changeset_set_property_string (changeset, "volume.disc.type", "bd_rom");
+                          	libhal_changeset_set_property_string (cs, "volume.disc.type", "bd_rom");
 				break;
 			case 0x41: /* BD-R Sequential */
-                          	libhal_changeset_set_property_string (changeset, "volume.disc.type", "bd_r");
+                          	libhal_changeset_set_property_string (cs, "volume.disc.type", "bd_r");
 				break;
 			case 0x42: /* BD-R Random */
-                          	libhal_changeset_set_property_string (changeset, "volume.disc.type", "bd_r");
+                          	libhal_changeset_set_property_string (cs, "volume.disc.type", "bd_r");
 				break;
 			case 0x43: /* BD-RE */
-                          	libhal_changeset_set_property_string (changeset, "volume.disc.type", "bd_re");
-				libhal_changeset_set_property_bool (changeset, "volume.disc.is_rewritable", TRUE);
+                          	libhal_changeset_set_property_string (cs, "volume.disc.type", "bd_re");
+				libhal_changeset_set_property_bool (cs, "volume.disc.is_rewritable", TRUE);
 				break;
 			case 0x50: /* HD DVD-ROM */
-                          	libhal_changeset_set_property_string (changeset, "volume.disc.type", "hddvd_rom");
+                          	libhal_changeset_set_property_string (cs, "volume.disc.type", "hddvd_rom");
 				break;
 			case 0x51: /* HD DVD-R */
-                          	libhal_changeset_set_property_string (changeset, "volume.disc.type", "hddvd_r");
+                          	libhal_changeset_set_property_string (cs, "volume.disc.type", "hddvd_r");
 				break;
 			case 0x52: /* HD DVD-Rewritable */
-                          	libhal_changeset_set_property_string (changeset, "volume.disc.type", "hddvd_rw");
-				libhal_changeset_set_property_bool (changeset, "volume.disc.is_rewritable", TRUE);
+                          	libhal_changeset_set_property_string (cs, "volume.disc.type", "hddvd_rw");
+				libhal_changeset_set_property_bool (cs, "volume.disc.is_rewritable", TRUE);
 				break;
 			default: 
 				break;
@@ -642,16 +507,16 @@ main (int argc, char *argv[])
 
 		if (get_disc_capacity_for_type (fd, type, &capacity) == 0) {
 			HAL_DEBUG(("volume.disc.capacity = %llu", capacity));
-			libhal_changeset_set_property_uint64 (changeset, "volume.disc.capacity", capacity);
+			libhal_changeset_set_property_uint64 (cs, "volume.disc.capacity", capacity);
 		}
 
 		/* On some hardware the get_disc_type call fails, so we use this as a backup */
 		if (disc_is_rewritable (fd)) {
-			libhal_changeset_set_property_bool (changeset, "volume.disc.is_rewritable", TRUE);
+			libhal_changeset_set_property_bool (cs, "volume.disc.is_rewritable", TRUE);
 		}
 		
 		if (disc_is_appendable (fd)) {
-			libhal_changeset_set_property_bool (changeset, "volume.disc.is_appendable", TRUE);
+			libhal_changeset_set_property_bool (cs, "volume.disc.is_appendable", TRUE);
 		}
 
 #if 0
@@ -703,14 +568,15 @@ main (int argc, char *argv[])
 		vid = volume_id_open_fd (fd);
 		if (vid != NULL) {
 			if (volume_id_probe_all (vid, vol_probe_offset , vol_size) == 0) {
-				set_volume_id_values(ctx, udi, changeset, vid);
+				set_volume_id_values(ctx, udi, cs, vid);
 			} else {
-				libhal_changeset_set_property_string (changeset, "info.product", "Volume");
+				libhal_changeset_set_property_string (cs, "info.product", "Volume");
 			}
 
 			/* VOLUME_ID_UNUSED means vol_id didn't detect anything that it knows about - look if 
 			 * it's an extended msdos partition table 
 			 */
+#if 0
 			if (vid->usage_id == VOLUME_ID_UNUSED) {
 				unsigned char buf[2];
 
@@ -724,64 +590,113 @@ main (int argc, char *argv[])
 					if (memcmp (buf, MSDOS_MAGIC, 2) == 0) {
 						HAL_DEBUG (("partition is an extended msdos partition table"));
 
-						libhal_changeset_set_property_string (changeset, "volume.fsusage", "partitiontable");
-						libhal_changeset_set_property_string (changeset, "volume.fstype", "msdos_extended_partitiontable");
-						libhal_changeset_set_property_string (changeset, "volume.fsversion", "");
+						libhal_changeset_set_property_string (cs, "volume.fsusage", "partitiontable");
+						libhal_changeset_set_property_string (cs, "volume.fstype", "msdos_extended_partitiontable");
+						libhal_changeset_set_property_string (cs, "volume.fsversion", "");
 						
 					}
 				}
 				
 			}
+#endif
 
 			volume_id_close(vid);
 		}
 
 		/* get partition type number, if we find a msdos partition table */
-		if (partition_number_str != NULL && partition_number <= 256 && partition_number > 0) {
+		if (partition_number_str != NULL && 
+		    partition_number <= 256 && partition_number > 0 &&
+		    partition_start > 0) {
 			struct msdos_part_entry *idx;
 			int fd;
+			PartitionTable *p;
 
 			if ((stordev_dev_file = libhal_device_get_property_string (
 					ctx, parent_udi, "block.device", &error)) == NULL) {
 				goto out;
 			}
-			fd = open(stordev_dev_file, O_RDONLY);
-			if (fd >= 0) {
-				idx = probe_msdos_part_table(fd);
-				if (idx != NULL) {
-					uint64_t start;
-					uint64_t size;
-					unsigned char type;
-
-					type = idx[partition_number - 1].part_type;
-					start = idx[partition_number - 1].start;
-					size = idx[partition_number - 1].size;
-					if (type > 0) {
-						libhal_changeset_set_property_int (
-							changeset, "volume.partition.msdos_part_table_type", type);
-						libhal_changeset_set_property_uint64 (
-							changeset, "volume.partition.msdos_part_table_start", start);
-						libhal_changeset_set_property_uint64 (
-							changeset, "volume.partition.msdos_part_table_size", size);
-
-						/* NOTE: We trust the type from the partition table
-						 * if it explicitly got correct entries for RAID and
-						 * LVM partitions.
-						 *
-						 * But in general it's not a good idea to trust the
-						 * partition table type as many geek^Wexpert users use 
-						 * FAT filesystems on type 0x83 which is Linux.
-						 *
-						 * Linux RAID autodetect is 0xfd and Linux LVM is 0x8e
-						 */
-						if (type == 0xfd || type == 0x8e ) {
-							libhal_changeset_set_property_string (
-								changeset, "volume.fsusage", "raid");
-						}
+
+			HAL_INFO (("Loading part table"));
+			p = part_table_load_from_disk (stordev_dev_file);
+			if (p != NULL) {
+				PartitionTable *p2;
+				int entry;
+
+				HAL_INFO (("Looking at part table"));
+				part_table_find (p, partition_start, &p2, &entry);
+				if (entry >= 0) {
+					const char *scheme;
+					char *type;
+					char *label;
+					char *uuid;
+					char **flags;
+
+					scheme = part_get_scheme_name (part_table_get_scheme (p2));
+					type = part_table_entry_get_type (p2, entry);
+					label = part_table_entry_get_label (p2, entry);
+					uuid = part_table_entry_get_uuid (p2, entry);
+					flags = part_table_entry_get_flags (p2, entry);
+
+					if (type == NULL)
+						type = g_strdup ("");
+					if (label == NULL)
+						label = g_strdup ("");
+					if (uuid == NULL)
+						uuid = g_strdup ("");
+					if (flags == NULL) {
+						flags = g_new0 (char *, 2);
+						flags[0] = NULL;
+					}
+
+					libhal_changeset_set_property_string (cs, "volume.partition.scheme", scheme);
+					libhal_changeset_set_property_string (cs, "volume.partition.type", type);
+					libhal_changeset_set_property_string (cs, "volume.partition.label", label);
+					libhal_changeset_set_property_string (cs, "volume.partition.uuid", uuid);
+					libhal_changeset_set_property_strlist (cs, "volume.partition.flags", flags);
+					
+					/* NOTE: We trust the type from the partition table
+					 * if it explicitly got correct entries for RAID and
+					 * LVM partitions.
+					 *
+					 * But in general it's not a good idea to trust the
+					 * partition table type as many geek^Wexpert users use 
+					 * FAT filesystems on type 0x83 which is Linux.
+					 *
+					 * For MBR, Linux RAID autodetect is 0xfd and Linux LVM is 0x8e
+					 *
+					 * For GPT, RAID is A19D880F-05FC-4D3B-A006-743F0F84911E and
+					 * LVM is E6D6D379-F507-44C2-A23C-238F2A3DF928.
+					 */
+					if (
+						((strcmp (scheme, "mbr") == 0 || strcmp (scheme, "embr") == 0) &&
+						 (0xfd == atoi (type) || 0x8e == atoi (type)))
+						||
+						((strcmp (scheme, "gpt") == 0) &&
+						 ((strcmp (type, "A19D880F-05FC-4D3B-A006-743F0F84911E") == 0) ||
+						  (strcmp (type, "E6D6D379-F507-44C2-A23C-238F2A3DF928")) == 0)) ) {
+
+						libhal_changeset_set_property_string (cs, "volume.fsusage", "raid");
+
+					}
+
+					/* see if this partition is an embedded partition table */
+					if (part_table_entry_get_nested (p2, entry) != NULL) {
+
+						libhal_changeset_set_property_string (cs, "volume.fsusage", "partitiontable");
+						libhal_changeset_set_property_string (cs, "volume.fstype", "");
+						libhal_changeset_set_property_string (cs, "volume.fsversion", "");
 					}
+
+					g_free (type);
+					g_free (label);
+					g_free (uuid);
+					g_strfreev (flags);
 				}
-				close (fd);
+
+				part_table_free (p);
 			}
+			HAL_INFO (("Done looking at part table"));
+
 			libhal_free_string (stordev_dev_file);
 		}
 	}
@@ -789,15 +704,17 @@ main (int argc, char *argv[])
 	/* good so far */
 	ret = 0;
 
-	/* for testing...
-	  char *values[4] = {"foo", "bar", "baz", NULL};
-	  libhal_changeset_set_property_strlist (changeset, "foo.bar", values);
-	*/
+out:
+	if (cs != NULL) {
+		/* for testing...
+		   char *values[4] = {"foo", "bar", "baz", NULL};
+		   libhal_changeset_set_property_strlist (cs, "foo.bar", values);
+		*/
+		libhal_device_commit_changeset (ctx, cs, &error);
+		libhal_device_free_changeset (cs);
+	}
 
-	libhal_device_commit_changeset (ctx, changeset, &error);
-	libhal_device_free_changeset (changeset);
 
-out:
 	if (fd >= 0)
 		close (fd);
 
diff --git a/libhal-storage/libhal-storage.c b/libhal-storage/libhal-storage.c
index 206ffd3..b20a5a8 100644
--- a/libhal-storage/libhal-storage.c
+++ b/libhal-storage/libhal-storage.c
@@ -711,6 +711,7 @@ struct LibHalDrive_s {
 
 	dbus_uint64_t drive_size;
 	dbus_uint64_t drive_media_size;
+	char *partition_scheme;
 
 	LibHalContext *hal_ctx;
 
@@ -738,6 +739,11 @@ struct LibHalVolume_s {
 
 	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;
@@ -806,6 +812,7 @@ libhal_drive_free (LibHalDrive *drive)
 	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);
 }
@@ -833,6 +840,12 @@ libhal_volume_free (LibHalVolume *vol)
 	libhal_free_string (vol->crypto_backing_volume);
 	libhal_free_string (vol->storage_device);
 
+	libhal_free_string (vol->partition_scheme);
+	libhal_free_string (vol->partition_type);
+	libhal_free_string (vol->partition_label);
+	libhal_free_string (vol->partition_uuid);
+	libhal_free_string (vol->partition_flags);
+
 	free (vol);
 }
 
@@ -941,6 +954,8 @@ libhal_drive_from_udi (LibHalContext *ha
 		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.physical_device",   drive->physical_device);
 		LIBHAL_PROP_EXTRACT_STRING ("storage.firmware_version",  drive->firmware_version);
 		LIBHAL_PROP_EXTRACT_STRING ("storage.serial",            drive->serial);
@@ -1114,6 +1129,12 @@ libhal_volume_from_udi (LibHalContext *h
 
 		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);
@@ -1425,6 +1446,13 @@ libhal_drive_get_media_size (LibHalDrive
 	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)
 {
@@ -1569,6 +1597,37 @@ libhal_volume_get_partition_number (LibH
 	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 volume->partition_flags;
+}
+
+
 dbus_uint64_t 
 libhal_volume_get_partition_start_offset (LibHalVolume *volume)
 {
diff --git a/libhal-storage/libhal-storage.h b/libhal-storage/libhal-storage.h
index 0ce5f2d..c88a389 100644
--- a/libhal-storage/libhal-storage.h
+++ b/libhal-storage/libhal-storage.h
@@ -32,6 +32,9 @@
 
 #if defined(__cplusplus)
 extern "C" {
+#if 0
+} /* shut up emacs indenting */
+#endif
 #endif
 
 struct LibHalDrive_s;
@@ -128,17 +131,17 @@ typedef struct {
 	const char *icon_path;
 } LibHalStoragePolicyIconPair;
 
-LibHalStoragePolicy *libhal_storage_policy_new		    (void);
-void                 libhal_storage_policy_free		    (LibHalStoragePolicy *policy);
+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);
+							     const char *path) LIBHAL_DEPRECATED;
 
 void                 libhal_storage_policy_set_icon_mapping (LibHalStoragePolicy *policy, 
-							     LibHalStoragePolicyIconPair *pairs);
+							     LibHalStoragePolicyIconPair *pairs) LIBHAL_DEPRECATED;
 const char  	    *libhal_storage_policy_lookup_icon	    (LibHalStoragePolicy *policy, 
-						  	     LibHalStoragePolicyIcon icon);
+						  	     LibHalStoragePolicyIcon icon) LIBHAL_DEPRECATED;
 
 typedef enum {
 	LIBHAL_DRIVE_BUS_UNKNOWN     = 0x00,
@@ -197,6 +200,7 @@ dbus_bool_t          libhal_drive_uses_r
 dbus_bool_t          libhal_drive_is_media_detected        (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);
@@ -218,29 +222,29 @@ const char          *libhal_drive_get_de
 
 char                *libhal_drive_policy_compute_display_name (LibHalDrive        *drive, 
 							       LibHalVolume        *volume, 
-							       LibHalStoragePolicy *policy);
+							       LibHalStoragePolicy *policy) LIBHAL_DEPRECATED;
 char                *libhal_drive_policy_compute_icon_name    (LibHalDrive         *drive, 
 							       LibHalVolume        *volume, 
-							       LibHalStoragePolicy *policy);
+							       LibHalStoragePolicy *policy) LIBHAL_DEPRECATED;
 
 dbus_bool_t          libhal_drive_policy_is_mountable            (LibHalDrive         *drive, 
-								  LibHalStoragePolicy *policy);
+								  LibHalStoragePolicy *policy) LIBHAL_DEPRECATED;
 const char          *libhal_drive_policy_get_desired_mount_point (LibHalDrive         *drive, 
-								  LibHalStoragePolicy *policy);
+								  LibHalStoragePolicy *policy) LIBHAL_DEPRECATED;
 const char          *libhal_drive_policy_get_mount_options       (LibHalDrive         *drive, 
-							          LibHalStoragePolicy *policy);
+							          LibHalStoragePolicy *policy) LIBHAL_DEPRECATED;
 const char          *libhal_drive_policy_get_mount_fs            (LibHalDrive      *drive, 
-								  LibHalStoragePolicy *policy);
+								  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);
-dbus_bool_t  libhal_drive_policy_default_use_managed_keyword           (LibHalContext *hal_ctx);
-char        *libhal_drive_policy_default_get_managed_keyword_primary   (LibHalContext *hal_ctx);
-char        *libhal_drive_policy_default_get_managed_keyword_secondary (LibHalContext *hal_ctx);
+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 {
@@ -290,9 +294,16 @@ dbus_bool_t          libhal_volume_is_mo
 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);
@@ -309,38 +320,39 @@ dbus_bool_t          libhal_volume_disc_
 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);
-dbus_uint64_t     libhal_volume_get_msdos_part_table_start    (LibHalVolume     *volume);
-dbus_uint64_t     libhal_volume_get_msdos_part_table_size     (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);
+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);
+							       LibHalStoragePolicy *policy) LIBHAL_DEPRECATED;
 char             *libhal_volume_policy_compute_icon_name      (LibHalDrive         *drive, 
 							       LibHalVolume        *volume, 
-							       LibHalStoragePolicy *policy);
+							       LibHalStoragePolicy *policy) LIBHAL_DEPRECATED;
 
 dbus_bool_t       libhal_volume_policy_should_be_visible      (LibHalDrive         *drive, 
 							       LibHalVolume        *volume, 
 							       LibHalStoragePolicy *policy, 
-							       const char          *target_mount_point);
+							       const char          *target_mount_point) LIBHAL_DEPRECATED;
 
 dbus_bool_t       libhal_volume_policy_is_mountable		(LibHalDrive         *drive, 
 								 LibHalVolume        *volume, 
-								 LibHalStoragePolicy *policy);
+								 LibHalStoragePolicy *policy) LIBHAL_DEPRECATED;
 const char       *libhal_volume_policy_get_desired_mount_point  (LibHalDrive         *drive, 
 								 LibHalVolume        *volume, 
-								 LibHalStoragePolicy *policy);
+								 LibHalStoragePolicy *policy) LIBHAL_DEPRECATED;
 const char       *libhal_volume_policy_get_mount_options   	(LibHalDrive         *drive, 
 							    	 LibHalVolume        *volume, 
-							    	 LibHalStoragePolicy *policy);
+							    	 LibHalStoragePolicy *policy) LIBHAL_DEPRECATED;
 const char       *libhal_volume_policy_get_mount_fs        	(LibHalDrive         *drive, 
 							    	 LibHalVolume        *volume, 
-							    	 LibHalStoragePolicy *policy);
+							    	 LibHalStoragePolicy *policy) LIBHAL_DEPRECATED;
 
 
 #if defined(__cplusplus)
diff --git a/libhal/libhal.h b/libhal/libhal.h
index 15ee2d4..ab00e57 100644
--- a/libhal/libhal.h
+++ b/libhal/libhal.h
@@ -35,6 +35,13 @@ extern "C" {
 #endif
 #endif
 
+#if defined(__GNUC__)
+#define LIBHAL_DEPRECATED __attribute__ ((deprecated))  
+#else  
+#define LIBHAL_DEPRECATED  
+#endif 
+
+
 #define LIBHAL_FREE_DBUS_ERROR(_dbus_error_)					\
 	do {									\
 		if (dbus_error_is_set(_dbus_error_))				\
diff --git a/partutil/Makefile.am b/partutil/Makefile.am
new file mode 100644
index 0000000..5d409bb
--- /dev/null
+++ b/partutil/Makefile.am
@@ -0,0 +1,11 @@
+
+INCLUDES = @GLIB_CFLAGS@
+
+noinst_LTLIBRARIES = libpartutil.la
+
+libpartutil_la_SOURCES = partutil.h partutil.c ../hald/logger.c
+
+libpartutil_la_LIBADD = @GLIB_LIBS@ @PARTED_LIBS@
+
+clean-local :
+	rm -f *~
diff --git a/partutil/partutil.c b/partutil/partutil.c
new file mode 100644
index 0000000..beeaedb
--- /dev/null
+++ b/partutil/partutil.c
@@ -0,0 +1,1791 @@
+/***************************************************************************
+ *
+ * part.c : library for reading and writing partition tables - uses
+ *          libparted for the heavy lifting
+ *
+ * Copyright (C) 2006 David Zeuthen, <david at fubar.dk>
+ *
+ * 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
+ *
+ **************************************************************************/
+
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <ctype.h>
+
+#include <linux/hdreg.h>
+
+#define BLKGETSIZE64 _IOR(0x12,114,size_t)
+
+#include "../hald/logger.h"
+#include "partutil.h"
+
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+
+#ifdef USE_PARTED
+#include <parted/parted.h>
+#endif
+
+const char *
+part_get_scheme_name (PartitionScheme scheme)
+{
+	const char *s;
+
+	switch (scheme) {
+	case PART_TYPE_GPT:
+		s = "gpt";
+		break;
+	case PART_TYPE_MSDOS:
+		s = "mbr";
+		break;
+	case PART_TYPE_MSDOS_EXTENDED:
+		s = "embr";
+		break;
+	case PART_TYPE_APPLE:
+		s = "apm";
+		break;
+	default:
+		s = NULL;
+		break;
+	}
+
+	return s;
+}
+
+struct PartitionEntry_s;
+typedef struct PartitionEntry_s PartitionEntry;
+
+struct PartitionEntry_s
+{
+	gboolean is_part_table;
+
+	/* NULL iff is_part_table==FALSE */
+	PartitionTable *part_table;
+
+	/* these are always set */
+	guint8 *data;
+	int length;
+
+	/* offset _on disk_ where the entry starts */
+	guint64 offset;
+};
+
+struct PartitionTable_s
+{
+	/* partitioning scheme used */
+	PartitionScheme scheme;
+
+	/* offset of table on disk */
+	guint64 offset;
+	guint64 size;
+
+	/* entries in partition table */
+	GSList *entries;
+};
+
+void
+part_table_find (PartitionTable *p, guint64 offset,
+		 PartitionTable **out_part_table, int *out_entry)
+{
+	int n;
+	int num_entries;
+
+	*out_part_table = p;
+	*out_entry = -1;
+
+	num_entries = part_table_get_num_entries (p);
+	for (n = 0; n < num_entries; n++) {
+		guint64 pe_offset;
+		guint64 pe_size;
+
+		pe_offset = part_table_entry_get_offset (p, n);
+		pe_size = part_table_entry_get_size (p, n);
+
+		if ((offset >= pe_offset) && (offset < pe_offset + pe_size)) {
+			PartitionTable *part_table_nested;
+
+			part_table_nested = part_table_entry_get_nested (p, n);
+			/* return the extended partition only if the offset points to it - otherwise
+			 * look for a logical partition
+			 */
+			if (part_table_nested != NULL && offset > pe_offset) {
+				part_table_find (part_table_nested, offset, out_part_table, out_entry);
+			} else {
+				*out_entry = n;
+			}
+
+			/* and we're done... */
+			break;
+		}
+	}
+}
+
+
+static guint16
+get_le16 (const void *buf)
+{
+	return GUINT16_FROM_LE ( * ((guint16 *) buf) );
+}
+
+
+static guint32
+get_le32 (const void *buf)
+{
+	return GUINT32_FROM_LE ( * ((guint32 *) buf) );
+}
+
+static guint64
+get_le64 (const void *buf)
+{
+	return GUINT64_FROM_LE ( * ((guint64 *) buf) );
+}
+
+
+static guint32
+get_be32 (const void *buf)
+{
+	return GUINT32_FROM_BE ( * ((guint32 *) buf) );
+}
+
+/* see http://en.wikipedia.org/wiki/Globally_Unique_Identifier - excerpt
+ *
+ * Guids are most commonly written in text as a sequence of hexadecimal digits as such:
+ *
+ *   3F2504E0-4F89-11D3-9A0C-0305E82C3301
+ *
+ * This text notation follows from the data structure defined above. The sequence is
+ *
+ *  1. Data1 (8 characters)
+ *  2. Hyphen
+ *  3. Data2 (4 characters)
+ *  4. Hyphen
+ *  5. Data3 (4 characters)
+ *  6. Hyphen
+ *  7. Initial two items from Data4 (4 characters)
+ *  8. Hyphen
+ *  9. Remaining six items from Data4 (12 characters)
+ *
+ * Often braces are added to enclose the above format, as such:
+ *
+ *   {3F2504E0-4F89-11D3-9A0C-0305E82C3301}
+ *
+ * When printing fewer characters is desired guids are sometimes encoded
+ * into a base64 string of 22 to 24 characters (depending on
+ * padding). For instance:
+ *
+ *   7QDBkvCA1+B9K/U0vrQx1A
+ *   7QDBkvCA1+B9K/U0vrQx1A==
+ */
+
+typedef struct efi_guid_s {
+	guint32 data1;
+	guint16 data2;
+	guint16 data3;
+	guint8  data4[8];
+} __attribute__ ((packed)) efi_guid;
+
+static char *
+get_le_guid (const guint8 *buf)
+{
+	efi_guid *guid = (efi_guid *) buf;
+
+	return g_strdup_printf("%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
+			       get_le32 (&(guid->data1)), 
+			       get_le16 (&(guid->data2)),
+			       get_le16 (&(guid->data3)),
+			       guid->data4[0],
+			       guid->data4[1],
+			       guid->data4[2],
+			       guid->data4[3],
+			       guid->data4[4],
+			       guid->data4[5],
+			       guid->data4[6],
+			       guid->data4[7]);
+}
+
+static gboolean
+set_le_guid (guint8 *buf, const char *source)
+{
+	efi_guid *guid = (efi_guid *) buf;
+	guint32 __attribute__((__unused__)) data1;
+	guint16 __attribute__((__unused__)) data2;
+	guint16 __attribute__((__unused__)) data3;
+	guint8  __attribute__((__unused__)) data4[8];
+	gboolean ret;
+	int n;
+
+	n = sscanf (source, "%x-%hx-%hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
+		    &guid->data1,
+		    &guid->data2,
+		    &guid->data3,
+		    &(guid->data4[0]),
+		    &(guid->data4[1]),
+		    &(guid->data4[2]),
+		    &(guid->data4[3]),
+		    &(guid->data4[4]),
+		    &(guid->data4[5]),
+		    &(guid->data4[6]),
+		    &(guid->data4[7]));
+
+	if (n != 11) {
+		HAL_INFO (("guid '%s' is not valid"));
+		goto out;
+	}
+
+#if 0
+	HAL_INFO (("source = %s", source));
+	HAL_INFO (("data1 = %08x", guid->data1));
+	HAL_INFO (("data2 = %04x", guid->data2));
+	HAL_INFO (("data3 = %04x", guid->data3));
+	HAL_INFO (("data4[0] = %02x", guid->data4[0]));
+	HAL_INFO (("data4[1] = %02x", guid->data4[1]));
+	HAL_INFO (("data4[2] = %02x", guid->data4[2]));
+	HAL_INFO (("data4[3] = %02x", guid->data4[3]));
+	HAL_INFO (("data4[4] = %02x", guid->data4[4]));
+	HAL_INFO (("data4[5] = %02x", guid->data4[5]));
+	HAL_INFO (("data4[6] = %02x", guid->data4[6]));
+	HAL_INFO (("data4[7] = %02x", guid->data4[7]));
+#endif
+
+	guid->data1 = GUINT32_TO_LE (guid->data1);
+	guid->data2 = GUINT16_TO_LE (guid->data2);
+	guid->data3 = GUINT16_TO_LE (guid->data3);
+
+	ret = TRUE;
+
+out:
+	return ret;
+}
+
+static PartitionEntry *
+part_entry_new (PartitionTable *e_part_table, const guint8 *data, int length, guint64 offset)
+{
+	PartitionEntry *pe;
+
+	pe = g_new0 (PartitionEntry, 1);
+	pe->is_part_table = (e_part_table != NULL);
+	pe->part_table = e_part_table;
+	pe->offset = offset;
+	pe->length = length;
+	pe->data = g_new0 (guint8, length);
+	memcpy (pe->data, data, length);
+
+	return pe;
+}
+
+static void 
+part_entry_free (PartitionEntry *pe)
+{
+	if (pe->part_table != NULL) {
+		part_table_free (pe->part_table);
+	}
+	g_free (pe->data);
+	g_free (pe);
+}
+
+static PartitionTable *
+part_table_new_empty (PartitionScheme scheme)
+{
+	PartitionTable *p;
+
+	p = g_new0 (PartitionTable, 1);
+	p->scheme = scheme;
+	p->offset = 0;
+	p->entries = NULL;
+
+	return p;
+}
+
+void
+part_table_free (PartitionTable *p)
+{
+	GSList *i;
+
+	for (i = p->entries; i != NULL; i = i->next) {
+		PartitionEntry *pe = i->data;
+		part_entry_free (pe);
+	}
+	g_slist_free (p->entries);
+	g_free (p);
+}
+
+#if 0
+static PartitionTable *
+part_table_parse_bsd (int fd, guint64 offset, guint64 size)
+{
+	PartitionTable *p;
+
+	p = NULL;
+
+	/* TODO */
+
+	return p;
+}
+#endif
+
+
+#define MSDOS_MAGIC			"\x55\xaa"
+#define MSDOS_PARTTABLE_OFFSET		0x1be
+#define MSDOS_SIG_OFF			0x1fe
+
+#if 0
+static void
+hexdump (const guint8 *mem, int size)
+{
+	int i;
+	int j;
+	int n;
+	const guint8 *buf = (const guint8 *) mem;
+
+	n = 0;
+	printf ("Dumping %d=0x%x bytes\n", size, size);
+	while (n < size) {
+
+		printf ("0x%04x: ", n);
+
+		j = n;
+		for (i = 0; i < 16; i++) {
+			if (j >= size)
+				break;
+			printf ("%02x ", buf[j]);
+			j++;
+		}
+		
+		for ( ; i < 16; i++) {
+			printf ("   ");
+		}
+		
+		printf ("   ");
+		
+		j = n;
+		for (i = 0; i < 16; i++) {
+			if (j >= size)
+				break;
+			printf ("%c", isprint(buf[j]) ? buf[j] : '.');
+			j++;
+		}
+
+		printf ("\n");
+		
+		n += 16;
+	}
+}
+#endif
+
+static PartitionTable *
+part_table_parse_msdos_extended (int fd, guint64 offset, guint64 size)
+{
+	int n;
+	PartitionTable *p;
+	guint64 next;
+
+	//HAL_INFO (("Entering MS-DOS extended parser"));
+
+	p = NULL;
+
+	next = offset;
+
+	while (next != 0) {
+		guint64 readfrom;
+		const guint8 embr[512];
+
+		readfrom = next;
+		next = 0;
+
+		//HAL_INFO (("readfrom = %lld", readfrom));
+
+		if (lseek (fd, readfrom, SEEK_SET) < 0) {
+			HAL_INFO (("lseek failed (%s)", strerror (errno)));
+			goto out;
+		}
+		if (read (fd, &embr, sizeof (embr)) != sizeof (embr)) {
+			HAL_INFO (("read failed (%s)", strerror (errno)));
+			goto out;
+		}
+		
+		if (memcmp (&embr[MSDOS_SIG_OFF], MSDOS_MAGIC, 2) != 0) {
+			HAL_INFO (("No MSDOS_MAGIC found"));
+			goto out;
+		}
+		
+		//HAL_INFO (("MSDOS_MAGIC found"));
+		
+		if (p == NULL) {
+			p = part_table_new_empty (PART_TYPE_MSDOS_EXTENDED);
+			p->offset = offset;
+			p->size = size;
+		}
+
+
+		for (n = 0; n < 2; n++) {
+			PartitionEntry *pe;
+			guint64 pstart;
+			guint64 psize;
+
+			pstart = 0x200 * ((guint64) get_le32 (&(embr[MSDOS_PARTTABLE_OFFSET + n * 16 + 8])));
+			psize  = 0x200 * ((guint64) get_le32 (&(embr[MSDOS_PARTTABLE_OFFSET + n * 16 + 12])));
+
+			if (psize == 0)
+				continue;
+
+			pe = NULL;
+
+			if (n == 0) {
+				//HAL_INFO (("part %d (offset %lld, size %lld, type 0x%02x)", 
+				//     n, readfrom + pstart, psize, ptype));
+
+				//HAL_INFO (("pstart = %lld", pstart));
+
+				//hexdump (&(embr[MSDOS_PARTTABLE_OFFSET + n * 16]), 16);
+
+				pe = part_entry_new (NULL,
+						     &(embr[MSDOS_PARTTABLE_OFFSET + n * 16]),
+						     16, 
+						     readfrom + MSDOS_PARTTABLE_OFFSET + n * 16);
+			} else {
+				if (pstart != 0) {
+					//HAL_INFO (("found chain at offset %lld", offset + pstart);
+					next = offset + pstart;
+				}
+			}
+
+			//HAL_INFO (("pe = %p", pe));
+			
+			if (pe != NULL) {
+				p->entries = g_slist_append (p->entries, pe);
+			}
+		}
+
+	}
+
+out:
+	//HAL_INFO (("Exiting MS-DOS extended parser"));
+	return p;
+}
+
+static PartitionTable *
+part_table_parse_msdos (int fd, guint64 offset, guint64 size, gboolean *found_gpt)
+{
+	int n;
+	const guint8 mbr[512];
+	PartitionTable *p;
+
+	//HAL_INFO (("Entering MS-DOS parser"));
+
+	*found_gpt = FALSE;
+
+	p = NULL;
+
+	if (lseek (fd, offset, SEEK_SET) < 0) {
+		HAL_INFO (("lseek failed (%s)", strerror (errno)));
+		goto out;
+	}
+	if (read (fd, &mbr, sizeof (mbr)) != sizeof (mbr)) {
+		HAL_INFO (("read failed (%s)", strerror (errno)));
+		goto out;
+	}
+
+	if (memcmp (&mbr[MSDOS_SIG_OFF], MSDOS_MAGIC, 2) != 0) {
+		HAL_INFO (("No MSDOS_MAGIC found"));
+		goto out;
+	}
+
+	//HAL_INFO (("MSDOS_MAGIC found"));
+
+	/* sanity checks */
+	for (n = 0; n < 4; n++) {
+		if (mbr[MSDOS_PARTTABLE_OFFSET + n * 16 + 0] != 0 &&
+		    mbr[MSDOS_PARTTABLE_OFFSET + n * 16 + 0] != 0x80) {
+			HAL_INFO (("partitioning flag for part %d is not 0x00 or 0x80", n));
+			goto out;
+		}
+		/* protective MBR for GPT => GPT, not MS-DOS */
+		if (mbr[MSDOS_PARTTABLE_OFFSET + n * 16 + 4] == 0xee) {
+			HAL_INFO (("found partition type 0xee => protective MBR for GPT", n));
+			*found_gpt = TRUE;
+			goto out;
+		}
+	}
+
+	p = part_table_new_empty (PART_TYPE_MSDOS);
+	p->offset = offset;
+	p->size = size;
+
+	/* we _always_ want to create four partitions */
+	for (n = 0; n < 4; n++) {
+		PartitionEntry *pe;
+		guint64 pstart;
+		guint64 psize;
+		guint8 ptype;
+		PartitionTable *e_part_table;
+
+		pstart = 0x200 * ((guint64) get_le32 (&(mbr[MSDOS_PARTTABLE_OFFSET + n * 16 + 8])));
+		psize  = 0x200 * ((guint64) get_le32 (&(mbr[MSDOS_PARTTABLE_OFFSET + n * 16 + 12])));
+		ptype = mbr[MSDOS_PARTTABLE_OFFSET + n * 16 + 4];
+
+		//HAL_INFO (("looking at part %d (offset %lld, size %lld, type 0x%02x)", n, pstart, psize, ptype));
+
+		pe = NULL;
+		e_part_table = NULL;
+
+		/* look for embedded partition tables */
+		switch (ptype) {
+
+                /* extended partitions */
+		case 0x05: /* MS-DOS */
+		case 0x0f: /* Win95 */
+		case 0x85: /* Linux */
+			e_part_table = part_table_parse_msdos_extended (fd, pstart, psize);
+			if (e_part_table != NULL) {
+				pe = part_entry_new (e_part_table,
+						     &(mbr[MSDOS_PARTTABLE_OFFSET + n * 16]),
+						     16, 
+						     offset + MSDOS_PARTTABLE_OFFSET + n * 16);
+			}
+			break;
+
+		case 0xa5: /* FreeBSD */
+		case 0xa6: /* OpenBSD */
+		case 0xa9: /* NetBSD */
+			//e_part_table = part_table_parse_bsd (fd, pstart, psize);
+			//break;
+
+		default:
+			//HAL_INFO (("new part entry"));
+			pe = part_entry_new (NULL,
+					     &(mbr[MSDOS_PARTTABLE_OFFSET + n * 16]),
+					     16, 
+					     offset + MSDOS_PARTTABLE_OFFSET + n * 16);
+			break;
+		}
+
+		//HAL_INFO (("pe = %p", pe));
+
+		p->entries = g_slist_append (p->entries, pe);
+	}
+
+out:
+	//HAL_INFO (("Exiting MS-DOS parser"));
+	return p;
+}
+
+#define GPT_MAGIC "EFI PART"
+
+#define GPT_PART_TYPE_GUID_EMPTY "00000000-0000-0000-0000-000000000000"
+
+static PartitionTable *
+part_table_parse_gpt (int fd, guint64 offset, guint64 size)
+{
+	int n;
+	PartitionTable *p;
+	guint8 buf[16];
+	guint64 partition_entry_lba;
+	int num_entries;
+	int size_of_entry;
+
+	HAL_INFO (("Entering EFI GPT parser"));
+
+	/* by way of getting here, we've already checked for a protective MBR */
+
+	p = NULL;
+
+	/* Check GPT signature */
+	if (lseek (fd, offset + 512 + 0, SEEK_SET) < 0) {
+		HAL_INFO (("lseek failed (%s)", strerror (errno)));
+		goto out;
+	}
+	if (read (fd, buf, 8) != 8) {
+		HAL_INFO (("read failed (%s)", strerror (errno)));
+		goto out;
+	}
+	if (memcmp (buf, GPT_MAGIC, 8) != 0) {
+		HAL_INFO (("No GPT_MAGIC found"));
+		goto out;
+	}
+
+	HAL_INFO (("GPT magic found"));
+
+	/* Disk UUID */
+	if (lseek (fd, offset + 512 + 56, SEEK_SET) < 0) {
+		HAL_INFO (("lseek failed (%s)", strerror (errno)));
+		goto out;
+	}
+	if (read (fd, buf, 16) != 16) {
+		HAL_INFO (("read failed (%s)", strerror (errno)));
+		goto out;
+	}
+	//hexdump ((guint8*) buf, 16);
+
+	if (lseek (fd, offset + 512 + 72, SEEK_SET) < 0) {
+		HAL_INFO (("lseek failed (%s)", strerror (errno)));
+		goto out;
+	}
+	if (read (fd, buf, 8) != 8) {
+		HAL_INFO (("read failed (%s)", strerror (errno)));
+		goto out;
+	}
+	partition_entry_lba = get_le64 (buf);
+
+	if (lseek (fd, offset + 512 + 80, SEEK_SET) < 0) {
+		HAL_INFO (("lseek failed (%s)", strerror (errno)));
+		goto out;
+	}
+	if (read (fd, buf, 4) != 4) {
+		HAL_INFO (("read failed (%s)", strerror (errno)));
+		goto out;
+	}
+	num_entries = get_le32 (buf);
+
+	if (lseek (fd, offset + 512 + 84, SEEK_SET) < 0) {
+		HAL_INFO (("lseek failed (%s)", strerror (errno)));
+		goto out;
+	}
+	if (read (fd, buf, 4) != 4) {
+		HAL_INFO (("read failed (%s)", strerror (errno)));
+		goto out;
+	}
+	size_of_entry = get_le32(buf);
+
+
+	p = part_table_new_empty (PART_TYPE_GPT);
+	p->offset = offset;
+	p->size = size;
+
+	HAL_INFO (("partition_entry_lba=%d", partition_entry_lba));
+	HAL_INFO (("num_entries=%d", num_entries));
+	HAL_INFO (("size_of_entry=%d", size_of_entry));
+
+	for (n = 0; n < num_entries; n++) {
+		PartitionEntry *pe;
+		struct {
+			guint8 partition_type_guid[16];
+			guint8 partition_guid[16];
+			guint8 starting_lba[8];
+			guint8 ending_lba[8];
+			guint8 attributes[8];
+			guint8 partition_name[72];
+		} gpt_part_entry;
+		char *partition_type_guid;
+
+		if (lseek (fd, offset + partition_entry_lba * 512 + n * size_of_entry, SEEK_SET) < 0) {
+			HAL_INFO (("lseek failed (%s)", strerror (errno)));
+			goto out;
+		}
+		if (read (fd, &gpt_part_entry, 128) != 128) {
+			HAL_INFO (("read failed (%s)", strerror (errno)));
+			goto out;
+		}
+
+		partition_type_guid = get_le_guid (gpt_part_entry.partition_type_guid);
+
+		if (strcmp (partition_type_guid, GPT_PART_TYPE_GUID_EMPTY) == 0)
+			continue;
+
+		pe = part_entry_new (NULL,
+				     (guint8*) &gpt_part_entry,
+				     128, 
+				     offset + partition_entry_lba * 512 + n * size_of_entry);
+		p->entries = g_slist_append (p->entries, pe);
+
+		g_free (partition_type_guid);
+
+		//hexdump ((guint8 *) &gpt_part_entry, 128);
+
+	}
+
+
+out:
+	HAL_INFO (("Leaving EFI GPT parser"));
+	return p;
+}
+
+#define MAC_MAGIC "ER"
+#define MAC_PART_MAGIC "PM"
+
+static PartitionTable *
+part_table_parse_apple (int fd, guint64 offset, guint64 size)
+{
+	int n;
+	PartitionTable *p;
+	struct {
+		guint16 signature;
+		guint16 block_size;
+		guint32 block_count;
+		/* more stuff */
+	} __attribute__ ((packed)) mac_header;
+	struct {
+		guint16 signature;
+		guint16 res1;
+		guint32 map_count;
+		guint32 start_block;
+		guint32 block_count;
+		char name[32];
+		char type[32];
+		guint32 data_start;
+		guint32 data_count;
+		guint32 status;
+		guint32 boot_start;
+		guint32 boot_size;
+		guint32 boot_load;
+		guint32 boot_load2;
+		guint32 boot_entry;
+		guint32 boot_entry2;
+		guint32 boot_cksum;
+		char processor[16]; /* identifies ISA of boot */
+		/* more stuff */
+	} __attribute__ ((packed)) mac_part;
+	int block_size;
+	int block_count;
+	int map_count;
+
+	HAL_INFO (("Entering Apple parser"));
+
+	p = NULL;
+
+	/* Check Mac start of disk signature */
+	if (lseek (fd, offset + 0, SEEK_SET) < 0) {
+		HAL_INFO (("lseek failed (%s)", strerror (errno)));
+		goto out;
+	}
+	if (read (fd, &mac_header, sizeof (mac_header)) != sizeof (mac_header)) {
+		HAL_INFO (("read failed (%s)", strerror (errno)));
+		goto out;
+	}
+	if (memcmp (&(mac_header.signature), MAC_MAGIC, 2) != 0) {
+		HAL_INFO (("No MAC_MAGIC found"));
+		goto out;
+	}
+
+	block_size = GUINT16_FROM_BE (mac_header.block_size);
+	block_count = GUINT32_FROM_BE (mac_header.block_count); /* num blocks on whole disk */
+
+	HAL_INFO (("Mac MAGIC found, block_size=%d", block_size));
+
+	p = part_table_new_empty (PART_TYPE_APPLE);
+	p->offset = offset;
+	p->size = size;
+
+	/* get number of entries from first entry   */
+	if (lseek (fd, offset + block_size, SEEK_SET) < 0) {
+		HAL_INFO (("lseek failed (%s)", strerror (errno)));
+		goto out;
+	}
+	if (read (fd, &mac_part, sizeof (mac_part)) != sizeof (mac_part)) {
+		HAL_INFO (("read failed (%s)", strerror (errno)));
+		goto out;
+	}
+	map_count = GUINT32_FROM_BE (mac_part.map_count); /* num blocks in part map */
+
+	HAL_INFO (("map_count = %d", map_count));
+
+	for (n = 0; n < map_count; n++) {
+		PartitionEntry *pe;
+
+		if (memcmp (&(mac_part.signature), MAC_PART_MAGIC, 2) != 0) {
+			HAL_INFO (("No MAC_PART_MAGIC found"));
+			break;
+		}
+
+		if (lseek (fd, offset + (n + 1) * block_size, SEEK_SET) < 0) {
+			HAL_INFO (("lseek failed (%s)", strerror (errno)));
+			goto out;
+		}
+		if (read (fd, &mac_part, sizeof (mac_part)) != sizeof (mac_part)) {
+			HAL_INFO (("read failed (%s)", strerror (errno)));
+			goto out;
+		}
+
+		pe = part_entry_new (NULL,
+				     (guint8*) &mac_part,
+				     sizeof (mac_part), 
+				     offset + (n + 1) * block_size);
+		p->entries = g_slist_append (p->entries, pe);
+		
+	}
+
+out:
+	HAL_INFO (("Leaving Apple parser"));
+	return p;
+}
+
+PartitionTable *
+part_table_load_from_disk (char *device)
+{
+	int fd;
+	guint64 size;
+	PartitionTable *p;
+	gboolean found_gpt;
+
+	p = NULL;
+
+	fd = open (device, O_RDONLY);
+	if (fd < 0) {
+		HAL_INFO (("Cannot open device %s", device));
+		goto out;
+	}
+
+	if (ioctl (fd, BLKGETSIZE64, &size) != 0) {
+		HAL_INFO (("Cannot determine size of device"));
+		goto out;
+	}
+
+	p = part_table_parse_msdos (fd, 0, size, &found_gpt);
+	if (p != NULL) {
+		HAL_INFO (("MSDOS partition table detected"));
+		goto out;
+	}
+
+	if (found_gpt) {
+		p = part_table_parse_gpt (fd, 0, size);
+		if (p != NULL) {
+			HAL_INFO (("EFI GPT partition table detected"));
+			goto out;
+		}
+	}
+
+	p = part_table_parse_apple (fd, 0, size);
+	if (p != NULL) {
+		HAL_INFO (("Apple partition table detected"));
+		goto out;
+	}
+
+	HAL_INFO (("No known partition table found"));
+
+
+out:
+	if (fd >= 0)
+		close (fd);
+
+	return p;
+}
+
+
+
+PartitionScheme
+part_table_get_scheme (PartitionTable *p)
+{
+	return p->scheme;
+}
+
+int
+part_table_get_num_entries (PartitionTable *p)
+{
+	return g_slist_length (p->entries);
+}
+
+guint64
+part_table_get_offset (PartitionTable *p)
+{
+	return p->offset;
+}
+
+guint64 
+part_table_get_size (PartitionTable *p)
+{
+	return p->size;
+}
+
+PartitionTable *
+part_table_entry_get_nested (PartitionTable *p, int entry)
+{
+	PartitionEntry *pe = g_slist_nth_data (p->entries, entry);
+
+	if (pe->is_part_table)
+		return pe->part_table;
+	else
+		return NULL;
+}
+
+/**************************************************************************/
+
+char *
+part_table_entry_get_type (PartitionTable *p, int entry)
+{
+	char *s = NULL;
+	PartitionEntry *pe = g_slist_nth_data (p->entries, entry);
+
+	if (p == NULL)
+		goto out;
+
+	switch (p->scheme) {
+	case PART_TYPE_GPT:
+		s = get_le_guid (&(pe->data[0]));
+		break;
+	case PART_TYPE_MSDOS:
+	case PART_TYPE_MSDOS_EXTENDED:
+		s = g_strdup_printf ("0x%02x", pe->data[4]);
+		break;
+	case PART_TYPE_APPLE:
+		s = g_strdup ((char *) pe->data + 2*2 + 3*4 + 32);
+		g_strchomp (s);
+		break;
+	default:
+		break;
+	}
+out:
+	if (s != NULL) {
+		g_strchomp (s);
+	}
+	return s;
+}
+
+char *
+part_table_entry_get_uuid (PartitionTable *p, int entry)
+{
+	char *s = NULL;
+	PartitionEntry *pe = g_slist_nth_data (p->entries, entry);
+
+	if (p == NULL)
+		goto out;
+
+	switch (p->scheme) {
+	case PART_TYPE_GPT:
+		s = get_le_guid (&(pe->data[16]));
+		break;
+	default:
+		break;
+	}
+out:
+	if (s != NULL) {
+		g_strchomp (s);
+	}
+	return s;
+}
+
+char *
+part_table_entry_get_label (PartitionTable *p, int entry)
+{
+	char *s = NULL;
+	PartitionEntry *pe = g_slist_nth_data (p->entries, entry);
+
+	if (p == NULL)
+		goto out;
+
+	switch (p->scheme) {
+	case PART_TYPE_GPT:
+		s = g_utf16_to_utf8 ((const gunichar2 *) &(pe->data[56]), 36, NULL, NULL, NULL);
+		break;
+	case PART_TYPE_APPLE:
+		s = g_strdup ((char *) pe->data + 2*2 + 3*4);
+		g_strchomp (s);
+		break;
+	default:
+		break;
+	}
+out:
+	if (s != NULL) {
+		g_strchomp (s);
+	}
+	return s;
+}
+
+char **
+part_table_entry_get_flags (PartitionTable *p, int entry)
+{
+	int n;
+	char **ss = NULL;
+	guint32 apm_status;
+	guint64 gpt_attributes;
+	PartitionEntry *pe = g_slist_nth_data (p->entries, entry);
+
+	if (p == NULL)
+		goto out;
+
+	ss = g_new0 (char*, 6 + 1); /* hard coded to max items we'll return */
+	ss[0] = NULL;
+	n = 0;
+
+	switch (p->scheme) {
+	case PART_TYPE_GPT:
+		gpt_attributes = get_le64 (&(pe->data[48]));
+
+		/* From Table 16 of EFI 2.0 spec, bit zero means:
+		 *
+		 * "Required for the platform to function. The system
+		 * cannot function normally if this partition is
+		 * removed. This partition should be considered as
+		 * part of the hardware of the system, and if it is
+		 * removed the system may not boot. It may contain
+		 * diagnostics, recovery tools, or other code or data
+		 * that is critical to the functioning of a system
+		 * independent of any OS."
+		 *
+		 */
+		if (gpt_attributes & (1<<0)) {
+			ss[n++] = g_strdup ("required");
+		}
+
+		/* TODO: handle partition type specific attributes 
+		 *
+		 * Found on the Internet: "For basic data partitions, the following attribute is
+		 * defined:0x8000000000000000 prevents the partition from having a drive letter automatically
+		 * assigned. By default, each partition is assigned a new drive letter. Setting this
+		 * attribute ensures that when a disk is moved to a new computer, a new drive letter
+		 * will not be automatically generated. Instead, the user can manually assign drive 
+		 * letters. Note: Other attributes can be added at any time."
+		 */
+		break;
+
+	case PART_TYPE_MSDOS:
+	case PART_TYPE_MSDOS_EXTENDED:
+		if (pe->data[0] == 0x80) {
+			ss[n++] = g_strdup ("boot");
+		}
+		break;
+
+	case PART_TYPE_APPLE:
+		apm_status = get_be32 (&(pe->data[2*2 + 3*4 + 2*32 + 2*4]));
+		if (apm_status&(1<<1))
+			ss[n++] = g_strdup ("allocated");
+		if (apm_status&(1<<2))
+			ss[n++] = g_strdup ("in_use");
+		if (apm_status&(1<<3))
+			ss[n++] = g_strdup ("boot");
+		if (apm_status&(1<<4))
+			ss[n++] = g_strdup ("allow_read");
+		if (apm_status&(1<<5))
+			ss[n++] = g_strdup ("allow_write");
+		if (apm_status&(1<<6))
+			ss[n++] = g_strdup ("boot_code_is_pic");
+		break;
+	default:
+		break;
+	}
+	ss[n] = NULL;
+
+out:
+	return ss;
+}
+
+guint64
+part_table_entry_get_offset (PartitionTable *p, int entry)
+{
+	guint64 val;
+	PartitionEntry *pe = g_slist_nth_data (p->entries, entry);
+
+	val = G_MAXUINT64;
+	if (p == NULL)
+		goto out;
+
+	switch (p->scheme) {
+	case PART_TYPE_GPT:
+		val = 0x200 * ((guint64) get_le64 (pe->data + 32));
+		break;
+
+	case PART_TYPE_MSDOS:
+		val = 0x200 * ((guint64) get_le32 (pe->data + 8));
+		break;
+	case PART_TYPE_MSDOS_EXTENDED:
+		/* tricky here.. the offset in the EMBR is from the start of the EMBR and they are
+		 * scattered around the ext partition... Hence, just use the entry's offset and subtract
+		 * it's offset from the EMBR..
+		 */
+		val = 0x200 * ((guint64) get_le32 (pe->data + 8)) + pe->offset - MSDOS_PARTTABLE_OFFSET;
+		break;
+	case PART_TYPE_APPLE:
+		val = 0x200 * ((guint64) get_be32 (pe->data + 2*2 + 1*4));
+		break;
+	default:
+		break;
+	}
+out:
+	return val;
+}
+
+guint64
+part_table_entry_get_size (PartitionTable *p, int entry)
+{
+	guint64 val;
+	PartitionEntry *pe = g_slist_nth_data (p->entries, entry);
+
+	val = G_MAXUINT64;
+	if (p == NULL)
+		goto out;
+
+	switch (p->scheme) {
+	case PART_TYPE_GPT:
+		val = 0x200 * (((guint64) get_le64 (pe->data + 40)) - ((guint64) get_le64 (pe->data + 32)) + 1);
+		break;
+	case PART_TYPE_MSDOS:
+	case PART_TYPE_MSDOS_EXTENDED:
+		val = 0x200 * ((guint64) get_le32 (pe->data + 12));
+		break;
+	case PART_TYPE_APPLE:
+		val = 0x200 * ((guint64) get_be32 (pe->data + 2*2 + 2*4));
+		break;
+	default:
+		break;
+	}
+out:
+	return val;
+}
+
+/**************************************************************************/
+
+#ifdef USE_PARTED
+
+/* internal function to both add OR change a partition - if size==0,
+ * then we're changing, otherwise we're adding
+ */
+
+static gboolean
+part_add_change_partition (char *device_file, 
+			   guint64 start, guint64 size, 
+			   guint64 new_start, guint64 new_size, 
+			   guint64 *out_start, guint64 *out_size, 
+			   char *type, char *label, char **flags,
+			   int geometry_hps, int geometry_spt)
+{
+	int n;
+	gboolean is_change;
+	gboolean res;
+	PedDevice *device;
+	PedDisk *disk;
+	PedPartition *part;
+	PedConstraint* constraint;
+	PedPartitionType ped_type;
+	guint64 start_sector;
+	guint64 end_sector;
+	guint64 new_start_sector;
+	guint64 new_end_sector;
+	PartitionTable *p;
+	PartitionTable *container_p;
+	int container_entry;
+	PartitionScheme scheme;
+	guint8 mbr_flags = 0;
+	guint8 mbr_part_type = 0;
+	char *endp;
+	guint64 gpt_attributes = 0;
+	guint32 apm_status = 0;
+
+	res = FALSE;
+
+	is_change = FALSE;
+	if (size == 0) {
+		is_change = TRUE;
+	}
+
+	if (is_change) {
+		HAL_INFO (("In part_change_partition: device_file=%s, start=%lld, new_start=%lld, new_size=%lld, type=%s", device_file, start, new_start, new_size, type));
+	} else {
+		HAL_INFO (("In part_add_partition: device_file=%s, start=%lld, size=%lld, type=%s", device_file, start, size, type));
+	}
+
+	/* first, find the kind of (embedded) partition table the new partition is going to be part of */
+	p = part_table_load_from_disk (device_file);
+	if (p == NULL) {
+		HAL_INFO (("Cannot load partition table from %s", device_file));
+		goto out;
+	}
+
+	part_table_find (p, start + 512, &container_p, &container_entry);
+	scheme = part_table_get_scheme (container_p);
+
+	if (is_change) {
+		/* if changing, make sure there is a partition to change */
+		if (container_entry < 0) {
+			HAL_INFO (("Couldn't find partition to change"));
+			goto out;
+		}
+	} else {
+		/* if adding, make sure there is no partition in the way... */
+		if (container_entry >= 0) {
+			char *part_type;
+			
+			/* this might be Apple_Free if we're on PART_TYPE_APPLE */
+			part_type = part_table_entry_get_type (p, container_entry);
+			if (! (p->scheme == PART_TYPE_APPLE && part_type != NULL && (strcmp (part_type, "Apple_Free") == 0))) {
+				part_table_free (p);
+				HAL_INFO (("There is a partition in the way on %s", device_file));
+				goto out;
+			}
+		}
+	}
+
+	HAL_INFO (("containing partition table scheme = %d", scheme));
+
+	part_table_free (p);
+	p = NULL;
+
+	if (!is_change) {
+		if (type == NULL) {
+			HAL_INFO (("No type specified"));
+			goto out;
+		}
+	}
+
+	/* now that we know the partitoning scheme, sanity check type and flags */
+	switch (scheme) {
+	case PART_TYPE_MSDOS:
+	case PART_TYPE_MSDOS_EXTENDED:
+		mbr_flags = 0;
+		if (flags != NULL) {
+			for (n = 0; flags[n] != NULL; n++) {
+				if (strcmp (flags[n], "boot") == 0) {
+					mbr_flags |= 0x80;
+				} else {
+					HAL_INFO (("unknown flag '%s'", flags[n]));
+					goto out;
+				}
+			}
+		}
+
+		if (type != NULL) {
+			mbr_part_type = (guint8) (strtol (type, &endp, 0));
+			if (*endp != '\0') {
+				HAL_INFO (("invalid type '%s' given", type));
+				goto out;
+			}
+		}
+
+		if (label != NULL) {
+			HAL_INFO (("labeled partitions not supported on MSDOS or MSDOS_EXTENDED"));
+			goto out;
+		}
+		
+		break;
+
+	case PART_TYPE_GPT:
+		gpt_attributes = 0;
+		if (flags != NULL) {
+			for (n = 0; flags[n] != NULL; n++) {
+				if (strcmp (flags[n], "required") == 0) {
+					gpt_attributes |= 1;
+				} else {
+					HAL_INFO (("unknown flag '%s'", flags[n]));
+					goto out;
+				}
+			}
+		}
+		break;
+
+	case PART_TYPE_APPLE:
+		apm_status = 0;
+		if (flags != NULL) {
+			for (n = 0; flags[n] != NULL; n++) {
+				if (strcmp (flags[n], "allocated") == 0) {
+					apm_status |= (1<<1);
+				} else if (strcmp (flags[n], "in_use") == 0) {
+					apm_status |= (1<<2);
+				} else if (strcmp (flags[n], "boot") == 0) {
+					apm_status |= (1<<3);
+				} else if (strcmp (flags[n], "allow_read") == 0) {
+					apm_status |= (1<<4);
+				} else if (strcmp (flags[n], "allow_write") == 0) {
+					apm_status |= (1<<5);
+				} else if (strcmp (flags[n], "boot_code_is_pic") == 0) {
+					apm_status |= (1<<6);
+				} else {
+					HAL_INFO (("unknown flag '%s'", flags[n]));
+					goto out;
+				}
+			}
+		}
+		break;
+
+	default:
+		HAL_INFO (("partitioning scheme %d not supported", scheme));
+		goto out;
+	}
+
+	switch (scheme) {
+	case PART_TYPE_MSDOS:
+		if (mbr_part_type == 0x05 || mbr_part_type == 0x85 || mbr_part_type == 0x0f) {
+			ped_type = PED_PARTITION_EXTENDED;
+		} else {
+			ped_type = PED_PARTITION_NORMAL;
+		}
+		break;
+
+	case PART_TYPE_MSDOS_EXTENDED:
+		ped_type = PED_PARTITION_LOGICAL;
+		if (mbr_part_type == 0x05 || mbr_part_type == 0x85 || mbr_part_type == 0x0f) {
+			HAL_INFO (("Cannot create an extended partition inside an extended partition"));
+			goto out;
+		}
+		break;
+
+	default:
+		ped_type = PED_PARTITION_NORMAL;
+		break;
+	}
+
+	/* now, create the partition */
+
+	start_sector = start / 512;
+	end_sector = (start + size) / 512 - 1;
+	new_start_sector = new_start / 512;
+	new_end_sector = (new_start + new_size) / 512 - 1;
+
+	device = ped_device_get (device_file);
+	if (device == NULL) {
+		HAL_INFO (("ped_device_get() failed"));
+		goto out;
+	}
+	HAL_INFO (("got it"));
+
+	/* set drive geometry on libparted object if the user requested it */
+	if (geometry_hps > 0 && geometry_spt > 0 ) {
+		/* not sure this is authorized use of libparted, but, eh, it seems to work */
+		device->hw_geom.cylinders = device->bios_geom.cylinders = device->length / geometry_hps / geometry_spt;
+		device->hw_geom.heads = device->bios_geom.heads = geometry_hps;
+		device->hw_geom.sectors = device->bios_geom.sectors = geometry_spt;
+	}
+
+	disk = ped_disk_new (device);
+	if (disk == NULL) {
+		HAL_INFO (("ped_disk_new() failed"));
+		goto out_ped_device;
+	}
+	HAL_INFO (("got disk"));
+
+	if (!is_change) {
+		part = ped_partition_new (disk, 
+					  ped_type,
+					  NULL,
+					  start_sector,
+					  end_sector);
+		if (part == NULL) {
+			HAL_INFO (("ped_partition_new() failed"));
+			goto out_ped_disk;
+		}
+		HAL_INFO (("new partition"));
+	} else {
+		part = ped_disk_get_partition_by_sector (disk,
+							 start_sector);
+		if (part == NULL) {
+			HAL_INFO (("ped_partition_get_by_sector() failed"));
+			goto out_ped_disk;
+		}
+		HAL_INFO (("got partition"));
+	}
+				  
+
+	/* TODO HACK XXX FIXME UGLY BAD: This is super ugly abuse of
+	 * libparted - we poke at their internal data structures - but
+	 * there ain't nothing we can do about it until libparted
+	 * provides API for this...
+	 */
+	if (scheme == PART_TYPE_GPT) {
+		struct {
+			efi_guid	type;
+			efi_guid	uuid;
+			char		name[37];
+			int		lvm;
+			int		raid;
+			int		boot;
+			int		hp_service;
+			int             hidden;
+			/* more stuff */
+		} *gpt_data = (void *) part->disk_specific;
+
+		if (type != NULL) {
+			if (!set_le_guid ((guint8*) &gpt_data->type, type)) {
+				HAL_INFO (("type '%s' for GPT appear to be malformed", type));
+				goto out_ped_partition;
+			}
+		}
+
+		if (flags != NULL) {
+			if (gpt_attributes & 1) {
+				gpt_data->hidden = 1;
+			} else {
+				gpt_data->hidden = 0;
+			}
+		}
+
+	} else if (scheme == PART_TYPE_MSDOS || scheme == PART_TYPE_MSDOS_EXTENDED) {
+		struct {
+			unsigned char	system;
+			int		boot;
+			/* more stuff */
+		} *dos_data = (void *) part->disk_specific;
+
+		if (type != NULL) {
+			dos_data->system = mbr_part_type;
+		}
+		if (flags != NULL) {
+			if (mbr_flags & 0x80) {
+				dos_data->boot = 1;
+			} else {
+				dos_data->boot = 0;
+			}
+		}
+
+	} else if (scheme == PART_TYPE_APPLE) {
+		struct {
+			char            volume_name[33];	/* eg: "Games" */
+			char            system_name[33];	/* eg: "Apple_Unix_SVR2" */
+			char            processor_name[17];
+			int             is_boot;
+			int             is_driver;
+			int             has_driver;
+			int             is_root;
+			int             is_swap;
+			int             is_lvm;
+			int             is_raid;
+			PedSector       data_region_length;
+			PedSector       boot_region_length;
+			guint32         boot_base_address;
+			guint32         boot_entry_address;
+			guint32         boot_checksum;
+			guint32         status;
+			/* more stuff */
+		} *mac_data = (void *) part->disk_specific;
+
+		if (type != NULL) {
+			memset (mac_data->system_name, 0, 33);
+			strncpy (mac_data->system_name, type, 32);
+		}
+
+		if (flags != NULL) {
+			mac_data->status = apm_status;
+		}
+	}
+
+	if (label != NULL) {
+		ped_partition_set_name (part, label);
+	}
+
+	if (geometry_hps > 0 && geometry_spt > 0 ) {
+		/* respect drive geometry */
+		constraint = ped_constraint_any (device);
+	} else if (geometry_hps == -1 && geometry_spt == -1 ) {
+
+		/* undocumented (or is it?) libparted usage again.. it appears that
+		 * the probed geometry is stored in hw_geom
+		 */
+		device->bios_geom.cylinders = device->hw_geom.cylinders;
+		device->bios_geom.heads     = device->hw_geom.heads;
+		device->bios_geom.sectors   = device->hw_geom.sectors;
+
+		constraint = ped_constraint_any (device);
+	} else {
+		PedGeometry *geo_start;
+		PedGeometry *geo_end;
+
+		/* ignore drive geometry */
+		if (is_change) {
+			geo_start = ped_geometry_new (device, new_start_sector, 1);
+			geo_end = ped_geometry_new (device, new_end_sector, 1);
+		} else {
+			geo_start = ped_geometry_new (device, start_sector, 1);
+			geo_end = ped_geometry_new (device, end_sector, 1);
+		}
+
+		constraint = ped_constraint_new (ped_alignment_any, ped_alignment_any,
+						 geo_start, geo_end, 1, device->length);
+	}
+
+try_change_again:
+	if (is_change) {
+		if (ped_disk_set_partition_geom (disk,
+						 part,
+						 constraint,
+						 new_start_sector, new_end_sector) == 0) {
+			HAL_INFO (("ped_disk_set_partition_geom() failed"));
+			goto out_ped_constraint;
+		}
+	} else {
+		if (ped_disk_add_partition (disk,
+					    part,
+					    constraint) == 0) {
+			HAL_INFO (("ped_disk_add_partition() failed"));
+			goto out_ped_constraint;
+		}
+	}
+
+	*out_start = part->geom.start * 512;
+	*out_size = part->geom.length * 512;
+
+	if (is_change) {
+		/* make sure the resulting size is never smaller than requested
+		 * (this is because one will resize the FS and *then* change the partition table)
+		 */
+		if (*out_size < new_size) {
+			HAL_INFO (("new_size=%lld but resulting size, %lld, smaller than requested", new_size, *out_size));
+			new_end_sector++;
+			goto try_change_again;
+		} else {
+			HAL_INFO (("changed partition to start=%lld size=%lld", *out_start, *out_size));
+		}
+	} else {
+		HAL_INFO (("added partition start=%lld size=%lld", *out_start, *out_size));
+	}
+
+
+	/* hmm, if we don't do this libparted crashes.. I assume that
+	 * ped_disk_add_partition assumes ownership of the
+	 * PedPartition when adding it... sadly this is not documented
+	 * anywhere.. sigh..
+	 */
+	part = NULL;
+
+	/* use commit_to_dev rather than just commit to avoid
+	 * libparted sending BLKRRPART to the kernel - we want to do
+	 * this ourselves... 
+	 */
+	if (ped_disk_commit_to_dev (disk) == 0) {
+		HAL_INFO (("ped_disk_commit_to_dev() failed"));
+		goto out_ped_constraint;
+	}
+	HAL_INFO (("committed to disk"));
+
+	res = TRUE;
+
+	ped_constraint_destroy (constraint);
+	ped_disk_destroy (disk);
+	ped_device_destroy (device);
+	goto out;
+
+out_ped_constraint:
+	ped_constraint_destroy (constraint);
+
+out_ped_partition:
+	if (part != NULL) {
+		ped_partition_destroy (part);
+	}
+
+out_ped_disk:
+	ped_disk_destroy (disk);
+
+out_ped_device:
+	ped_device_destroy (device);
+
+out:
+	return res;
+}
+
+gboolean
+part_add_partition (char *device_file, 
+		    guint64 start, guint64 size, 
+		    guint64 *out_start, guint64 *out_size, 
+		    char *type, char *label, char **flags,
+		    int geometry_hps, int geometry_spt)
+{
+	return part_add_change_partition (device_file,
+					  start, size,
+					  0, 0,
+					  out_start, out_size,
+					  type, label, flags,
+					  geometry_hps, geometry_spt);
+}
+
+gboolean
+part_change_partition (char *device_file, 
+		       guint64 start,
+		       guint64 new_start, guint64 new_size, 
+		       guint64 *out_start, guint64 *out_size, 
+		       char *type, char *label, char **flags,
+		       int geometry_hps, int geometry_spt)
+{
+	return part_add_change_partition (device_file,
+					  start, 0,
+					  new_start, new_size,
+					  out_start, out_size,
+					  type, label, flags,
+					  geometry_hps, geometry_spt);
+}
+
+gboolean
+part_del_partition (char *device_file, guint64 offset)
+{
+	gboolean ret;
+	PedDevice *device;
+	PedDisk *disk;
+	PedPartition *part;
+	PartitionTable *p;
+	gboolean is_extended;
+	int n;
+
+	HAL_INFO (("In part_del_partition: device_file=%s, offset=%lld", device_file, offset));
+	
+	ret = FALSE;
+
+
+	/* sigh.. one would think that if you passed the sector of where the
+	 * the beginning of the extended partition starts, then _by_sector
+	 * would return the same as _extended_partition. 
+	 *
+	 * Sadly it's not so..
+	 *
+	 * So, check if the passed offset actually corresponds to a nested
+	 * partition table...
+	 */
+	is_extended = FALSE;
+	p = part_table_load_from_disk (device_file);
+	if (p == NULL) {
+		HAL_INFO (("Cannot load partition table from %s", device_file));
+		goto out;
+	}
+	for (n = 0; n < part_table_get_num_entries (p); n++) {
+		PartitionTable *nested;
+		nested = part_table_entry_get_nested (p, n);
+		if (nested != NULL) {
+			if (part_table_get_offset (nested) == offset) {
+				HAL_INFO (("partition to delete is an extended partition"));
+				is_extended = TRUE;
+			}
+		}
+	}
+	part_table_free (p);
+
+	device = ped_device_get (device_file);
+	if (device == NULL) {
+		HAL_INFO (("ped_device_get() failed"));
+		goto out;
+	}
+	HAL_INFO (("got it"));
+
+	disk = ped_disk_new (device);
+	if (disk == NULL) {
+		HAL_INFO (("ped_disk_new() failed"));
+		goto out_ped_device;
+	}
+	HAL_INFO (("got disk"));
+
+	if (is_extended) {
+		part = ped_disk_extended_partition (disk);
+	} else {
+		part = ped_disk_get_partition_by_sector (disk, offset / 512);
+	}
+
+	if (part == NULL) {
+		HAL_INFO (("ped_disk_get_partition_by_sector() failed"));
+		goto out_ped_disk;
+	}
+				  
+	HAL_INFO (("got partition - part->type=%d", part->type));
+	/* allow only to delete primary, logical and extended partitions */
+	if (! ((part->type == PED_PARTITION_NORMAL) ||
+	       (part->type == PED_PARTITION_LOGICAL) ||
+	       (part->type == PED_PARTITION_EXTENDED))) {
+		HAL_INFO (("no data partition at given offset %lld for device %s", offset, device_file));
+		goto out_ped_disk;
+	}
+
+	if (ped_disk_delete_partition (disk, part) == 0) {
+		HAL_INFO (("ped_disk_delete_partition() failed"));
+		goto out_ped_disk;
+	}
+
+	/* use commit_to_dev rather than just commit to avoid
+	 * libparted sending BLKRRPART to the kernel - we want to do
+	 * this ourselves... 
+	 */
+
+	if (ped_disk_commit_to_dev (disk) == 0) {
+		HAL_INFO (("ped_disk_commit_to_dev() failed"));
+		goto out_ped_disk;
+	}
+	HAL_INFO (("committed to disk"));
+
+	ret = TRUE;
+
+	ped_disk_destroy (disk);
+	ped_device_destroy (device);
+	goto out;
+
+out_ped_disk:
+	ped_disk_destroy (disk);
+
+out_ped_device:
+	ped_device_destroy (device);
+
+out:
+	return ret;
+}
+
+gboolean
+part_create_partition_table (char *device_file, PartitionScheme scheme)
+{
+	PedDevice *device;
+	PedDisk *disk;
+	PedDiskType *disk_type;
+	gboolean ret;
+
+	ret = FALSE;
+
+	HAL_INFO (("In part_create_partition_table: device_file=%s, scheme=%d", device_file, scheme));
+
+	device = ped_device_get (device_file);
+	if (device == NULL) {
+		HAL_INFO (("ped_device_get() failed"));
+		goto out;
+	}
+	HAL_INFO (("got it"));
+
+	switch (scheme) {
+	case PART_TYPE_MSDOS:
+		disk_type = ped_disk_type_get ("msdos");
+		break;
+	case PART_TYPE_APPLE:
+		disk_type = ped_disk_type_get ("mac");
+		break;
+	case PART_TYPE_GPT:
+		disk_type = ped_disk_type_get ("gpt");
+		break;
+	default:
+		disk_type = NULL;
+		break;
+	}
+
+	if (disk_type == NULL) {
+		HAL_INFO (("Unknown or unsupported partitioning scheme %d", scheme));
+		goto out;
+	}
+
+        disk = ped_disk_new_fresh (device, disk_type);
+	if (disk == NULL) {
+		HAL_INFO (("ped_disk_new_fresh() failed"));
+		goto out_ped_device;
+	}
+	HAL_INFO (("got disk"));
+
+	if (ped_disk_commit_to_dev (disk) == 0) {
+		HAL_INFO (("ped_disk_commit_to_dev() failed"));
+		goto out_ped_disk;
+	}
+	HAL_INFO (("committed to disk"));
+
+	ret = TRUE;
+
+	ped_disk_destroy (disk);
+	ped_device_destroy (device);
+	goto out;
+
+out_ped_disk:
+	ped_disk_destroy (disk);
+
+out_ped_device:
+	ped_device_destroy (device);
+
+out:
+	return ret;
+}
+
+#endif /* USE_PARTED */
+
+/**************************************************************************/
diff --git a/partutil/partutil.h b/partutil/partutil.h
new file mode 100644
index 0000000..61dec2f
--- /dev/null
+++ b/partutil/partutil.h
@@ -0,0 +1,412 @@
+/***************************************************************************
+ *
+ * part.h : library for reading and writing partition tables - uses
+ *          libparted for the heavy lifting
+ *
+ * Copyright (C) 2006 David Zeuthen, <david at fubar.dk>
+ *
+ * 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 PARTUTIL_H
+#define PARTUTIL_H
+
+#include <stdio.h>
+#include <glib.h>
+
+/* Partition schemes understood by this library */
+typedef enum {
+	PART_TYPE_MSDOS           = 0,
+	PART_TYPE_MSDOS_EXTENDED  = 1,
+	PART_TYPE_APPLE           = 2,
+	PART_TYPE_GPT             = 3
+} PartitionScheme;
+
+/**
+ * part_get_scheme_name:
+ * @scheme: the partitioning scheme
+ *
+ * Get a name for the partitioning scheme. The current mapping is used
+ *
+ *  PART_TYPE_MSDOS          -> mbr
+ *  PART_TYPE_MSDOS_EXTENDED -> embr
+ *  PART_TYPE_APPLE          -> apm
+ *  PART_TYPE_GPT            -> gpt
+ *
+ * Returns: Name of scheme or NULL for unknown scheme. Caller shall not free this string.
+ */
+const char           *part_get_scheme_name (PartitionScheme scheme);
+
+struct PartitionTable_s;
+typedef struct PartitionTable_s PartitionTable;
+
+
+/**
+ * part_table_load_from_disk:
+ * @device: name of device file for entire disk, e.g. /dev/sda
+ *
+ * Scans a disk and collect all partition entries and nested partition tables.
+ *
+ * Returns: A partition table object. Use part_table_free() to free this object.
+ */
+PartitionTable       *part_table_load_from_disk   (char *device);
+
+/**
+ * part_table_free:
+ * @part_table: the partition table
+ *
+ * Frees the partition table returned from part_table_load_from_disk().
+ */
+void                  part_table_free             (PartitionTable *part_table);
+
+/* partition table inspection */
+
+/**
+ * part_table_get_scheme:
+ * @part_table: the partition table
+ *
+ * Get partitioning scheme. 
+ *
+ * Returns: The partitioning scheme.
+ */
+PartitionScheme       part_table_get_scheme       (PartitionTable *part_table);
+
+/**
+ * part_table_get_num_entries:
+ * @part_table: the partition table
+ *
+ * Get number of entries in partition table.
+ *
+ * Returns: Number of entries.
+ */
+int                   part_table_get_num_entries  (PartitionTable *part_table);
+
+/**
+ * part_table_get_offset:
+ * @part_table: the partition table
+ *
+ * Get offset from start of disk where partition table starts (as
+ * referenced in the partition table entry if it's an embedded
+ * partition table, otherwise zero for the full disk)
+ *
+ * Returns: offset, from start of disk, in bytes
+ */
+guint64               part_table_get_offset (PartitionTable *part_table);
+
+/**
+ * part_table_get_size:
+ * @part_table: the partition table
+ *
+ * Get size of partition table (as referenced in the partition table
+ * entry if it's an embedded partition table, otherwise the size of
+ * the full disk)
+ *
+ * Returns: size of partition, in bytes
+ */
+guint64               part_table_get_size   (PartitionTable *part_table);
+
+/**
+ * part_table_find:
+ * @part_table: the partition table
+ * @offset: the offset to test for
+ * @out_part_table: where the (embedded) enclosing the entry will be stored
+ * @out_entry: there the partition table entry number will be stored
+ *
+ * This function finds the entry that a certain byte of the disk belongs to.
+ * As partition tables can be embedded (think MS-DOS extended partitions)
+ * the returned partition table (out_part_table) might be different from
+ * the one passed. If the offset belongs to a primary partition then the
+ * return partition_table will be the same as the passed one.
+ *
+ * If there is no partition at the given offset (might be free space), 
+ * out_entry will be set to -1. Note that out_part_table will always
+ * be set though and free space in the primary disk space and the 
+ * extended partition space differs.
+ *
+ * This is a convenience function.
+ */
+void                  part_table_find (PartitionTable *part_table, 
+				       guint64 offset,
+				       PartitionTable **out_part_table, 
+				       int *out_entry);
+
+
+/**
+ * part_table_entry_get_nested:
+ * @part_table: the partition table
+ * @entry: zero-based index of entry in partition table
+ *
+ * If the partition table entry points to an embedded partition table this
+ * function will return a PartitionTable object representing it.
+ *
+ * Returns: NULL if the entry does not point to a an embedded partition table.
+ *          Do not free with part_table_free() - the object will be freed when
+ *          freeing the root object.
+ */
+PartitionTable       *part_table_entry_get_nested (PartitionTable *part_table, int entry);
+
+/**
+ * part_table_entry_get_type:
+ * @part_table: the partition table
+ * @entry: zero-based index of entry in partition table
+ *
+ * Get the partition table type - the type itself is partitioning scheme
+ * specific as described below.
+ *
+ * For PART_TYPE_MSDOS and PART_TYPE_MSDOS_EXTENDED, the type is an integer
+ * encoded in a string, e.g. 0x83 is Linux. Use atoi() to convert back to
+ * an integer. See http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
+ * for details.
+ *
+ * For PART_TYPE_GPT, this is the GUID encoded as a string, see
+ * http://en.wikipedia.org/wiki/GUID_Partition_Table for details.
+ *
+ * For PART_TYPE_APPLE, this is a string as defined in 
+ * http://developer.apple.com/documentation/mac/Devices/Devices-126.html.
+ * For FAT file systems, it appears that "DOS_FAT_32", "DOS_FAT_16" and
+ * "DOS_FAT_12" are also recognized under Mac OS X (I've tested this too) cf. 
+ * http://lists.apple.com/archives/Darwin-drivers/2003/May/msg00021.html
+ *
+ * Returns: The partition table type. Caller shall free this with g_free().
+ */
+char                 *part_table_entry_get_type   (PartitionTable *part_table, int entry);
+
+/**
+ * part_table_entry_get_label:
+ * @part_table: the partition table
+ * @entry: zero-based index of entry in partition table
+ *
+ * Label of the partition. This is only supported for PART_TYPE_APPLE and
+ * PART_TYPE_GPT. Note that this is not the same as the file system label
+ * in a file system in the partition.
+ *
+ * Returns: The label or NULL if the partitioning scheme does not support
+ *          labels. Caller shall free this with g_free().
+ */
+char                 *part_table_entry_get_label  (PartitionTable *part_table, int entry);
+
+/**
+ * part_table_entry_get_uuid:
+ * @part_table: the partition table
+ * @entry: zero-based index of entry in partition table
+ *
+ * Some UUID/GUID of the partition. This is only supported for PART_TYPE_GPT.
+ *
+ * Returns: The UUID or NULL if the partitioning scheme does not support
+ *          UUID/GUID. Caller shall free this with g_free().
+ */
+char                 *part_table_entry_get_uuid  (PartitionTable *part_table, int entry);
+
+/**
+ * part_table_entry_get_flags:
+ * @part_table: the partition table
+ * @entry: zero-based index of entry in partition table
+ *
+ * Get flags of partition table entry. This is dependent on the partitioning
+ * scheme.
+ *
+ * For PART_TYPE_MSDOS and PART_TYPE_MSDOS_EXTENDED the following flags are
+ * recognized: 
+ * - "boot"; meaning that the bootable flag is set. This is used by some
+ *   BIOS'es and boot loaders to populate a boot menu.
+ *
+ * For PART_TYPE_GPT the following flags are recognized:
+ * - "required" which corresponds to bit 0 of the attibutes
+ *   (offset 48), meaning "Required for the platform to function. The
+ *   system cannot function normally if this partition is removed. This
+ *   partition should be considered as part of the hardware of the
+ *   system, and if it is removed the system may not boot. It may
+ *   contain diagnostics, recovery tools, or other code or data that is
+ *   critical to the functioning of a system independent of any OS."
+ *
+ *
+ * For PART_TYPE_APPLE the following flags are recognized:
+ * - "allocated"; if the partition is already allocated
+ * - "in_use"; if the partition is in use; may be cleared after a system reset
+ * - "boot"; if partition contains valid boot information
+ * - "allow_read"; if partition allows reading
+ * - "allow_write"; if partition allows writing
+ * - "boot_code_is_pic"; if boot code is position independent
+ *
+ * Returns: An array of strings, one per flag, terminated by NULL. Caller
+ *          shall free this with g_strfreev().
+ */
+char                **part_table_entry_get_flags  (PartitionTable *part_table, int entry);
+
+/**
+ * part_table_entry_get_offset:
+ * @part_table: the partition table
+ * @entry: zero-based index of entry in partition table
+ *
+ * Get offset from start of disk where partition starts (as referenced in the
+ * partition table entry)
+ *
+ * Returns: offset, from start of disk, in bytes
+ */
+guint64               part_table_entry_get_offset (PartitionTable *part_table, int entry);
+
+/**
+ * part_table_entry_get_size:
+ * @part_table: the partition table
+ * @entry: zero-based index of entry in partition table
+ *
+ * Get size of partition (as referenced in the partition table entry)
+ *
+ * Returns: size of partition, in bytes
+ */
+guint64               part_table_entry_get_size   (PartitionTable *part_table, int entry);
+
+
+/**
+ * part_create_partition_table:
+ * @device: name of device file for entire disk, e.g. /dev/sda
+ * @scheme: the partitioning scheme
+ *
+ * Create a new fresh partition on a disk.
+ * 
+ * Returns: TRUE if the operation was succesful, otherwise FALSE
+ */
+gboolean              part_create_partition_table (char *device, PartitionScheme scheme);
+
+
+/**
+ * part_add_partition:
+ * @device: name of device file for entire disk, e.g. /dev/sda
+ * @start: start offset of partition, in bytes
+ * @size: size of partition, in bytes
+ * @out_start: where partition will start, after satisfying disk geometry constraints
+ * @out_size: size of partition, after satisfying disk geometry constraints
+ * @type: the partition type as defined in part_table_entry_get_type()
+ * @flags: the partition flags as defined in part_table_entry_get_flags()
+ * @label: the partition label as defined in part_table_entry_get_label()
+ * @geometry_hps: heads-per-sector used for LBA<->CHS conversions
+ * @geometry_spt: sectors-per-track used for LBA<->CHS conversions
+ *
+ * Adds a new partition to a disk. 
+ *
+ * If geometry_hps and geomtry_spt are both positive, they will be
+ * used as the geometry of the disk for CHS<->LBA conversions. Notably
+ * this is only applicable for MSDOS / MSDOS_EXTENDED partition
+ * tables. Also, in this case, geometry is enforced to ensure that
+ * partitions start and end at cylinder boundaries.
+ * 
+ * If either geometry_hps or geomtry_spt are zero, geometry is
+ * simply ignored and partitions will only be aligned to blocks, e.g.
+ * normally 512 byte boundaries.
+ *
+ * If both geometry_hps or geomtry_spt are -1, then geometry information
+ * probed from existing partition table entries / file systems on the
+ * disk. This is not always reliable.
+ *
+ * As such, the caller cannot always expect that the partition created
+ * will be at the requested offset and size due to e.g. geometry and
+ * block boundary alignment. Therefore, the start and size where the
+ * partition ends up is passed in the out_start and out_size
+ * arguments.
+ *
+ * As embedded partition tables are supported, the caller should use
+ * part_table_find() in advance to make sure that the passed type,
+ * label and flags match the (embedded) partition table that this
+ * partition will be part of.
+ *
+ * To create an MSDOS extended partition table in a MSDOS partition
+ * table, simply pass 0x05, 0x0f or 0x85 as the partition type.
+ *
+ * In order for changes to take effect, the caller needs to poke the
+ * OS kernel himself to make it reload the partition table. It is not
+ * automatically done by this function.
+ *
+ * NOTE: After calling this function you need to discard any partition table
+ * obtained with part_table_load_from_disk() since the in-memory data structure
+ * is not updated.
+ *
+ * Returns: TRUE if the operation was succesful, otherwise FALSE
+ */
+gboolean              part_add_partition (char *device, 
+					  guint64 start, guint64 size, 
+					  guint64 *out_start, guint64 *out_size, 
+					  char *type, char *label, char **flags,
+					  int geometry_hps, int geometry_spt);
+
+/**
+ * @device: name of device file for entire disk, e.g. /dev/sda
+ * @start: start offset of existing partition, in bytes
+ * @new_start: new start offset of partition, in bytes
+ * @new_size: new size of partition, in bytes
+ * @out_start: where partition will start, after satisfying disk geometry constraints
+ * @out_size: size of partition, after satisfying disk geometry constraints
+ * @type: the partition type as defined in part_table_entry_get_type() or NULL to not change
+ * @flags: the partition flags as defined in part_table_entry_get_flags() or NULL to not change
+ * @label: the partition label as defined in part_table_entry_get_label() or NULL to not change
+ * @geometry_hps: heads-per-sector used for LBA<->CHS conversions
+ * @geometry_spt: sectors-per-track used for LBA<->CHS conversions
+ *
+ * Changes an existing partition table entry on disk. The contents of
+ * the partition will not be touched. 
+ * 
+ * XXX TODO FIXME: probably be careful with overlapping partitions as
+ * e.g. extended MS-DOS partitions have the partition information just
+ * before the partition data itself. Need to look into this.
+ *
+ * If new_start and new_size matches the existing start and size, only
+ * flags, label and type are changed. Any of flags, label and type can
+ * be set to NULL to signal there should be no change. Thus, this
+ * function serves two purposes. It can be used to both change offset and/or
+ * size and it can be used to change type and/or flags and/or label.
+ *
+ * See part_add_partition() for information about geometry_hps and
+ * geometry_spt and how it affects the resulting partition offset and
+ * size. This function gives one guarantee though: the resulting size
+ * will never be smaller than the requested size. This is useful for
+ * two-step operations by which a file system is first shrinked and
+ * then the partition table is updated.
+ *
+ * In order for changes to take effect, the caller needs to poke the
+ * OS kernel himself to make it reload the partition table. It is not
+ * automatically done by this function.
+ *
+ * NOTE: After calling this function you need to discard any partition
+ * table obtained with part_table_load_from_disk() since the in-memory
+ * data structure is not updated.
+ *
+ * Returns: TRUE if the operation was succesful, otherwise FALSE
+ */
+gboolean              part_change_partition (char *device_file, 
+					     guint64 start, 
+					     guint64 new_start, guint64 new_size,
+					     guint64 *out_start, guint64 *out_size, 
+					     char *type, char *label, char **flags,
+					     int geometry_hps, int geometry_spt);
+
+/**
+ * part_del_partition:
+ * @device: name of device file for entire disk, e.g. /dev/sda
+ * @offset: offset of somewhere within the partition to delete, in bytes
+ *
+ * Deletes a partition. Just pass the offset of the partition. If you
+ * delete an extended partition all logical partitions will be deleted
+ * too.
+ *
+ * NOTE: After calling this function you need to discard any partition table
+ * obtained with part_table_load_from_disk() since the in-memory data structure
+ * is not updated.
+ *
+ * Returns: TRUE if the operation was succesful, otherwise FALSE
+ */
+gboolean              part_del_partition (char *device, guint64 offset);
+
+
+#endif /* PARTUTIL_H */


More information about the hal-commit mailing list