Update blkid to 2.25.0
Break libblkid into 4 libraries: libblkid, libuuid, libutil-linux and libfdisk.

This should help in later patch updates.

Change-Id: I680d9a7feb031e5c29a603e9c58aff4b65826262
diff --git a/Android.mk b/Android.mk
index 203c901..a1e6834 100644
--- a/Android.mk
+++ b/Android.mk
@@ -34,8 +34,9 @@
     twrp.cpp \
     fixPermissions.cpp \
     twrpTar.cpp \
-	twrpDU.cpp \
+    twrpDU.cpp \
     twrpDigest.cpp \
+    digest/md5.c \
     find_file.cpp \
     infomanager.cpp
 
diff --git a/libblkid/Android.mk b/libblkid/Android.mk
index d6c203f..630e069 100644
--- a/libblkid/Android.mk
+++ b/libblkid/Android.mk
@@ -2,12 +2,194 @@
 
 include $(CLEAR_VARS)
 
+LOCAL_MODULE := libutil-linux
+LOCAL_MODULE_TAGS := optional
+#LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
+LOCAL_CFLAGS = -D_FILE_OFFSET_BITS=64 -DHAVE_LOFF_T -DHAVE_ERR_H -DHAVE_MEMPCPY -DHAVE_FSYNC
+LOCAL_SRC_FILES = 	lib/at.c \
+			lib/blkdev.c \
+			lib/canonicalize.c \
+			lib/colors.c \
+			lib/crc32.c \
+			lib/crc64.c \
+			lib/env.c \
+			lib/exec_shell.c \
+			lib/fileutils.c \
+			lib/ismounted.c \
+			lib/langinfo.c \
+			lib/linux_version.c \
+			lib/loopdev.c \
+			lib/mangle.c \
+			lib/match.c \
+			lib/mbsalign.c \
+			lib/md5.c \
+			lib/pager.c \
+			lib/path.c \
+			lib/procutils.c \
+			lib/randutils.c \
+			lib/setproctitle.c \
+			lib/strutils.c \
+			lib/sysfs.c \
+
+LOCAL_C_INCLUDES += 	$(LOCAL_PATH)/libfdisk/src \
+			$(LOCAL_PATH)/include \
+			$(LOCAL_PATH)/libuuid/src \
+		    	$(LOCAL_PATH)/src
+
+LOCAL_SHARED_LIBRARIES += libc
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libuuid
+LOCAL_MODULE_TAGS := optional
+#LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
+LOCAL_CFLAGS = -D_FILE_OFFSET_BITS=64 -DHAVE_LOFF_T -DHAVE_ERR_H -DHAVE_MEMPCPY -DHAVE_FSYNC
+LOCAL_SRC_FILES =	libuuid/src/clear.c \
+			libuuid/src/copy.c \
+			libuuid/src/isnull.c \
+			libuuid/src/parse.c \
+			libuuid/src/unpack.c \
+			libuuid/src/uuid_time.c \
+			libuuid/src/compare.c \
+			libuuid/src/gen_uuid.c \
+			libuuid/src/pack.c \
+			libuuid/src/test_uuid.c \
+			libuuid/src/unparse.c
+
+LOCAL_C_INCLUDES += 	$(LOCAL_PATH)/libuuid/src \
+			$(LOCAL_PATH)/include \
+		    	$(LOCAL_PATH)/src
+
+LOCAL_SHARED_LIBRARIES += libc libutil-linux
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libfdisk
+LOCAL_MODULE_TAGS := optional
+#LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
+LOCAL_CFLAGS = -D_FILE_OFFSET_BITS=64 -DHAVE_LOFF_T -DHAVE_ERR_H -DHAVE_MEMPCPY -DHAVE_FSYNC
+LOCAL_SRC_FILES = 	libfdisk/src/alignment.c \
+			libfdisk/src/context.c  \
+			libfdisk/src/init.c   \
+			libfdisk/src/partition.c \
+			libfdisk/src/sgi.c \
+			libfdisk/src/test.c \
+			libfdisk/src/ask.c \
+			libfdisk/src/dos.c \
+			libfdisk/src/iter.c \
+			libfdisk/src/parttype.c \
+			libfdisk/src/sun.c \
+			libfdisk/src/utils.c \
+			libfdisk/src/bsd.c \
+			libfdisk/src/gpt.c \
+			libfdisk/src/label.c \
+			libfdisk/src/script.c \
+			libfdisk/src/table.c
+
+LOCAL_C_INCLUDES += 	$(LOCAL_PATH)/libfdisk/src \
+			$(LOCAL_PATH)/include \
+			$(LOCAL_PATH)/libuuid/src \
+		    	$(LOCAL_PATH)/src
+
+LOCAL_SHARED_LIBRARIES += libc libutil-linux libuuid
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
 LOCAL_MODULE := libblkid
 LOCAL_MODULE_TAGS := optional
 #LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
-LOCAL_CFLAGS = -D_FILE_OFFSET_BITS=64 -DHAVE_LOFF_T
-LOCAL_SRC_FILES = aix.c at.c befs.c bfs.c blkdev.c bsd.c btrfs.c cache.c canonicalize.c colors.c config.c cramfs.c crc32.c ddf_raid.c dev.c devname.c devno.c dm.c dos.c drbd.c drbdproxy_datalog.c encode.c env.c evaluate.c evms.c exec_shell.c exfat.c ext.c f2fs.c fileutils.c getsize.c gfs.c gpt.c hfs.c highpoint_raid.c hpfs.c ioctl.c ismounted.c iso9660.c isw_raid.c jfs.c jmicron_raid.c langinfo.c linux_raid.c linux_version.c llseek.c loopdev.c lsi_raid.c luks.c lvm1.c lvm2.c mac.c mangle.c match.c mbsalign.c md5.c md.c minix1.c minix2.c netware.c nilfs.c ntfs.c nvidia_raid.c ocfs.c pager.c partitions.c path.c probe.c procutils.c promise_raid.c randutils.c read.c reiserfs.c resolve.c romfs.c save.c setproctitle.c sgi.c silicon_raid.c solaris_x86.c squashfs.c sun.c superblocks.c swap.c sysfs1.c sysfs2.c sysv.c tag.c topology.c  ubifs.c udf.c ufs.c ultrix.c unixware.c verify.c version.c vfat.c via_raid.c vmfs.c vxfs.c wholedisk.c xfs.c zfs.c adaptec_raid.c
-LOCAL_C_INCLUDES += $(LOCAL_PATH) \
-LOCAL_SHARED_LIBRARIES += libc
+LOCAL_CFLAGS = -D_FILE_OFFSET_BITS=64 -DHAVE_LOFF_T -DHAVE_ERR_H -DHAVE_MEMPCPY -DHAVE_FSYNC
+LOCAL_SRC_FILES = 	src/cache.c \
+			src/config.c \
+			src/dev.c \
+			src/devname.c \
+			src/devno.c \
+			src/encode.c \
+			src/evaluate.c \
+			src/getsize.c \
+			src/init.c \
+			src/llseek.c \
+			src/probe.c \
+			src/read.c \
+			src/resolve.c \
+			src/save.c \
+			src/tag.c \
+			src/verify.c \
+			src/version.c \
+			src/partitions/aix.c \
+			src/partitions/bsd.c \
+			src/partitions/dos.c \
+			src/partitions/gpt.c \
+			src/partitions/mac.c \
+			src/partitions/minix.c \
+			src/partitions/partitions.c \
+			src/partitions/sgi.c \
+			src/partitions/solaris_x86.c \
+			src/partitions/sun.c \
+			src/partitions/ultrix.c \
+			src/partitions/unixware.c \
+			src/superblocks/adaptec_raid.c  \
+			src/superblocks/bcache.c  \
+			src/superblocks/befs.c  \
+			src/superblocks/bfs.c \
+			src/superblocks/btrfs.c \
+			src/superblocks/cramfs.c \
+			src/superblocks/ddf_raid.c \
+			src/superblocks/drbd.c \
+			src/superblocks/drbdproxy_datalog.c \
+			src/superblocks/exfat.c \
+			src/superblocks/ext.c \
+			src/superblocks/f2fs.c \
+			src/superblocks/gfs.c \
+			src/superblocks/hfs.c \
+			src/superblocks/highpoint_raid.c \
+			src/superblocks/hpfs.c \
+			src/superblocks/iso9660.c \
+			src/superblocks/isw_raid.c \
+			src/superblocks/jfs.c \
+			src/superblocks/jmicron_raid.c \
+			src/superblocks/linux_raid.c \
+			src/superblocks/lsi_raid.c \
+			src/superblocks/luks.c \
+			src/superblocks/lvm.c \
+			src/superblocks/minix.c \
+			src/superblocks/netware.c \
+			src/superblocks/nilfs.c \
+			src/superblocks/ntfs.c \
+			src/superblocks/nvidia_raid.c \
+			src/superblocks/ocfs.c \
+			src/superblocks/promise_raid.c \
+			src/superblocks/refs.c \
+			src/superblocks/reiserfs.c \
+			src/superblocks/romfs.c \
+			src/superblocks/silicon_raid.c \
+			src/superblocks/squashfs.c \
+			src/superblocks/superblocks.c \
+			src/superblocks/swap.c \
+			src/superblocks/sysv.c \
+			src/superblocks/ubifs.c \
+			src/superblocks/udf.c \
+			src/superblocks/ufs.c \
+			src/superblocks/vfat.c \
+			src/superblocks/via_raid.c \
+			src/superblocks/vmfs.c \
+			src/superblocks/vxfs.c \
+			src/superblocks/xfs.c \
+			src/superblocks/zfs.c \
+			src/topology/dm.c \
+			src/topology/evms.c \
+			src/topology/ioctl.c \
+			src/topology/lvm.c \
+			src/topology/md.c \
+			src/topology/sysfs.c \
+			src/topology/topology.c \
 
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/include \
+		    $(LOCAL_PATH)/src
+
+LOCAL_SHARED_LIBRARIES += libc libfdisk libutil-linux
 include $(BUILD_SHARED_LIBRARY)
diff --git a/libblkid/COPYING b/libblkid/COPYING
new file mode 100644
index 0000000..be1a5b3
--- /dev/null
+++ b/libblkid/COPYING
@@ -0,0 +1,8 @@
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later
+version.
+
+The complete text of the license is available in the
+../Documentation/licenses/COPYING.LGPLv2.1 file.
diff --git a/libblkid/Makemodule.am b/libblkid/Makemodule.am
new file mode 100644
index 0000000..b4f6f9c
--- /dev/null
+++ b/libblkid/Makemodule.am
@@ -0,0 +1,16 @@
+if BUILD_LIBBLKID
+
+include libblkid/src/Makemodule.am
+include libblkid/samples/Makemodule.am
+
+if ENABLE_GTK_DOC
+# Docs uses separate Makefiles
+SUBDIRS += libblkid/docs
+endif
+
+pkgconfig_DATA += libblkid/blkid.pc
+PATHFILES      += libblkid/blkid.pc
+dist_man_MANS  += libblkid/libblkid.3
+EXTRA_DIST     += libblkid/libblkid.3 libblkid/COPYING
+
+endif # BUILD_LIBBLKID
diff --git a/libblkid/blkid.pc.in b/libblkid/blkid.pc.in
new file mode 100644
index 0000000..40ec8a9
--- /dev/null
+++ b/libblkid/blkid.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@usrlib_execdir@
+includedir=@includedir@
+
+Name: blkid
+Description: Block device id library
+Version: @LIBBLKID_VERSION@
+Requires.private: uuid
+Cflags: -I${includedir}/blkid
+Libs: -L${libdir} -lblkid
diff --git a/libblkid/blkid_parttypes.h b/libblkid/blkid_parttypes.h
deleted file mode 100644
index b0aad86..0000000
--- a/libblkid/blkid_parttypes.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Partition types
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-/* Note, _L32M means <32M (less), for example FAT16_L32M */
-
-enum {
-	BLKID_EMPTY_PARTITION			= 0x00,
-	BLKID_FAT12_PARTITION			= 0x01,
-	BLKID_XENIX_ROOT_PARTITION		= 0x02,
-	BLKID_XENIX_USR_PARTITION		= 0x03,
-	BLKID_FAT16_LESS32M_PARTITION		= 0x04,
-	BLKID_DOS_EXTENDED_PARTITION		= 0x05,
-	BLKID_FAT16_PARTITION			= 0x06, /* DOS 16-bit >=32M */
-	BLKID_HPFS_NTFS_PARTITION		= 0x07, /* OS/2 IFS, eg, HPFS or NTFS or QNX */
-	BLKID_AIX_PARTITION			= 0x08, /* AIX boot (AIX -- PS/2 port) or SplitDrive */
-	BLKID_AIX_BOOTABLE_PARTITION		= 0x09, /* AIX data or Coherent */
-	BLKID_OS2_BOOTMNGR_PARTITION		= 0x0a, /* OS/2 Boot Manager */
-	BLKID_W95_FAT32_PARTITION		= 0x0b,
-	BLKID_W95_FAT32_LBA_PARTITION		= 0x0c, /* LBA really is `Extended Int 13h' */
-	BLKID_W95_FAT16_LBA_PARTITION		= 0x0e,
-	BLKID_W95_EXTENDED_PARTITION		= 0x0f,
-	BLKID_OPUS_PARTITION			= 0x10,
-	BLKID_HIDDEN_FAT12_PARTITION		= 0x11,
-	BLKID_COMPAQ_DIAGNOSTICS_PARTITION	= 0x12,
-	BLKID_HIDDEN_FAT16_L32M_PARTITION	= 0x14,
-	BLKID_HIDDEN_FAT16_PARTITION		= 0x16,
-	BLKID_HIDDEN_HPFS_NTFS_PARTITION	= 0x17,
-	BLKID_AST_SMARTSLEEP_PARTITION		= 0x18,
-	BLKID_HIDDEN_W95_FAT32_PARTITION	= 0x1b,
-	BLKID_HIDDEN_W95_FAT32LBA_PARTITION	= 0x1c,
-	BLKID_HIDDEN_W95_FAT16LBA_PARTITION	= 0x1e,
-	BLKID_NEC_DOS_PARTITION			= 0x24,
-	BLKID_PLAN9_PARTITION			= 0x39,
-	BLKID_PARTITIONMAGIC_PARTITION		= 0x3c,
-	BLKID_VENIX80286_PARTITION		= 0x40,
-	BLKID_PPC_PREP_BOOT_PARTITION		= 0x41,
-	BLKID_SFS_PARTITION			= 0x42,
-	BLKID_QNX_4X_PARTITION			= 0x4d,
-	BLKID_QNX_4X_2ND_PARTITION		= 0x4e,
-	BLKID_QNX_4X_3RD_PARTITION		= 0x4f,
-	BLKID_DM_PARTITION			= 0x50,
-	BLKID_DM6_AUX1_PARTITION		= 0x51, /* (or Novell) */
-	BLKID_CPM_PARTITION			= 0x52, /* CP/M or Microport SysV/AT */
-	BLKID_DM6_AUX3_PARTITION		= 0x53,
-	BLKID_DM6_PARTITION			= 0x54,
-	BLKID_EZ_DRIVE_PARTITION		= 0x55,
-	BLKID_GOLDEN_BOW_PARTITION		= 0x56,
-	BLKID_PRIAM_EDISK_PARTITION		= 0x5c,
-	BLKID_SPEEDSTOR_PARTITION		= 0x61,
-	BLKID_GNU_HURD_PARTITION		= 0x63, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
-	BLKID_UNIXWARE_PARTITION		= BLKID_GNU_HURD_PARTITION,
-	BLKID_NETWARE_286_PARTITION		= 0x64,
-	BLKID_NETWARE_386_PARTITION		= 0x65,
-	BLKID_DISKSECURE_MULTIBOOT_PARTITION	= 0x70,
-	BLKID_PC_IX_PARTITION			= 0x75,
-	BLKID_OLD_MINIX_PARTITION		= 0x80, /* Minix 1.4a and earlier */
-	BLKID_MINIX_PARTITION			= 0x81, /* Minix 1.4b and later */
-	BLKID_LINUX_SWAP_PARTITION		= 0x82,
-	BLKID_SOLARIS_X86_PARTITION		= BLKID_LINUX_SWAP_PARTITION,
-	BLKID_LINUX_DATA_PARTITION		= 0x83,
-	BLKID_OS2_HIDDEN_DRIVE_PARTITION	= 0x84,
-	BLKID_LINUX_EXTENDED_PARTITION		= 0x85,
-	BLKID_NTFS_VOL_SET1_PARTITION		= 0x86,
-	BLKID_NTFS_VOL_SET2_PARTITION		= 0x87,
-	BLKID_LINUX_PLAINTEXT_PARTITION		= 0x88,
-	BLKID_LINUX_LVM_PARTITION		= 0x8e,
-	BLKID_AMOEBA_PARTITION			= 0x93,
-	BLKID_AMOEBA_BBT_PARTITION		= 0x94, /* (bad block table) */
-	BLKID_BSD_OS_PARTITION			= 0x9f, /* BSDI */
-	BLKID_THINKPAD_HIBERNATION_PARTITION	= 0xa0,
-	BLKID_FREEBSD_PARTITION			= 0xa5, /* various BSD flavours */
-	BLKID_OPENBSD_PARTITION			= 0xa6,
-	BLKID_NEXTSTEP_PARTITION		= 0xa7,
-	BLKID_DARWIN_UFS_PARTITION		= 0xa8,
-	BLKID_NETBSD_PARTITION			= 0xa9,
-	BLKID_DARWIN_BOOT_PARTITION		= 0xab,
-	BLKID_HFS_HFS_PARTITION			= 0xaf,
-	BLKID_BSDI_FS_PARTITION			= 0xb7,
-	BLKID_BSDI_SWAP_PARTITION		= 0xb8,
-	BLKID_BOOTWIZARD_HIDDEN_PARTITION	= 0xbb,
-	BLKID_SOLARIS_BOOT_PARTITION		= 0xbe,
-	BLKID_SOLARIS_PARTITION			= 0xbf,
-	BLKID_DRDOS_FAT12_PARTITION		= 0xc1,
-	BLKID_DRDOS_FAT16_L32M_PARTITION	= 0xc4,
-	BLKID_DRDOS_FAT16_PARTITION		= 0xc6,
-	BLKID_SYRINX_PARTITION			= 0xc7,
-	BLKID_NONFS_DATA_PARTITION		= 0xda,
-	BLKID_CPM_CTOS_PARTITION		= 0xdb, /* CP/M or Concurrent CP/M or Concurrent DOS or CTOS */
-	BLKID_DELL_UTILITY_PARTITION		= 0xde, /* Dell PowerEdge Server utilities */
-	BLKID_BOOTIT_PARTITION			= 0xdf, /* BootIt EMBRM */
-	BLKID_DOS_ACCESS_PARTITION		= 0xe1, /* DOS access or SpeedStor 12-bit FAT extended partition */
-	BLKID_DOS_RO_PARTITION			= 0xe3, /* DOS R/O or SpeedStor */
-	BLKID_SPEEDSTOR_EXTENDED_PARTITION	= 0xe4, /* SpeedStor 16-bit FAT extended partition < 1024 cyl. */
-	BLKID_BEOS_FS_PARTITION			= 0xeb,
-	BLKID_GPT_PARTITION			= 0xee, /* Intel EFI GUID Partition Table */
-	BLKID_EFI_SYSTEM_PARTITION		= 0xef, /* Intel EFI System Partition */
-	BLKID_LINUX_PARISC_BOOT_PARTITION	= 0xf0, /* Linux/PA-RISC boot loader */
-	BLKID_SPEEDSTOR1_PARTITION		= 0xf1,
-	BLKID_SPEEDSTOR2_PARTITION		= 0xf4, /* SpeedStor large partition */
-	BLKID_DOS_SECONDARY_PARTITION		= 0xf2, /* DOS 3.3+ secondary */
-	BLKID_VMWARE_VMFS_PARTITION		= 0xfb,
-	BLKID_VMWARE_VMKCORE_PARTITION		= 0xfc, /* VMware kernel dump partition */
-	BLKID_LINUX_RAID_PARTITION		= 0xfd, /* New (2.2.x) raid partition with autodetect using persistent superblock */
-	BLKID_LANSTEP_PARTITION			= 0xfe, /* SpeedStor >1024 cyl. or LANstep */
-	BLKID_XENIX_BBT_PARTITION		= 0xff, /* Xenix Bad Block Table */
-};
diff --git a/libblkid/bsd.c b/libblkid/bsd.c
deleted file mode 100644
index ee15ad2..0000000
--- a/libblkid/bsd.c
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * BSD/OSF partition parsing code
- *
- * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
- *
- * This file may be redistributed under the terms of the
- * GNU Lesser General Public License.
- *
- * Inspired by fdisk, partx, Linux kernel, libparted and openbsd header files.
- */
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdint.h>
-
-#include "partitions.h"
-
-#define BSD_MAXPARTITIONS	16
-#define BSD_FS_UNUSED		0
-
-struct bsd_disklabel {
-	uint32_t	d_magic;		/* the magic number */
-	int16_t		d_type;			/* drive type */
-	int16_t		d_subtype;		/* controller/d_type specific */
-	char		d_typename[16];		/* type name, e.g. "eagle" */
-	char		d_packname[16];		/* pack identifier */
-
-			/* disk geometry: */
-	uint32_t	d_secsize;		/* # of bytes per sector */
-	uint32_t	d_nsectors;		/* # of data sectors per track */
-	uint32_t	d_ntracks;		/* # of tracks per cylinder */
-	uint32_t	d_ncylinders;		/* # of data cylinders per unit */
-	uint32_t	d_secpercyl;		/* # of data sectors per cylinder */
-	uint32_t	d_secperunit;		/* # of data sectors per unit */
-
-	/*
-	 * Spares (bad sector replacements) below
-	 * are not counted in d_nsectors or d_secpercyl.
-	 * Spare sectors are assumed to be physical sectors
-	 * which occupy space at the end of each track and/or cylinder.
-	 */
-	uint16_t	d_sparespertrack;	/* # of spare sectors per track */
-	uint16_t	d_sparespercyl;		/* # of spare sectors per cylinder */
-
-	/*
-	 * Alternate cylinders include maintenance, replacement,
-	 * configuration description areas, etc.
-	 */
-	uint32_t	d_acylinders;		/* # of alt. cylinders per unit */
-
-			/* hardware characteristics: */
-	/*
-	 * d_interleave, d_trackskew and d_cylskew describe perturbations
-	 * in the media format used to compensate for a slow controller.
-	 * Interleave is physical sector interleave, set up by the formatter
-	 * or controller when formatting.  When interleaving is in use,
-	 * logically adjacent sectors are not physically contiguous,
-	 * but instead are separated by some number of sectors.
-	 * It is specified as the ratio of physical sectors traversed
-	 * per logical sector.  Thus an interleave of 1:1 implies contiguous
-	 * layout, while 2:1 implies that logical sector 0 is separated
-	 * by one sector from logical sector 1.
-	 * d_trackskew is the offset of sector 0 on track N
-	 * relative to sector 0 on track N-1 on the same cylinder.
-	 * Finally, d_cylskew is the offset of sector 0 on cylinder N
-	 * relative to sector 0 on cylinder N-1.
-	 */
-	uint16_t	d_rpm;			/* rotational speed */
-	uint16_t	d_interleave;		/* hardware sector interleave */
-	uint16_t	d_trackskew;		/* sector 0 skew, per track */
-	uint16_t	d_cylskew;		/* sector 0 skew, per cylinder */
-	uint32_t	d_headswitch;		/* head switch time, usec */
-	uint32_t	d_trkseek;		/* track-to-track seek, usec */
-	uint32_t	d_flags;		/* generic flags */
-	uint32_t	d_drivedata[5];		/* drive-type specific information */
-	uint32_t	d_spare[5];		/* reserved for future use */
-	uint32_t	d_magic2;		/* the magic number (again) */
-	uint16_t	d_checksum;		/* xor of data incl. partitions */
-
-			/* filesystem and partition information: */
-	uint16_t	d_npartitions;	        /* number of partitions in following */
-	uint32_t	d_bbsize;	        /* size of boot area at sn0, bytes */
-	uint32_t	d_sbsize;	        /* max size of fs superblock, bytes */
-
-	struct bsd_partition	 {		/* the partition table */
-		uint32_t	p_size;	        /* number of sectors in partition */
-		uint32_t	p_offset;       /* starting sector */
-		uint32_t	p_fsize;        /* filesystem basic fragment size */
-		uint8_t		p_fstype;	/* filesystem type, see below */
-		uint8_t		p_frag;		/* filesystem fragments per block */
-		uint16_t	p_cpg;	        /* filesystem cylinders per group */
-	} __attribute__((packed)) d_partitions[BSD_MAXPARTITIONS];	/* actually may be more */
-} __attribute__((packed));
-
-
-/* Returns 'blkid_idmag' in 512-sectors */
-#define BLKID_MAG_SECTOR(_mag)  (((_mag)->kboff * 2)  + ((_mag)->sboff >> 9))
-
-/* Returns 'blkid_idmag' in bytes */
-#define BLKID_MAG_OFFSET(_mag)  ((_mag)->kboff >> 10) + ((_mag)->sboff)
-
-/* Returns 'blkid_idmag' offset in bytes within the last sector */
-#define BLKID_MAG_LASTOFFSET(_mag) \
-		 (BLKID_MAG_OFFSET(_mag) - (BLKID_MAG_SECTOR(_mag) << 9))
-
-static int probe_bsd_pt(blkid_probe pr, const struct blkid_idmag *mag)
-{
-	struct bsd_disklabel *l;
-	struct bsd_partition *p;
-	const char *name = "bsd" ;
-	blkid_parttable tab = NULL;
-	blkid_partition parent;
-	blkid_partlist ls;
-	int i, nparts = BSD_MAXPARTITIONS;
-	unsigned char *data;
-
-	if (blkid_partitions_need_typeonly(pr))
-		/* caller does not ask for details about partitions */
-		return 0;
-
-	data = blkid_probe_get_sector(pr, BLKID_MAG_SECTOR(mag));
-	if (!data)
-		goto nothing;
-
-	l = (struct bsd_disklabel *) data + BLKID_MAG_LASTOFFSET(mag);
-
-	ls = blkid_probe_get_partlist(pr);
-	if (!ls)
-		goto err;
-
-	/* try to determine the real type of BSD system according to
-	 * (parental) primary partition */
-	parent = blkid_partlist_get_parent(ls);
-	if (parent) {
-		switch(blkid_partition_get_type(parent)) {
-		case BLKID_FREEBSD_PARTITION:
-			name = "freebsd";
-			break;
-		case BLKID_NETBSD_PARTITION:
-			name = "netbsd";
-			break;
-		case BLKID_OPENBSD_PARTITION:
-			name = "openbsd";
-			break;
-		default:
-			DBG(DEBUG_LOWPROBE, printf(
-				"WARNING: BSD label detected on unknown (0x%x) "
-				"primary partition\n",
-				blkid_partition_get_type(parent)));
-			break;
-		}
-	}
-
-	tab = blkid_partlist_new_parttable(ls, name, BLKID_MAG_OFFSET(mag));
-	if (!tab)
-		goto err;
-
-	if (le16_to_cpu(l->d_npartitions) < BSD_MAXPARTITIONS)
-		nparts = le16_to_cpu(l->d_npartitions);
-
-	else if (le16_to_cpu(l->d_npartitions) > BSD_MAXPARTITIONS)
-		DBG(DEBUG_LOWPROBE, printf(
-			"WARNING: ignore %d more BSD partitions\n",
-			le16_to_cpu(l->d_npartitions) - BSD_MAXPARTITIONS));
-
-	for (i = 0, p = l->d_partitions; i < nparts; i++, p++) {
-		blkid_partition par;
-		uint32_t start, size;
-
-		/* TODO: in fdisk-mode returns all non-zero (p_size) partitions */
-		if (p->p_fstype == BSD_FS_UNUSED)
-			continue;
-
-		start = le32_to_cpu(p->p_offset);
-		size = le32_to_cpu(p->p_size);
-
-		if (parent && !blkid_is_nested_dimension(parent, start, size)) {
-			DBG(DEBUG_LOWPROBE, printf(
-				"WARNING: BSD partition (%d) overflow "
-				"detected, ignore\n", i));
-			continue;
-		}
-
-		par = blkid_partlist_add_partition(ls, tab, start, size);
-		if (!par)
-			goto err;
-
-		blkid_partition_set_type(par, p->p_fstype);
-	}
-
-	return 0;
-
-nothing:
-	return 1;
-err:
-	return -1;
-}
-
-
-/*
- * All BSD variants use the same magic string (little-endian),
- * and the same disklabel.
- *
- * The difference between {Free,Open,...}BSD is in the (parental)
- * primary partition type.
- *
- * See also: http://en.wikipedia.org/wiki/BSD_disklabel
- *
- * The location of BSD disk label is architecture specific and in defined by
- * LABELSECTOR and LABELOFFSET macros in the disklabel.h file. The location
- * also depends on BSD variant, FreeBSD uses only one location, NetBSD and
- * OpenBSD are more creative...
- *
- * The basic overview:
- *
- * arch                    | LABELSECTOR | LABELOFFSET
- * ------------------------+-------------+------------
- * amd64 arm hppa hppa64   |             |
- * i386, macppc, mvmeppc   |      1      |      0
- * sgi, aviion, sh, socppc |             |
- * ------------------------+-------------+------------
- * alpha luna88k mac68k    |      0      |     64
- * sparc(OpenBSD) vax      |             |
- * ------------------------+-------------+------------
- * spark64 sparc(NetBSD)   |      0      |    128
- * ------------------------+-------------+------------
- *
- * ...and more (see http://fxr.watson.org/fxr/ident?v=NETBSD;i=LABELSECTOR)
- *
- */
-const struct blkid_idinfo bsd_pt_idinfo =
-{
-	.name		= "bsd",
-	.probefunc	= probe_bsd_pt,
-	.magics		=
-	{
-		{ .magic = "\x57\x45\x56\x82", .len = 4, .sboff = 512 },
-		{ .magic = "\x57\x45\x56\x82", .len = 4, .sboff = 64 },
-		{ .magic = "\x57\x45\x56\x82", .len = 4, .sboff = 128 },
-		{ NULL }
-	}
-};
-
diff --git a/libblkid/canonicalize.c b/libblkid/canonicalize.c
deleted file mode 100644
index 1e8aff4..0000000
--- a/libblkid/canonicalize.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * canonicalize.c -- canonicalize pathname by removing symlinks
- * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Library Public License as published by
- * the Free Software Foundation; either version 2, 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 Library Public License for more details.
- *
- */
-
-/*
- * This routine is part of libc.  We include it nevertheless,
- * since the libc version has some security flaws.
- *
- * TODO: use canonicalize_file_name() when exist in glibc
- */
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include "canonicalize.h"
-
-#ifndef MAXSYMLINKS
-# define MAXSYMLINKS 256
-#endif
-
-static char *
-myrealpath(const char *path, char *resolved_path, int maxreslth) {
-	int readlinks = 0;
-	char *npath;
-	char link_path[PATH_MAX+1];
-	int n;
-	char *buf = NULL;
-
-	npath = resolved_path;
-
-	/* If it's a relative pathname use getcwd for starters. */
-	if (*path != '/') {
-		if (!getcwd(npath, maxreslth-2))
-			return NULL;
-		npath += strlen(npath);
-		if (npath[-1] != '/')
-			*npath++ = '/';
-	} else {
-		*npath++ = '/';
-		path++;
-	}
-
-	/* Expand each slash-separated pathname component. */
-	while (*path != '\0') {
-		/* Ignore stray "/" */
-		if (*path == '/') {
-			path++;
-			continue;
-		}
-		if (*path == '.' && (path[1] == '\0' || path[1] == '/')) {
-			/* Ignore "." */
-			path++;
-			continue;
-		}
-		if (*path == '.' && path[1] == '.' &&
-		    (path[2] == '\0' || path[2] == '/')) {
-			/* Backup for ".." */
-			path += 2;
-			while (npath > resolved_path+1 &&
-			       (--npath)[-1] != '/')
-				;
-			continue;
-		}
-		/* Safely copy the next pathname component. */
-		while (*path != '\0' && *path != '/') {
-			if (npath-resolved_path > maxreslth-2) {
-				errno = ENAMETOOLONG;
-				goto err;
-			}
-			*npath++ = *path++;
-		}
-
-		/* Protect against infinite loops. */
-		if (readlinks++ > MAXSYMLINKS) {
-			errno = ELOOP;
-			goto err;
-		}
-
-		/* See if last pathname component is a symlink. */
-		*npath = '\0';
-		n = readlink(resolved_path, link_path, PATH_MAX);
-		if (n < 0) {
-			/* EINVAL means the file exists but isn't a symlink. */
-			if (errno != EINVAL)
-				goto err;
-		} else {
-			int m;
-			char *newbuf;
-
-			/* Note: readlink doesn't add the null byte. */
-			link_path[n] = '\0';
-			if (*link_path == '/')
-				/* Start over for an absolute symlink. */
-				npath = resolved_path;
-			else
-				/* Otherwise back up over this component. */
-				while (*(--npath) != '/')
-					;
-
-			/* Insert symlink contents into path. */
-			m = strlen(path);
-			newbuf = malloc(m + n + 1);
-			if (!newbuf)
-				goto err;
-			memcpy(newbuf, link_path, n);
-			memcpy(newbuf + n, path, m + 1);
-			free(buf);
-			path = buf = newbuf;
-		}
-		*npath++ = '/';
-	}
-	/* Delete trailing slash but don't whomp a lone slash. */
-	if (npath != resolved_path+1 && npath[-1] == '/')
-		npath--;
-	/* Make sure it's null terminated. */
-	*npath = '\0';
-
-	free(buf);
-	return resolved_path;
-
- err:
-	free(buf);
-	return NULL;
-}
-
-/*
- * Converts private "dm-N" names to "/dev/mapper/<name>"
- *
- * Since 2.6.29 (patch 784aae735d9b0bba3f8b9faef4c8b30df3bf0128) kernel sysfs
- * provides the real DM device names in /sys/block/<ptname>/dm/name
- */
-char *
-canonicalize_dm_name(const char *ptname)
-{
-	FILE	*f;
-	size_t	sz;
-	char	path[256], name[256], *res = NULL;
-
-	snprintf(path, sizeof(path), "/sys/block/%s/dm/name", ptname);
-	if (!(f = fopen(path, "r")))
-		return NULL;
-
-	/* read "<name>\n" from sysfs */
-	if (fgets(name, sizeof(name), f) && (sz = strlen(name)) > 1) {
-		name[sz - 1] = '\0';
-		snprintf(path, sizeof(path), "/dev/mapper/%s", name);
-		res = strdup(path);
-	}
-	fclose(f);
-	return res;
-}
-
-char *
-canonicalize_path(const char *path)
-{
-	char canonical[PATH_MAX+2];
-	char *p;
-
-	if (path == NULL)
-		return NULL;
-
-	if (!myrealpath(path, canonical, PATH_MAX+1))
-		return strdup(path);
-
-
-	p = strrchr(canonical, '/');
-	if (p && strncmp(p, "/dm-", 4) == 0 && isdigit(*(p + 4))) {
-		p = canonicalize_dm_name(p+1);
-		if (p)
-			return p;
-	}
-
-	return strdup(canonical);
-}
-
-char *
-canonicalize_path_restricted(const char *path)
-{
-	char canonical[PATH_MAX+2];
-	char *p = NULL;
-	int errsv;
-	uid_t euid;
-	gid_t egid;
-
-	if (path == NULL)
-		return NULL;
-
-	euid = geteuid();
-	egid = getegid();
-
-	/* drop permissions */
-	if (setegid(getgid()) < 0 || seteuid(getuid()) < 0)
-		return NULL;
-
-	errsv = errno = 0;
-
-	if (myrealpath(path, canonical, PATH_MAX+1)) {
-		p = strrchr(canonical, '/');
-		if (p && strncmp(p, "/dm-", 4) == 0 && isdigit(*(p + 4)))
-			p = canonicalize_dm_name(p+1);
-		else
-			p = NULL;
-		if (!p)
-			p = strdup(canonical);
-	} else
-		errsv = errno;
-
-	/* restore */
-	if (setegid(egid) < 0 || seteuid(euid) < 0) {
-		free(p);
-		return NULL;
-	}
-
-	errno = errsv;
-	return p;
-}
-
-
-#ifdef TEST_PROGRAM_CANONICALIZE
-int main(int argc, char **argv)
-{
-	if (argc < 2) {
-		fprintf(stderr, "usage: %s <device>\n", argv[0]);
-		exit(EXIT_FAILURE);
-	}
-
-	fprintf(stdout, "orig: %s\n", argv[1]);
-	fprintf(stdout, "real: %s\n", canonicalize_path(argv[1]));
-
-	exit(EXIT_SUCCESS);
-}
-#endif
diff --git a/libblkid/carefulputc.h b/libblkid/carefulputc.h
deleted file mode 100644
index 2d857eb..0000000
--- a/libblkid/carefulputc.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef _CAREFUULPUTC_H
-#define _CAREFUULPUTC_H
-
-/* putc() for use in write and wall (that sometimes are sgid tty) */
-/* Avoid control characters in our locale, and also ASCII control characters.
-   Note that the locale of the recipient is unknown. */
-#include <stdio.h>
-#include <ctype.h>
-
-#define iso8859x_iscntrl(c) \
-	(((c) & 0x7f) < 0x20 || (c) == 0x7f)
-
-static inline int carefulputc(int c, FILE *fp) {
-	int ret;
-
-	if (c == '\007' || c == '\t' || c == '\r' || c == '\n' ||
-	    (!iso8859x_iscntrl(c) && (isprint(c) || isspace(c))))
-		ret = putc(c, fp);
-	else if ((c & 0x80) || !isprint(c^0x40))
-		ret = fprintf(fp, "\\%3o", (unsigned char) c);
-	else {
-		ret = putc('^', fp);
-		if (ret != EOF)
-			ret = putc(c^0x40, fp);
-	}
-	return (ret < 0) ? EOF : 0;
-}
-
-#endif  /*  _CAREFUULPUTC_H  */
diff --git a/libblkid/colors.c b/libblkid/colors.c
deleted file mode 100644
index bb9c057..0000000
--- a/libblkid/colors.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2012 Ondrej Oprala <ooprala@redhat.com>
- *
- * This file may be distributed under the terms of the
- * GNU Lesser General Public License.
- */
-
-#include "colors.h"
-
-static int ul_color_term_ok;
-
-int colors_init(void)
-{
-	ul_color_term_ok = isatty(STDOUT_FILENO);
-	return ul_color_term_ok;
-}
-
-void color_enable(const char *color_scheme)
-{
-	if (ul_color_term_ok)
-		fputs(color_scheme, stdout);
-}
-
-void color_disable(void)
-{
-	if (ul_color_term_ok)
-		fputs(UL_COLOR_RESET, stdout);
-}
diff --git a/libblkid/colors.h b/libblkid/colors.h
deleted file mode 100644
index 0eb1946..0000000
--- a/libblkid/colors.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2012 Ondrej Oprala <ooprala@redhat.com>
- *
- * This file may be distributed under the terms of the
- * GNU Lesser General Public License.
- */
-#ifndef UTIL_LINUX_COLORS_H
-#define UTIL_LINUX_COLORS_H
-
-#include <stdio.h>
-#include <unistd.h>
-
-#define UL_COLOR_RESET		"\033[0m"
-#define UL_COLOR_BOLD		"\033[1m"
-#define UL_COLOR_HALFBRIGHT	"\033[2m"
-#define UL_COLOR_UNDERSCORE	"\033[4m"
-#define UL_COLOR_BLINK		"\033[5m"
-#define UL_COLOR_REVERSE	"\033[7m"
-
-/* Standard colors */
-#define UL_COLOR_BLACK		"\033[30m"
-#define UL_COLOR_RED		"\033[31m"
-#define UL_COLOR_GREEN		"\033[32m"
-#define UL_COLOR_YELLOW		"\033[33m"
-#define UL_COLOR_BLUE		"\033[34m"
-#define UL_COLOR_MAGENTA	"\033[35m"
-#define UL_COLOR_CYAN		"\033[36m"
-#define UL_COLOR_GRAY		"\033[37m"
-
-/* Bold variants */
-#define UL_COLOR_DARK_GRAY	"\033[1;30m"
-#define UL_COLOR_BOLD_RED	"\033[1;31m"
-#define UL_COLOR_BOLD_GREEN	"\033[1;32m"
-#define UL_COLOR_BOLD_YELLOW	"\033[1;33m"
-#define UL_COLOR_BOLD_BLUE	"\033[1;34m"
-#define UL_COLOR_BOLD_MAGENTA	"\033[1;35m"
-#define UL_COLOR_BOLD_CYAN	"\033[1;36m"
-
-#define UL_COLOR_WHITE		"\033[1;37m"
-
-/* Initialize the global variable OUT_IS_TERM */
-extern int colors_init(void);
-
-/* Set the color to CLR_SCHEME */
-extern void color_enable(const char *clr_scheme);
-
-/* Reset colors to default */
-extern void color_disable(void);
-
-#endif /* UTIL_LINUX_COLORS_H */
diff --git a/libblkid/docs/.gitignore b/libblkid/docs/.gitignore
new file mode 100644
index 0000000..f91f93d
--- /dev/null
+++ b/libblkid/docs/.gitignore
@@ -0,0 +1,18 @@
+*-decl-list.txt
+*-decl.txt
+*-overrides.txt
+*-undeclared.txt
+*-undocumented.txt
+*-unused.txt
+*.args
+*.bak
+*.hierarchy
+*.interfaces
+*.prerequisites
+*.signals
+*.stamp
+*.types
+html/*
+tmpl/*
+version.xml
+xml/*
diff --git a/libblkid/docs/Makefile.am b/libblkid/docs/Makefile.am
new file mode 100644
index 0000000..dc6dd3e
--- /dev/null
+++ b/libblkid/docs/Makefile.am
@@ -0,0 +1,95 @@
+## Process this file with automake to produce Makefile.in
+
+# We require automake 1.10 at least.
+AUTOMAKE_OPTIONS = 1.10
+
+# This is a blank Makefile.am for using gtk-doc.
+# Copy this to your project's API docs directory and modify the variables to
+# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples
+# of using the various options.
+
+# The name of the module, e.g. 'glib'.
+DOC_MODULE=libblkid
+
+# Uncomment for versioned docs and specify the version of the module, e.g. '2'.
+#DOC_MODULE_VERSION=2
+
+# The top-level SGML file. You can change this if you want to.
+DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml
+
+# The directory containing the source code. Relative to $(srcdir).
+# gtk-doc will search all .c & .h files beneath here for inline comments
+# documenting the functions and macros.
+# e.g. DOC_SOURCE_DIR=../../../gtk
+DOC_SOURCE_DIR=../src
+
+# Extra options to pass to gtkdoc-scangobj. Not normally needed.
+SCANGOBJ_OPTIONS=
+
+# Extra options to supply to gtkdoc-scan.
+# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
+SCAN_OPTIONS=--deprecated-guards="BLKID_DISABLE_DEPRECATED"
+
+# Extra options to supply to gtkdoc-mkdb.
+# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml
+MKDB_OPTIONS=--sgml-mode --output-format=xml --name-space blkid
+
+# Extra options to supply to gtkdoc-mktmpl
+# e.g. MKTMPL_OPTIONS=--only-section-tmpl
+MKTMPL_OPTIONS=
+
+# Extra options to supply to gtkdoc-mkhtml
+MKHTML_OPTIONS=
+
+# Extra options to supply to gtkdoc-fixref. Not normally needed.
+# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html
+FIXXREF_OPTIONS=
+
+# Used for dependencies. The docs will be rebuilt if any of these change.
+# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h
+# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c
+HFILE_GLOB=$(top_builddir)/libblkid/src/blkid.h
+CFILE_GLOB=$(top_srcdir)/libblkid/src/*.c
+
+# Extra header to include when scanning, which are not under DOC_SOURCE_DIR
+# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h
+EXTRA_HFILES=
+
+# Header files to ignore when scanning. Use base file name, no paths
+# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h
+IGNORE_HFILES=blkidP.h partitions.h superblocks.h \
+	      topology.h aix.h dos.h iso9660.h
+
+# Images to copy into HTML directory.
+# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
+HTML_IMAGES=
+
+# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
+# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
+content_files = $(builddir)/version.xml $(srcdir)/libblkid-config.xml
+
+# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
+# These files must be listed here *and* in content_files
+# e.g. expand_content_files=running.sgml
+expand_content_files=
+
+# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
+# Only needed if you are using gtkdoc-scangobj to dynamically query widget
+# signals and properties.
+# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
+# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
+GTKDOC_CFLAGS=
+GTKDOC_LIBS=
+
+# This includes the standard gtk-doc make rules, copied by gtkdocize.
+include $(top_srcdir)/config/gtk-doc.make
+
+# Other files to distribute
+# e.g. EXTRA_DIST += version.xml.in
+EXTRA_DIST += version.xml.in $(srcdir)/libblkid-config.xml
+
+# Files not to distribute
+# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
+# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
+DISTCLEANFILES += version.xml
+
diff --git a/libblkid/docs/libblkid-config.xml b/libblkid/docs/libblkid-config.xml
new file mode 100644
index 0000000..89fbb7f
--- /dev/null
+++ b/libblkid/docs/libblkid-config.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
+               "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
+[
+  <!ENTITY version SYSTEM "version.xml">
+]>
+<refentry id="libblkid-config">
+<refmeta>
+<refentrytitle role="top_of_page" id="libblkid-config.top_of_page">Config file</refentrytitle>
+<manvolnum>3</manvolnum>
+<refmiscinfo>LIBBLKID Library</refmiscinfo>
+</refmeta>
+
+<refnamediv>
+<refname>Config file</refname>
+<refpurpose>config file to control paths and basic library behavior</refpurpose>
+</refnamediv>
+
+<refsect1 id="libblkid-config.description" role="desc">
+<title role="desc.title">Description</title>
+<para>
+The standard location of the
+/etc/blkid.conf config file can be overridden by the environment variable
+BLKID_CONF.  The following options control the libblkid library:
+</para>
+
+<variablelist role="params">
+ <varlistentry>
+  <term>SEND_UEVENT=<parameter>yes|not</parameter></term>
+  <listitem><simpara>
+   Sends uevent when /dev/disk/by-{label,uuid}/
+   symlink does not match with LABEL or UUID on the device. Default is "yes".
+  </simpara></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>CACHE_FILE=<parameter>path</parameter></term>
+  <listitem><simpara>
+   Overrides the standard location of the cache file. This
+   setting can be overridden by the environment variable BLKID_FILE. Default is
+   /etc/blkid.tab.
+  </simpara></listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>EVALUATE=<parameter>method</parameter></term>
+  <listitem><simpara>
+   Defines LABEL and UUID evaluation method(s). Currently,
+   the libblkid library supports "udev" and "scan" methods. More than one methods
+   may be specified in a comma separated list. Default is "udev,scan". The "udev"
+   method uses udev /dev/disk/by-* symlinks and the "scan" method scans all
+   block devices from the /proc/partitions file.
+  </simpara></listitem>
+ </varlistentry>
+</variablelist>
+
+</refsect1>
+
+</refentry>
diff --git a/libblkid/docs/libblkid-docs.xml b/libblkid/docs/libblkid-docs.xml
new file mode 100644
index 0000000..1f412c1
--- /dev/null
+++ b/libblkid/docs/libblkid-docs.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
+               "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
+[
+  <!ENTITY version SYSTEM "version.xml">
+]>
+<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
+  <bookinfo>
+    <title>libblkid Reference Manual</title>
+    <releaseinfo>for libblkid version &version;</releaseinfo>
+    <copyright>
+      <year>2009-2013</year>
+      <holder>Karel Zak &lt;kzak@redhat.com&gt;</holder>
+    </copyright>
+  </bookinfo>
+
+  <part id="gtk">
+    <title>libblkid Overview</title>
+    <partintro>
+    <para>
+The libblkid library is used to identify block devices (disks) as to their
+content (e.g.  filesystem type, partitions) as well as extracting additional
+information such as filesystem labels/volume names, partitions, unique
+identifiers/serial numbers, etc.  A common use is to allow use of LABEL= and
+UUID= tags instead of hard-coding specific block device names into
+configuration files.
+    </para>
+    <para>
+The libblkid librray
+was written by Andreas Dilger for the ext2 filesystem utilties, with input
+from Ted Ts'o.  The library was subsequently heavily modified by Ted Ts'o.
+    </para>
+    <para>
+The low-level probing code, topology and partitions support was written
+by Karel Zak. Currently, the library is mainatned by Karel Zak.
+    </para>
+    <para>
+The library is part of the util-linux package since version 2.15 and is
+available from ftp://ftp.kernel.org/pub/linux/utils/util-linux/.
+    </para>
+  </partintro>
+  <xi:include href="xml/libblkid-config.xml"/>
+ </part>
+
+  <part>
+    <title>High-level</title>
+    <xi:include href="xml/evaluate.xml"/>
+    <xi:include href="xml/cache.xml"/>
+    <xi:include href="xml/search.xml"/>
+  </part>
+  <part>
+    <title>Low-level</title>
+    <xi:include href="xml/init.xml"/>
+    <xi:include href="xml/lowprobe.xml"/>
+    <xi:include href="xml/lowprobe-tags.xml"/>
+    <xi:include href="xml/superblocks.xml"/>
+    <xi:include href="xml/partitions.xml"/>
+    <xi:include href="xml/topology.xml"/>
+  </part>
+  <part>
+    <title>Common utils</title>
+    <xi:include href="xml/encode.xml"/>
+    <xi:include href="xml/misc.xml"/>
+  </part>
+
+  <index id="api-index-full">
+    <title>API Index</title>
+    <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
+  </index>
+</book>
diff --git a/libblkid/docs/libblkid-sections.txt b/libblkid/docs/libblkid-sections.txt
new file mode 100644
index 0000000..53cf84b
--- /dev/null
+++ b/libblkid/docs/libblkid-sections.txt
@@ -0,0 +1,201 @@
+<SECTION>
+<FILE>evaluate</FILE>
+blkid_evaluate_tag
+blkid_evaluate_spec
+</SECTION>
+
+<SECTION>
+<FILE>init</FILE>
+blkid_init_debug
+</SECTION>
+
+<SECTION>
+<FILE>cache</FILE>
+blkid_cache
+blkid_gc_cache
+blkid_get_cache
+blkid_put_cache
+blkid_probe_all
+blkid_probe_all_removable
+blkid_probe_all_new
+blkid_verify
+</SECTION>
+
+<SECTION>
+<FILE>search</FILE>
+blkid_dev
+blkid_dev_devname
+blkid_dev_has_tag
+blkid_dev_iterate
+blkid_dev_iterate_begin
+blkid_dev_iterate_end
+blkid_dev_next
+blkid_dev_set_search
+blkid_find_dev_with_tag
+blkid_get_dev
+blkid_get_devname
+blkid_get_tag_value
+blkid_tag_iterate
+blkid_tag_iterate_begin
+blkid_tag_iterate_end
+blkid_tag_next
+</SECTION>
+
+<SECTION>
+<FILE>lowprobe</FILE>
+blkid_probe
+blkid_free_probe
+blkid_new_probe
+blkid_new_probe_from_filename
+blkid_probe_get_devno
+blkid_probe_get_fd
+blkid_probe_get_offset
+blkid_probe_get_sectors
+blkid_probe_get_sectorsize
+blkid_probe_get_size
+blkid_probe_get_wholedisk_devno
+blkid_probe_is_wholedisk
+blkid_probe_set_device
+blkid_probe_step_back
+blkid_reset_probe
+</SECTION>
+
+<SECTION>
+<FILE>lowprobe-tags</FILE>
+blkid_do_fullprobe
+blkid_do_wipe
+blkid_do_probe
+blkid_do_safeprobe
+<SUBSECTION>
+blkid_probe_get_value
+blkid_probe_has_value
+blkid_probe_lookup_value
+blkid_probe_numof_values
+</SECTION>
+
+<SECTION>
+<FILE>partitions</FILE>
+blkid_partlist
+blkid_partition
+blkid_parttable
+blkid_probe_enable_partitions
+blkid_probe_set_partitions_flags
+blkid_probe_filter_partitions_type
+blkid_probe_invert_partitions_filter
+blkid_probe_reset_partitions_filter
+<SUBSECTION>
+blkid_known_pttype
+<SUBSECTION>
+blkid_partition_get_name
+blkid_partition_get_flags
+blkid_partition_get_partno
+blkid_partition_get_size
+blkid_partition_get_start
+blkid_partition_get_table
+blkid_partition_get_type
+blkid_partition_get_type_string
+blkid_partition_get_uuid
+blkid_partition_is_extended
+blkid_partition_is_logical
+blkid_partition_is_primary
+<SUBSECTION>
+blkid_partlist_get_partition
+blkid_partlist_get_partition_by_partno
+blkid_partlist_numof_partitions
+blkid_partlist_devno_to_partition
+blkid_partlist_get_table
+<SUBSECTION>
+blkid_parttable_get_id
+blkid_parttable_get_offset
+blkid_parttable_get_parent
+blkid_parttable_get_type
+<SUBSECTION>
+blkid_probe_get_partitions
+</SECTION>
+
+<SECTION>
+<FILE>superblocks</FILE>
+blkid_probe_enable_superblocks
+<SUBSECTION>
+blkid_known_fstype
+blkid_superblocks_get_name
+<SUBSECTION>
+blkid_probe_filter_superblocks_type
+blkid_probe_filter_superblocks_usage
+blkid_probe_invert_superblocks_filter
+blkid_probe_reset_superblocks_filter
+blkid_probe_set_superblocks_flags
+<SUBSECTION>
+blkid_probe_reset_filter
+blkid_probe_filter_types
+blkid_probe_filter_usage
+blkid_probe_invert_filter
+blkid_probe_set_request
+</SECTION>
+
+<SECTION>
+<FILE>topology</FILE>
+blkid_topology
+blkid_probe_enable_topology
+<SUBSECTION>
+blkid_probe_get_topology
+blkid_topology_get_alignment_offset
+blkid_topology_get_logical_sector_size
+blkid_topology_get_minimum_io_size
+blkid_topology_get_optimal_io_size
+blkid_topology_get_physical_sector_size
+</SECTION>
+
+<SECTION>
+<FILE>encode</FILE>
+blkid_encode_string
+blkid_safe_string
+</SECTION>
+
+<SECTION>
+<FILE>misc</FILE>
+blkid_loff_t
+blkid_devno_to_devname
+blkid_devno_to_wholedisk
+blkid_get_dev_size
+blkid_get_library_version
+blkid_parse_tag_string
+blkid_parse_version_string
+blkid_send_uevent
+BLKID_VERSION
+BLKID_DATE
+BLKID_FLTR_NOTIN
+BLKID_FLTR_ONLYIN
+BLKID_DEV_CREATE
+BLKID_DEV_FIND
+BLKID_DEV_NORMAL
+BLKID_DEV_VERIFY
+BLKID_PARTS_ENTRY_DETAILS
+BLKID_PARTS_FORCE_GPT
+BLKID_PARTS_MAGIC
+BLKID_PROBREQ_LABEL
+BLKID_PROBREQ_LABELRAW
+BLKID_PROBREQ_SECTYPE
+BLKID_PROBREQ_TYPE
+BLKID_PROBREQ_USAGE
+BLKID_PROBREQ_UUID
+BLKID_PROBREQ_UUIDRAW
+BLKID_PROBREQ_VERSION
+BLKID_SUBLKS_BADCSUM
+BLKID_SUBLKS_DEFAULT
+BLKID_SUBLKS_LABEL
+BLKID_SUBLKS_LABELRAW
+BLKID_SUBLKS_MAGIC
+BLKID_SUBLKS_SECTYPE
+BLKID_SUBLKS_TYPE
+BLKID_SUBLKS_USAGE
+BLKID_SUBLKS_UUID
+BLKID_SUBLKS_UUIDRAW
+BLKID_SUBLKS_VERSION
+BLKID_USAGE_CRYPTO
+BLKID_USAGE_FILESYSTEM
+BLKID_USAGE_OTHER
+BLKID_USAGE_RAID
+</SECTION>
+
+
diff --git a/libblkid/docs/version.xml.in b/libblkid/docs/version.xml.in
new file mode 100644
index 0000000..d78bda9
--- /dev/null
+++ b/libblkid/docs/version.xml.in
@@ -0,0 +1 @@
+@VERSION@
diff --git a/libblkid/dos.h b/libblkid/dos.h
deleted file mode 100644
index d7588a8..0000000
--- a/libblkid/dos.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef BLKID_PARTITIONS_DOS_H
-#define BLKID_PARTITIONS_DOS_H
-
-struct dos_partition {
-	unsigned char boot_ind;		/* 0x80 - active */
-	unsigned char bh, bs, bc;	/* begin CHS */
-	unsigned char sys_type;
-	unsigned char eh, es, ec;	/* end CHS */
-	unsigned char start_sect[4];
-	unsigned char nr_sects[4];
-} __attribute__((packed));
-
-#define BLKID_MSDOS_PT_OFFSET		0x1be
-
-/* assemble badly aligned little endian integer */
-static inline unsigned int assemble4le(const unsigned char *p)
-{
-	return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
-}
-
-static inline unsigned int dos_partition_start(struct dos_partition *p)
-{
-	return assemble4le(&(p->start_sect[0]));
-}
-
-static inline unsigned int dos_partition_size(struct dos_partition *p)
-{
-	return assemble4le(&(p->nr_sects[0]));
-}
-
-static inline int is_valid_mbr_signature(const unsigned char *mbr)
-{
-	return mbr[510] == 0x55 && mbr[511] == 0xaa ? 1 : 0;
-}
-
-static inline unsigned int dos_parttable_id(const unsigned char *mbr)
-{
-	return assemble4le(&mbr[440]);
-}
-
-#endif /* BLKID_PARTITIONS_DOS_H */
diff --git a/libblkid/exec_shell.c b/libblkid/exec_shell.c
deleted file mode 100644
index 95620cd..0000000
--- a/libblkid/exec_shell.c
+++ /dev/null
@@ -1,27 +0,0 @@
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-
-#include "nls.h"
-#include "c.h"
-#include "xalloc.h"
-
-#include "exec_shell.h"
-
-#define DEFAULT_SHELL "/bin/sh"
-
-void __attribute__((__noreturn__)) exec_shell(void) {
-	const char *shell = getenv("SHELL"), *shell_basename;
-	char *arg0;
-	if (!shell)
-		shell = DEFAULT_SHELL;
-
-	shell_basename = basename(shell);
-	arg0 = xmalloc(strlen(shell_basename) + 2);
-	arg0[0] = '-';
-	strcpy(arg0 + 1, shell_basename);
-
-	execl(shell, arg0, NULL);
-	err(EXIT_FAILURE, _("failed to execute %s"), shell);
-}
diff --git a/libblkid/include/Makemodule.am b/libblkid/include/Makemodule.am
new file mode 100644
index 0000000..c4a52e4
--- /dev/null
+++ b/libblkid/include/Makemodule.am
@@ -0,0 +1,57 @@
+
+dist_noinst_HEADERS += \
+	include/all-io.h \
+	include/at.h \
+	include/bitops.h \
+	include/blkdev.h \
+	include/monotonic.h \
+	include/c.h \
+	include/canonicalize.h \
+	include/carefulputc.h \
+	include/closestream.h \
+	include/colors.h \
+	include/cpuset.h \
+	include/crc32.h \
+	include/crc64.h \
+	include/debug.h \
+	include/env.h \
+	include/exec_shell.h \
+	include/exitcodes.h \
+	include/fileutils.h \
+	include/ismounted.h \
+	include/linux_reboot.h \
+	include/linux_version.h \
+	include/list.h \
+	include/loopdev.h \
+	include/mangle.h \
+	include/match.h \
+	include/mbsalign.h \
+	include/md5.h \
+	include/minix.h \
+	include/namespace.h \
+	include/nls.h \
+	include/optutils.h \
+	include/pager.h \
+	include/pamfail.h \
+	include/path.h \
+	include/pathnames.h \
+	include/procutils.h \
+	include/randutils.h \
+	include/readutmp.h \
+	include/rpmatch.h \
+	include/setproctitle.h \
+	include/strutils.h \
+	include/swapprober.h \
+	include/swapheader.h \
+	include/sysfs.h \
+	include/timer.h \
+	include/timeutils.h \
+	include/ttyutils.h \
+	include/widechar.h \
+	include/xalloc.h \
+	include/pt-sgi.h \
+	include/pt-bsd.h \
+	include/pt-mbr.h \
+	include/pt-mbr-partnames.h \
+	include/pt-sun.h \
+	include/statfs_magic.h
diff --git a/libblkid/all-io.h b/libblkid/include/all-io.h
similarity index 94%
rename from libblkid/all-io.h
rename to libblkid/include/all-io.h
index 424ab7d..1fad66e 100644
--- a/libblkid/all-io.h
+++ b/libblkid/include/all-io.h
@@ -29,7 +29,7 @@
 		} else if (errno != EINTR && errno != EAGAIN)
 			return -1;
 		if (errno == EAGAIN)	/* Try later, *sigh* */
-			usleep(10000);
+			usleep(250000);
 	}
 	return 0;
 }
@@ -49,7 +49,7 @@
 		} else if (errno != EINTR && errno != EAGAIN)
 			return -1;
 		if (errno == EAGAIN)	/* Try later, *sigh* */
-			usleep(10000);
+			xusleep(250000);
 	}
 	return 0;
 }
@@ -65,8 +65,10 @@
 		ret = read(fd, buf, count);
 		if (ret <= 0) {
 			if ((errno == EAGAIN || errno == EINTR || ret == 0) &&
-			    (tries++ < 5))
+			    (tries++ < 5)) {
+				usleep(250000);
 				continue;
+			}
 			return c ? c : -1;
 		}
 		if (ret > 0)
diff --git a/libblkid/at.h b/libblkid/include/at.h
similarity index 100%
rename from libblkid/at.h
rename to libblkid/include/at.h
diff --git a/libblkid/include/bitops.h b/libblkid/include/bitops.h
new file mode 100644
index 0000000..498ec63
--- /dev/null
+++ b/libblkid/include/bitops.h
@@ -0,0 +1,124 @@
+/*
+ * No copyright is claimed.  This code is in the public domain; do with
+ * it what you wish.
+ *
+ * Written by Karel Zak <kzak@redhat.com>
+ */
+#ifndef BITOPS_H
+#define BITOPS_H
+
+#include <stdint.h>
+#include <sys/param.h>
+
+#if defined(HAVE_BYTESWAP_H)
+# include <byteswap.h>
+#endif
+
+#if defined(HAVE_ENDIAN_H)
+#  include <endian.h>
+#elif defined(HAVE_SYS_ENDIAN_H)	/* BSDs have them here */
+#  include <sys/endian.h>
+#endif
+
+#if defined(__OpenBSD__)
+# include <sys/types.h>
+# define be16toh(x) betoh16(x)
+# define be32toh(x) betoh32(x)
+# define be64toh(x) betoh64(x)
+#endif
+
+/*
+ * Fallbacks
+ */
+#ifndef bswap_16
+# define bswap_16(x)   ((((x) & 0x00FF) << 8) | \
+			(((x) & 0xFF00) >> 8))
+#endif
+
+#ifndef bswap_32
+# define bswap_32(x)   ((((x) & 0x000000FF) << 24) | \
+			(((x) & 0x0000FF00) << 8)  | \
+			(((x) & 0x00FF0000) >> 8)  | \
+			(((x) & 0xFF000000) >> 24))
+#endif
+
+#ifndef bswap_64
+# define bswap_64(x) ((((x) & 0x00000000000000FFULL) << 56) | \
+                      (((x) & 0x000000000000FF00ULL) << 40) | \
+                      (((x) & 0x0000000000FF0000ULL) << 24) | \
+                      (((x) & 0x00000000FF000000ULL) << 8)  | \
+                      (((x) & 0x000000FF00000000ULL) >> 8)  | \
+                      (((x) & 0x0000FF0000000000ULL) >> 24) | \
+                      (((x) & 0x00FF000000000000ULL) >> 40) | \
+                      (((x) & 0xFF00000000000000ULL) >> 56))
+#endif
+
+#ifndef htobe16
+# if !defined(WORDS_BIGENDIAN)
+#  define htobe16(x) bswap_16 (x)
+#  define htole16(x) (x)
+#  define be16toh(x) bswap_16 (x)
+#  define le16toh(x) (x)
+#  define htobe32(x) bswap_32 (x)
+#  define htole32(x) (x)
+#  define be32toh(x) bswap_32 (x)
+#  define le32toh(x) (x)
+#  define htobe64(x) bswap_64 (x)
+#  define htole64(x) (x)
+#  define be64toh(x) bswap_64 (x)
+#  define le64toh(x) (x)
+# else
+#  define htobe16(x) (x)
+#  define htole16(x) bswap_16 (x)
+#  define be16toh(x) (x)
+#  define le16toh(x) bswap_16 (x)
+#  define htobe32(x) (x)
+#  define htole32(x) bswap_32 (x)
+#  define be32toh(x) (x)
+#  define le32toh(x) bswap_32 (x)
+#  define htobe64(x) (x)
+#  define htole64(x) bswap_64 (x)
+#  define be64toh(x) (x)
+#  define le64toh(x) bswap_64 (x)
+# endif
+#endif
+
+/*
+ * Byte swab macros (based on linux/byteorder/swab.h)
+ */
+#define swab16(x) bswap_16(x)
+#define swab32(x) bswap_32(x)
+#define swab64(x) bswap_64(x)
+
+#define cpu_to_le16(x) ((uint16_t) htole16(x))
+#define cpu_to_le32(x) ((uint32_t) htole32(x))
+#define cpu_to_le64(x) ((uint64_t) htole64(x))
+
+#define cpu_to_be16(x) ((uint16_t) htobe16(x))
+#define cpu_to_be32(x) ((uint32_t) htobe32(x))
+#define cpu_to_be64(x) ((uint64_t) htobe64(x))
+
+#define le16_to_cpu(x) ((uint16_t) le16toh(x))
+#define le32_to_cpu(x) ((uint32_t) le32toh(x))
+#define le64_to_cpu(x) ((uint64_t) le64toh(x))
+
+#define be16_to_cpu(x) ((uint16_t) be16toh(x))
+#define be32_to_cpu(x) ((uint32_t) be32toh(x))
+#define be64_to_cpu(x) ((uint64_t) be64toh(x))
+
+/*
+ * Bit map related macros. Usually provided by libc.
+ */
+#ifndef NBBY
+# define NBBY            CHAR_BIT
+#endif
+
+#ifndef setbit
+# define setbit(a,i)	((a)[(i)/NBBY] |= 1<<((i)%NBBY))
+# define clrbit(a,i)	((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
+# define isset(a,i)	((a)[(i)/NBBY] & (1<<((i)%NBBY)))
+# define isclr(a,i)	(((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)
+#endif
+
+#endif /* BITOPS_H */
+
diff --git a/libblkid/include/blkdev.h b/libblkid/include/blkdev.h
new file mode 100644
index 0000000..c994795
--- /dev/null
+++ b/libblkid/include/blkdev.h
@@ -0,0 +1,146 @@
+/*
+ * No copyright is claimed.  This code is in the public domain; do with
+ * it what you wish.
+ *
+ * Written by Karel Zak <kzak@redhat.com>
+ */
+#ifndef BLKDEV_H
+#define BLKDEV_H
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_IOCCOM_H
+# include <sys/ioccom.h> /* for _IO macro on e.g. Solaris */
+#endif
+#include <fcntl.h>
+#include <unistd.h>
+
+#ifdef HAVE_SYS_MKDEV_H
+# include <sys/mkdev.h>		/* major and minor on Solaris */
+#endif
+
+#define DEFAULT_SECTOR_SIZE       512
+
+#ifdef __linux__
+/* very basic ioctls, should be available everywhere */
+# ifndef BLKROSET
+#  define BLKROSET   _IO(0x12,93)	/* set device read-only (0 = read-write) */
+#  define BLKROGET   _IO(0x12,94)	/* get read-only status (0 = read_write) */
+#  define BLKRRPART  _IO(0x12,95)	/* re-read partition table */
+#  define BLKGETSIZE _IO(0x12,96)	/* return device size /512 (long *arg) */
+#  define BLKFLSBUF  _IO(0x12,97)	/* flush buffer cache */
+#  define BLKRASET   _IO(0x12,98)	/* set read ahead for block device */
+#  define BLKRAGET   _IO(0x12,99)	/* get current read ahead setting */
+#  define BLKFRASET  _IO(0x12,100)	/* set filesystem (mm/filemap.c) read-ahead */
+#  define BLKFRAGET  _IO(0x12,101)	/* get filesystem (mm/filemap.c) read-ahead */
+#  define BLKSECTSET _IO(0x12,102)	/* set max sectors per request (ll_rw_blk.c) */
+#  define BLKSECTGET _IO(0x12,103)	/* get max sectors per request (ll_rw_blk.c) */
+#  define BLKSSZGET  _IO(0x12,104)	/* get block device sector size */
+
+/* ioctls introduced in 2.2.16, removed in 2.5.58 */
+#  define BLKELVGET  _IOR(0x12,106,size_t) /* elevator get */
+#  define BLKELVSET  _IOW(0x12,107,size_t) /* elevator set */
+
+#  define BLKBSZGET  _IOR(0x12,112,size_t)
+#  define BLKBSZSET  _IOW(0x12,113,size_t)
+# endif /* !BLKROSET */
+
+# ifndef BLKGETSIZE64
+#  define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (u64 *arg) */
+# endif
+
+/* block device topology ioctls, introduced in 2.6.32 (commit ac481c20) */
+# ifndef BLKIOMIN
+#  define BLKIOMIN   _IO(0x12,120)
+#  define BLKIOOPT   _IO(0x12,121)
+#  define BLKALIGNOFF _IO(0x12,122)
+#  define BLKPBSZGET _IO(0x12,123)
+# endif
+
+/* discard zeroes support, introduced in 2.6.33 (commit 98262f27) */
+# ifndef BLKDISCARDZEROES
+#  define BLKDISCARDZEROES _IO(0x12,124)
+# endif
+
+/* filesystem freeze, introduced in 2.6.29 (commit fcccf502) */
+# ifndef FIFREEZE
+#  define FIFREEZE   _IOWR('X', 119, int)    /* Freeze */
+#  define FITHAW     _IOWR('X', 120, int)    /* Thaw */
+# endif
+
+/* uniform CD-ROM information */
+# ifndef CDROM_GET_CAPABILITY
+#  define CDROM_GET_CAPABILITY 0x5331
+# endif
+
+#endif /* __linux */
+
+
+#ifdef APPLE_DARWIN
+# define BLKGETSIZE DKIOCGETBLOCKCOUNT32
+#endif
+
+#ifndef HDIO_GETGEO
+# ifdef __linux__
+#  define HDIO_GETGEO 0x0301
+# endif
+
+struct hd_geometry {
+	unsigned char heads;
+	unsigned char sectors;
+	unsigned short cylinders;	/* truncated */
+	unsigned long start;
+};
+#endif /* HDIO_GETGEO */
+
+
+/* are we working with block device? */
+int is_blkdev(int fd);
+
+/* Determine size in bytes */
+off_t blkdev_find_size (int fd);
+
+/* get size in bytes */
+int blkdev_get_size(int fd, unsigned long long *bytes);
+
+/* get 512-byte sector count */
+int blkdev_get_sectors(int fd, unsigned long long *sectors);
+
+/* get hardware sector size */
+int blkdev_get_sector_size(int fd, int *sector_size);
+
+/* specifies whether or not the device is misaligned */
+int blkdev_is_misaligned(int fd);
+
+/* get physical block device size */
+int blkdev_get_physector_size(int fd, int *sector_size);
+
+/* is the device cdrom capable? */
+int blkdev_is_cdrom(int fd);
+
+/* get device's geometry - legacy */
+int blkdev_get_geometry(int fd, unsigned int *h, unsigned int *s);
+
+/* SCSI device types.  Copied almost as-is from kernel header.
+ * http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/scsi/scsi.h */
+#define SCSI_TYPE_DISK			0x00
+#define SCSI_TYPE_TAPE			0x01
+#define SCSI_TYPE_PRINTER		0x02
+#define SCSI_TYPE_PROCESSOR		0x03	/* HP scanners use this */
+#define SCSI_TYPE_WORM			0x04	/* Treated as ROM by our system */
+#define SCSI_TYPE_ROM			0x05
+#define SCSI_TYPE_SCANNER		0x06
+#define SCSI_TYPE_MOD			0x07	/* Magneto-optical disk - treated as SCSI_TYPE_DISK */
+#define SCSI_TYPE_MEDIUM_CHANGER	0x08
+#define SCSI_TYPE_COMM			0x09	/* Communications device */
+#define SCSI_TYPE_RAID			0x0c
+#define SCSI_TYPE_ENCLOSURE		0x0d	/* Enclosure Services Device */
+#define SCSI_TYPE_RBC			0x0e
+#define SCSI_TYPE_OSD			0x11
+#define SCSI_TYPE_NO_LUN		0x7f
+
+/* convert scsi type code to name */
+const char *blkdev_scsi_type_to_name(int type);
+
+
+#endif /* BLKDEV_H */
diff --git a/libblkid/blkid.h b/libblkid/include/blkid.h
similarity index 78%
rename from libblkid/blkid.h
rename to libblkid/include/blkid.h
index b283009..4d43130 100644
--- a/libblkid/blkid.h
+++ b/libblkid/include/blkid.h
@@ -26,13 +26,12 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#define _SC_HOST_NAME_MAX 255
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-#define BLKID_VERSION   "2.22.0"
-#define BLKID_DATE      "04-Sep-2012"
+#define LIBBLKID_VERSION   "2.25.0"
+#define LIBBLKID_DATE      "22-Jul-2014"
 
 /**
  * blkid_dev:
@@ -139,6 +138,7 @@
 #endif
 
 /* cache.c */
+extern void blkid_init_debug(int mask);
 extern void blkid_put_cache(blkid_cache cache);
 extern int blkid_get_cache(blkid_cache *cache, const char *filename);
 extern void blkid_gc_cache(blkid_cache cache);
@@ -147,8 +147,7 @@
 extern const char *blkid_dev_devname(blkid_dev dev)
 			__ul_attribute__((warn_unused_result));
 
-extern blkid_dev_iterate blkid_dev_iterate_begin(blkid_cache cache)
-			__ul_attribute__((nonnull));
+extern blkid_dev_iterate blkid_dev_iterate_begin(blkid_cache cache);
 extern int blkid_dev_set_search(blkid_dev_iterate iter,
 				char *search_type, char *search_value);
 extern int blkid_dev_next(blkid_dev_iterate iterate, blkid_dev *dev);
@@ -169,8 +168,7 @@
 extern blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags);
 
 /* getsize.c */
-extern blkid_loff_t blkid_get_dev_size(int fd)
-			__ul_attribute__((warn_unused_result));
+extern blkid_loff_t blkid_get_dev_size(int fd);
 
 /* verify.c */
 extern blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev);
@@ -186,25 +184,21 @@
 			__ul_attribute__((warn_unused_result));
 
 /* tag.c */
-extern blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev)
-			__ul_attribute__((warn_unused_result));
+extern blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev);
 extern int blkid_tag_next(blkid_tag_iterate iterate,
 			      const char **type, const char **value);
 extern void blkid_tag_iterate_end(blkid_tag_iterate iterate);
-extern int blkid_dev_has_tag(blkid_dev dev, const char *type, const char *value)
-			__ul_attribute__((nonnull(1,2)));
+extern int blkid_dev_has_tag(blkid_dev dev, const char *type, const char *value);
 
 extern blkid_dev blkid_find_dev_with_tag(blkid_cache cache,
 					 const char *type,
-					 const char *value)
-			__ul_attribute__((warn_unused_result));
+					 const char *value);
 
 extern int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val);
 
 /* version.c */
 extern int blkid_parse_version_string(const char *ver_string)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 extern int blkid_get_library_version(const char **ver_string,
 				     const char **date_string);
 
@@ -233,34 +227,25 @@
 	                blkid_loff_t off, blkid_loff_t size);
 
 extern dev_t blkid_probe_get_devno(blkid_probe pr)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 
 extern dev_t blkid_probe_get_wholedisk_devno(blkid_probe pr)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 
 extern int blkid_probe_is_wholedisk(blkid_probe pr)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 
-extern blkid_loff_t blkid_probe_get_size(blkid_probe pr)
-			__ul_attribute__((warn_unused_result));
-extern blkid_loff_t blkid_probe_get_offset(blkid_probe pr)
-			__ul_attribute__((warn_unused_result));
-extern unsigned int blkid_probe_get_sectorsize(blkid_probe pr)
-			__ul_attribute__((warn_unused_result));
-extern blkid_loff_t blkid_probe_get_sectors(blkid_probe pr)
-			__ul_attribute__((warn_unused_result));
+extern blkid_loff_t blkid_probe_get_size(blkid_probe pr);
+extern blkid_loff_t blkid_probe_get_offset(blkid_probe pr);
+extern unsigned int blkid_probe_get_sectorsize(blkid_probe pr);
+extern blkid_loff_t blkid_probe_get_sectors(blkid_probe pr);
 
-extern int blkid_probe_get_fd(blkid_probe pr)
-			__ul_attribute__((warn_unused_result));
+extern int blkid_probe_get_fd(blkid_probe pr);
 
 /*
  * superblocks probing
  */
-extern int blkid_known_fstype(const char *fstype)
-			__ul_attribute__((warn_unused_result));
+extern int blkid_known_fstype(const char *fstype);
 
 extern int blkid_superblocks_get_name(size_t idx, const char **name, int *usage);
 
@@ -275,6 +260,7 @@
 #define BLKID_SUBLKS_USAGE	(1 << 7) /* define USAGE result value */
 #define BLKID_SUBLKS_VERSION	(1 << 8) /* read FS type from superblock */
 #define BLKID_SUBLKS_MAGIC	(1 << 9) /* define SBMAGIC and SBMAGIC_OFFSET */
+#define BLKID_SUBLKS_BADCSUM	(1 << 10) /* allow a bad checksum */
 
 #define BLKID_SUBLKS_DEFAULT	(BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID | \
 				 BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE)
@@ -305,30 +291,23 @@
 extern int blkid_probe_enable_topology(blkid_probe pr, int enable);
 
 /* binary interface */
-extern blkid_topology blkid_probe_get_topology(blkid_probe pr)
-			__ul_attribute__((warn_unused_result));
+extern blkid_topology blkid_probe_get_topology(blkid_probe pr);
 
 extern unsigned long blkid_topology_get_alignment_offset(blkid_topology tp)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 extern unsigned long blkid_topology_get_minimum_io_size(blkid_topology tp)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 extern unsigned long blkid_topology_get_optimal_io_size(blkid_topology tp)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 extern unsigned long blkid_topology_get_logical_sector_size(blkid_topology tp)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 extern unsigned long blkid_topology_get_physical_sector_size(blkid_topology tp)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 
 /*
  * partitions probing
  */
-extern int blkid_known_pttype(const char *pttype)
-			__ul_attribute__((warn_unused_result));
+extern int blkid_known_pttype(const char *pttype);
 
 extern int blkid_probe_enable_partitions(blkid_probe pr, int enable);
 
@@ -343,62 +322,41 @@
 extern int blkid_probe_set_partitions_flags(blkid_probe pr, int flags);
 
 /* binary interface */
-extern blkid_partlist blkid_probe_get_partitions(blkid_probe pr)
-			__ul_attribute__((warn_unused_result));
+extern blkid_partlist blkid_probe_get_partitions(blkid_probe pr);
 
-extern int blkid_partlist_numof_partitions(blkid_partlist ls)
-			__ul_attribute__((warn_unused_result));
-extern blkid_parttable blkid_partlist_get_table(blkid_partlist ls)
-			__ul_attribute__((warn_unused_result));
-extern blkid_partition blkid_partlist_get_partition(blkid_partlist ls, int n)
-			__ul_attribute__((warn_unused_result));
-extern blkid_partition blkid_partlist_devno_to_partition(blkid_partlist ls, dev_t devno)
-			__ul_attribute__((warn_unused_result));
-extern blkid_parttable blkid_partition_get_table(blkid_partition par)
-			__ul_attribute__((warn_unused_result));
+extern int blkid_partlist_numof_partitions(blkid_partlist ls);
+extern blkid_parttable blkid_partlist_get_table(blkid_partlist ls);
+extern blkid_partition blkid_partlist_get_partition(blkid_partlist ls, int n);
+extern blkid_partition blkid_partlist_get_partition_by_partno(blkid_partlist ls, int n);
+extern blkid_partition blkid_partlist_devno_to_partition(blkid_partlist ls, dev_t devno);
+extern blkid_parttable blkid_partition_get_table(blkid_partition par);
 
-extern const char *blkid_partition_get_name(blkid_partition par)
-			__ul_attribute__((warn_unused_result));
-extern const char *blkid_partition_get_uuid(blkid_partition par)
-			__ul_attribute__((warn_unused_result));
-extern int blkid_partition_get_partno(blkid_partition par)
-			__ul_attribute__((warn_unused_result));
-extern blkid_loff_t blkid_partition_get_start(blkid_partition par)
-			__ul_attribute__((warn_unused_result));
-extern blkid_loff_t blkid_partition_get_size(blkid_partition par)
-			__ul_attribute__((warn_unused_result));
+extern const char *blkid_partition_get_name(blkid_partition par);
+extern const char *blkid_partition_get_uuid(blkid_partition par);
+extern int blkid_partition_get_partno(blkid_partition par);
+extern blkid_loff_t blkid_partition_get_start(blkid_partition par);
+extern blkid_loff_t blkid_partition_get_size(blkid_partition par);
 
 extern int blkid_partition_get_type(blkid_partition par)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 
-extern const char *blkid_partition_get_type_string(blkid_partition par)
-			__ul_attribute__((warn_unused_result));
+extern const char *blkid_partition_get_type_string(blkid_partition par);
 
 extern unsigned long long blkid_partition_get_flags(blkid_partition par)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 
 extern int blkid_partition_is_logical(blkid_partition par)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 extern int blkid_partition_is_extended(blkid_partition par)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 extern int blkid_partition_is_primary(blkid_partition par)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 
-extern const char *blkid_parttable_get_type(blkid_parttable tab)
-			__ul_attribute__((warn_unused_result));
+extern const char *blkid_parttable_get_type(blkid_parttable tab);
+extern const char *blkid_parttable_get_id(blkid_parttable tab);
 
-extern const char *blkid_parttable_get_id(blkid_parttable tab)
-			__ul_attribute__((warn_unused_result));
-
-extern blkid_loff_t blkid_parttable_get_offset(blkid_parttable tab)
-			__ul_attribute__((warn_unused_result));
-extern blkid_partition blkid_parttable_get_parent(blkid_parttable tab)
-			__ul_attribute__((warn_unused_result));
+extern blkid_loff_t blkid_parttable_get_offset(blkid_parttable tab);
+extern blkid_partition blkid_parttable_get_parent(blkid_parttable tab);
 
 /*
  * NAME=value low-level interface
@@ -407,15 +365,13 @@
 extern int blkid_do_safeprobe(blkid_probe pr);
 extern int blkid_do_fullprobe(blkid_probe pr);
 
-extern int blkid_probe_numof_values(blkid_probe pr)
-			__ul_attribute__((warn_unused_result));
+extern int blkid_probe_numof_values(blkid_probe pr);
 extern int blkid_probe_get_value(blkid_probe pr, int num, const char **name,
                         const char **data, size_t *len);
 extern int blkid_probe_lookup_value(blkid_probe pr, const char *name,
                         const char **data, size_t *len);
 extern int blkid_probe_has_value(blkid_probe pr, const char *name)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 
 extern int blkid_do_wipe(blkid_probe pr, int dryrun);
 extern int blkid_probe_step_back(blkid_probe pr);
diff --git a/libblkid/canonicalize.h b/libblkid/include/canonicalize.h
similarity index 100%
copy from libblkid/canonicalize.h
copy to libblkid/include/canonicalize.h
diff --git a/libblkid/include/carefulputc.h b/libblkid/include/carefulputc.h
new file mode 100644
index 0000000..3a0ec5b
--- /dev/null
+++ b/libblkid/include/carefulputc.h
@@ -0,0 +1,67 @@
+#ifndef UTIL_LINUX_CAREFUULPUTC_H
+#define UTIL_LINUX_CAREFUULPUTC_H
+
+/*
+ * A putc() for use in write and wall (that sometimes are sgid tty).
+ * It avoids control characters in our locale, and also ASCII control
+ * characters.   Note that the locale of the recipient is unknown.
+*/
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+static inline int fputc_careful(int c, FILE *fp, const char fail)
+{
+	int ret;
+
+	if (isprint(c) || c == '\a' || c == '\t' || c == '\r' || c == '\n')
+		ret = putc(c, fp);
+	else if (!isascii(c))
+		ret = fprintf(fp, "\\%3o", (unsigned char)c);
+	else {
+		ret = putc(fail, fp);
+		if (ret != EOF)
+			ret = putc(c ^ 0x40, fp);
+	}
+	return (ret < 0) ? EOF : 0;
+}
+
+static inline void fputs_quoted(const char *data, FILE *out)
+{
+	const char *p;
+
+	fputc('"', out);
+	for (p = data; p && *p; p++) {
+		if ((unsigned char) *p == 0x22 ||		/* " */
+		    (unsigned char) *p == 0x5c ||		/* \ */
+		    (unsigned char) *p == 0x60 ||		/* ` */
+		    (unsigned char) *p == 0x24 ||		/* $ */
+		    !isprint((unsigned char) *p) ||
+		    iscntrl((unsigned char) *p)) {
+
+			fprintf(out, "\\x%02x", (unsigned char) *p);
+		} else
+			fputc(*p, out);
+	}
+	fputc('"', out);
+}
+
+static inline void fputs_nonblank(const char *data, FILE *out)
+{
+	const char *p;
+
+	for (p = data; p && *p; p++) {
+		if (isblank((unsigned char) *p) ||
+		    (unsigned char) *p == 0x5c ||		/* \ */
+		    !isprint((unsigned char) *p) ||
+		    iscntrl((unsigned char) *p)) {
+
+			fprintf(out, "\\x%02x", (unsigned char) *p);
+
+		} else
+			fputc(*p, out);
+	}
+}
+
+
+#endif  /*  _CAREFUULPUTC_H  */
diff --git a/libblkid/closestream.h b/libblkid/include/closestream.h
similarity index 74%
rename from libblkid/closestream.h
rename to libblkid/include/closestream.h
index d61b83b..7842456 100644
--- a/libblkid/closestream.h
+++ b/libblkid/include/closestream.h
@@ -24,8 +24,9 @@
 	const int some_pending = (__fpending(stream) != 0);
 	const int prev_fail = (ferror(stream) != 0);
 	const int fclose_fail = (fclose(stream) != 0);
+
 	if (prev_fail || (fclose_fail && (some_pending || errno != EBADF))) {
-		if (!fclose_fail)
+		if (!fclose_fail && !(errno == EPIPE))
 			errno = 0;
 		return EOF;
 	}
@@ -48,4 +49,23 @@
 		_exit(EXIT_FAILURE);
 }
 
+#ifndef HAVE_FSYNC
+static inline int
+fsync(int fd __attribute__((__unused__)))
+{
+	return 0;
+}
+#endif
+
+static inline int
+close_fd(int fd)
+{
+	const int fsync_fail = (fsync(fd) != 0);
+	const int close_fail = (close(fd) != 0);
+
+	if (fsync_fail || close_fail)
+		return EOF;
+	return 0;
+}
+
 #endif /* UTIL_LINUX_CLOSESTREAM_H */
diff --git a/libblkid/include/colors.h b/libblkid/include/colors.h
new file mode 100644
index 0000000..97efc48
--- /dev/null
+++ b/libblkid/include/colors.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2012 Ondrej Oprala <ooprala@redhat.com>
+ * Copyright (C) 2012-2014 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be distributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#ifndef UTIL_LINUX_COLORS_H
+#define UTIL_LINUX_COLORS_H
+
+#include <stdio.h>
+#include <unistd.h>
+
+#define UL_COLOR_RESET		"\033[0m"
+#define UL_COLOR_BOLD		"\033[1m"
+#define UL_COLOR_HALFBRIGHT	"\033[2m"
+#define UL_COLOR_UNDERSCORE	"\033[4m"
+#define UL_COLOR_BLINK		"\033[5m"
+#define UL_COLOR_REVERSE	"\033[7m"
+
+/* Standard colors */
+#define UL_COLOR_BLACK		"\033[30m"
+#define UL_COLOR_RED		"\033[31m"
+#define UL_COLOR_GREEN		"\033[32m"
+#define UL_COLOR_BROWN		"\033[33m"	/* well, brown */
+#define UL_COLOR_BLUE		"\033[34m"
+#define UL_COLOR_MAGENTA	"\033[35m"
+#define UL_COLOR_CYAN		"\033[36m"
+#define UL_COLOR_GRAY		"\033[37m"
+
+/* Bold variants */
+#define UL_COLOR_DARK_GRAY	"\033[1;30m"
+#define UL_COLOR_BOLD_RED	"\033[1;31m"
+#define UL_COLOR_BOLD_GREEN	"\033[1;32m"
+#define UL_COLOR_BOLD_YELLOW	"\033[1;33m"
+#define UL_COLOR_BOLD_BLUE	"\033[1;34m"
+#define UL_COLOR_BOLD_MAGENTA	"\033[1;35m"
+#define UL_COLOR_BOLD_CYAN	"\033[1;36m"
+
+#define UL_COLOR_WHITE		"\033[1;37m"
+
+/* --color[=WHEN] */
+enum colortmode {
+	UL_COLORMODE_AUTO = 0,
+	UL_COLORMODE_NEVER,
+	UL_COLORMODE_ALWAYS,
+	UL_COLORMODE_UNDEF,
+
+	__UL_NCOLORMODES	/* last */
+};
+
+extern int colormode_from_string(const char *str);
+extern int colormode_or_err(const char *str, const char *errmsg);
+
+/* Initialize the global variable UL_COLOR_TERM_OK */
+extern int colors_init(int mode, const char *util_name);
+
+/* Returns 1 or 0 */
+extern int colors_wanted(void);
+
+/* temporary enable/disable colors */
+extern void colors_off(void);
+extern void colors_on(void);
+
+
+/* Set the color */
+extern void color_fenable(const char *seq, FILE *f);
+
+extern void color_scheme_fenable(const char *name, const char *dflt, FILE *f);
+extern const char *color_scheme_get_sequence(const char *name, const char *dflt);
+
+static inline void color_enable(const char *seq)
+{
+	color_fenable(seq, stdout);
+}
+
+static inline void color_scheme_enable(const char *name, const char *dflt)
+{
+	color_scheme_fenable(name, dflt, stdout);
+}
+
+/* Reset colors to default */
+extern void color_fdisable(FILE *f);
+
+static inline void color_disable(void)
+{
+	color_fdisable(stdout);
+}
+
+/* converts "red" to UL_COLOR_RED, etc. */
+extern const char *color_sequence_from_colorname(const char *str);
+
+
+#endif /* UTIL_LINUX_COLORS_H */
diff --git a/libblkid/config.h b/libblkid/include/config.h
similarity index 85%
rename from libblkid/config.h
rename to libblkid/include/config.h
index 3b4b18b..0a71fcf 100644
--- a/libblkid/config.h
+++ b/libblkid/include/config.h
@@ -4,9 +4,15 @@
 /* Define if building universal (internal helper macro) */
 /* #undef AC_APPLE_UNIVERSAL_BUILD */
 
+/* Enable agetty --reload feature */
+#define AGETTY_RELOAD 1
+
 /* Should chfn and chsh require the user to enter the password? */
 #define CHFN_CHSH_PASSWORD 1
 
+/* Path to hwclock adjtime file */
+#define CONFIG_ADJTIME_PATH "/etc/adjtime"
+
 /* Define to 1 if translation of program messages to the user's native
    language is requested. */
 #define ENABLE_NLS 1
@@ -20,6 +26,17 @@
 /* Define to 1 if you have the <byteswap.h> header file. */
 #define HAVE_BYTESWAP_H 1
 
+/* Define to 1 if you have the Mac OS X function CFLocaleCopyCurrent in the
+   CoreFoundation framework. */
+/* #undef HAVE_CFLOCALECOPYCURRENT */
+
+/* Define to 1 if you have the Mac OS X function CFPreferencesCopyAppValue in
+   the CoreFoundation framework. */
+/* #undef HAVE_CFPREFERENCESCOPYAPPVALUE */
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#define HAVE_CLOCK_GETTIME 1
+
 /* Define to 1 if the system has the type `cpu_set_t'. */
 #define HAVE_CPU_SET_T 1
 
@@ -30,22 +47,6 @@
    */
 #define HAVE_DCGETTEXT 1
 
-/* Define to 1 if you have the declaration of `ADDR_COMPAT_LAYOUT', and to 0
-   if you don't. */
-#define HAVE_DECL_ADDR_COMPAT_LAYOUT 1
-
-/* Define to 1 if you have the declaration of `ADDR_LIMIT_32BIT', and to 0 if
-   you don't. */
-#define HAVE_DECL_ADDR_LIMIT_32BIT 1
-
-/* Define to 1 if you have the declaration of `ADDR_LIMIT_3GB', and to 0 if
-   you don't. */
-#define HAVE_DECL_ADDR_LIMIT_3GB 1
-
-/* Define to 1 if you have the declaration of `ADDR_NO_RANDOMIZE', and to 0 if
-   you don't. */
-#define HAVE_DECL_ADDR_NO_RANDOMIZE 1
-
 /* Define to 1 if you have the declaration of `CPU_ALLOC', and to 0 if you
    don't. */
 #define HAVE_DECL_CPU_ALLOC 1
@@ -54,30 +55,6 @@
    */
 /* #undef HAVE_DECL_DIRFD */
 
-/* Define to 1 if you have the declaration of `FDPIC_FUNCPTRS', and to 0 if
-   you don't. */
-#define HAVE_DECL_FDPIC_FUNCPTRS 1
-
-/* Define to 1 if you have the declaration of `MMAP_PAGE_ZERO', and to 0 if
-   you don't. */
-#define HAVE_DECL_MMAP_PAGE_ZERO 1
-
-/* Define to 1 if you have the declaration of `READ_IMPLIES_EXEC', and to 0 if
-   you don't. */
-#define HAVE_DECL_READ_IMPLIES_EXEC 1
-
-/* Define to 1 if you have the declaration of `STICKY_TIMEOUTS', and to 0 if
-   you don't. */
-#define HAVE_DECL_STICKY_TIMEOUTS 1
-
-/* Define to 1 if you have the declaration of `UNAME26', and to 0 if you
-   don't. */
-#define HAVE_DECL_UNAME26 1
-
-/* Define to 1 if you have the declaration of `WHOLE_SECONDS', and to 0 if you
-   don't. */
-#define HAVE_DECL_WHOLE_SECONDS 1
-
 /* Define to 1 if you have the declaration of `_NL_TIME_WEEK_1STDAY', and to 0
    if you don't. */
 #define HAVE_DECL__NL_TIME_WEEK_1STDAY 1
@@ -145,15 +122,21 @@
 /* Define to 1 if you have the `getrlimit' function. */
 #define HAVE_GETRLIMIT 1
 
+/* Define to 1 if you have the `getsgnam' function. */
+#define HAVE_GETSGNAM 1
+
 /* Define if the GNU gettext() function is already present or preinstalled. */
 #define HAVE_GETTEXT 1
 
-/* Define if you have the iconv() function. */
+/* Define if you have the iconv() function and it works. */
 /* #undef HAVE_ICONV */
 
 /* Define to 1 if you have the `inotify_init' function. */
 #define HAVE_INOTIFY_INIT 1
 
+/* Define to 1 if you have the `inotify_init1' function. */
+#define HAVE_INOTIFY_INIT1 1
+
 /* Define to 1 if you have the <inttypes.h> header file. */
 #define HAVE_INTTYPES_H 1
 
@@ -193,13 +176,16 @@
 /* Define if SELinux is available */
 /* #undef HAVE_LIBSELINUX */
 
+/* Define if libsystemd is available */
+/* #undef HAVE_LIBSYSTEMD */
+
 /* Define to 1 if you have the `termcap' library (-ltermcap). */
 #define HAVE_LIBTERMCAP 1
 
 /* Define to 1 if you have the `udev' library (-ludev). */
 /* #undef HAVE_LIBUDEV */
 
-/* Define to 1 if you have the `user' library (-luser). */
+/* Define if libuser is available */
 /* #undef HAVE_LIBUSER */
 
 /* Define to 1 if you have the `utempter' library (-lutempter). */
@@ -226,12 +212,18 @@
 /* Define to 1 if you have the <linux/fd.h> header file. */
 #define HAVE_LINUX_FD_H 1
 
+/* Define to 1 if you have the <linux/gsmmux.h> header file. */
+/* #undef HAVE_LINUX_GSMMUX_H */
+
 /* Define to 1 if you have the <linux/major.h> header file. */
 #define HAVE_LINUX_MAJOR_H 1
 
 /* Define to 1 if you have the <linux/raw.h> header file. */
 #define HAVE_LINUX_RAW_H 1
 
+/* Define to 1 if you have the <linux/securebits.h> header file. */
+#define HAVE_LINUX_SECUREBITS_H 1
+
 /* Define to 1 if you have the <linux/tiocl.h> header file. */
 #define HAVE_LINUX_TIOCL_H 1
 
@@ -263,7 +255,7 @@
 #define HAVE_MEMORY_H 1
 
 /* Define to 1 if you have the `mempcpy' function. */
-#define HAVE_MEMPCPY 0
+#define HAVE_MEMPCPY 1
 
 /* Define to 1 if you have the <mntent.h> header file. */
 #define HAVE_MNTENT_H 1
@@ -292,6 +284,9 @@
 /* Define to 1 if you have the `openat' function. */
 #define HAVE_OPENAT 1
 
+/* Define to 1 if you have the `open_memstream' function. */
+#define HAVE_OPEN_MEMSTREAM 1
+
 /* Define to 1 if you have the <paths.h> header file. */
 #define HAVE_PATHS_H 1
 
@@ -313,6 +308,12 @@
 /* Define to 1 if you have the <pty.h> header file. */
 #define HAVE_PTY_H 1
 
+/* Define to 1 if you have the `qsort_r' function. */
+#define HAVE_QSORT_R 1
+
+/* Define if curses library has the resizeterm(). */
+/* #undef HAVE_RESIZETERM */
+
 /* Define to 1 if you have the `rpmatch' function. */
 #define HAVE_RPMATCH 1
 
@@ -329,10 +330,19 @@
 #define HAVE_SCANF_MS_MODIFIER 1
 
 /* Define to 1 if you have the `secure_getenv' function. */
-/* #undef HAVE_SECURE_GETENV */
+#define HAVE_SECURE_GETENV 1
+
+/* Define to 1 if you have the `security_get_initial_context' function. */
+/* #undef HAVE_SECURITY_GET_INITIAL_CONTEXT */
+
+/* Define to 1 if you have the <security/openpam.h> header file. */
+/* #undef HAVE_SECURITY_OPENPAM_H */
+
+/* Define to 1 if you have the <security/pam_appl.h> header file. */
+/* #undef HAVE_SECURITY_PAM_APPL_H */
 
 /* Define to 1 if you have the <security/pam_misc.h> header file. */
-#define HAVE_SECURITY_PAM_MISC_H 1
+/* #undef HAVE_SECURITY_PAM_MISC_H */
 
 /* Define to 1 if you have the `setns' function. */
 #define HAVE_SETNS 1
@@ -343,6 +353,9 @@
 /* Define to 1 if you have the `setresuid' function. */
 #define HAVE_SETRESUID 1
 
+/* Define to 1 if the system has the type `sighandler_t'. */
+#define HAVE_SIGHANDLER_T 1
+
 /* Define to 1 if you have the `sigqueue' function. */
 #define HAVE_SIGQUEUE 1
 
@@ -358,6 +371,9 @@
 /* Define to 1 if you have the <slcurses.h> header file. */
 /* #undef HAVE_SLCURSES_H */
 
+/* Add SMACK support */
+/* #undef HAVE_SMACK */
+
 /* Define to 1 if you have the `srandom' function. */
 #define HAVE_SRANDOM 1
 
@@ -400,6 +416,9 @@
 /* Define to 1 if you have the `sysconf' function. */
 #define HAVE_SYSCONF 1
 
+/* Define to 1 if you have the `sysinfo' function. */
+#define HAVE_SYSINFO 1
+
 /* Define to 1 if you have the <sys/disklabel.h> header file. */
 /* #undef HAVE_SYS_DISKLABEL_H */
 
@@ -451,6 +470,9 @@
 /* Define to 1 if you have the <sys/time.h> header file. */
 #define HAVE_SYS_TIME_H 1
 
+/* Define to 1 if you have the <sys/ttydefaults.h> header file. */
+#define HAVE_SYS_TTYDEFAULTS_H 1
+
 /* Define to 1 if you have the <sys/types.h> header file. */
 #define HAVE_SYS_TYPES_H 1
 
@@ -478,9 +500,15 @@
 /* Define to 1 if you have the `updwtmp' function. */
 #define HAVE_UPDWTMP 1
 
+/* Define if curses library has the use_default_colors(). */
+/* #undef HAVE_USE_DEFAULT_COLORS */
+
 /* Define to 1 if you have the `usleep' function. */
 #define HAVE_USLEEP 1
 
+/* Define to 1 if you have the `utimensat' function. */
+#define HAVE_UTIMENSAT 1
+
 /* Define to 1 if you want to use uuid daemon. */
 #define HAVE_UUIDD 1
 
@@ -500,16 +528,22 @@
 #define HAVE___PROGNAME 1
 
 /* Define to 1 if you have the `__secure_getenv' function. */
-#define HAVE___SECURE_GETENV 1
+/* #undef HAVE___SECURE_GETENV */
 
 /* libblkid date string */
-#define LIBBLKID_DATE "04-Sep-2012"
+#define LIBBLKID_DATE "22-Jul-2014"
 
 /* libblkid version string */
-#define LIBBLKID_VERSION "2.22.0"
+#define LIBBLKID_VERSION "2.25.0"
+
+/* libfdisk version string */
+#define LIBFDISK_VERSION "2.25.0"
 
 /* libmount version string */
-#define LIBMOUNT_VERSION "2.22.0"
+#define LIBMOUNT_VERSION "2.25.0"
+
+/* libsmartcols version string */
+#define LIBSMARTCOLS_VERSION "2.25.0"
 
 /* Should login chown /dev/vcsN? */
 /* #undef LOGIN_CHOWN_VCS */
@@ -521,9 +555,6 @@
    */
 #define LT_OBJDIR ".libs/"
 
-/* Define to 1 if your C compiler doesn't accept -c and -o together. */
-/* #undef NO_MINUS_C_MINUS_O */
-
 /* Should chsh allow only shells in /etc/shells? */
 #define ONLY_LISTED_SHELLS 1
 
@@ -537,7 +568,7 @@
 #define PACKAGE_NAME "util-linux"
 
 /* Define to the full name and version of this package. */
-#define PACKAGE_STRING "util-linux 2.22.552-d48f6"
+#define PACKAGE_STRING "util-linux 2.25.590-bf6c"
 
 /* Define to the one symbol short name of this package. */
 #define PACKAGE_TARNAME "util-linux"
@@ -546,7 +577,7 @@
 #define PACKAGE_URL "http://www.kernel.org/pub/linux/utils/util-linux/"
 
 /* Define to the version of this package. */
-#define PACKAGE_VERSION "2.22.552-d48f6"
+#define PACKAGE_VERSION "2.25.590-bf6c"
 
 /* Should pg ring the bell on invalid keys? */
 #define PG_BELL 1
@@ -581,9 +612,6 @@
 /* Fallback syscall number for unshare */
 /* #undef SYS_unshare */
 
-/* Should uuidd support socket activation? */
-/* #undef USE_SOCKET_ACTIVATION */
-
 /* Should sulogin use a emergency mount of /dev and /proc? */
 /* #undef USE_SULOGIN_EMERGENCY_MOUNT */
 
@@ -613,7 +641,7 @@
 #define USE_TTY_GROUP 1
 
 /* Version number of package */
-#define VERSION "2.22.552-d48f6"
+#define VERSION "2.25.590-bf6c"
 
 /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
    significant byte first (like Motorola and SPARC, unlike Intel). */
@@ -627,6 +655,11 @@
 # endif
 #endif
 
+/* Enable large inode numbers on Mac OS X 10.5.  */
+#ifndef _DARWIN_USE_64_BIT_INODE
+# define _DARWIN_USE_64_BIT_INODE 1
+#endif
+
 /* Number of bits in a file offset, on hosts where this is settable. */
 /* #undef _FILE_OFFSET_BITS */
 
diff --git a/libblkid/cpuset.h b/libblkid/include/cpuset.h
similarity index 100%
rename from libblkid/cpuset.h
rename to libblkid/include/cpuset.h
diff --git a/libblkid/crc32.h b/libblkid/include/crc32.h
similarity index 86%
rename from libblkid/crc32.h
rename to libblkid/include/crc32.h
index b454be9..2616910 100644
--- a/libblkid/crc32.h
+++ b/libblkid/include/crc32.h
@@ -1,6 +1,7 @@
 #ifndef UL_NG_CRC32_H
 #define UL_NG_CRC32_H
 
+#include <sys/types.h>
 #include <stdint.h>
 
 extern uint32_t crc32(uint32_t seed, const unsigned char *buf, size_t len);
diff --git a/libblkid/include/crc64.h b/libblkid/include/crc64.h
new file mode 100644
index 0000000..40475d5
--- /dev/null
+++ b/libblkid/include/crc64.h
@@ -0,0 +1,9 @@
+#ifndef UTIL_LINUX_CRC64_H
+#define UTIL_LINUX_CRC64_H
+
+#include <sys/types.h>
+#include <stdint.h>
+
+extern uint64_t crc64(uint64_t seed, const unsigned char *data, size_t len);
+
+#endif
diff --git a/libblkid/include/debug.h b/libblkid/include/debug.h
new file mode 100644
index 0000000..0229ab3
--- /dev/null
+++ b/libblkid/include/debug.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
+ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be distributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#ifndef UTIL_LINUX_DEBUG_H
+#define UTIL_LINUX_DEBUG_H
+
+
+/*
+ * util-linux debug macros
+ *
+ * The debug stuff is based on <name>_debug_mask that controls what outputs is
+ * expected. The mask is usually initialized by <NAME>_DEBUG= env.variable
+ *
+ * After successful initialization the flag <PREFIX>_DEBUG_INIT is always set
+ * to the mask (this flag is required). The <PREFIX> is usually library API
+ * prefix (e.g. MNT_) or program name (e.g. CFDISK_)
+ *
+ * In the code is possible to use
+ *
+ *	DBG(FOO, ul_debug("this is output for foo"));
+ *
+ * where for the FOO has to be defined <PREFIX>_DEBUG_FOO.
+ *
+ * It's possible to initialize the mask by comma delimited strings with
+ * subsystem names (e.g. "LIBMOUNT_DEBUG=options,tab"). In this case is
+ * necessary to define mask names array. This functionality is optional.
+ *
+ * It's stringly recommended to use UL_* macros to define/declare/use
+ * the debug stuff.
+ *
+ * See disk-utils/cfdisk.c: cfdisk_init_debug()  for programs debug
+ *  or libmount/src/init.c: mnt_init_debug()     for library debug
+ *
+ */
+
+#include <stdarg.h>
+#include <string.h>
+
+struct ul_debug_maskname {
+	const char *name;
+	int mask;
+	const char *help;
+};
+#define UL_DEBUG_EMPTY_MASKNAMES {{ NULL, 0, NULL }}
+#define UL_DEBUG_DEFINE_MASKNAMES(m) static const struct ul_debug_maskname m ## _masknames[]
+#define UL_DEBUG_MASKNAMES(m)	m ## _masknames
+
+#define UL_DEBUG_DEFINE_MASK(m) int m ## _debug_mask
+#define UL_DEBUG_DECLARE_MASK(m) extern UL_DEBUG_DEFINE_MASK(m)
+
+/* p - flag prefix, m - flag postfix */
+#define UL_DEBUG_DEFINE_FLAG(p, m) p ## m
+
+/* l - library name, p - flag prefix, m - flag postfix, x - function */
+#define __UL_DBG(l, p, m, x) \
+	do { \
+		if ((p ## m) & l ## _debug_mask) { \
+			fprintf(stderr, "%d: %s: %8s: ", getpid(), # l, # m); \
+			x; \
+		} \
+	} while (0)
+
+#define __UL_DBG_CALL(l, p, m, x) \
+	do { \
+		if ((p ## m) & l ## _debug_mask) { \
+			x; \
+		} \
+	} while (0)
+
+#define __UL_DBG_FLUSH(l, p) \
+	do { \
+		if (l ## _debug_mask && \
+		    l ## _debug_mask != p ## INIT) { \
+			fflush(stderr); \
+		} \
+	} while (0)
+
+
+#define __UL_INIT_DEBUG(lib, pref, mask, env) \
+	do { \
+		if (lib ## _debug_mask & pref ## INIT) \
+		; \
+		else if (!mask) { \
+			char *str = getenv(# env); \
+			if (str) \
+				lib ## _debug_mask = ul_debug_parse_envmask(lib ## _masknames, str); \
+		} else \
+			lib ## _debug_mask = mask; \
+		lib ## _debug_mask |= pref ## INIT; \
+	} while (0)
+
+
+static inline void __attribute__ ((__format__ (__printf__, 1, 2)))
+ul_debug(const char *mesg, ...)
+{
+	va_list ap;
+	va_start(ap, mesg);
+	vfprintf(stderr, mesg, ap);
+	va_end(ap);
+	fputc('\n', stderr);
+}
+
+static inline void __attribute__ ((__format__ (__printf__, 2, 3)))
+ul_debugobj(void *handler, const char *mesg, ...)
+{
+	va_list ap;
+
+	if (handler)
+		fprintf(stderr, "[%p]: ", handler);
+	va_start(ap, mesg);
+	vfprintf(stderr, mesg, ap);
+	va_end(ap);
+	fputc('\n', stderr);
+}
+
+static inline int ul_debug_parse_envmask(
+			const struct ul_debug_maskname flagnames[],
+			const char *mask)
+{
+	int res;
+	char *ptr;
+
+	/* let's check for a numeric mask first */
+	res = strtoul(mask, &ptr, 0);
+
+	/* perhaps it's a comma-separated string? */
+	if (ptr && *ptr && flagnames && flagnames[0].name) {
+		char *msbuf, *ms, *name;
+		res = 0;
+
+		ms = msbuf = strdup(mask);
+		if (!ms)
+			return res;
+
+		while ((name = strtok_r(ms, ",", &ptr))) {
+			const struct ul_debug_maskname *d;
+			ms = ptr;
+
+			for (d = flagnames; d && d->name; d++) {
+				if (strcmp(name, d->name) == 0) {
+					res |= d->mask;
+					break;
+				}
+			}
+			/* nothing else we can do by OR-ing the mask */
+			if (res == 0xffff)
+				break;
+		}
+		free(msbuf);
+	} else if (ptr && strcmp(ptr, "all") == 0)
+		res = 0xffff;
+
+	return res;
+}
+
+static inline void ul_debug_print_masks(
+			const char *env,
+			const struct ul_debug_maskname flagnames[])
+{
+	const struct ul_debug_maskname *d;
+
+	if (!flagnames)
+		return;
+
+	fprintf(stderr, "Available \"%s=<name>[,...]|<mask>\" debug masks:\n",
+			env);
+	for (d = flagnames; d && d->name; d++) {
+		if (!d->help)
+			continue;
+		fprintf(stderr, "   %-8s [0x%04x] : %s\n",
+				d->name, d->mask, d->help);
+	}
+}
+
+#endif /* UTIL_LINUX_DEBUG_H */
diff --git a/libblkid/env.h b/libblkid/include/env.h
similarity index 100%
copy from libblkid/env.h
copy to libblkid/include/env.h
diff --git a/libblkid/exec_shell.h b/libblkid/include/exec_shell.h
similarity index 100%
copy from libblkid/exec_shell.h
copy to libblkid/include/exec_shell.h
diff --git a/libblkid/exitcodes.h b/libblkid/include/exitcodes.h
similarity index 100%
rename from libblkid/exitcodes.h
rename to libblkid/include/exitcodes.h
diff --git a/libblkid/fileutils.h b/libblkid/include/fileutils.h
similarity index 66%
rename from libblkid/fileutils.h
rename to libblkid/include/fileutils.h
index cf29e1b..b4e0a4a 100644
--- a/libblkid/fileutils.h
+++ b/libblkid/include/fileutils.h
@@ -1,16 +1,23 @@
 #ifndef UTIL_LINUX_FILEUTILS
 #define UTIL_LINUX_FILEUTILS
 
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "c.h"
+
 extern int xmkstemp(char **tmpname, char *dir);
 
 static inline FILE *xfmkstemp(char **tmpname, char *dir)
 {
 	int fd;
 	FILE *ret;
+
 	fd = xmkstemp(tmpname, dir);
-	if (fd == -1) {
+	if (fd == -1)
 		return NULL;
-	}
+
 	if (!(ret = fdopen(fd, "w+"))) {
 		close(fd);
 		return NULL;
@@ -20,4 +27,7 @@
 
 extern int get_fd_tabsize(void);
 
+extern int mkdir_p(const char *path, mode_t mode);
+extern char *stripoff_last_component(char *path);
+
 #endif /* UTIL_LINUX_FILEUTILS */
diff --git a/libblkid/ismounted.h b/libblkid/include/ismounted.h
similarity index 100%
copy from libblkid/ismounted.h
copy to libblkid/include/ismounted.h
diff --git a/libblkid/linux_reboot.h b/libblkid/include/linux_reboot.h
similarity index 100%
rename from libblkid/linux_reboot.h
rename to libblkid/include/linux_reboot.h
diff --git a/libblkid/linux_version.h b/libblkid/include/linux_version.h
similarity index 100%
copy from libblkid/linux_version.h
copy to libblkid/include/linux_version.h
diff --git a/libblkid/include/list.h b/libblkid/include/list.h
new file mode 100644
index 0000000..3c08aa5
--- /dev/null
+++ b/libblkid/include/list.h
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ * Copyright (C) 1999-2008 by Theodore Ts'o
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ * (based on list.h from e2fsprogs)
+ * Merge sort based on kernel's implementation.
+ */
+
+#ifndef UTIL_LINUX_LIST_H
+#define UTIL_LINUX_LIST_H
+
+/* TODO: use AC_C_INLINE */
+#ifdef __GNUC__
+#define _INLINE_ static __inline__
+#else                         /* For Watcom C */
+#define _INLINE_ static inline
+#endif
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+	struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+	(ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+_INLINE_ void __list_add(struct list_head * add,
+	struct list_head * prev,
+	struct list_head * next)
+{
+	next->prev = add;
+	add->next = next;
+	add->prev = prev;
+	prev->next = add;
+}
+
+/**
+ * list_add - add a new entry
+ * @add:	new entry to be added
+ * @head:	list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+_INLINE_ void list_add(struct list_head *add, struct list_head *head)
+{
+	__list_add(add, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @add:	new entry to be added
+ * @head:	list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+_INLINE_ void list_add_tail(struct list_head *add, struct list_head *head)
+{
+	__list_add(add, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+_INLINE_ void __list_del(struct list_head * prev,
+				  struct list_head * next)
+{
+	next->prev = prev;
+	prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry:	the element to delete from the list.
+ *
+ * list_empty() on @entry does not return true after this, @entry is
+ * in an undefined state.
+ */
+_INLINE_ void list_del(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry:	the element to delete from the list.
+ */
+_INLINE_ void list_del_init(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head:	the list to test.
+ */
+_INLINE_ int list_empty(struct list_head *head)
+{
+	return head->next == head;
+}
+
+/**
+ * list_entry_is_last - tests whether is entry last in the list
+ * @entry:	the entry to test.
+ * @head:	the list to test.
+ */
+_INLINE_ int list_entry_is_last(struct list_head *entry, struct list_head *head)
+{
+	return head->prev == entry;
+}
+
+/**
+ * list_splice - join two lists
+ * @list:	the new list to add.
+ * @head:	the place to add it in the first list.
+ */
+_INLINE_ void list_splice(struct list_head *list, struct list_head *head)
+{
+	struct list_head *first = list->next;
+
+	if (first != list) {
+		struct list_head *last = list->prev;
+		struct list_head *at = head->next;
+
+		first->prev = head;
+		head->next = first;
+
+		last->next = at;
+		at->prev = last;
+	}
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:	the &struct list_head pointer.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) __extension__ ({              \
+	const typeof( ((type *)0)->member ) *__mptr = (ptr);   \
+	(type *)( (char *)__mptr - offsetof(type,member) );})
+
+
+#define list_first_entry(head, type, member) \
+	((head) && (head)->next != (head) ? list_entry((head)->next, type, member) : NULL)
+
+#define list_last_entry(head, type, member) \
+	((head) && (head)->prev != (head) ? list_entry((head)->prev, type, member) : NULL)
+
+/**
+ * list_for_each - iterate over elements in a list
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @head:	the head for your list.
+ */
+#define list_for_each(pos, head) \
+	for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_backwardly - iterate over elements in a list in reverse
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @head:	the head for your list.
+ */
+#define list_for_each_backwardly(pos, head) \
+	for (pos = (head)->prev; pos != (head); pos = pos->prev)
+
+/**
+ * list_for_each_safe - iterate over elements in a list, but don't dereference
+ *                      pos after the body is done (in case it is freed)
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @pnext:	the &struct list_head to use as a pointer to the next item.
+ * @head:	the head for your list (not included in iteration).
+ */
+#define list_for_each_safe(pos, pnext, head) \
+	for (pos = (head)->next, pnext = pos->next; pos != (head); \
+	     pos = pnext, pnext = pos->next)
+
+#define MAX_LIST_LENGTH_BITS 20
+
+/*
+ * Returns a list organized in an intermediate format suited
+ * to chaining of merge() calls: null-terminated, no reserved or
+ * sentinel head node, "prev" links not maintained.
+ */
+_INLINE_ struct list_head *merge(int (*cmp)(struct list_head *a,
+					  struct list_head *b,
+					  void *data),
+			       void *data,
+			       struct list_head *a, struct list_head *b)
+{
+	struct list_head head, *tail = &head;
+
+	while (a && b) {
+		/* if equal, take 'a' -- important for sort stability */
+		if ((*cmp)(a, b, data) <= 0) {
+			tail->next = a;
+			a = a->next;
+		} else {
+			tail->next = b;
+			b = b->next;
+		}
+		tail = tail->next;
+	}
+	tail->next = a ? a : b;
+	return head.next;
+}
+
+/*
+ * Combine final list merge with restoration of standard doubly-linked
+ * list structure.  This approach duplicates code from merge(), but
+ * runs faster than the tidier alternatives of either a separate final
+ * prev-link restoration pass, or maintaining the prev links
+ * throughout.
+ */
+_INLINE_ void merge_and_restore_back_links(int (*cmp)(struct list_head *a,
+						    struct list_head *b,
+						    void *data),
+					 void *data,
+					 struct list_head *head,
+					 struct list_head *a, struct list_head *b)
+{
+	struct list_head *tail = head;
+
+	while (a && b) {
+		/* if equal, take 'a' -- important for sort stability */
+		if ((*cmp)(a, b, data) <= 0) {
+			tail->next = a;
+			a->prev = tail;
+			a = a->next;
+		} else {
+			tail->next = b;
+			b->prev = tail;
+			b = b->next;
+		}
+		tail = tail->next;
+	}
+	tail->next = a ? a : b;
+
+	do {
+		/*
+		 * In worst cases this loop may run many iterations.
+		 * Continue callbacks to the client even though no
+		 * element comparison is needed, so the client's cmp()
+		 * routine can invoke cond_resched() periodically.
+		 */
+		(*cmp)(tail->next, tail->next, data);
+
+		tail->next->prev = tail;
+		tail = tail->next;
+	} while (tail->next);
+
+	tail->next = head;
+	head->prev = tail;
+}
+
+
+/**
+ * list_sort - sort a list
+ * @head: the list to sort
+ * @cmp: the elements comparison function
+ *
+ * This function implements "merge sort", which has O(nlog(n))
+ * complexity.
+ *
+ * The comparison function @cmp must return a negative value if @a
+ * should sort before @b, and a positive value if @a should sort after
+ * @b. If @a and @b are equivalent, and their original relative
+ * ordering is to be preserved, @cmp must return 0.
+ */
+_INLINE_ void list_sort(struct list_head *head,
+			int (*cmp)(struct list_head *a,
+				   struct list_head *b,
+				   void *data),
+			void *data)
+{
+	struct list_head *part[MAX_LIST_LENGTH_BITS+1]; /* sorted partial lists
+							   -- last slot is a sentinel */
+	size_t lev;  /* index into part[] */
+	size_t max_lev = 0;
+	struct list_head *list;
+
+	if (list_empty(head))
+		return;
+
+	memset(part, 0, sizeof(part));
+
+	head->prev->next = NULL;
+	list = head->next;
+
+	while (list) {
+		struct list_head *cur = list;
+		list = list->next;
+		cur->next = NULL;
+
+		for (lev = 0; part[lev]; lev++) {
+			cur = merge(cmp, data, part[lev], cur);
+			part[lev] = NULL;
+		}
+		if (lev > max_lev) {
+			/* list passed to list_sort() too long for efficiency */
+			if (lev >= ARRAY_SIZE(part) - 1)
+				lev--;
+			max_lev = lev;
+		}
+		part[lev] = cur;
+	}
+
+	for (lev = 0; lev < max_lev; lev++)
+		if (part[lev])
+			list = merge(cmp, data, part[lev], list);
+
+	merge_and_restore_back_links(cmp, data, head, part[max_lev], list);
+}
+
+#undef _INLINE_
+
+#endif /* UTIL_LINUX_LIST_H */
diff --git a/libblkid/loopdev.h b/libblkid/include/loopdev.h
similarity index 96%
rename from libblkid/loopdev.h
rename to libblkid/include/loopdev.h
index 6efa0c7..573a569 100644
--- a/libblkid/loopdev.h
+++ b/libblkid/include/loopdev.h
@@ -45,7 +45,7 @@
 #define LO_KEY_SIZE	32
 
 /*
- * Linux LOOP_{SET,GET}_STATUS64 ioclt struct
+ * Linux LOOP_{SET,GET}_STATUS64 ioctl struct
  */
 struct loop_info64 {
 	uint64_t	lo_device;
@@ -97,8 +97,8 @@
 	int		flags;		/* LOOPDEV_FL_* flags */
 	unsigned int	has_info:1;	/* .info contains data */
 	unsigned int	extra_check:1;	/* unusual stuff for iterator */
-	unsigned int	debug:1;	/* debug mode ON/OFF */
 	unsigned int	info_failed:1;	/* LOOP_GET_STATUS ioctl failed */
+	unsigned int    control_ok:1;	/* /dev/loop-control success */
 
 	struct sysfs_cxt	sysfs;	/* pointer to /sys/dev/block/<maj:min>/ */
 	struct loop_info64	info;	/* for GET/SET ioctl */
@@ -144,11 +144,11 @@
 extern int loopcxt_init(struct loopdev_cxt *lc, int flags)
 				__attribute__ ((warn_unused_result));
 extern void loopcxt_deinit(struct loopdev_cxt *lc);
-extern void loopcxt_enable_debug(struct loopdev_cxt *lc, int enable);
 
 extern int loopcxt_set_device(struct loopdev_cxt *lc, const char *device)
 				__attribute__ ((warn_unused_result));
 extern int loopcxt_has_device(struct loopdev_cxt *lc);
+extern int loopcxt_add_device(struct loopdev_cxt *lc);
 extern char *loopcxt_strdup_device(struct loopdev_cxt *lc);
 extern const char *loopcxt_get_device(struct loopdev_cxt *lc);
 extern struct sysfs_cxt *loopcxt_get_sysfs(struct loopdev_cxt *lc);
@@ -163,6 +163,7 @@
 
 extern int loopcxt_setup_device(struct loopdev_cxt *lc);
 extern int loopcxt_delete_device(struct loopdev_cxt *lc);
+extern int loopcxt_set_capacity(struct loopdev_cxt *lc);
 
 int loopcxt_set_offset(struct loopdev_cxt *lc, uint64_t offset);
 int loopcxt_set_sizelimit(struct loopdev_cxt *lc, uint64_t sizelimit);
diff --git a/libblkid/mangle.h b/libblkid/include/mangle.h
similarity index 100%
copy from libblkid/mangle.h
copy to libblkid/include/mangle.h
diff --git a/libblkid/match.h b/libblkid/include/match.h
similarity index 100%
copy from libblkid/match.h
copy to libblkid/include/match.h
diff --git a/libblkid/mbsalign.h b/libblkid/include/mbsalign.h
similarity index 68%
rename from libblkid/mbsalign.h
rename to libblkid/include/mbsalign.h
index fd957b3..5eaf606 100644
--- a/libblkid/mbsalign.h
+++ b/libblkid/include/mbsalign.h
@@ -1,9 +1,10 @@
 /* Align/Truncate a string in a given screen width
    Copyright (C) 2009-2010 Free Software Foundation, Inc.
+   Copyright (C) 2010-2013 Karel Zak <kzak@redhat.com>
 
    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
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 2.1 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -13,8 +14,9 @@
 
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
-
-#include <stddef.h>
+#ifndef UTIL_LINUX_MBSALIGN_H
+# define UTIL_LINUX_MBSALIGN_H
+# include <stddef.h>
 
 typedef enum { MBS_ALIGN_LEFT, MBS_ALIGN_RIGHT, MBS_ALIGN_CENTER } mbs_align_t;
 
@@ -43,3 +45,12 @@
 extern size_t mbsalign (const char *src, char *dest,
 			size_t dest_size,  size_t *width,
 			mbs_align_t align, int flags);
+
+extern size_t mbs_safe_nwidth(const char *buf, size_t bufsz, size_t *sz);
+extern size_t mbs_safe_width(const char *s);
+
+extern char *mbs_safe_encode(const char *s, size_t *width);
+extern char *mbs_safe_encode_to_buffer(const char *s, size_t *width, char *buf);
+extern size_t mbs_safe_encode_size(size_t bytes);
+
+#endif /* UTIL_LINUX_MBSALIGN_H */
diff --git a/libblkid/md5.h b/libblkid/include/md5.h
similarity index 100%
copy from libblkid/md5.h
copy to libblkid/include/md5.h
diff --git a/libblkid/minix.h b/libblkid/include/minix.h
similarity index 88%
rename from libblkid/minix.h
rename to libblkid/include/minix.h
index 57be239..f28991c 100644
--- a/libblkid/minix.h
+++ b/libblkid/include/minix.h
@@ -73,10 +73,13 @@
 #define MINIX_VALID_FS       0x0001          /* Clean fs. */
 #define MINIX_ERROR_FS       0x0002          /* fs has errors. */
 
-#define MINIX_SUPER_MAGIC    0x137F          /* original minix fs */
-#define MINIX_SUPER_MAGIC2   0x138F          /* minix fs, 30 char names */
-#define MINIX2_SUPER_MAGIC   0x2468	     /* minix V2 fs */
+
+#define MINIX_SUPER_MAGIC    0x137F          /* minix V1 fs, 14 char names */
+#define MINIX_SUPER_MAGIC2   0x138F          /* minix V1 fs, 30 char names */
+
+#define MINIX2_SUPER_MAGIC   0x2468	     /* minix V2 fs, 14 char names */
 #define MINIX2_SUPER_MAGIC2  0x2478	     /* minix V2 fs, 30 char names */
+
 #define MINIX3_SUPER_MAGIC   0x4d5a          /* minix V3 fs (60 char names) */
 
 #endif /* UTIL_LINUX_MINIX_H */
diff --git a/libblkid/include/monotonic.h b/libblkid/include/monotonic.h
new file mode 100644
index 0000000..f3b03d3
--- /dev/null
+++ b/libblkid/include/monotonic.h
@@ -0,0 +1,11 @@
+#ifndef UTIL_LINUX_BOOTTIME_H
+#define UTIL_LINUX_BOOTTIME_H
+
+/*
+ * Uses clock_gettime() that requires $CLOCKGETTIME_LIBS
+ */
+extern int get_boot_time(struct timeval *boot_time);
+
+extern int gettime_monotonic(struct timeval *tv);
+
+#endif /* UTIL_LINUX_BOOTTIME_H */
diff --git a/libblkid/namespace.h b/libblkid/include/namespace.h
similarity index 80%
rename from libblkid/namespace.h
rename to libblkid/include/namespace.h
index 3a219ce..ea231ca 100644
--- a/libblkid/namespace.h
+++ b/libblkid/include/namespace.h
@@ -4,7 +4,7 @@
 
 # include <sched.h>
 
-# ifndef CLONE_NEWSNS
+# ifndef CLONE_NEWNS
 #  define CLONE_NEWNS 0x00020000
 # endif
 # ifndef CLONE_NEWUTS
@@ -23,16 +23,18 @@
 #  define CLONE_NEWPID 0x20000000
 # endif
 
-# ifndef HAVE_UNSHARE
+# if !defined(HAVE_UNSHARE) || !defined(HAVE_SETNS)
 #  include <sys/syscall.h>
+# endif
+
+# if !defined(HAVE_UNSHARE) && defined(SYS_unshare)
 static inline int unshare(int flags)
 {
 	return syscall(SYS_unshare, flags);
 }
 # endif
 
-# ifndef HAVE_SETNS
-#  include <sys/syscall.h>
+# if !defined(HAVE_SETNS) && defined(SYS_setns)
 static inline int setns(int fd, int nstype)
 {
 	return syscall(SYS_setns, fd, nstype);
diff --git a/libblkid/nls.h b/libblkid/include/nls.h
similarity index 100%
copy from libblkid/nls.h
copy to libblkid/include/nls.h
diff --git a/libblkid/optutils.h b/libblkid/include/optutils.h
similarity index 81%
rename from libblkid/optutils.h
rename to libblkid/include/optutils.h
index 28a54b2..99ad7e4 100644
--- a/libblkid/optutils.h
+++ b/libblkid/include/optutils.h
@@ -48,6 +48,9 @@
  * Note that the options in the group have to be in ASCII order (ABC..abc..) and
  * groups have to be also in ASCII order.
  *
+ * The maximal number of the options in the group is 15 (size of the array is
+ * 16, last is zero).
+ *
  * The current status of options is stored in excl_st array. The size of the array
  * must be the same as number of the groups in the ul_excl_t array.
  *
@@ -73,16 +76,21 @@
 			if (status[e] == 0)
 				status[e] = c;
 			else if (status[e] != c) {
-				fprintf(stderr, _("%s: options "),
+				size_t ct = 0;
+
+				fprintf(stderr, _("%s: these options are "
+						  "mutually exclusive:"),
 						program_invocation_short_name);
-				for (op = excl[e]; *op; op++) {
-					if (opts)
-						fprintf(stderr, "--%s ",
-							option_to_longopt(*op, opts));
+
+				for (op = excl[e];
+				     ct + 1 < ARRAY_SIZE(excl[0]) && *op;
+				     op++, ct++) {
+					const char *n = option_to_longopt(*op, opts);
+					if (n)
+						fprintf(stderr, " --%s", n);
 					else
-						fprintf(stderr, "-%c ", *op);
+						fprintf(stderr, " -%c", *op);
 				}
-				fprintf(stderr, _("are mutually exclusive."));
 				fputc('\n', stderr);
 				exit(OPTUTILS_EXIT_CODE);
 			}
diff --git a/libblkid/pager.h b/libblkid/include/pager.h
similarity index 100%
rename from libblkid/pager.h
rename to libblkid/include/pager.h
diff --git a/libblkid/pamfail.h b/libblkid/include/pamfail.h
similarity index 75%
rename from libblkid/pamfail.h
rename to libblkid/include/pamfail.h
index e102df2..bb83b94 100644
--- a/libblkid/pamfail.h
+++ b/libblkid/include/pamfail.h
@@ -6,7 +6,11 @@
  */
 #ifndef UTIL_LINUX_PAMFAIL_H
 #include <security/pam_appl.h>
-#include <security/pam_misc.h>
+#ifdef HAVE_SECURITY_PAM_MISC_H
+# include <security/pam_misc.h>
+#elif defined(HAVE_SECURITY_OPENPAM_H)
+# include <security/openpam.h>
+#endif
 #include "c.h"
 
 static inline int
diff --git a/libblkid/path.h b/libblkid/include/path.h
similarity index 91%
rename from libblkid/path.h
rename to libblkid/include/path.h
index 615d284..45da692 100644
--- a/libblkid/path.h
+++ b/libblkid/include/path.h
@@ -4,6 +4,8 @@
 #include <stdio.h>
 #include <stdint.h>
 
+extern char *path_strdup(const char *path, ...)
+			__attribute__ ((__format__ (__printf__, 1, 2)));
 extern FILE *path_fopen(const char *mode, int exit_on_err, const char *path, ...)
 			__attribute__ ((__format__ (__printf__, 3, 4)));
 extern void path_read_str(char *result, size_t len, const char *path, ...)
diff --git a/libblkid/pathnames.h b/libblkid/include/pathnames.h
similarity index 90%
rename from libblkid/pathnames.h
rename to libblkid/include/pathnames.h
index 6d300a9..0d21b98 100644
--- a/libblkid/pathnames.h
+++ b/libblkid/include/pathnames.h
@@ -31,11 +31,14 @@
 #define	_PATH_HUSHLOGIN		".hushlogin"
 #define	_PATH_HUSHLOGINS	"/etc/hushlogins"
 
+#define _PATH_NOLOGIN_TXT	"/etc/nologin.txt"
+
 #ifndef _PATH_MAILDIR
 #define	_PATH_MAILDIR		"/var/spool/mail"
 #endif
 #define	_PATH_MOTDFILE		"/etc/motd"
 #define	_PATH_NOLOGIN		"/etc/nologin"
+#define	_PATH_VAR_NOLOGIN	"/var/run/nologin"
 
 #define _PATH_LOGIN		"/bin/login"
 #define _PATH_INITTAB		"/etc/inittab"
@@ -48,6 +51,9 @@
 #define _PATH_SECURE		"/etc/securesingle"
 #define _PATH_USERTTY           "/etc/usertty"
 
+#define _PATH_TERMCOLORS_DIRNAME "terminal-colors.d"
+#define _PATH_TERMCOLORS_DIR	"/etc/" _PATH_TERMCOLORS_DIRNAME
+
 /* used in login-utils/shutdown.c */
 
 /* used in login-utils/setpwnam.h and login-utils/islocal.c */
@@ -63,6 +69,7 @@
 
 /* used in term-utils/agetty.c */
 #define _PATH_ISSUE		"/etc/issue"
+#define _PATH_OS_RELEASE	"/etc/os-release"
 #define _PATH_NUMLOCK_ON	_PATH_LOCALSTATEDIR "/numlock-on"
 
 #define _PATH_LOGINDEFS		"/etc/login.defs"
@@ -84,6 +91,9 @@
 #define _PATH_PROC_LOCKS        "/proc/locks"
 #define _PATH_PROC_CDROMINFO	"/proc/sys/dev/cdrom/info"
 
+#define _PATH_PROC_UIDMAP	"/proc/self/uid_map"
+#define _PATH_PROC_GIDMAP	"/proc/self/gid_map"
+
 #define _PATH_PROC_ATTR_CURRENT	"/proc/self/attr/current"
 #define _PATH_PROC_ATTR_EXEC	"/proc/self/attr/exec"
 #define _PATH_PROC_CAPLASTCAP	"/proc/sys/kernel/cap_last_cap"
@@ -125,6 +135,8 @@
 # define _PATH_DEV		"/dev/"
 #endif
 
+#define _PATH_DEV_MEM		"/dev/mem"
+
 #define _PATH_DEV_LOOP		"/dev/loop"
 #define _PATH_DEV_LOOPCTL	"/dev/loop-control"
 #define _PATH_DEV_TTY		"/dev/tty"
@@ -139,7 +151,12 @@
 #define _PATH_DEV_BYPARTUUID	"/dev/disk/by-partuuid"
 
 /* hwclock paths */
-#define _PATH_ADJPATH		"/etc/adjtime"
+#ifdef CONFIG_ADJTIME_PATH
+# define _PATH_ADJTIME		CONFIG_ADJTIME_PATH
+#else
+# define _PATH_ADJTIME		"/etc/adjtime"
+#endif
+
 #define _PATH_LASTDATE		"/var/lib/lastdate"
 #ifdef __ia64__
 # define _PATH_RTC_DEV		"/dev/efirtc"
diff --git a/libblkid/include/procutils.h b/libblkid/include/procutils.h
new file mode 100644
index 0000000..14b766c
--- /dev/null
+++ b/libblkid/include/procutils.h
@@ -0,0 +1,32 @@
+#ifndef UTIL_LINUX_PROCUTILS
+#define UTIL_LINUX_PROCUTILS
+
+#include <dirent.h>
+
+struct proc_tasks {
+	DIR *dir;
+};
+
+extern struct proc_tasks *proc_open_tasks(pid_t pid);
+extern void proc_close_tasks(struct proc_tasks *tasks);
+extern int proc_next_tid(struct proc_tasks *tasks, pid_t *tid);
+
+struct proc_processes {
+	DIR *dir;
+
+	const char *fltr_name;
+	uid_t fltr_uid;
+
+	unsigned int has_fltr_name : 1,
+		     has_fltr_uid : 1;
+};
+
+extern struct proc_processes *proc_open_processes(void);
+extern void proc_close_processes(struct proc_processes *ps);
+
+extern void proc_processes_filter_by_name(struct proc_processes *ps, const char *name);
+extern void proc_processes_filter_by_uid(struct proc_processes *ps, uid_t uid);
+extern int proc_next_pid(struct proc_processes *ps, pid_t *pid);
+
+
+#endif /* UTIL_LINUX_PROCUTILS */
diff --git a/libblkid/include/pt-bsd.h b/libblkid/include/pt-bsd.h
new file mode 100644
index 0000000..9bf47a5
--- /dev/null
+++ b/libblkid/include/pt-bsd.h
@@ -0,0 +1,156 @@
+#ifndef UTIL_LINUX_PT_BSD_H
+#define UTIL_LINUX_PT_BSD_H
+
+#define BSD_MAXPARTITIONS	16
+#define BSD_FS_UNUSED		0
+
+#ifndef BSD_DISKMAGIC
+# define BSD_DISKMAGIC     ((uint32_t) 0x82564557)
+#endif
+
+#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec"
+
+#if defined (__alpha__) || defined (__powerpc__) || \
+    defined (__ia64__) || defined (__hppa__)
+# define BSD_LABELSECTOR   0
+# define BSD_LABELOFFSET   64
+#else
+# define BSD_LABELSECTOR   1
+# define BSD_LABELOFFSET   0
+#endif
+
+#define	BSD_BBSIZE        8192		/* size of boot area, with label */
+#define	BSD_SBSIZE        8192		/* max size of fs superblock */
+
+struct bsd_disklabel {
+	uint32_t	d_magic;		/* the magic number */
+	int16_t		d_type;			/* drive type */
+	int16_t		d_subtype;		/* controller/d_type specific */
+	char		d_typename[16];		/* type name, e.g. "eagle" */
+	char		d_packname[16];		/* pack identifier */
+
+			/* disk geometry: */
+	uint32_t	d_secsize;		/* # of bytes per sector */
+	uint32_t	d_nsectors;		/* # of data sectors per track */
+	uint32_t	d_ntracks;		/* # of tracks per cylinder */
+	uint32_t	d_ncylinders;		/* # of data cylinders per unit */
+	uint32_t	d_secpercyl;		/* # of data sectors per cylinder */
+	uint32_t	d_secperunit;		/* # of data sectors per unit */
+
+	/*
+	 * Spares (bad sector replacements) below
+	 * are not counted in d_nsectors or d_secpercyl.
+	 * Spare sectors are assumed to be physical sectors
+	 * which occupy space at the end of each track and/or cylinder.
+	 */
+	uint16_t	d_sparespertrack;	/* # of spare sectors per track */
+	uint16_t	d_sparespercyl;		/* # of spare sectors per cylinder */
+
+	/*
+	 * Alternate cylinders include maintenance, replacement,
+	 * configuration description areas, etc.
+	 */
+	uint32_t	d_acylinders;		/* # of alt. cylinders per unit */
+
+			/* hardware characteristics: */
+	/*
+	 * d_interleave, d_trackskew and d_cylskew describe perturbations
+	 * in the media format used to compensate for a slow controller.
+	 * Interleave is physical sector interleave, set up by the formatter
+	 * or controller when formatting.  When interleaving is in use,
+	 * logically adjacent sectors are not physically contiguous,
+	 * but instead are separated by some number of sectors.
+	 * It is specified as the ratio of physical sectors traversed
+	 * per logical sector.  Thus an interleave of 1:1 implies contiguous
+	 * layout, while 2:1 implies that logical sector 0 is separated
+	 * by one sector from logical sector 1.
+	 * d_trackskew is the offset of sector 0 on track N
+	 * relative to sector 0 on track N-1 on the same cylinder.
+	 * Finally, d_cylskew is the offset of sector 0 on cylinder N
+	 * relative to sector 0 on cylinder N-1.
+	 */
+	uint16_t	d_rpm;			/* rotational speed */
+	uint16_t	d_interleave;		/* hardware sector interleave */
+	uint16_t	d_trackskew;		/* sector 0 skew, per track */
+	uint16_t	d_cylskew;		/* sector 0 skew, per cylinder */
+	uint32_t	d_headswitch;		/* head switch time, usec */
+	uint32_t	d_trkseek;		/* track-to-track seek, usec */
+	uint32_t	d_flags;		/* generic flags */
+	uint32_t	d_drivedata[5];		/* drive-type specific information */
+	uint32_t	d_spare[5];		/* reserved for future use */
+	uint32_t	d_magic2;		/* the magic number (again) */
+	uint16_t	d_checksum;		/* xor of data incl. partitions */
+
+			/* filesystem and partition information: */
+	uint16_t	d_npartitions;	        /* number of partitions in following */
+	uint32_t	d_bbsize;	        /* size of boot area at sn0, bytes */
+	uint32_t	d_sbsize;	        /* max size of fs superblock, bytes */
+
+	struct bsd_partition	 {		/* the partition table */
+		uint32_t	p_size;	        /* number of sectors in partition */
+		uint32_t	p_offset;       /* starting sector */
+		uint32_t	p_fsize;        /* filesystem basic fragment size */
+		uint8_t		p_fstype;	/* filesystem type, see below */
+		uint8_t		p_frag;		/* filesystem fragments per block */
+		uint16_t	p_cpg;	        /* filesystem cylinders per group */
+	} __attribute__((packed)) d_partitions[BSD_MAXPARTITIONS];	/* actually may be more */
+} __attribute__((packed));
+
+
+/* d_type values: */
+#define	BSD_DTYPE_SMD		1		/* SMD, XSMD; VAX hp/up */
+#define	BSD_DTYPE_MSCP		2		/* MSCP */
+#define	BSD_DTYPE_DEC		3		/* other DEC (rk, rl) */
+#define	BSD_DTYPE_SCSI		4		/* SCSI */
+#define	BSD_DTYPE_ESDI		5		/* ESDI interface */
+#define	BSD_DTYPE_ST506		6		/* ST506 etc. */
+#define	BSD_DTYPE_HPIB		7		/* CS/80 on HP-IB */
+#define BSD_DTYPE_HPFL		8		/* HP Fiber-link */
+#define	BSD_DTYPE_FLOPPY	10		/* floppy */
+
+/* d_subtype values: */
+#define BSD_DSTYPE_INDOSPART	0x8		/* is inside dos partition */
+#define BSD_DSTYPE_DOSPART(s)	((s) & 3)	/* dos partition number */
+#define BSD_DSTYPE_GEOMETRY	0x10		/* drive params in label */
+
+/*
+ * Filesystem type and version.
+ * Used to interpret other filesystem-specific
+ * per-partition information.
+ */
+#define	BSD_FS_UNUSED	0		/* unused */
+#define	BSD_FS_SWAP    	1		/* swap */
+#define	BSD_FS_V6      	2		/* Sixth Edition */
+#define	BSD_FS_V7      	3		/* Seventh Edition */
+#define	BSD_FS_SYSV    	4		/* System V */
+#define	BSD_FS_V71K    	5		/* V7 with 1K blocks (4.1, 2.9) */
+#define	BSD_FS_V8      	6		/* Eighth Edition, 4K blocks */
+#define	BSD_FS_BSDFFS	7		/* 4.2BSD fast file system */
+#define	BSD_FS_BSDLFS	9		/* 4.4BSD log-structured file system */
+#define	BSD_FS_OTHER	10		/* in use, but unknown/unsupported */
+#define	BSD_FS_HPFS	11		/* OS/2 high-performance file system */
+#define	BSD_FS_ISO9660	12		/* ISO-9660 filesystem (cdrom) */
+#define BSD_FS_ISOFS	BSD_FS_ISO9660
+#define	BSD_FS_BOOT	13		/* partition contains bootstrap */
+#define BSD_FS_ADOS	14		/* AmigaDOS fast file system */
+#define BSD_FS_HFS	15		/* Macintosh HFS */
+#define BSD_FS_ADVFS	16		/* Digital Unix AdvFS */
+
+/* this is annoying, but it's also the way it is :-( */
+#ifdef __alpha__
+#define	BSD_FS_EXT2	8		/* ext2 file system */
+#else
+#define	BSD_FS_MSDOS	8		/* MS-DOS file system */
+#endif
+
+/*
+ * flags shared by various drives:
+ */
+#define	BSD_D_REMOVABLE	0x01		/* removable media */
+#define	BSD_D_ECC      	0x02		/* supports ECC */
+#define	BSD_D_BADSECT	0x04		/* supports bad sector forw. */
+#define	BSD_D_RAMDISK	0x08		/* disk emulator */
+#define	BSD_D_CHAIN    	0x10		/* can do back-back transfers */
+#define	BSD_D_DOSPART	0x20		/* within MSDOS partition */
+
+#endif /* UTIL_LINUX_PT_BSD_H */
diff --git a/libblkid/include/pt-mbr-partnames.h b/libblkid/include/pt-mbr-partnames.h
new file mode 100644
index 0000000..282adba
--- /dev/null
+++ b/libblkid/include/pt-mbr-partnames.h
@@ -0,0 +1,105 @@
+	{0x00, N_("Empty")},
+	{0x01, N_("FAT12")},
+	{0x02, N_("XENIX root")},
+	{0x03, N_("XENIX usr")},
+	{0x04, N_("FAT16 <32M")},
+	{0x05, N_("Extended")},		/* DOS 3.3+ extended partition */
+	{0x06, N_("FAT16")},		/* DOS 16-bit >=32M */
+	{0x07, N_("HPFS/NTFS/exFAT")},	/* OS/2 IFS, eg, HPFS or NTFS or QNX or exFAT */
+	{0x08, N_("AIX")},		/* AIX boot (AIX -- PS/2 port) or SplitDrive */
+	{0x09, N_("AIX bootable")},	/* AIX data or Coherent */
+	{0x0a, N_("OS/2 Boot Manager")},/* OS/2 Boot Manager */
+	{0x0b, N_("W95 FAT32")},
+	{0x0c, N_("W95 FAT32 (LBA)")},/* LBA really is `Extended Int 13h' */
+	{0x0e, N_("W95 FAT16 (LBA)")},
+	{0x0f, N_("W95 Ext'd (LBA)")},
+	{0x10, N_("OPUS")},
+	{0x11, N_("Hidden FAT12")},
+	{0x12, N_("Compaq diagnostics")},
+	{0x14, N_("Hidden FAT16 <32M")},
+	{0x16, N_("Hidden FAT16")},
+	{0x17, N_("Hidden HPFS/NTFS")},
+	{0x18, N_("AST SmartSleep")},
+	{0x1b, N_("Hidden W95 FAT32")},
+	{0x1c, N_("Hidden W95 FAT32 (LBA)")},
+	{0x1e, N_("Hidden W95 FAT16 (LBA)")},
+	{0x24, N_("NEC DOS")},
+	{0x27, N_("Hidden NTFS WinRE")},
+	{0x39, N_("Plan 9")},
+	{0x3c, N_("PartitionMagic recovery")},
+	{0x40, N_("Venix 80286")},
+	{0x41, N_("PPC PReP Boot")},
+	{0x42, N_("SFS")},
+	{0x4d, N_("QNX4.x")},
+	{0x4e, N_("QNX4.x 2nd part")},
+	{0x4f, N_("QNX4.x 3rd part")},
+	{0x50, N_("OnTrack DM")},
+	{0x51, N_("OnTrack DM6 Aux1")},	/* (or Novell) */
+	{0x52, N_("CP/M")},		/* CP/M or Microport SysV/AT */
+	{0x53, N_("OnTrack DM6 Aux3")},
+	{0x54, N_("OnTrackDM6")},
+	{0x55, N_("EZ-Drive")},
+	{0x56, N_("Golden Bow")},
+	{0x5c, N_("Priam Edisk")},
+	{0x61, N_("SpeedStor")},
+	{0x63, N_("GNU HURD or SysV")},	/* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
+	{0x64, N_("Novell Netware 286")},
+	{0x65, N_("Novell Netware 386")},
+	{0x70, N_("DiskSecure Multi-Boot")},
+	{0x75, N_("PC/IX")},
+	{0x80, N_("Old Minix")},	/* Minix 1.4a and earlier */
+	{0x81, N_("Minix / old Linux")},/* Minix 1.4b and later */
+	{0x82, N_("Linux swap / Solaris")},
+	{0x83, N_("Linux")},
+	{0x84, N_("OS/2 hidden C: drive")},
+	{0x85, N_("Linux extended")},
+	{0x86, N_("NTFS volume set")},
+	{0x87, N_("NTFS volume set")},
+	{0x88, N_("Linux plaintext")},
+	{0x8e, N_("Linux LVM")},
+	{0x93, N_("Amoeba")},
+	{0x94, N_("Amoeba BBT")},	/* (bad block table) */
+	{0x9f, N_("BSD/OS")},		/* BSDI */
+	{0xa0, N_("IBM Thinkpad hibernation")},
+	{0xa5, N_("FreeBSD")},		/* various BSD flavours */
+	{0xa6, N_("OpenBSD")},
+	{0xa7, N_("NeXTSTEP")},
+	{0xa8, N_("Darwin UFS")},
+	{0xa9, N_("NetBSD")},
+	{0xab, N_("Darwin boot")},
+	{0xaf, N_("HFS / HFS+")},
+	{0xb7, N_("BSDI fs")},
+	{0xb8, N_("BSDI swap")},
+	{0xbb, N_("Boot Wizard hidden")},
+	{0xbe, N_("Solaris boot")},
+	{0xbf, N_("Solaris")},
+	{0xc1, N_("DRDOS/sec (FAT-12)")},
+	{0xc4, N_("DRDOS/sec (FAT-16 < 32M)")},
+	{0xc6, N_("DRDOS/sec (FAT-16)")},
+	{0xc7, N_("Syrinx")},
+	{0xda, N_("Non-FS data")},
+	{0xdb, N_("CP/M / CTOS / ...")},/* CP/M or Concurrent CP/M or
+					   Concurrent DOS or CTOS */
+	{0xde, N_("Dell Utility")},	/* Dell PowerEdge Server utilities */
+	{0xdf, N_("BootIt")},		/* BootIt EMBRM */
+	{0xe1, N_("DOS access")},	/* DOS access or SpeedStor 12-bit FAT
+					   extended partition */
+	{0xe3, N_("DOS R/O")},		/* DOS R/O or SpeedStor */
+	{0xe4, N_("SpeedStor")},	/* SpeedStor 16-bit FAT extended
+					   partition < 1024 cyl. */
+	{0xeb, N_("BeOS fs")},
+	{0xee, N_("GPT")},		/* Intel EFI GUID Partition Table */
+	{0xef, N_("EFI (FAT-12/16/32)")},/* Intel EFI System Partition */
+	{0xf0, N_("Linux/PA-RISC boot")},/* Linux/PA-RISC boot loader */
+	{0xf1, N_("SpeedStor")},
+	{0xf4, N_("SpeedStor")},	/* SpeedStor large partition */
+	{0xf2, N_("DOS secondary")},	/* DOS 3.3+ secondary */
+	{0xfb, N_("VMware VMFS")},
+	{0xfc, N_("VMware VMKCORE")},	/* VMware kernel dump partition */
+	{0xfd, N_("Linux raid autodetect")},/* New (2.2.x) raid partition with
+					       autodetect using persistent
+					       superblock */
+	{0xfe, N_("LANstep")},		/* SpeedStor >1024 cyl. or LANstep */
+	{0xff, N_("BBT")},		/* Xenix Bad Block Table */
+
+	{ 0, 0 }
diff --git a/libblkid/include/pt-mbr.h b/libblkid/include/pt-mbr.h
new file mode 100644
index 0000000..1279e3c
--- /dev/null
+++ b/libblkid/include/pt-mbr.h
@@ -0,0 +1,178 @@
+#ifndef UTIL_LINUX_PT_MBR_H
+#define UTIL_LINUX_PT_MBR_H
+
+struct dos_partition {
+	unsigned char boot_ind;		/* 0x80 - active */
+	unsigned char bh, bs, bc;	/* begin CHS */
+	unsigned char sys_ind;
+	unsigned char eh, es, ec;	/* end CHS */
+	unsigned char start_sect[4];
+	unsigned char nr_sects[4];
+} __attribute__((packed));
+
+#define MBR_PT_OFFSET		0x1be
+
+static inline struct dos_partition *mbr_get_partition(unsigned char *mbr, int i)
+{
+	return (struct dos_partition *)
+		(mbr + MBR_PT_OFFSET + (i * sizeof(struct dos_partition)));
+}
+
+/* assemble badly aligned little endian integer */
+static inline unsigned int __dos_assemble_4le(const unsigned char *p)
+{
+	return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
+}
+
+static inline void __dos_store_4le(unsigned char *p, unsigned int val)
+{
+	p[0] = (val & 0xff);
+	p[1] = ((val >> 8) & 0xff);
+	p[2] = ((val >> 16) & 0xff);
+	p[3] = ((val >> 24) & 0xff);
+}
+
+static inline unsigned int dos_partition_get_start(struct dos_partition *p)
+{
+	return __dos_assemble_4le(&(p->start_sect[0]));
+}
+
+static inline void dos_partition_set_start(struct dos_partition *p, unsigned int n)
+{
+	__dos_store_4le(p->start_sect, n);
+}
+
+static inline unsigned int dos_partition_get_size(struct dos_partition *p)
+{
+	return __dos_assemble_4le(&(p->nr_sects[0]));
+}
+
+static inline void dos_partition_set_size(struct dos_partition *p, unsigned int n)
+{
+	__dos_store_4le(p->nr_sects, n);
+}
+
+static inline int mbr_is_valid_magic(const unsigned char *mbr)
+{
+	return mbr[510] == 0x55 && mbr[511] == 0xaa ? 1 : 0;
+}
+
+static inline void mbr_set_magic(unsigned char *b)
+{
+	b[510] = 0x55;
+	b[511] = 0xaa;
+}
+
+static inline unsigned int mbr_get_id(const unsigned char *mbr)
+{
+	return __dos_assemble_4le(&mbr[440]);
+}
+
+static inline void mbr_set_id(unsigned char *b, unsigned int id)
+{
+	__dos_store_4le(&b[440], id);
+}
+
+enum {
+	MBR_EMPTY_PARTITION		= 0x00,
+	MBR_FAT12_PARTITION		= 0x01,
+	MBR_XENIX_ROOT_PARTITION	= 0x02,
+	MBR_XENIX_USR_PARTITION		= 0x03,
+	MBR_FAT16_LESS32M_PARTITION	= 0x04,
+	MBR_DOS_EXTENDED_PARTITION	= 0x05,
+	MBR_FAT16_PARTITION		= 0x06, /* DOS 16-bit >=32M */
+	MBR_HPFS_NTFS_PARTITION		= 0x07, /* OS/2 IFS, eg, HPFS or NTFS or QNX */
+	MBR_AIX_PARTITION		= 0x08, /* AIX boot (AIX -- PS/2 port) or SplitDrive */
+	MBR_AIX_BOOTABLE_PARTITION	= 0x09, /* AIX data or Coherent */
+	MBR_OS2_BOOTMNGR_PARTITION	= 0x0a, /* OS/2 Boot Manager */
+	MBR_W95_FAT32_PARTITION		= 0x0b,
+	MBR_W95_FAT32_LBA_PARTITION	= 0x0c, /* LBA really is `Extended Int 13h' */
+	MBR_W95_FAT16_LBA_PARTITION	= 0x0e,
+	MBR_W95_EXTENDED_PARTITION	= 0x0f,
+	MBR_OPUS_PARTITION		= 0x10,
+	MBR_HIDDEN_FAT12_PARTITION	= 0x11,
+	MBR_COMPAQ_DIAGNOSTICS_PARTITION = 0x12,
+	MBR_HIDDEN_FAT16_L32M_PARTITION	= 0x14,
+	MBR_HIDDEN_FAT16_PARTITION	= 0x16,
+	MBR_HIDDEN_HPFS_NTFS_PARTITION	= 0x17,
+	MBR_AST_SMARTSLEEP_PARTITION	= 0x18,
+	MBR_HIDDEN_W95_FAT32_PARTITION	= 0x1b,
+	MBR_HIDDEN_W95_FAT32LBA_PARTITION = 0x1c,
+	MBR_HIDDEN_W95_FAT16LBA_PARTITION = 0x1e,
+	MBR_NEC_DOS_PARTITION		= 0x24,
+	MBR_PLAN9_PARTITION		= 0x39,
+	MBR_PARTITIONMAGIC_PARTITION	= 0x3c,
+	MBR_VENIX80286_PARTITION	= 0x40,
+	MBR_PPC_PREP_BOOT_PARTITION	= 0x41,
+	MBR_SFS_PARTITION		= 0x42,
+	MBR_QNX_4X_PARTITION		= 0x4d,
+	MBR_QNX_4X_2ND_PARTITION	= 0x4e,
+	MBR_QNX_4X_3RD_PARTITION	= 0x4f,
+	MBR_DM_PARTITION		= 0x50,
+	MBR_DM6_AUX1_PARTITION		= 0x51, /* (or Novell) */
+	MBR_CPM_PARTITION		= 0x52, /* CP/M or Microport SysV/AT */
+	MBR_DM6_AUX3_PARTITION		= 0x53,
+	MBR_DM6_PARTITION		= 0x54,
+	MBR_EZ_DRIVE_PARTITION		= 0x55,
+	MBR_GOLDEN_BOW_PARTITION	= 0x56,
+	MBR_PRIAM_EDISK_PARTITION	= 0x5c,
+	MBR_SPEEDSTOR_PARTITION		= 0x61,
+	MBR_GNU_HURD_PARTITION		= 0x63, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
+	MBR_UNIXWARE_PARTITION		= MBR_GNU_HURD_PARTITION,
+	MBR_NETWARE_286_PARTITION	= 0x64,
+	MBR_NETWARE_386_PARTITION	= 0x65,
+	MBR_DISKSECURE_MULTIBOOT_PARTITION = 0x70,
+	MBR_PC_IX_PARTITION		= 0x75,
+	MBR_OLD_MINIX_PARTITION		= 0x80, /* Minix 1.4a and earlier */
+	MBR_MINIX_PARTITION		= 0x81, /* Minix 1.4b and later */
+	MBR_LINUX_SWAP_PARTITION	= 0x82,
+	MBR_SOLARIS_X86_PARTITION	= MBR_LINUX_SWAP_PARTITION,
+	MBR_LINUX_DATA_PARTITION	= 0x83,
+	MBR_OS2_HIDDEN_DRIVE_PARTITION	= 0x84,
+	MBR_LINUX_EXTENDED_PARTITION	= 0x85,
+	MBR_NTFS_VOL_SET1_PARTITION	= 0x86,
+	MBR_NTFS_VOL_SET2_PARTITION	= 0x87,
+	MBR_LINUX_PLAINTEXT_PARTITION	= 0x88,
+	MBR_LINUX_LVM_PARTITION		= 0x8e,
+	MBR_AMOEBA_PARTITION		= 0x93,
+	MBR_AMOEBA_BBT_PARTITION	= 0x94, /* (bad block table) */
+	MBR_BSD_OS_PARTITION		= 0x9f, /* BSDI */
+	MBR_THINKPAD_HIBERNATION_PARTITION = 0xa0,
+	MBR_FREEBSD_PARTITION		= 0xa5, /* various BSD flavours */
+	MBR_OPENBSD_PARTITION		= 0xa6,
+	MBR_NEXTSTEP_PARTITION		= 0xa7,
+	MBR_DARWIN_UFS_PARTITION	= 0xa8,
+	MBR_NETBSD_PARTITION		= 0xa9,
+	MBR_DARWIN_BOOT_PARTITION	= 0xab,
+	MBR_HFS_HFS_PARTITION		= 0xaf,
+	MBR_BSDI_FS_PARTITION		= 0xb7,
+	MBR_BSDI_SWAP_PARTITION		= 0xb8,
+	MBR_BOOTWIZARD_HIDDEN_PARTITION	= 0xbb,
+	MBR_SOLARIS_BOOT_PARTITION	= 0xbe,
+	MBR_SOLARIS_PARTITION		= 0xbf,
+	MBR_DRDOS_FAT12_PARTITION	= 0xc1,
+	MBR_DRDOS_FAT16_L32M_PARTITION	= 0xc4,
+	MBR_DRDOS_FAT16_PARTITION	= 0xc6,
+	MBR_SYRINX_PARTITION		= 0xc7,
+	MBR_NONFS_DATA_PARTITION	= 0xda,
+	MBR_CPM_CTOS_PARTITION		= 0xdb, /* CP/M or Concurrent CP/M or Concurrent DOS or CTOS */
+	MBR_DELL_UTILITY_PARTITION	= 0xde, /* Dell PowerEdge Server utilities */
+	MBR_BOOTIT_PARTITION		= 0xdf, /* BootIt EMBRM */
+	MBR_DOS_ACCESS_PARTITION	= 0xe1, /* DOS access or SpeedStor 12-bit FAT extended partition */
+	MBR_DOS_RO_PARTITION		= 0xe3, /* DOS R/O or SpeedStor */
+	MBR_SPEEDSTOR_EXTENDED_PARTITION = 0xe4, /* SpeedStor 16-bit FAT extended partition < 1024 cyl. */
+	MBR_BEOS_FS_PARTITION		= 0xeb,
+	MBR_GPT_PARTITION		= 0xee, /* Intel EFI GUID Partition Table */
+	MBR_EFI_SYSTEM_PARTITION	= 0xef, /* Intel EFI System Partition */
+	MBR_LINUX_PARISC_BOOT_PARTITION	= 0xf0, /* Linux/PA-RISC boot loader */
+	MBR_SPEEDSTOR1_PARTITION	= 0xf1,
+	MBR_SPEEDSTOR2_PARTITION	= 0xf4, /* SpeedStor large partition */
+	MBR_DOS_SECONDARY_PARTITION	= 0xf2, /* DOS 3.3+ secondary */
+	MBR_VMWARE_VMFS_PARTITION	= 0xfb,
+	MBR_VMWARE_VMKCORE_PARTITION	= 0xfc, /* VMware kernel dump partition */
+	MBR_LINUX_RAID_PARTITION	= 0xfd, /* New (2.2.x) raid partition with autodetect using persistent superblock */
+	MBR_LANSTEP_PARTITION		= 0xfe, /* SpeedStor >1024 cyl. or LANstep */
+	MBR_XENIX_BBT_PARTITION		= 0xff, /* Xenix Bad Block Table */
+};
+
+#endif /* UTIL_LINUX_PT_MBR_H */
diff --git a/libblkid/include/pt-sgi.h b/libblkid/include/pt-sgi.h
new file mode 100644
index 0000000..547b37a
--- /dev/null
+++ b/libblkid/include/pt-sgi.h
@@ -0,0 +1,110 @@
+#ifndef UTIL_LINUX_PT_SUN_H
+#define UTIL_LINUX_PT_SUN_H
+
+#include <stdint.h>
+
+#define	SGI_LABEL_MAGIC		0x0be5a941
+
+#define SGI_MAXPARTITIONS	16
+#define SGI_MAXVOLUMES		15
+
+/* partition types */
+enum {
+	SGI_TYPE_VOLHDR		= 0x00,
+	SGI_TYPE_TRKREPL	= 0x01,
+	SGI_TYPE_SECREPL	= 0x02,
+	SGI_TYPE_SWAP		= 0x03,
+	SGI_TYPE_BSD		= 0x04,
+	SGI_TYPE_SYSV		= 0x05,
+	SGI_TYPE_ENTIRE_DISK	= 0x06,
+	SGI_TYPE_EFS		= 0x07,
+	SGI_TYPE_LVOL		= 0x08,
+	SGI_TYPE_RLVOL		= 0x09,
+	SGI_TYPE_XFS		= 0x0a,
+	SGI_TYPE_XFSLOG		= 0x0b,
+	SGI_TYPE_XLV		= 0x0c,
+	SGI_TYPE_XVM		= 0x0d
+};
+
+struct sgi_device_parameter {
+	unsigned char skew;
+	unsigned char gap1;
+	unsigned char gap2;
+	unsigned char sparecyl;
+
+	uint16_t pcylcount;
+	uint16_t head_vol0;
+	uint16_t ntrks;		/* tracks in cyl 0 or vol 0 */
+
+	unsigned char cmd_tag_queue_depth;
+	unsigned char unused0;
+
+	uint16_t unused1;
+	uint16_t nsect;		/* sectors/tracks in cyl 0 or vol 0 */
+	uint16_t bytes;
+	uint16_t ilfact;
+	uint32_t flags;		/* SGI_DEVPARAM_* controller flags */
+	uint32_t datarate;
+	uint32_t retries_on_error;
+	uint32_t ms_per_word;
+	uint16_t xylogics_gap1;
+	uint16_t xylogics_syncdelay;
+	uint16_t xylogics_readdelay;
+	uint16_t xylogics_gap2;
+	uint16_t xylogics_readgate;
+	uint16_t xylogics_writecont;
+} __attribute__((packed));
+
+enum {
+	SGI_DEVPARAM_SECTOR_SLIP	= 0x01,
+	SGI_DEVPARAM_SECTOR_FWD		= 0x02,
+	SGI_DEVPARAM_TRACK_FWD		= 0x04,
+	SGI_DEVPARAM_TRACK_MULTIVOL	= 0x08,
+	SGI_DEVPARAM_IGNORE_ERRORS	= 0x10,
+	SGI_DEVPARAM_RESEEK		= 0x20,
+	SGI_DEVPARAM_CMDTAGQ_ENABLE	= 0x40
+};
+
+
+struct sgi_disklabel {
+	uint32_t magic;			/* magic number */
+	uint16_t root_part_num;		/* # root partition */
+	uint16_t swap_part_num;		/* # swap partition */
+	unsigned char boot_file[16];	/* name of boot file */
+
+	struct sgi_device_parameter	devparam;	/* not used now */
+
+	struct sgi_volume {
+		unsigned char name[8];	/* name of volume */
+		uint32_t block_num;	/* logical block number */
+		uint32_t num_bytes;	/* how big, in bytes */
+	} __attribute__((packed)) volume[SGI_MAXVOLUMES];
+
+	struct sgi_partition {
+		uint32_t num_blocks;	/* size in logical blocks */
+		uint32_t first_block;	/* first logical block */
+		uint32_t type;		/* type of this partition */
+	} __attribute__((packed)) partitions[SGI_MAXPARTITIONS];
+
+	/* checksum is the 32bit 2's complement sum of the disklabel */
+	uint32_t csum;			/* disk label checksum */
+	uint32_t padding;		/* padding */
+} __attribute__((packed));
+
+static inline uint32_t sgi_pt_checksum(struct sgi_disklabel *label)
+{
+	int i;
+	uint32_t *ptr = (uint32_t *) label;
+	uint32_t sum = 0;
+
+	i = sizeof(*label) / sizeof(*ptr);
+
+	while (i) {
+		i--;
+		sum -= be32_to_cpu(ptr[i]);
+	}
+
+	return sum;
+}
+
+#endif /* UTIL_LINUX_PT_SUN_H */
diff --git a/libblkid/include/pt-sun.h b/libblkid/include/pt-sun.h
new file mode 100644
index 0000000..b085268
--- /dev/null
+++ b/libblkid/include/pt-sun.h
@@ -0,0 +1,90 @@
+#ifndef UTIL_LINUX_PT_SUN_H
+#define UTIL_LINUX_PT_SUN_H
+
+#include <stdint.h>
+
+#define SUN_LABEL_MAGIC		0xDABE
+
+/* Supported VTOC setting */
+#define SUN_VTOC_SANITY		0x600DDEEE	/* magic number */
+#define SUN_VTOC_VERSION	1
+#define SUN_MAXPARTITIONS	8
+
+struct sun_disklabel {
+	unsigned char label_id[128];   /* Informative text string */
+
+	struct sun_vtoc {
+		uint32_t version;     /* version */
+		char	 volume_id[8];/* volume name */
+		uint16_t nparts;      /* num of partitions */
+
+		struct sun_info {        /* partition information */
+			uint16_t id;     /* SUN_TAG_*  */
+			uint16_t flags;  /* SUN_FLAG_* */
+		} __attribute__ ((packed)) infos[8];
+
+		uint16_t padding;      /* padding */
+		uint32_t bootinfo[3];  /* info needed by mboot */
+		uint32_t sanity;       /* magic number */
+		uint32_t reserved[10]; /* padding */
+		uint32_t timestamp[8]; /* partition timestamp */
+	} __attribute__ ((packed)) vtoc;
+
+	uint32_t write_reinstruct;     /* sectors to skip, writes */
+	uint32_t read_reinstruct;      /* sectors to skip, reads */
+	unsigned char spare[148];      /* padding */
+	uint16_t rpm;                  /* disk rotational speed */
+	uint16_t pcyl;                 /* physical cylinder count */
+	uint16_t apc;                  /* extra sects per cylinder */
+	uint16_t obs1;
+	uint16_t obs2;
+	uint16_t intrlv;               /* interleave factor */
+	uint16_t ncyl;                 /* data cylinder count */
+	uint16_t acyl;                 /* alt. cylinder count */
+	uint16_t nhead;                /* tracks per cylinder   <---- */
+	uint16_t nsect;                /* sectors per track     <---- */
+	uint16_t obs3;
+	uint16_t obs4;
+
+	struct sun_partition {         /* partitions */
+		uint32_t start_cylinder;
+		uint32_t num_sectors;
+	} __attribute__ ((packed)) partitions[8];
+
+	uint16_t magic;                /* magic number */
+	uint16_t csum;                 /* label xor'd checksum */
+} __attribute__ ((packed));
+
+
+#define SUN_TAG_UNASSIGNED	0x00	/* Unassigned partition */
+#define SUN_TAG_BOOT		0x01	/* Boot partition	*/
+#define SUN_TAG_ROOT		0x02	/* Root filesystem	*/
+#define SUN_TAG_SWAP		0x03	/* Swap partition	*/
+#define SUN_TAG_USR		0x04	/* /usr filesystem	*/
+#define SUN_TAG_WHOLEDISK	0x05	/* Full-disk slice	*/
+#define SUN_TAG_STAND		0x06	/* Stand partition	*/
+#define SUN_TAG_VAR		0x07	/* /var filesystem	*/
+#define SUN_TAG_HOME		0x08	/* /home filesystem	*/
+#define SUN_TAG_ALTSCTR		0x09	/* Alt sector partition	*/
+#define SUN_TAG_CACHE		0x0a	/* Cachefs partition	*/
+#define SUN_TAG_RESERVED	0x0b	/* SMI reserved data	*/
+#define SUN_TAG_LINUX_SWAP	0x82	/* Linux SWAP		*/
+#define SUN_TAG_LINUX_NATIVE	0x83	/* Linux filesystem	*/
+#define SUN_TAG_LINUX_LVM	0x8e	/* Linux LVM		*/
+#define SUN_TAG_LINUX_RAID	0xfd	/* LInux RAID		*/
+
+#define SUN_FLAG_UNMNT		0x01	/* Unmountable partition*/
+#define SUN_FLAG_RONLY		0x10	/* Read only		*/
+
+static inline uint16_t sun_pt_checksum(struct sun_disklabel *label)
+{
+	uint16_t *ptr = ((uint16_t *) (label + 1)) - 1;
+	uint16_t sum;
+
+	for (sum = 0; ptr >= ((uint16_t *) label);)
+		sum ^= *ptr--;
+
+	return sum;
+}
+
+#endif /* UTIL_LINUX_PT_SUN_H */
diff --git a/libblkid/randutils.h b/libblkid/include/randutils.h
similarity index 83%
rename from libblkid/randutils.h
rename to libblkid/include/randutils.h
index dec5e35..17e2a02 100644
--- a/libblkid/randutils.h
+++ b/libblkid/include/randutils.h
@@ -8,5 +8,6 @@
 
 extern int random_get_fd(void);
 extern void random_get_bytes(void *buf, size_t nbytes);
+extern const char *random_tell_source(void);
 
 #endif
diff --git a/libblkid/include/readutmp.h b/libblkid/include/readutmp.h
new file mode 100644
index 0000000..93251ea
--- /dev/null
+++ b/libblkid/include/readutmp.h
@@ -0,0 +1,28 @@
+/* Declarations for GNU's read utmp module.
+
+   Copyright (C) 1992-2007, 2009-2014 Free Software Foundation, Inc.
+
+   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 3 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, see <http://www.gnu.org/licenses/>.  */
+
+/* Written by jla; revised by djm */
+
+#ifndef READUTMP_H
+#define READUTMP_H
+
+#include <sys/types.h>
+#include <utmp.h>
+
+int read_utmp (char const *file, size_t *n_entries, struct utmp **utmp_buf);
+
+#endif /* READUTMP_H */
diff --git a/libblkid/rpmatch.h b/libblkid/include/rpmatch.h
similarity index 100%
rename from libblkid/rpmatch.h
rename to libblkid/include/rpmatch.h
diff --git a/libblkid/setproctitle.h b/libblkid/include/setproctitle.h
similarity index 100%
rename from libblkid/setproctitle.h
rename to libblkid/include/setproctitle.h
diff --git a/libblkid/include/statfs_magic.h b/libblkid/include/statfs_magic.h
new file mode 100644
index 0000000..7397a4e
--- /dev/null
+++ b/libblkid/include/statfs_magic.h
@@ -0,0 +1,99 @@
+#ifndef UTIL_LINUX_STATFS_MAGIC_H
+#define UTIL_LINUX_STATFS_MAGIC_H
+
+#include <sys/statfs.h>
+
+/*
+ * If possible then don't depend on internal libc __SWORD_TYPE type.
+ */
+#ifdef __GNUC__
+#define F_TYPE_EQUAL(a, b) (a == (__typeof__(a)) b)
+#else
+#define F_TYPE_EQUAL(a, b) (a == (__SWORD_TYPE) b)
+#endif
+
+/*
+ *  Unfortunately, Linux kernel hedeader file <linux/magic.h> is incomplete
+ *  mess and kernel returns by statfs f_type many numbers that are nowhere
+ *  specified (in API).
+ *
+ *  This is collection of the magic numbers.
+ */
+#define STATFS_ADFS_MAGIC	0xadf5
+#define STATFS_AFFS_MAGIC	0xadff
+#define STATFS_AFS_MAGIC	0x5346414F
+#define STATFS_AUTOFS_MAGIC	0x0187
+#define STATFS_BDEVFS_MAGIC	0x62646576
+#define STATFS_BEFS_MAGIC	0x42465331
+#define STATFS_BFS_MAGIC	0x1BADFACE
+#define STATFS_BINFMTFS_MAGIC	0x42494e4d
+#define STATFS_BTRFS_MAGIC	0x9123683E
+#define STATFS_CEPH_MAGIC	0x00c36400
+#define STATFS_CGROUP_MAGIC	0x27e0eb
+#define STATFS_CIFS_MAGIC	0xff534d42
+#define STATFS_CODA_MAGIC	0x73757245
+#define STATFS_CONFIGFS_MAGIC	0x62656570
+#define STATFS_CRAMFS_MAGIC	0x28cd3d45
+#define STATFS_DEBUGFS_MAGIC	0x64626720
+#define STATFS_DEVPTS_MAGIC	0x1cd1
+#define STATFS_ECRYPTFS_MAGIC	0xf15f
+#define STATFS_EFIVARFS_MAGIC	0xde5e81e4
+#define STATFS_EFS_MAGIC	0x414A53
+#define STATFS_EXOFS_MAGIC	0x5DF5
+#define STATFS_EXT2_MAGIC	0xEF53
+#define STATFS_EXT3_MAGIC	0xEF53
+#define STATFS_EXT4_MAGIC	0xEF53
+#define STATFS_F2FS_MAGIC	0xF2F52010
+#define STATFS_FUSE_MAGIC	0x65735546
+#define STATFS_FUTEXFS_MAGIC	0xBAD1DEA
+#define STATFS_GFS2_MAGIC	0x01161970
+#define STATFS_HFSPLUS_MAGIC	0x482b
+#define STATFS_HOSTFS_MAGIC	0x00c0ffee
+#define STATFS_HPFS_MAGIC	0xf995e849
+#define STATFS_HPPFS_MAGIC	0xb00000ee
+#define STATFS_HUGETLBFS_MAGIC	0x958458f6
+#define STATFS_ISOFS_MAGIC	0x9660
+#define STATFS_JFFS2_MAGIC	0x72b6
+#define STATFS_JFS_MAGIC	0x3153464a
+#define STATFS_LOGFS_MAGIC	0xc97e8168
+#define STATFS_MINIX2_MAGIC	0x2468
+#define STATFS_MINIX2_MAGIC2	0x2478
+#define STATFS_MINIX3_MAGIC	0x4d5a
+#define STATFS_MINIX_MAGIC	0x137F
+#define STATFS_MINIX_MAGIC2	0x138F
+#define STATFS_MQUEUE_MAGIC	0x19800202
+#define STATFS_MSDOS_MAGIC	0x4d44
+#define STATFS_NCP_MAGIC	0x564c
+#define STATFS_NFS_MAGIC	0x6969
+#define STATFS_NILFS_MAGIC	0x3434
+#define STATFS_NTFS_MAGIC	0x5346544e
+#define STATFS_OCFS2_MAGIC	0x7461636f
+#define STATFS_OMFS_MAGIC	0xC2993D87
+#define STATFS_OPENPROMFS_MAGIC	0x9fa1
+#define STATFS_PIPEFS_MAGIC	0x50495045
+#define STATFS_PROC_MAGIC	0x9fa0
+#define STATFS_PSTOREFS_MAGIC	0x6165676C
+#define STATFS_QNX4_MAGIC	0x002f
+#define STATFS_QNX6_MAGIC	0x68191122
+#define STATFS_RAMFS_MAGIC	0x858458f6
+#define STATFS_REISERFS_MAGIC	0x52654973
+#define STATFS_ROMFS_MAGIC	0x7275
+#define STATFS_SECURITYFS_MAGIC	0x73636673
+#define STATFS_SELINUXFS_MAGIC	0xf97cff8c
+#define STATFS_SMACKFS_MAGIC	0x43415d53
+#define STATFS_SMB_MAGIC	0x517B
+#define STATFS_SOCKFS_MAGIC	0x534F434B
+#define STATFS_SQUASHFS_MAGIC	0x73717368
+#define STATFS_SYSFS_MAGIC	0x62656572
+#define STATFS_TMPFS_MAGIC	0x01021994
+#define STATFS_UBIFS_MAGIC	0x24051905
+#define STATFS_UDF_MAGIC	0x15013346
+#define STATFS_UFS2_MAGIC	0x19540119
+#define STATFS_UFS_MAGIC	0x00011954
+#define STATFS_V9FS_MAGIC	0x01021997
+#define STATFS_VXFS_MAGIC	0xa501FCF5
+#define STATFS_XENFS_MAGIC	0xabba1974
+#define STATFS_XFS_MAGIC	0x58465342
+
+#endif /* UTIL_LINUX_STATFS_MAGIC_H */
+
diff --git a/libblkid/include/strutils.h b/libblkid/include/strutils.h
new file mode 100644
index 0000000..4d8463a
--- /dev/null
+++ b/libblkid/include/strutils.h
@@ -0,0 +1,204 @@
+#ifndef UTIL_LINUX_STRUTILS
+#define UTIL_LINUX_STRUTILS
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include <sys/types.h>
+#include <ctype.h>
+
+/* default strtoxx_or_err() exit code */
+#ifndef STRTOXX_EXIT_CODE
+# define STRTOXX_EXIT_CODE EXIT_FAILURE
+#endif
+
+
+extern int parse_size(const char *str, uintmax_t *res, int *power);
+extern int strtosize(const char *str, uintmax_t *res);
+extern uintmax_t strtosize_or_err(const char *str, const char *errmesg);
+
+extern int16_t strtos16_or_err(const char *str, const char *errmesg);
+extern uint16_t strtou16_or_err(const char *str, const char *errmesg);
+
+extern int32_t strtos32_or_err(const char *str, const char *errmesg);
+extern uint32_t strtou32_or_err(const char *str, const char *errmesg);
+
+extern int64_t strtos64_or_err(const char *str, const char *errmesg);
+extern uint64_t strtou64_or_err(const char *str, const char *errmesg);
+
+extern double strtod_or_err(const char *str, const char *errmesg);
+
+extern long strtol_or_err(const char *str, const char *errmesg);
+extern unsigned long strtoul_or_err(const char *str, const char *errmesg);
+
+extern void strtotimeval_or_err(const char *str, struct timeval *tv,
+		const char *errmesg);
+
+extern int isdigit_string(const char *str);
+
+#ifndef HAVE_MEMPCPY
+extern void *mempcpy(void *restrict dest, const void *restrict src, size_t n);
+#endif
+#ifndef HAVE_STRNLEN
+extern size_t strnlen(const char *s, size_t maxlen);
+#endif
+#ifndef HAVE_STRNDUP
+extern char *strndup(const char *s, size_t n);
+#endif
+#ifndef HAVE_STRNCHR
+extern char *strnchr(const char *s, size_t maxlen, int c);
+#endif
+
+/* caller guarantees n > 0 */
+static inline void xstrncpy(char *dest, const char *src, size_t n)
+{
+	strncpy(dest, src, n-1);
+	dest[n-1] = 0;
+}
+
+static inline char *strdup_to_offset(void *stru, size_t offset, const char *str)
+{
+	char *n = NULL;
+	char **o = (char **) ((char *) stru + offset);
+
+	if (str) {
+		n = strdup(str);
+		if (!n)
+			return NULL;
+	}
+
+	free(*o);
+	*o = n;
+	return n;
+}
+
+#define strdup_to_struct_member(_s, _m, _str) \
+		strdup_to_offset((void *) _s, offsetof(__typeof__(*(_s)), _m), _str)
+
+extern void strmode(mode_t mode, char *str);
+
+/* Options for size_to_human_string() */
+enum
+{
+        SIZE_SUFFIX_1LETTER = 0,
+        SIZE_SUFFIX_3LETTER = 1,
+        SIZE_SUFFIX_SPACE   = 2
+};
+
+extern char *size_to_human_string(int options, uint64_t bytes);
+
+extern int string_to_idarray(const char *list, int ary[], size_t arysz,
+			   int (name2id)(const char *, size_t));
+extern int string_add_to_idarray(const char *list, int ary[],
+				 size_t arysz, int *ary_pos,
+				 int (name2id)(const char *, size_t));
+
+extern int string_to_bitarray(const char *list, char *ary,
+			    int (*name2bit)(const char *, size_t));
+
+extern int string_to_bitmask(const char *list,
+			     unsigned long *mask,
+			     long (*name2flag)(const char *, size_t));
+extern int parse_range(const char *str, int *lower, int *upper, int def);
+
+extern int streq_except_trailing_slash(const char *s1, const char *s2);
+
+/*
+ * Match string beginning.
+ */
+static inline const char *startswith(const char *s, const char *prefix)
+{
+	size_t sz = prefix ? strlen(prefix) : 0;
+
+        if (s && sz && strncmp(s, prefix, sz) == 0)
+                return s + sz;
+	return NULL;
+}
+
+/*
+ * Case insensitive match string beginning.
+ */
+static inline const char *startswith_no_case(const char *s, const char *prefix)
+{
+	size_t sz = prefix ? strlen(prefix) : 0;
+
+        if (s && sz && strncasecmp(s, prefix, sz) == 0)
+                return s + sz;
+	return NULL;
+}
+
+/*
+ * Match string ending.
+ */
+static inline const char *endswith(const char *s, const char *postfix)
+{
+	size_t sl = s ? strlen(s) : 0;
+	size_t pl = postfix ? strlen(postfix) : 0;
+
+	if (pl == 0)
+		return (char *)s + sl;
+	if (sl < pl)
+		return NULL;
+	if (memcmp(s + sl - pl, postfix, pl) != 0)
+		return NULL;
+	return (char *)s + sl - pl;
+}
+
+/*
+ * Skip leading white space.
+ */
+static inline const char *skip_space(const char *p)
+{
+	while (isspace(*p))
+		++p;
+	return p;
+}
+
+static inline const char *skip_blank(const char *p)
+{
+	while (isblank(*p))
+		++p;
+	return p;
+}
+
+
+/* Removes whitespace from the right-hand side of a string (trailing
+ * whitespace).
+ *
+ * Returns size of the new string (without \0).
+ */
+static inline size_t rtrim_whitespace(unsigned char *str)
+{
+	size_t i = strlen((char *) str);
+
+	while (i) {
+		i--;
+		if (!isspace(str[i])) {
+			i++;
+			break;
+		}
+	}
+	str[i] = '\0';
+	return i;
+}
+
+/* Removes whitespace from the left-hand side of a string.
+ *
+ * Returns size of the new string (without \0).
+ */
+static inline size_t ltrim_whitespace(unsigned char *str)
+{
+	size_t len;
+	unsigned char *p;
+
+	for (p = str; p && isspace(*p); p++);
+
+	len = strlen((char *) p);
+
+	if (len && p > str)
+		memmove(str, p, len + 1);
+
+	return len;
+}
+
+#endif
diff --git a/libblkid/include/swapheader.h b/libblkid/include/swapheader.h
new file mode 100644
index 0000000..3fce0d0
--- /dev/null
+++ b/libblkid/include/swapheader.h
@@ -0,0 +1,23 @@
+#ifndef _SWAPHEADER_H
+#define _SWAPHEADER_H
+
+#define SWAP_VERSION 1
+#define SWAP_UUID_LENGTH 16
+#define SWAP_LABEL_LENGTH 16
+#define SWAP_SIGNATURE "SWAPSPACE2"
+#define SWAP_SIGNATURE_SZ (sizeof(SWAP_SIGNATURE) - 1)
+
+#include <stdint.h>
+
+struct swap_header_v1_2 {
+	char	      bootbits[1024];    /* Space for disklabel etc. */
+	uint32_t      version;
+	uint32_t      last_page;
+	uint32_t      nr_badpages;
+	unsigned char uuid[SWAP_UUID_LENGTH];
+	char	      volume_name[SWAP_LABEL_LENGTH];
+	uint32_t      padding[117];
+	uint32_t      badpages[1];
+};
+
+#endif /* _SWAPHEADER_H */
diff --git a/libblkid/include/swapprober.h b/libblkid/include/swapprober.h
new file mode 100644
index 0000000..5107700
--- /dev/null
+++ b/libblkid/include/swapprober.h
@@ -0,0 +1,9 @@
+#ifndef UTIL_LINUX_SWAP_PROBER_H
+#define UTIL_LINUX_SWAP_PROBER_H
+
+#include <blkid.h>
+
+blkid_probe get_swap_prober(const char *devname);
+
+#endif /* UTIL_LINUX_SWAP_PROBER_H */
+
diff --git a/libblkid/sysfs.h b/libblkid/include/sysfs.h
similarity index 85%
rename from libblkid/sysfs.h
rename to libblkid/include/sysfs.h
index 739f9de..1de624a 100644
--- a/libblkid/sysfs.h
+++ b/libblkid/include/sysfs.h
@@ -58,6 +58,9 @@
 extern int sysfs_read_u64(struct sysfs_cxt *cxt, const char *attr, uint64_t *res);
 extern int sysfs_read_int(struct sysfs_cxt *cxt, const char *attr, int *res);
 
+extern int sysfs_write_string(struct sysfs_cxt *cxt, const char *attr, const char *str);
+extern int sysfs_write_u64(struct sysfs_cxt *cxt, const char *attr, uint64_t num);
+
 extern char *sysfs_get_devname(struct sysfs_cxt *cxt, char *buf, size_t bufsiz);
 
 extern char *sysfs_strdup(struct sysfs_cxt *cxt, const char *attr);
@@ -67,12 +70,19 @@
 extern dev_t sysfs_partno_to_devno(struct sysfs_cxt *cxt, int partno);
 extern char *sysfs_get_slave(struct sysfs_cxt *cxt);
 
+extern char *sysfs_get_devchain(struct sysfs_cxt *cxt, char *buf, size_t bufsz);
+extern int sysfs_next_subsystem(struct sysfs_cxt *cxt, char *devchain, char **subsys);
+extern int sysfs_is_hotpluggable(struct sysfs_cxt *cxt);
+
 extern int sysfs_is_partition_dirent(DIR *dir, struct dirent *d,
 			const char *parent_name);
 
 extern int sysfs_devno_to_wholedisk(dev_t dev, char *diskname,
             size_t len, dev_t *diskdevno);
 
+extern int sysfs_devno_is_lvm_private(dev_t devno);
+extern int sysfs_devno_is_wholedisk(dev_t devno);
+
 extern int sysfs_scsi_get_hctl(struct sysfs_cxt *cxt, int *h,
 			       int *c, int *t, int *l);
 extern char *sysfs_scsi_host_strdup_attribute(struct sysfs_cxt *cxt,
diff --git a/libblkid/include/timer.h b/libblkid/include/timer.h
new file mode 100644
index 0000000..79ef649
--- /dev/null
+++ b/libblkid/include/timer.h
@@ -0,0 +1,31 @@
+#ifndef UTIL_LINUX_TIMER_H
+#define UTIL_LINUX_TIMER_H
+
+#include <signal.h>
+#include <sys/time.h>
+
+static inline int setup_timer(
+			struct itimerval *timer,
+			struct itimerval *old_timer,
+			struct sigaction *old_sa,
+			void (*timeout_handler)(int))
+{
+	struct sigaction sa;
+
+	memset(&sa, 0, sizeof sa);
+	sa.sa_handler = timeout_handler;
+	sa.sa_flags = SA_RESETHAND;
+	sigaction(SIGALRM, &sa, old_sa);
+
+	return setitimer(ITIMER_REAL, timer, old_timer);
+}
+
+static inline void cancel_timer(
+			struct itimerval *old_timer,
+			struct sigaction *old_sa)
+{
+	setitimer(ITIMER_REAL, old_timer, NULL);
+	sigaction(SIGALRM, old_sa, NULL);
+}
+
+#endif
diff --git a/libblkid/include/timeutils.h b/libblkid/include/timeutils.h
new file mode 100644
index 0000000..8ed501b
--- /dev/null
+++ b/libblkid/include/timeutils.h
@@ -0,0 +1,56 @@
+/***
+  First set of functions in this file are part of systemd, and were
+  copied to util-linux at August 2013.
+
+  Copyright 2010 Lennart Poettering
+  Copyright (C) 2014 Karel Zak <kzak@redhat.com>
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd 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
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+#ifndef UTIL_LINUX_TIME_UTIL_H
+#define UTIL_LINUX_TIME_UTIL_H
+
+#include <stdio.h>
+#include <inttypes.h>
+
+typedef uint64_t usec_t;
+typedef uint64_t nsec_t;
+
+#define MSEC_PER_SEC  1000ULL
+#define USEC_PER_SEC  1000000ULL
+#define USEC_PER_MSEC 1000ULL
+#define NSEC_PER_SEC  1000000000ULL
+#define NSEC_PER_MSEC 1000000ULL
+#define NSEC_PER_USEC 1000ULL
+
+#define USEC_PER_MINUTE	(60ULL*USEC_PER_SEC)
+#define NSEC_PER_MINUTE	(60ULL*NSEC_PER_SEC)
+#define USEC_PER_HOUR	(60ULL*USEC_PER_MINUTE)
+#define NSEC_PER_HOUR	(60ULL*NSEC_PER_MINUTE)
+#define USEC_PER_DAY	(24ULL*USEC_PER_HOUR)
+#define NSEC_PER_DAY	(24ULL*NSEC_PER_HOUR)
+#define USEC_PER_WEEK	(7ULL*USEC_PER_DAY)
+#define NSEC_PER_WEEK	(7ULL*NSEC_PER_DAY)
+#define USEC_PER_MONTH	(2629800ULL*USEC_PER_SEC)
+#define NSEC_PER_MONTH	(2629800ULL*NSEC_PER_SEC)
+#define USEC_PER_YEAR	(31557600ULL*USEC_PER_SEC)
+#define NSEC_PER_YEAR	(31557600ULL*NSEC_PER_SEC)
+
+#define FORMAT_TIMESTAMP_MAX ((4*4+1)+11+9+4+1)	/* weekdays can be unicode */
+#define FORMAT_TIMESTAMP_RELATIVE_MAX 256
+#define FORMAT_TIMESPAN_MAX 64
+
+int parse_timestamp(const char *t, usec_t *usec);
+
+#endif /* UTIL_LINUX_TIME_UTIL_H */
diff --git a/libblkid/ttyutils.h b/libblkid/include/ttyutils.h
similarity index 83%
rename from libblkid/ttyutils.h
rename to libblkid/include/ttyutils.h
index 021156d..e842f9f 100644
--- a/libblkid/ttyutils.h
+++ b/libblkid/include/ttyutils.h
@@ -13,6 +13,9 @@
 #ifdef HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
 #endif
+#ifdef HAVE_SYS_TTYDEFAULTS_H
+#include <sys/ttydefaults.h>
+#endif
 
 /* Some shorthands for control characters. */
 #define CTL(x)		((x) ^ 0100)	/* Assumes ASCII dialect */
@@ -48,7 +51,8 @@
 	} while (0)
 
 extern int get_terminal_width(void);
-extern int get_terminal_name(const char **path, const char **name, const char **number);
+extern int get_terminal_name(int fd, const char **path, const char **name,
+			     const char **number);
 
 #define UL_TTY_KEEPCFLAGS	(1 << 1)
 #define UL_TTY_UTF8		(1 << 2)
@@ -70,13 +74,53 @@
 	/* Sane setting, allow eight bit characters, no carriage return delay
 	 * the same result as `stty sane cr0 pass8'
 	 */
+#ifndef IUCLC
+# define IUCLC 0
+#endif
+#ifndef NL0
+# define NL0 0
+#endif
+#ifndef CR0
+# define CR0 0
+#endif
+#ifndef BS0
+# define BS0 0
+#endif
+#ifndef VT0
+# define VT0 0
+#endif
+#ifndef FF0
+# define FF0 0
+#endif
+#ifndef OLCUC
+# define OLCUC 0
+#endif
+#ifndef OFILL
+# define OFILL 0
+#endif
+#ifndef NLDLY
+# define NLDLY 0
+#endif
+#ifndef CRDLY
+# define CRDLY 0
+#endif
+#ifndef BSDLY
+# define BSDLY 0
+#endif
+#ifndef VTDLY
+# define VTDLY 0
+#endif
+#ifndef FFDLY
+# define FFDLY 0
+#endif
+
 	tp->c_iflag |=  (BRKINT | ICRNL | IMAXBEL);
 	tp->c_iflag &= ~(IGNBRK | INLCR | IGNCR | IXOFF | IUCLC | IXANY | ISTRIP);
 	tp->c_oflag |=  (OPOST | ONLCR | NL0 | CR0 | TAB0 | BS0 | VT0 | FF0);
 	tp->c_oflag &= ~(OLCUC | OCRNL | ONOCR | ONLRET | OFILL | \
 			    NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY);
-	tp->c_lflag |=  (ISIG | ICANON | IEXTEN | ECHO|ECHOE|ECHOK|ECHOKE);
-	tp->c_lflag &= ~(ECHONL|ECHOCTL|ECHOPRT | NOFLSH | TOSTOP);
+	tp->c_lflag |=  (ISIG | ICANON | IEXTEN | ECHO|ECHOE|ECHOK|ECHOKE|ECHOCTL);
+	tp->c_lflag &= ~(ECHONL|ECHOPRT | NOFLSH | TOSTOP);
 
 	if ((flags & UL_TTY_KEEPCFLAGS) == 0) {
 		tp->c_cflag |=  (CREAD | CS8 | HUPCL);
@@ -121,6 +165,4 @@
 	tp->c_cc[VEOL2]    = _POSIX_VDISABLE;
 }
 
-
-
 #endif /* UTIL_LINUX_TTYUTILS_H */
diff --git a/libblkid/widechar.h b/libblkid/include/widechar.h
similarity index 100%
copy from libblkid/widechar.h
copy to libblkid/include/widechar.h
diff --git a/libblkid/xalloc.h b/libblkid/include/xalloc.h
similarity index 71%
rename from libblkid/xalloc.h
rename to libblkid/include/xalloc.h
index 7b685e7..f012fb2 100644
--- a/libblkid/xalloc.h
+++ b/libblkid/include/xalloc.h
@@ -49,7 +49,7 @@
         return ret;
 }
 
-static inline char *xstrdup(const char *str)
+static inline char __attribute__((warn_unused_result)) *xstrdup(const char *str)
 {
         char *ret;
 
@@ -63,6 +63,21 @@
         return ret;
 }
 
+static inline char * __attribute__((warn_unused_result)) xstrndup(const char *str, size_t size)
+{
+        char *ret;
+
+        if (!str)
+                return NULL;
+
+        ret = strndup(str, size);
+
+        if (!ret)
+                err(XALLOC_EXIT_CODE, "cannot duplicate string");
+        return ret;
+}
+
+
 static inline int __attribute__ ((__format__(printf, 2, 3)))
     xasprintf(char **strp, const char *fmt, ...)
 {
@@ -76,16 +91,26 @@
 	return ret;
 }
 
+static inline int xvasprintf(char **strp, const char *fmt, va_list ap)
+{
+	int ret = vasprintf(&(*strp), fmt, ap);
+	if (ret < 0)
+		err(XALLOC_EXIT_CODE, "cannot allocate string");
+	return ret;
+}
 
-static inline char *xgethostname(void)
+
+static inline char * __attribute__((warn_unused_result)) xgethostname(void)
 {
 	char *name;
 	size_t sz = get_hostname_max() + 1;
 
 	name = xmalloc(sizeof(char) * sz);
-	if (gethostname(name, sz) != 0)
-		return NULL;
 
+	if (gethostname(name, sz) != 0) {
+		free(name);
+		return NULL;
+	}
 	name[sz - 1] = '\0';
 	return name;
 }
diff --git a/libblkid/lib/Makemodule.am b/libblkid/lib/Makemodule.am
new file mode 100644
index 0000000..565294e
--- /dev/null
+++ b/libblkid/lib/Makemodule.am
@@ -0,0 +1,115 @@
+
+noinst_LTLIBRARIES += libcommon.la
+libcommon_la_CFLAGS = $(AM_CFLAGS)
+libcommon_la_SOURCES = \
+	lib/at.c \
+	lib/blkdev.c \
+	lib/canonicalize.c \
+	lib/colors.c \
+	lib/crc32.c \
+	lib/crc64.c \
+	lib/env.c \
+	lib/fileutils.c \
+	lib/ismounted.c \
+	lib/mangle.c \
+	lib/match.c \
+	lib/mbsalign.c \
+	lib/md5.c \
+	lib/pager.c \
+	lib/path.c \
+	lib/procutils.c \
+	lib/randutils.c \
+	lib/setproctitle.c \
+	lib/strutils.c \
+	lib/sysfs.c \
+	lib/timeutils.c \
+	lib/ttyutils.c \
+	lib/exec_shell.c \
+	lib/readutmp.c
+
+if LINUX
+libcommon_la_SOURCES += \
+	lib/linux_version.c \
+	lib/loopdev.c
+endif
+
+if !HAVE_LANGINFO
+libcommon_la_SOURCES += lib/langinfo.c
+endif
+
+if HAVE_CPU_SET_T
+libcommon_la_SOURCES += lib/cpuset.c
+endif
+
+dist_man_MANS += lib/terminal-colors.d.5
+
+check_PROGRAMS += \
+	test_at \
+	test_blkdev \
+	test_canonicalize \
+	test_colors \
+	test_fileutils \
+	test_ismounted \
+	test_mangle \
+	test_procutils \
+	test_randutils \
+	test_strutils \
+	test_ttyutils
+
+if LINUX
+if HAVE_CPU_SET_T
+check_PROGRAMS += test_cpuset
+endif
+check_PROGRAMS += \
+	test_sysfs \
+	test_pager
+endif
+
+test_ttyutils_SOURCES = lib/ttyutils.c
+test_ttyutils_CFLAGS = -DTEST_PROGRAM
+test_ttyutils_LDADD = libcommon.la
+
+test_blkdev_SOURCES = lib/blkdev.c
+test_blkdev_CFLAGS = -DTEST_PROGRAM_BLKDEV
+test_blkdev_LDADD = libcommon.la
+
+test_ismounted_SOURCES = lib/ismounted.c
+test_ismounted_CFLAGS = -DTEST_PROGRAM
+test_ismounted_LDADD = libcommon.la
+
+test_mangle_SOURCES = lib/mangle.c
+test_mangle_CFLAGS = -DTEST_PROGRAM
+
+test_at_SOURCES = lib/at.c
+test_at_CFLAGS = -DTEST_PROGRAM_AT
+
+test_strutils_SOURCES = lib/strutils.c
+test_strutils_CFLAGS = -DTEST_PROGRAM
+
+test_colors_SOURCES = lib/colors.c
+test_colors_CFLAGS = -DTEST_PROGRAM
+
+test_randutils_SOURCES = lib/randutils.c
+test_randutils_CFLAGS = -DTEST_PROGRAM
+
+test_procutils_SOURCES = lib/procutils.c lib/at.c
+test_procutils_CFLAGS = -DTEST_PROGRAM
+
+if LINUX
+test_cpuset_SOURCES = lib/cpuset.c
+test_cpuset_CFLAGS = -DTEST_PROGRAM
+
+test_sysfs_SOURCES = lib/sysfs.c
+test_sysfs_CFLAGS = -DTEST_PROGRAM_SYSFS
+test_sysfs_LDADD = libcommon.la
+
+test_pager_SOURCES = lib/pager.c
+test_pager_CFLAGS = -DTEST_PROGRAM
+endif
+
+test_fileutils_SOURCES = lib/fileutils.c
+test_fileutils_CFLAGS = -DTEST_PROGRAM
+
+test_canonicalize_SOURCES = lib/canonicalize.c
+test_canonicalize_CFLAGS = -DTEST_PROGRAM_CANONICALIZE
+
diff --git a/libblkid/at.c b/libblkid/lib/at.c
similarity index 100%
rename from libblkid/at.c
rename to libblkid/lib/at.c
diff --git a/libblkid/blkdev.c b/libblkid/lib/blkdev.c
similarity index 97%
rename from libblkid/blkdev.c
rename to libblkid/lib/blkdev.c
index 514082e..a293529 100644
--- a/libblkid/blkdev.c
+++ b/libblkid/lib/blkdev.c
@@ -25,10 +25,13 @@
 #include <sys/disk.h>
 #endif
 
+#ifdef __FreeBSD_kernel__
+#include <sys/disk.h>
+#endif
+
 #include "blkdev.h"
 #include "c.h"
 #include "linux_version.h"
-#include "xalloc.h"
 
 static long
 blkdev_valid_offset (int fd, off_t offset) {
@@ -336,7 +339,7 @@
 	return NULL;
 }
 
-#ifdef TEST_PROGRAM
+#ifdef TEST_PROGRAM_BLKDEV
 #include <stdio.h>
 #include <stdlib.h>
 #include <fcntl.h>
@@ -353,7 +356,7 @@
 		exit(EXIT_FAILURE);
 	}
 
-	if ((fd = open(argv[1], O_RDONLY)) < 0)
+	if ((fd = open(argv[1], O_RDONLY|O_CLOEXEC)) < 0)
 		err(EXIT_FAILURE, "open %s failed", argv[1]);
 
 	if (blkdev_get_size(fd, &bytes) < 0)
diff --git a/libblkid/lib/canonicalize.c b/libblkid/lib/canonicalize.c
new file mode 100644
index 0000000..303703b
--- /dev/null
+++ b/libblkid/lib/canonicalize.c
@@ -0,0 +1,145 @@
+/*
+ * canonicalize.c -- canonicalize pathname by removing symlinks
+ *
+ * This file may be distributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ * Copyright (C) 2009-2013 Karel Zak <kzak@redhat.com>
+ */
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "canonicalize.h"
+
+/*
+ * Converts private "dm-N" names to "/dev/mapper/<name>"
+ *
+ * Since 2.6.29 (patch 784aae735d9b0bba3f8b9faef4c8b30df3bf0128) kernel sysfs
+ * provides the real DM device names in /sys/block/<ptname>/dm/name
+ */
+char *canonicalize_dm_name(const char *ptname)
+{
+	FILE	*f;
+	size_t	sz;
+	char	path[256], name[256], *res = NULL;
+
+	if (!ptname || !*ptname)
+		return NULL;
+
+	snprintf(path, sizeof(path), "/sys/block/%s/dm/name", ptname);
+	if (!(f = fopen(path, "r")))
+		return NULL;
+
+	/* read "<name>\n" from sysfs */
+	if (fgets(name, sizeof(name), f) && (sz = strlen(name)) > 1) {
+		name[sz - 1] = '\0';
+		snprintf(path, sizeof(path), "/dev/mapper/%s", name);
+
+		if (access(path, F_OK) == 0)
+			res = strdup(path);
+	}
+	fclose(f);
+	return res;
+}
+
+static int is_dm_devname(char *canonical, char **name)
+{
+	struct stat sb;
+	char *p = strrchr(canonical, '/');
+
+	*name = NULL;
+
+	if (!p
+	    || strncmp(p, "/dm-", 4) != 0
+	    || !isdigit(*(p + 4))
+	    || stat(canonical, &sb) != 0
+	    || !S_ISBLK(sb.st_mode))
+		return 0;
+
+	*name = p + 1;
+	return 1;
+}
+
+char *canonicalize_path(const char *path)
+{
+	char *canonical, *dmname;
+
+	if (!path || !*path)
+		return NULL;
+
+	canonical = realpath(path, NULL);
+	if (!canonical)
+		return strdup(path);
+
+	if (is_dm_devname(canonical, &dmname)) {
+		char *dm = canonicalize_dm_name(dmname);
+		if (dm) {
+			free(canonical);
+			return dm;
+		}
+	}
+
+	return canonical;
+}
+
+char *canonicalize_path_restricted(const char *path)
+{
+	char *canonical, *dmname;
+	int errsv;
+	uid_t euid;
+	gid_t egid;
+
+	if (!path || !*path)
+		return NULL;
+
+	euid = geteuid();
+	egid = getegid();
+
+	/* drop permissions */
+	if (setegid(getgid()) < 0 || seteuid(getuid()) < 0)
+		return NULL;
+
+	errsv = errno = 0;
+
+	canonical = realpath(path, NULL);
+	if (!canonical)
+		errsv = errno;
+	else if (is_dm_devname(canonical, &dmname)) {
+		char *dm = canonicalize_dm_name(dmname);
+		if (dm) {
+			free(canonical);
+			canonical = dm;
+		}
+	}
+
+	/* restore */
+	if (setegid(egid) < 0 || seteuid(euid) < 0) {
+		free(canonical);
+		return NULL;
+	}
+
+	errno = errsv;
+	return canonical;
+}
+
+
+#ifdef TEST_PROGRAM_CANONICALIZE
+int main(int argc, char **argv)
+{
+	if (argc < 2) {
+		fprintf(stderr, "usage: %s <device>\n", argv[0]);
+		exit(EXIT_FAILURE);
+	}
+
+	fprintf(stdout, "orig: %s\n", argv[1]);
+	fprintf(stdout, "real: %s\n", canonicalize_path(argv[1]));
+
+	exit(EXIT_SUCCESS);
+}
+#endif
diff --git a/libblkid/lib/colors.c b/libblkid/lib/colors.c
new file mode 100644
index 0000000..6f79ac4
--- /dev/null
+++ b/libblkid/lib/colors.c
@@ -0,0 +1,877 @@
+/*
+ * Copyright (C) 2012 Ondrej Oprala <ooprala@redhat.com>
+ * Copyright (C) 2012-2014 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be distributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <assert.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <ctype.h>
+
+#include "c.h"
+#include "colors.h"
+#include "pathnames.h"
+#include "strutils.h"
+
+#include "debug.h"
+
+/*
+ * terminal-colors.d debug stuff
+ */
+UL_DEBUG_DEFINE_MASK(termcolors);
+UL_DEBUG_DEFINE_MASKNAMES(termcolors) = UL_DEBUG_EMPTY_MASKNAMES;
+
+#define TERMCOLORS_DEBUG_INIT	(1 << 1)
+#define TERMCOLORS_DEBUG_CONF	(1 << 2)
+#define TERMCOLORS_DEBUG_SCHEME	(1 << 3)
+#define TERMCOLORS_DEBUG_ALL	0xFFFF
+
+#define DBG(m, x)       __UL_DBG(termcolors, TERMCOLORS_DEBUG_, m, x)
+#define ON_DBG(m, x)    __UL_DBG_CALL(termcolors, TERMCOLORS_DEBUG_, m, x)
+
+/*
+ * terminal-colors.d file types
+ */
+enum {
+	UL_COLORFILE_DISABLE,		/* .disable */
+	UL_COLORFILE_ENABLE,		/* .enable */
+	UL_COLORFILE_SCHEME,		/* .scheme */
+
+	__UL_COLORFILE_COUNT
+};
+
+struct ul_color_scheme {
+	char *name;
+	char *seq;
+};
+
+/*
+ * Global colors control struct
+ *
+ * The terminal-colors.d/ evaluation is based on "scores":
+ *
+ *  filename                    score
+ *  ---------------------------------------
+ *  type			1
+ *  @termname.type		10 + 1
+ *  utilname.type		20 + 1
+ *  utilname@termname.type	20 + 10 + 1
+ *
+ * the match with higher score wins. The score is per type.
+ */
+struct ul_color_ctl {
+	const char	*utilname;	/* util name */
+	const char	*termname;	/* terminal name ($TERM) */
+
+	char		*sfile;	/* path to scheme */
+
+	struct ul_color_scheme	*schemes;	/* array with color schemes */
+	size_t			nschemes;	/* number of the items */
+	size_t			schemes_sz;	/* number of the allocated items */
+
+	int		mode;		/* UL_COLORMODE_* */
+	unsigned int	has_colors : 1,	/* based on mode and scores[] */
+			disabled   : 1, /* disable colors */
+			cs_configured : 1, /* color schemes read */
+			configured : 1; /* terminal-colors.d parsed */
+
+	int		scores[__UL_COLORFILE_COUNT];	/* the best match */
+};
+
+/*
+ * Control struct, globally shared.
+ */
+static struct ul_color_ctl ul_colors;
+
+static void colors_free_schemes(struct ul_color_ctl *cc);
+static int colors_read_schemes(struct ul_color_ctl *cc);
+
+/*
+ * qsort/bsearch buddy
+ */
+static int cmp_scheme_name(const void *a0, const void *b0)
+{
+	struct ul_color_scheme	*a = (struct ul_color_scheme *) a0,
+				*b = (struct ul_color_scheme *) b0;
+	return strcmp(a->name, b->name);
+}
+
+/*
+ * Maintains human readable color names
+ */
+const char *color_sequence_from_colorname(const char *str)
+{
+	static const struct ul_color_scheme basic_schemes[] = {
+		{ "black",	UL_COLOR_BLACK           },
+		{ "blue",	UL_COLOR_BLUE            },
+		{ "brown",	UL_COLOR_BROWN           },
+		{ "cyan",	UL_COLOR_CYAN            },
+		{ "darkgray",	UL_COLOR_DARK_GRAY       },
+		{ "gray",	UL_COLOR_GRAY            },
+		{ "green",	UL_COLOR_GREEN           },
+		{ "lightblue",	UL_COLOR_BOLD_BLUE       },
+		{ "lightcyan",	UL_COLOR_BOLD_CYAN       },
+		{ "lightgray,",	UL_COLOR_GRAY            },
+		{ "lightgreen", UL_COLOR_BOLD_GREEN      },
+		{ "lightmagenta", UL_COLOR_BOLD_MAGENTA  },
+		{ "lightred",	UL_COLOR_BOLD_RED        },
+		{ "magenta",	UL_COLOR_MAGENTA         },
+		{ "red",	UL_COLOR_RED             },
+		{ "yellow",	UL_COLOR_BOLD_YELLOW     },
+	};
+	struct ul_color_scheme key = { .name = (char *) str }, *res;
+
+	if (!str)
+		return NULL;
+
+	res = bsearch(&key, basic_schemes, ARRAY_SIZE(basic_schemes),
+				sizeof(struct ul_color_scheme),
+				cmp_scheme_name);
+	return res ? res->seq : NULL;
+}
+
+
+/*
+ * Resets control struct (note that we don't allocate the struct)
+ */
+static void colors_reset(struct ul_color_ctl *cc)
+{
+	if (!cc)
+		return;
+
+	colors_free_schemes(cc);
+
+	free(cc->sfile);
+
+	cc->sfile = NULL;
+	cc->utilname = NULL;
+	cc->termname = NULL;
+	cc->mode = UL_COLORMODE_UNDEF;
+
+	memset(cc->scores, 0, sizeof(cc->scores));
+}
+
+static void colors_debug(struct ul_color_ctl *cc)
+{
+	size_t i;
+
+	if (!cc)
+		return;
+
+	printf("Colors:\n");
+	printf("\tutilname = '%s'\n", cc->utilname);
+	printf("\ttermname = '%s'\n", cc->termname);
+	printf("\tscheme file = '%s'\n", cc->sfile);
+	printf("\tmode = %s\n",
+			cc->mode == UL_COLORMODE_UNDEF ? "undefined" :
+			cc->mode == UL_COLORMODE_AUTO ?  "auto" :
+			cc->mode == UL_COLORMODE_NEVER ? "never" :
+			cc->mode == UL_COLORMODE_ALWAYS ? "always" : "???");
+	printf("\thas_colors = %d\n", cc->has_colors);
+	printf("\tdisabled = %d\n", cc->disabled);
+	printf("\tconfigured = %d\n", cc->configured);
+	printf("\tcs configured = %d\n", cc->cs_configured);
+
+	fputc('\n', stdout);
+
+	for (i = 0; i < ARRAY_SIZE(cc->scores); i++)
+		printf("\tscore %s = %d\n",
+				i == UL_COLORFILE_DISABLE ? "disable" :
+				i == UL_COLORFILE_ENABLE ? "enable" :
+				i == UL_COLORFILE_SCHEME ? "scheme" : "???",
+				cc->scores[i]);
+
+	fputc('\n', stdout);
+
+	for (i = 0; i < cc->nschemes; i++) {
+		printf("\tscheme #%02zu ", i);
+		color_scheme_enable(cc->schemes[i].name, NULL);
+		fputs(cc->schemes[i].name, stdout);
+		color_disable();
+		fputc('\n', stdout);
+	}
+	fputc('\n', stdout);
+}
+
+/*
+ * Parses [[<utilname>][@<termname>].]<type>
+ */
+static int filename_to_tokens(const char *str,
+			      const char **name, size_t *namesz,
+			      const char **term, size_t *termsz,
+			      int  *filetype)
+{
+	const char *type_start, *term_start, *p;
+
+	if (!str || !*str || *str == '.' || strlen(str) > PATH_MAX)
+		return -EINVAL;
+
+	/* parse .type */
+	p = strrchr(str, '.');
+	type_start = p ? p + 1 : str;
+
+	if (strcmp(type_start, "disable") == 0)
+		*filetype = UL_COLORFILE_DISABLE;
+	else if (strcmp(type_start, "enable") == 0)
+		*filetype = UL_COLORFILE_ENABLE;
+	else if (strcmp(type_start, "scheme") == 0)
+		*filetype = UL_COLORFILE_SCHEME;
+	else {
+		DBG(CONF, ul_debug("unknown type '%s'", type_start));
+		return 1;				/* unknown type */
+	}
+
+	if (type_start == str)
+		return 0;				/* "type" only */
+
+	/* parse @termname */
+	p = strchr(str, '@');
+	term_start = p ? p + 1 : NULL;
+	if (term_start) {
+		*term = term_start;
+		*termsz = type_start - term_start - 1;
+		if (term_start - 1 == str)
+			return 0;			/* "@termname.type" */
+	}
+
+	/* parse utilname */
+	p = term_start ? term_start : type_start;
+	*name =  str;
+	*namesz	= p - str - 1;
+
+	return 0;
+}
+
+/*
+ * Scans @dirname and select the best matches for UL_COLORFILE_* types.
+ * The result is stored to cc->scores. The path to the best "scheme"
+ * file is stored to cc->scheme.
+ */
+static int colors_readdir(struct ul_color_ctl *cc, const char *dirname)
+{
+	DIR *dir;
+	int rc = 0;
+	struct dirent *d;
+	char sfile[PATH_MAX] = { '\0' };
+	size_t namesz, termsz;
+
+	if (!dirname || !cc || !cc->utilname || !*cc->utilname)
+		return -EINVAL;
+
+	DBG(CONF, ul_debug("reading dir: '%s'", dirname));
+
+	dir = opendir(dirname);
+	if (!dir)
+		return -errno;
+
+	namesz = strlen(cc->utilname);
+	termsz = cc->termname ? strlen(cc->termname) : 0;
+
+	while ((d = readdir(dir))) {
+		int type, score = 1;
+		const char *tk_name = NULL, *tk_term = NULL;
+		size_t tk_namesz = 0, tk_termsz = 0;
+
+		if (*d->d_name == '.')
+			continue;
+#ifdef _DIRENT_HAVE_D_TYPE
+		if (d->d_type != DT_UNKNOWN && d->d_type != DT_LNK &&
+		    d->d_type != DT_REG)
+			continue;
+#endif
+		if (filename_to_tokens(d->d_name,
+				       &tk_name, &tk_namesz,
+				       &tk_term, &tk_termsz, &type) != 0)
+			continue;
+
+		/* count teoretical score before we check names to avoid
+		 * unnecessary strcmp() */
+		if (tk_name)
+			score += 20;
+		if (tk_term)
+			score += 10;
+
+		DBG(CONF, ul_debug("item '%s': score=%d "
+			"[cur: %d, name(%zu): %s, term(%zu): %s]",
+			d->d_name, score, cc->scores[type],
+			tk_namesz, tk_name,
+			tk_termsz, tk_term));
+
+
+		if (score < cc->scores[type])
+			continue;
+
+		/* filter out by names */
+		if (tk_namesz && (tk_namesz != namesz ||
+				 strncmp(tk_name, cc->utilname, namesz) != 0))
+			continue;
+
+		if (tk_termsz && (termsz == 0 || tk_termsz != termsz ||
+				  strncmp(tk_term, cc->termname, termsz) != 0))
+			continue;
+
+		DBG(CONF, ul_debug("setting '%s' from %d -to-> %d",
+					type == UL_COLORFILE_SCHEME ? "scheme" :
+					type == UL_COLORFILE_DISABLE ? "disable" :
+					type == UL_COLORFILE_ENABLE ? "enable" : "???",
+					cc->scores[type], score));
+		cc->scores[type] = score;
+		if (type == UL_COLORFILE_SCHEME)
+			strncpy(sfile, d->d_name, sizeof(sfile));
+	}
+
+	if (*sfile) {
+		sfile[sizeof(sfile) - 1] = '\0';
+		if (asprintf(&cc->sfile, "%s/%s", dirname, sfile) <= 0)
+			rc = -ENOMEM;
+	}
+
+	closedir(dir);
+	return rc;
+}
+
+/* atexit() wrapper */
+static void colors_deinit(void)
+{
+	colors_reset(&ul_colors);
+}
+
+/*
+ * Returns path to $XDG_CONFIG_HOME/terminal-colors.d
+ */
+static char *colors_get_homedir(char *buf, size_t bufsz)
+{
+	char *p = getenv("XDG_CONFIG_HOME");
+
+	if (p) {
+		snprintf(buf, bufsz, "%s/" _PATH_TERMCOLORS_DIRNAME, p);
+		return buf;
+	}
+
+	p = getenv("HOME");
+	if (p) {
+		snprintf(buf, bufsz, "%s/.config/" _PATH_TERMCOLORS_DIRNAME, p);
+		return buf;
+	}
+
+	return NULL;
+}
+
+/* canonicalize sequence */
+static int cn_sequence(const char *str, char **seq)
+{
+	char *in, *out;
+
+	if (!str)
+		return -EINVAL;
+
+	*seq = NULL;
+
+	/* convert logical names like "red" to the real sequence */
+	if (*str != '\\' && isalpha(*str)) {
+		const char *s = color_sequence_from_colorname(str);
+		*seq = strdup(s ? s : str);
+
+		return *seq ? 0 : -ENOMEM;
+	}
+
+	/* convert xx;yy sequences to "\033[xx;yy" */
+	if (asprintf(seq, "\033[%sm", str) < 1)
+		return -ENOMEM;
+
+	for (in = *seq, out = *seq; in && *in; in++) {
+		if (*in != '\\') {
+			*out++ = *in;
+			continue;
+		}
+		switch(*(in + 1)) {
+		case 'a':
+			*out++ = '\a';	/* Bell */
+			break;
+		case 'b':
+			*out++ = '\b';	/* Backspace */
+			break;
+		case 'e':
+			*out++ = '\033';	/* Escape */
+			break;
+		case 'f':
+			*out++ = '\f';	/* Form Feed */
+			break;
+		case 'n':
+			*out++ = '\n';	/* Newline */
+			break;
+		case 'r':
+			*out++ = '\r';	/* Carriage Return */
+			break;
+		case 't':
+			*out++ = '\t';	/* Tab */
+			break;
+		case 'v':
+			*out++ = '\v';	/* Vertical Tab */
+			break;
+		case '\\':
+			*out++ = '\\';	/* Backslash */
+			break;
+		case '_':
+			*out++ = ' ';	/* Space */
+			break;
+		case '#':
+			*out++ = '#';	/* Hash mark */
+			break;
+		case '?':
+			*out++ = '?';	/* Qestion mark */
+			break;
+		default:
+			*out++ = *in;
+			*out++ = *(in + 1);
+			break;
+		}
+		in++;
+	}
+	*out = '\0';
+
+	return 0;
+}
+
+
+/*
+ * Adds one color sequence to array with color scheme.
+ * When returning success (0) this function takes ownership of
+ * @seq and @name, which have to be allocated strings.
+ */
+static int colors_add_scheme(struct ul_color_ctl *cc,
+			     char *name,
+			     char *seq0)
+{
+	struct ul_color_scheme *cs = NULL;
+	char *seq = NULL;
+	int rc;
+
+	if (!cc || !name || !*name || !seq0 || !*seq0)
+		return -EINVAL;
+
+	DBG(SCHEME, ul_debug("add '%s'", name));
+
+	rc = cn_sequence(seq0, &seq);
+	if (rc)
+		return rc;
+
+	rc = -ENOMEM;
+
+	/* convert logical name (e.g. "red") to real ESC code */
+	if (isalpha(*seq)) {
+		const char *s = color_sequence_from_colorname(seq);
+		char *p;
+
+		if (!s) {
+			DBG(SCHEME, ul_debug("unknown logical name: %s", seq));
+			rc = -EINVAL;
+			goto err;
+		}
+
+		p = strdup(s);
+		if (!p)
+			goto err;
+		free(seq);
+		seq = p;
+	}
+
+	/* enlarge the array */
+	if (cc->nschemes == cc->schemes_sz) {
+		void *tmp = realloc(cc->schemes, (cc->nschemes + 10)
+					* sizeof(struct ul_color_scheme));
+		if (!tmp)
+			goto err;
+		cc->schemes = tmp;
+		cc->schemes_sz = cc->nschemes + 10;
+	}
+
+	/* add a new item */
+	cs = &cc->schemes[cc->nschemes];
+	cs->seq = seq;
+	cs->name = strdup(name);
+	if (!cs->name)
+		goto err;
+
+	cc->nschemes++;
+	return 0;
+err:
+	if (cs) {
+		free(cs->seq);
+		free(cs->name);
+		cs->seq = cs->name = NULL;
+	} else
+		free(seq);
+	return rc;
+}
+
+/*
+ * Deallocates all regards to color schemes
+ */
+static void colors_free_schemes(struct ul_color_ctl *cc)
+{
+	size_t i;
+
+	DBG(SCHEME, ul_debug("free scheme"));
+
+	for (i = 0; i < cc->nschemes; i++) {
+		free(cc->schemes[i].name);
+		free(cc->schemes[i].seq);
+	}
+
+	free(cc->schemes);
+	cc->schemes = NULL;
+	cc->nschemes = 0;
+	cc->schemes_sz = 0;
+}
+
+/*
+ * The scheme configuration has to be sorted for bsearch
+ */
+static void colors_sort_schemes(struct ul_color_ctl *cc)
+{
+	if (!cc->nschemes)
+		return;
+
+	DBG(SCHEME, ul_debug("sort scheme"));
+
+	qsort(cc->schemes, cc->nschemes,
+	      sizeof(struct ul_color_scheme), cmp_scheme_name);
+}
+
+/*
+ * Returns just one color scheme
+ */
+static struct ul_color_scheme *colors_get_scheme(struct ul_color_ctl *cc,
+						 const char *name)
+{
+	struct ul_color_scheme key = { .name = (char *) name}, *res;
+
+	if (!cc || !name || !*name)
+		return NULL;
+
+	if (!cc->cs_configured) {
+		int rc = colors_read_schemes(cc);
+		if (rc)
+			return NULL;
+	}
+	if (!cc->nschemes)
+		return NULL;
+
+	DBG(SCHEME, ul_debug("search '%s'", name));
+
+	res = bsearch(&key, cc->schemes, cc->nschemes,
+				sizeof(struct ul_color_scheme),
+				cmp_scheme_name);
+
+	return res && res->seq ? res  : NULL;
+}
+
+/*
+ * Parses filenames in terminal-colors.d
+ */
+static int colors_read_configuration(struct ul_color_ctl *cc)
+{
+	int rc = -ENOENT;
+	char *dirname, buf[PATH_MAX];
+
+	cc->termname = getenv("TERM");
+
+	dirname = colors_get_homedir(buf, sizeof(buf));
+	if (dirname)
+		rc = colors_readdir(cc, dirname);		/* ~/.config */
+	if (rc == -EPERM || rc == -EACCES || rc == -ENOENT)
+		rc = colors_readdir(cc, _PATH_TERMCOLORS_DIR);	/* /etc */
+
+	cc->configured = 1;
+	return rc;
+}
+
+/*
+ * Reads terminal-colors.d/ scheme file into array schemes
+ */
+static int colors_read_schemes(struct ul_color_ctl *cc)
+{
+	int rc = 0;
+	FILE *f = NULL;
+	char buf[BUFSIZ],
+	     cn[129], seq[129];
+
+	if (!cc->configured)
+		rc = colors_read_configuration(cc);
+
+	cc->cs_configured = 1;
+
+	if (rc || !cc->sfile)
+		goto done;
+
+	DBG(SCHEME, ul_debug("reading file '%s'", cc->sfile));
+
+	f = fopen(cc->sfile, "r");
+	if (!f) {
+		rc = -errno;
+		goto done;
+	}
+
+	while (fgets(buf, sizeof(buf), f)) {
+		char *p = strchr(buf, '\n');
+
+		if (!p) {
+			if (feof(f))
+				p = strchr(buf, '\0');
+			else {
+				rc = -errno;
+				goto done;
+			}
+		}
+		*p = '\0';
+		p = (char *) skip_blank(buf);
+		if (*p == '\0' || *p == '#')
+			continue;
+
+		rc = sscanf(p, "%128[^ ] %128[^\n ]", cn, seq);
+		if (rc == 2 && *cn && *seq) {
+			rc = colors_add_scheme(cc, cn, seq);	/* set rc=0 on success */
+			if (rc)
+				goto done;
+		}
+	}
+	rc = 0;
+
+done:
+	if (f)
+		fclose(f);
+	colors_sort_schemes(cc);
+
+	return rc;
+}
+
+
+static void termcolors_init_debug(void)
+{
+	__UL_INIT_DEBUG(termcolors, TERMCOLORS_DEBUG_, 0, TERMINAL_COLORS_DEBUG);
+}
+
+/**
+ * colors_init:
+ * @mode: UL_COLORMODE_*
+ * @name: util argv[0]
+ *
+ * Initialize private color control struct and initialize the colors
+ * status. The color schemes are parsed on demand by colors_get_scheme().
+ *
+ * Returns: >0 on success.
+ */
+int colors_init(int mode, const char *name)
+{
+	int atty = -1;
+	struct ul_color_ctl *cc = &ul_colors;
+
+	cc->utilname = name;
+	cc->mode = mode;
+
+	termcolors_init_debug();
+
+	if (mode == UL_COLORMODE_UNDEF && (atty = isatty(STDOUT_FILENO))) {
+		int rc = colors_read_configuration(cc);
+		if (rc)
+			cc->mode = UL_COLORMODE_AUTO;
+		else {
+
+			/* evaluate scores */
+			if (cc->scores[UL_COLORFILE_DISABLE] >
+			    cc->scores[UL_COLORFILE_ENABLE])
+				cc->mode = UL_COLORMODE_NEVER;
+			else
+				cc->mode = UL_COLORMODE_AUTO;
+
+			atexit(colors_deinit);
+		}
+	}
+
+	switch (cc->mode) {
+	case UL_COLORMODE_AUTO:
+		cc->has_colors = atty == -1 ? isatty(STDOUT_FILENO) : atty;
+		break;
+	case UL_COLORMODE_ALWAYS:
+		cc->has_colors = 1;
+		break;
+	case UL_COLORMODE_NEVER:
+	default:
+		cc->has_colors = 0;
+	}
+
+	ON_DBG(CONF, colors_debug(cc));
+
+	return cc->has_colors;
+}
+
+/*
+ * Temporary disable colors (this setting is independent on terminal-colors.d/)
+ */
+void colors_off(void)
+{
+	ul_colors.disabled = 1;
+}
+
+/*
+ * Enable colors
+ */
+void colors_on(void)
+{
+	ul_colors.disabled = 0;
+}
+
+/*
+ * Is terminal-colors.d/ configured to use colors?
+ */
+int colors_wanted(void)
+{
+	return ul_colors.has_colors;
+}
+
+/*
+ * Enable @seq color
+ */
+void color_fenable(const char *seq, FILE *f)
+{
+	if (!ul_colors.disabled && ul_colors.has_colors && seq)
+		fputs(seq, f);
+}
+
+/*
+ * Returns escape sequence by logical @name, if undefined then returns @dflt.
+ */
+const char *color_scheme_get_sequence(const char *name, const char *dflt)
+{
+	struct ul_color_scheme *cs;
+
+	if (ul_colors.disabled || !ul_colors.has_colors)
+		return NULL;
+
+	cs = colors_get_scheme(&ul_colors, name);
+	return cs && cs->seq ? cs->seq : dflt;
+}
+
+/*
+ * Enable color by logical @name, if undefined enable @dflt.
+ */
+void color_scheme_fenable(const char *name, const char *dflt, FILE *f)
+{
+	const char *seq = color_scheme_get_sequence(name, dflt);
+
+	if (!seq)
+		return;
+	color_fenable(seq, f);
+}
+
+
+/*
+ * Disable previously enabled color
+ */
+void color_fdisable(FILE *f)
+{
+	if (!ul_colors.disabled && ul_colors.has_colors)
+		fputs(UL_COLOR_RESET, f);
+}
+
+/*
+ * Parses @str to return UL_COLORMODE_*
+ */
+int colormode_from_string(const char *str)
+{
+	size_t i;
+	static const char *modes[] = {
+		[UL_COLORMODE_AUTO]   = "auto",
+		[UL_COLORMODE_NEVER]  = "never",
+		[UL_COLORMODE_ALWAYS] = "always",
+		[UL_COLORMODE_UNDEF] = ""
+	};
+
+	if (!str || !*str)
+		return -EINVAL;
+
+	assert(ARRAY_SIZE(modes) == __UL_NCOLORMODES);
+
+	for (i = 0; i < ARRAY_SIZE(modes); i++) {
+		if (strcasecmp(str, modes[i]) == 0)
+			return i;
+	}
+
+	return -EINVAL;
+}
+
+/*
+ * Parses @str and exit(EXIT_FAILURE) on error
+ */
+int colormode_or_err(const char *str, const char *errmsg)
+{
+	const char *p = str && *str == '=' ? str + 1 : str;
+	int colormode;
+
+	colormode = colormode_from_string(p);
+	if (colormode < 0)
+		errx(EXIT_FAILURE, "%s: '%s'", errmsg, p);
+
+	return colormode;
+}
+
+#ifdef TEST_PROGRAM
+# include <getopt.h>
+int main(int argc, char *argv[])
+{
+	static const struct option longopts[] = {
+		{ "mode",	required_argument, 0, 'm' },
+		{ "color",	required_argument, 0, 'c' },
+		{ "color-scheme", required_argument, 0, 'C' },
+		{ "name",	required_argument, 0, 'n' },
+		{ NULL, 0, 0, 0 }
+	};
+	int c, mode = UL_COLORMODE_UNDEF;	/* default */
+	const char *color = "red", *name = NULL, *color_scheme = NULL;
+	const char *seq = NULL;
+
+	while ((c = getopt_long(argc, argv, "C:c:m:n:", longopts, NULL)) != -1) {
+		switch (c) {
+		case 'c':
+			color = optarg;
+			break;
+		case 'C':
+			color_scheme = optarg;
+			break;
+		case 'm':
+			mode = colormode_or_err(optarg, "unsupported color mode");
+			break;
+		case 'n':
+			name = optarg;
+			break;
+		default:
+			fprintf(stderr, "usage: %s [options]\n"
+			" -m, --mode <auto|never|always>  default is undefined\n"
+			" -c, --color <red|blue|...>      color for the test message\n"
+			" -C, --color-scheme <name>       color for the test message\n"
+			" -n, --name <utilname>           util name\n",
+			program_invocation_short_name);
+			return EXIT_FAILURE;
+		}
+	}
+
+	colors_init(mode, name ? name : program_invocation_short_name);
+
+	seq = color_sequence_from_colorname(color);
+
+	if (color_scheme)
+		color_scheme_enable(color_scheme, seq);
+	else
+		color_enable(seq);
+	printf("Hello World!");
+	color_disable();
+	fputc('\n', stdout);
+
+	return EXIT_SUCCESS;
+}
+#endif
+
diff --git a/libblkid/cpuset.c b/libblkid/lib/cpuset.c
similarity index 99%
rename from libblkid/cpuset.c
rename to libblkid/lib/cpuset.c
index e5b6b9d..d715720 100644
--- a/libblkid/cpuset.c
+++ b/libblkid/lib/cpuset.c
@@ -388,6 +388,7 @@
 	printf("[%s]\n", cpulist_create(buf, buflen, set, setsize));
 
 	free(buf);
+	free(mask);
 	free(range);
 	cpuset_free(set);
 
diff --git a/libblkid/crc32.c b/libblkid/lib/crc32.c
similarity index 99%
rename from libblkid/crc32.c
rename to libblkid/lib/crc32.c
index eaaa06a..be98f1a 100644
--- a/libblkid/crc32.c
+++ b/libblkid/lib/crc32.c
@@ -108,8 +108,10 @@
 	uint32_t crc = seed;
 	const unsigned char *p = buf;
 
-	while(len-- > 0)
+	while (len) {
 		crc = crc32_tab[(crc ^ *p++) & 0xff] ^ (crc >> 8);
+		len--;
+	}
 
 	return crc;
 }
diff --git a/libblkid/lib/crc64.c b/libblkid/lib/crc64.c
new file mode 100644
index 0000000..0be78e6
--- /dev/null
+++ b/libblkid/lib/crc64.c
@@ -0,0 +1,109 @@
+#include "crc64.h"
+
+static const uint64_t crc64_tab[256] = {
+	0x0000000000000000ULL, 0x42F0E1EBA9EA3693ULL, 0x85E1C3D753D46D26ULL,
+	0xC711223CFA3E5BB5ULL, 0x493366450E42ECDFULL, 0x0BC387AEA7A8DA4CULL,
+	0xCCD2A5925D9681F9ULL, 0x8E224479F47CB76AULL, 0x9266CC8A1C85D9BEULL,
+	0xD0962D61B56FEF2DULL, 0x17870F5D4F51B498ULL, 0x5577EEB6E6BB820BULL,
+	0xDB55AACF12C73561ULL, 0x99A54B24BB2D03F2ULL, 0x5EB4691841135847ULL,
+	0x1C4488F3E8F96ED4ULL, 0x663D78FF90E185EFULL, 0x24CD9914390BB37CULL,
+	0xE3DCBB28C335E8C9ULL, 0xA12C5AC36ADFDE5AULL, 0x2F0E1EBA9EA36930ULL,
+	0x6DFEFF5137495FA3ULL, 0xAAEFDD6DCD770416ULL, 0xE81F3C86649D3285ULL,
+	0xF45BB4758C645C51ULL, 0xB6AB559E258E6AC2ULL, 0x71BA77A2DFB03177ULL,
+	0x334A9649765A07E4ULL, 0xBD68D2308226B08EULL, 0xFF9833DB2BCC861DULL,
+	0x388911E7D1F2DDA8ULL, 0x7A79F00C7818EB3BULL, 0xCC7AF1FF21C30BDEULL,
+	0x8E8A101488293D4DULL, 0x499B3228721766F8ULL, 0x0B6BD3C3DBFD506BULL,
+	0x854997BA2F81E701ULL, 0xC7B97651866BD192ULL, 0x00A8546D7C558A27ULL,
+	0x4258B586D5BFBCB4ULL, 0x5E1C3D753D46D260ULL, 0x1CECDC9E94ACE4F3ULL,
+	0xDBFDFEA26E92BF46ULL, 0x990D1F49C77889D5ULL, 0x172F5B3033043EBFULL,
+	0x55DFBADB9AEE082CULL, 0x92CE98E760D05399ULL, 0xD03E790CC93A650AULL,
+	0xAA478900B1228E31ULL, 0xE8B768EB18C8B8A2ULL, 0x2FA64AD7E2F6E317ULL,
+	0x6D56AB3C4B1CD584ULL, 0xE374EF45BF6062EEULL, 0xA1840EAE168A547DULL,
+	0x66952C92ECB40FC8ULL, 0x2465CD79455E395BULL, 0x3821458AADA7578FULL,
+	0x7AD1A461044D611CULL, 0xBDC0865DFE733AA9ULL, 0xFF3067B657990C3AULL,
+	0x711223CFA3E5BB50ULL, 0x33E2C2240A0F8DC3ULL, 0xF4F3E018F031D676ULL,
+	0xB60301F359DBE0E5ULL, 0xDA050215EA6C212FULL, 0x98F5E3FE438617BCULL,
+	0x5FE4C1C2B9B84C09ULL, 0x1D14202910527A9AULL, 0x93366450E42ECDF0ULL,
+	0xD1C685BB4DC4FB63ULL, 0x16D7A787B7FAA0D6ULL, 0x5427466C1E109645ULL,
+	0x4863CE9FF6E9F891ULL, 0x0A932F745F03CE02ULL, 0xCD820D48A53D95B7ULL,
+	0x8F72ECA30CD7A324ULL, 0x0150A8DAF8AB144EULL, 0x43A04931514122DDULL,
+	0x84B16B0DAB7F7968ULL, 0xC6418AE602954FFBULL, 0xBC387AEA7A8DA4C0ULL,
+	0xFEC89B01D3679253ULL, 0x39D9B93D2959C9E6ULL, 0x7B2958D680B3FF75ULL,
+	0xF50B1CAF74CF481FULL, 0xB7FBFD44DD257E8CULL, 0x70EADF78271B2539ULL,
+	0x321A3E938EF113AAULL, 0x2E5EB66066087D7EULL, 0x6CAE578BCFE24BEDULL,
+	0xABBF75B735DC1058ULL, 0xE94F945C9C3626CBULL, 0x676DD025684A91A1ULL,
+	0x259D31CEC1A0A732ULL, 0xE28C13F23B9EFC87ULL, 0xA07CF2199274CA14ULL,
+	0x167FF3EACBAF2AF1ULL, 0x548F120162451C62ULL, 0x939E303D987B47D7ULL,
+	0xD16ED1D631917144ULL, 0x5F4C95AFC5EDC62EULL, 0x1DBC74446C07F0BDULL,
+	0xDAAD56789639AB08ULL, 0x985DB7933FD39D9BULL, 0x84193F60D72AF34FULL,
+	0xC6E9DE8B7EC0C5DCULL, 0x01F8FCB784FE9E69ULL, 0x43081D5C2D14A8FAULL,
+	0xCD2A5925D9681F90ULL, 0x8FDAB8CE70822903ULL, 0x48CB9AF28ABC72B6ULL,
+	0x0A3B7B1923564425ULL, 0x70428B155B4EAF1EULL, 0x32B26AFEF2A4998DULL,
+	0xF5A348C2089AC238ULL, 0xB753A929A170F4ABULL, 0x3971ED50550C43C1ULL,
+	0x7B810CBBFCE67552ULL, 0xBC902E8706D82EE7ULL, 0xFE60CF6CAF321874ULL,
+	0xE224479F47CB76A0ULL, 0xA0D4A674EE214033ULL, 0x67C58448141F1B86ULL,
+	0x253565A3BDF52D15ULL, 0xAB1721DA49899A7FULL, 0xE9E7C031E063ACECULL,
+	0x2EF6E20D1A5DF759ULL, 0x6C0603E6B3B7C1CAULL, 0xF6FAE5C07D3274CDULL,
+	0xB40A042BD4D8425EULL, 0x731B26172EE619EBULL, 0x31EBC7FC870C2F78ULL,
+	0xBFC9838573709812ULL, 0xFD39626EDA9AAE81ULL, 0x3A28405220A4F534ULL,
+	0x78D8A1B9894EC3A7ULL, 0x649C294A61B7AD73ULL, 0x266CC8A1C85D9BE0ULL,
+	0xE17DEA9D3263C055ULL, 0xA38D0B769B89F6C6ULL, 0x2DAF4F0F6FF541ACULL,
+	0x6F5FAEE4C61F773FULL, 0xA84E8CD83C212C8AULL, 0xEABE6D3395CB1A19ULL,
+	0x90C79D3FEDD3F122ULL, 0xD2377CD44439C7B1ULL, 0x15265EE8BE079C04ULL,
+	0x57D6BF0317EDAA97ULL, 0xD9F4FB7AE3911DFDULL, 0x9B041A914A7B2B6EULL,
+	0x5C1538ADB04570DBULL, 0x1EE5D94619AF4648ULL, 0x02A151B5F156289CULL,
+	0x4051B05E58BC1E0FULL, 0x87409262A28245BAULL, 0xC5B073890B687329ULL,
+	0x4B9237F0FF14C443ULL, 0x0962D61B56FEF2D0ULL, 0xCE73F427ACC0A965ULL,
+	0x8C8315CC052A9FF6ULL, 0x3A80143F5CF17F13ULL, 0x7870F5D4F51B4980ULL,
+	0xBF61D7E80F251235ULL, 0xFD913603A6CF24A6ULL, 0x73B3727A52B393CCULL,
+	0x31439391FB59A55FULL, 0xF652B1AD0167FEEAULL, 0xB4A25046A88DC879ULL,
+	0xA8E6D8B54074A6ADULL, 0xEA16395EE99E903EULL, 0x2D071B6213A0CB8BULL,
+	0x6FF7FA89BA4AFD18ULL, 0xE1D5BEF04E364A72ULL, 0xA3255F1BE7DC7CE1ULL,
+	0x64347D271DE22754ULL, 0x26C49CCCB40811C7ULL, 0x5CBD6CC0CC10FAFCULL,
+	0x1E4D8D2B65FACC6FULL, 0xD95CAF179FC497DAULL, 0x9BAC4EFC362EA149ULL,
+	0x158E0A85C2521623ULL, 0x577EEB6E6BB820B0ULL, 0x906FC95291867B05ULL,
+	0xD29F28B9386C4D96ULL, 0xCEDBA04AD0952342ULL, 0x8C2B41A1797F15D1ULL,
+	0x4B3A639D83414E64ULL, 0x09CA82762AAB78F7ULL, 0x87E8C60FDED7CF9DULL,
+	0xC51827E4773DF90EULL, 0x020905D88D03A2BBULL, 0x40F9E43324E99428ULL,
+	0x2CFFE7D5975E55E2ULL, 0x6E0F063E3EB46371ULL, 0xA91E2402C48A38C4ULL,
+	0xEBEEC5E96D600E57ULL, 0x65CC8190991CB93DULL, 0x273C607B30F68FAEULL,
+	0xE02D4247CAC8D41BULL, 0xA2DDA3AC6322E288ULL, 0xBE992B5F8BDB8C5CULL,
+	0xFC69CAB42231BACFULL, 0x3B78E888D80FE17AULL, 0x7988096371E5D7E9ULL,
+	0xF7AA4D1A85996083ULL, 0xB55AACF12C735610ULL, 0x724B8ECDD64D0DA5ULL,
+	0x30BB6F267FA73B36ULL, 0x4AC29F2A07BFD00DULL, 0x08327EC1AE55E69EULL,
+	0xCF235CFD546BBD2BULL, 0x8DD3BD16FD818BB8ULL, 0x03F1F96F09FD3CD2ULL,
+	0x41011884A0170A41ULL, 0x86103AB85A2951F4ULL, 0xC4E0DB53F3C36767ULL,
+	0xD8A453A01B3A09B3ULL, 0x9A54B24BB2D03F20ULL, 0x5D45907748EE6495ULL,
+	0x1FB5719CE1045206ULL, 0x919735E51578E56CULL, 0xD367D40EBC92D3FFULL,
+	0x1476F63246AC884AULL, 0x568617D9EF46BED9ULL, 0xE085162AB69D5E3CULL,
+	0xA275F7C11F7768AFULL, 0x6564D5FDE549331AULL, 0x279434164CA30589ULL,
+	0xA9B6706FB8DFB2E3ULL, 0xEB46918411358470ULL, 0x2C57B3B8EB0BDFC5ULL,
+	0x6EA7525342E1E956ULL, 0x72E3DAA0AA188782ULL, 0x30133B4B03F2B111ULL,
+	0xF7021977F9CCEAA4ULL, 0xB5F2F89C5026DC37ULL, 0x3BD0BCE5A45A6B5DULL,
+	0x79205D0E0DB05DCEULL, 0xBE317F32F78E067BULL, 0xFCC19ED95E6430E8ULL,
+	0x86B86ED5267CDBD3ULL, 0xC4488F3E8F96ED40ULL, 0x0359AD0275A8B6F5ULL,
+	0x41A94CE9DC428066ULL, 0xCF8B0890283E370CULL, 0x8D7BE97B81D4019FULL,
+	0x4A6ACB477BEA5A2AULL, 0x089A2AACD2006CB9ULL, 0x14DEA25F3AF9026DULL,
+	0x562E43B4931334FEULL, 0x913F6188692D6F4BULL, 0xD3CF8063C0C759D8ULL,
+	0x5DEDC41A34BBEEB2ULL, 0x1F1D25F19D51D821ULL, 0xD80C07CD676F8394ULL,
+	0x9AFCE626CE85B507ULL
+};
+
+/*
+ * This a generic crc64() function, it takes seed as an argument,
+ * and does __not__ xor at the end. Then individual users can do
+ * whatever they need.
+ */
+uint64_t crc64(uint64_t seed, const unsigned char *data, size_t len)
+{
+	uint64_t crc = seed;
+
+	while (len) {
+		int i = ((int) (crc >> 56) ^ *data++) & 0xFF;
+		crc = crc64_tab[i] ^ (crc << 8);
+		len--;
+	}
+
+	return crc;
+}
+
diff --git a/libblkid/env.c b/libblkid/lib/env.c
similarity index 100%
rename from libblkid/env.c
rename to libblkid/lib/env.c
diff --git a/libblkid/lib/exec_shell.c b/libblkid/lib/exec_shell.c
new file mode 100644
index 0000000..2b26364
--- /dev/null
+++ b/libblkid/lib/exec_shell.c
@@ -0,0 +1,46 @@
+/*
+ * exec_shell() - launch a shell, else exit!
+ *
+ * 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, 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "nls.h"
+#include "c.h"
+#include "xalloc.h"
+
+#include "exec_shell.h"
+
+#define DEFAULT_SHELL "/bin/sh"
+
+void exec_shell(void)
+{
+	const char *shell = getenv("SHELL"), *shell_basename;
+	char *arg0;
+	if (!shell)
+		shell = DEFAULT_SHELL;
+
+	shell_basename = basename(shell);
+	arg0 = xmalloc(strlen(shell_basename) + 2);
+	arg0[0] = '-';
+	strcpy(arg0 + 1, shell_basename);
+
+	execl(shell, arg0, NULL);
+	err(EXIT_FAILURE, _("failed to execute %s"), shell);
+}
diff --git a/libblkid/fileutils.c b/libblkid/lib/fileutils.c
similarity index 63%
rename from libblkid/fileutils.c
rename to libblkid/lib/fileutils.c
index ebfb128..4e884d3 100644
--- a/libblkid/fileutils.c
+++ b/libblkid/lib/fileutils.c
@@ -4,6 +4,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <paths.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <sys/time.h>
@@ -12,9 +13,7 @@
 #include "c.h"
 #include "fileutils.h"
 #include "pathnames.h"
-#include "xalloc.h"
 
-#define _PATH_TMP "/tmp"
 /* Create open temporary file in safe way.  Please notice that the
  * file permissions are -rw------- by default. */
 int xmkstemp(char **tmpname, char *dir)
@@ -22,7 +21,7 @@
 	char *localtmp;
 	char *tmpenv;
 	mode_t old_mode;
-	int fd;
+	int fd, rc;
 
 	/* Some use cases must be capable of being moved atomically
 	 * with rename(2), which is the reason why dir is here.  */
@@ -32,11 +31,15 @@
 		tmpenv = getenv("TMPDIR");
 
 	if (tmpenv)
-		xasprintf(&localtmp, "%s/%s.XXXXXX", tmpenv,
+		rc = asprintf(&localtmp, "%s/%s.XXXXXX", tmpenv,
 			  program_invocation_short_name);
 	else
-		xasprintf(&localtmp, "%s/%s.XXXXXX", _PATH_TMP,
+		rc = asprintf(&localtmp, "%s/%s.XXXXXX", _PATH_TMP,
 			  program_invocation_short_name);
+
+	if (rc < 0)
+		return -1;
+
 	old_mode = umask(077);
 	fd = mkstemp(localtmp);
 	umask(old_mode);
@@ -82,3 +85,51 @@
 	return EXIT_FAILURE;
 }
 #endif
+
+
+int mkdir_p(const char *path, mode_t mode)
+{
+	char *p, *dir;
+	int rc = 0;
+
+	if (!path || !*path)
+		return -EINVAL;
+
+	dir = p = strdup(path);
+	if (!dir)
+		return -ENOMEM;
+
+	if (*p == '/')
+		p++;
+
+	while (p && *p) {
+		char *e = strchr(p, '/');
+		if (e)
+			*e = '\0';
+		if (*p) {
+			rc = mkdir(dir, mode);
+			if (rc && errno != EEXIST)
+				break;
+			rc = 0;
+		}
+		if (!e)
+			break;
+		*e = '/';
+		p = e + 1;
+	}
+
+	free(dir);
+	return rc;
+}
+
+/* returns basename and keeps dirname in the @path, if @path is "/" (root)
+ * then returns empty string */
+char *stripoff_last_component(char *path)
+{
+	char *p = path ? strrchr(path, '/') : NULL;
+
+	if (!p)
+		return NULL;
+	*p = '\0';
+	return p + 1;
+}
diff --git a/libblkid/ismounted.c b/libblkid/lib/ismounted.c
similarity index 97%
rename from libblkid/ismounted.c
rename to libblkid/lib/ismounted.c
index d9f1f57..8099bd7 100644
--- a/libblkid/ismounted.c
+++ b/libblkid/lib/ismounted.c
@@ -156,7 +156,7 @@
 is_root:
 #define TEST_FILE "/.ismount-test-file"
 		*mount_flags |= MF_ISROOT;
-		fd = open(TEST_FILE, O_RDWR|O_CREAT, 0600);
+		fd = open(TEST_FILE, O_RDWR|O_CREAT|O_CLOEXEC, 0600);
 		if (fd < 0) {
 			if (errno == EROFS)
 				*mount_flags |= MF_READONLY;
@@ -317,7 +317,8 @@
 
 	if (is_swap_device(device)) {
 		*mount_flags = MF_MOUNTED | MF_SWAP;
-		strncpy(mtpt, "<swap>", mtlen);
+		if (mtpt && mtlen)
+			strncpy(mtpt, "[SWAP]", mtlen);
 	} else {
 #ifdef HAVE_MNTENT_H
 		retval = check_mntent(device, mount_flags, mtpt, mtlen);
@@ -339,7 +340,7 @@
 	if ((stat(device, &st_buf) != 0) ||
 	    !S_ISBLK(st_buf.st_mode))
 		return 0;
-	fd = open(device, O_RDONLY | O_EXCL);
+	fd = open(device, O_RDONLY|O_EXCL|O_CLOEXEC);
 	if (fd < 0) {
 		if (errno == EBUSY)
 			*mount_flags |= MF_BUSY;
diff --git a/libblkid/langinfo.c b/libblkid/lib/langinfo.c
similarity index 100%
rename from libblkid/langinfo.c
rename to libblkid/lib/langinfo.c
diff --git a/libblkid/linux_version.c b/libblkid/lib/linux_version.c
similarity index 100%
rename from libblkid/linux_version.c
rename to libblkid/lib/linux_version.c
diff --git a/libblkid/loopdev.c b/libblkid/lib/loopdev.c
similarity index 75%
rename from libblkid/loopdev.c
rename to libblkid/lib/loopdev.c
index a25a2fa..09b9bbf 100644
--- a/libblkid/loopdev.c
+++ b/libblkid/lib/loopdev.c
@@ -41,33 +41,31 @@
 #include "loopdev.h"
 #include "canonicalize.h"
 #include "at.h"
+#include "blkdev.h"
+#include "debug.h"
 
-#define CONFIG_LOOPDEV_DEBUG
+/*
+ * Debug stuff (based on include/debug.h)
+ */
+UL_DEBUG_DEFINE_MASK(loopdev);
+UL_DEBUG_DEFINE_MASKNAMES(loopdev) = UL_DEBUG_EMPTY_MASKNAMES;
 
-#ifdef CONFIG_LOOPDEV_DEBUG
-# include <stdarg.h>
+#define LOOPDEV_DEBUG_INIT	(1 << 1)
+#define LOOPDEV_DEBUG_CXT	(1 << 2)
+#define LOOPDEV_DEBUG_ITER	(1 << 3)
+#define LOOPDEV_DEBUG_SETUP	(1 << 4)
+#define SFDISKPROG_DEBUG_ALL	0xFFFF
 
-# define DBG(l,x)	do { \
-				if ((l)->debug) {\
-					fprintf(stderr, "loopdev:  [%p]: ", (l)); \
-					x; \
-				} \
-			} while(0)
+#define DBG(m, x)       __UL_DBG(loopdev, LOOPDEV_DEBUG_, m, x)
+#define ON_DBG(m, x)    __UL_DBG_CALL(loopdev, LOOPDEV_DEBUG_, m, x)
 
-static inline void __attribute__ ((__format__ (__printf__, 1, 2)))
-loopdev_debug(const char *mesg, ...)
+static void loopdev_init_debug(void)
 {
-	va_list ap;
-	va_start(ap, mesg);
-	vfprintf(stderr, mesg, ap);
-	va_end(ap);
-	fputc('\n', stderr);
+	if (loopdev_debug_mask)
+		return;
+	__UL_INIT_DEBUG(loopdev, LOOPDEV_DEBUG_, 0, LOOPDEV_DEBUG);
 }
 
-#else /* !CONFIG_LOOPDEV_DEBUG */
-# define DBG(m,x) do { ; } while(0)
-#endif
-
 /*
  * see loopcxt_init()
  */
@@ -83,6 +81,8 @@
  * names ("loop<N>") are converted to the path (/dev/loop<N> or to
  * /dev/loop/<N>)
  *
+ * This sets the device name, but does not check if the device exists!
+ *
  * Returns: <0 on error, 0 on success
  */
 int loopcxt_set_device(struct loopdev_cxt *lc, const char *device)
@@ -92,7 +92,7 @@
 
 	if (lc->fd >= 0) {
 		close(lc->fd);
-		DBG(lc, loopdev_debug("closing old open fd"));
+		DBG(CXT, ul_debugobj(lc, "closing old open fd"));
 	}
 	lc->fd = -1;
 	lc->mode = 0;
@@ -119,7 +119,7 @@
 			strncpy(lc->device, device, sizeof(lc->device));
 			lc->device[sizeof(lc->device) - 1] = '\0';
 		}
-		DBG(lc, loopdev_debug("%s successfully assigned", device));
+		DBG(CXT, ul_debugobj(lc, "%s name assigned", device));
 	}
 
 	sysfs_deinit(&lc->sysfs);
@@ -160,12 +160,12 @@
 	if (!lc)
 		return -EINVAL;
 
+	loopdev_init_debug();
+	DBG(CXT, ul_debugobj(lc, "initialize context"));
+
 	memcpy(lc, &dummy, sizeof(dummy));
 	lc->flags = flags;
 
-	if (getenv("LOOPDEV_DEBUG"))
-		loopcxt_enable_debug(lc, TRUE);
-
 	rc = loopcxt_set_device(lc, NULL);
 	if (rc)
 		return rc;
@@ -173,7 +173,7 @@
 	if (stat(_PATH_SYS_BLOCK, &st) || !S_ISDIR(st.st_mode)) {
 		lc->flags |= LOOPDEV_FL_NOSYSFS;
 		lc->flags &= ~LOOPDEV_FL_NOIOCTL;
-		DBG(lc, loopdev_debug("init: disable /sys usage"));
+		DBG(CXT, ul_debugobj(lc, "init: disable /sys usage"));
 	}
 
 	if (!(lc->flags & LOOPDEV_FL_NOSYSFS) &&
@@ -182,12 +182,12 @@
 		 * Use only sysfs for basic information about loop devices
 		 */
 		lc->flags |= LOOPDEV_FL_NOIOCTL;
-		DBG(lc, loopdev_debug("init: ignore ioctls"));
+		DBG(CXT, ul_debugobj(lc, "init: ignore ioctls"));
 	}
 
 	if (!(lc->flags & LOOPDEV_FL_CONTROL) && !stat(_PATH_DEV_LOOPCTL, &st)) {
 		lc->flags |= LOOPDEV_FL_CONTROL;
-		DBG(lc, loopdev_debug("init: loop-control detected "));
+		DBG(CXT, ul_debugobj(lc, "init: loop-control detected "));
 	}
 
 	return 0;
@@ -205,7 +205,7 @@
 	if (!lc)
 		return;
 
-	DBG(lc, loopdev_debug("de-initialize"));
+	DBG(CXT, ul_debugobj(lc, "de-initialize"));
 
 	free(lc->filename);
 	lc->filename = NULL;
@@ -218,24 +218,12 @@
 
 /*
  * @lc: context
- * @enable: TRUE/FALSE
- *
- * Enabled/disables debug messages
- */
-void loopcxt_enable_debug(struct loopdev_cxt *lc, int enable)
-{
-	if (lc)
-		lc->debug = enable ? 1 : 0;
-}
-
-/*
- * @lc: context
  *
  * Returns newly allocated device path.
  */
 char *loopcxt_strdup_device(struct loopdev_cxt *lc)
 {
-	if (!lc || !lc->device || !*lc->device)
+	if (!lc || !*lc->device)
 		return NULL;
 	return strdup(lc->device);
 }
@@ -247,7 +235,7 @@
  */
 const char *loopcxt_get_device(struct loopdev_cxt *lc)
 {
-	return lc && lc->device && *lc->device ? lc->device : NULL;
+	return lc && *lc->device ? lc->device : NULL;
 }
 
 /*
@@ -263,11 +251,11 @@
 	if (!lc->sysfs.devno) {
 		dev_t devno = sysfs_devname_to_devno(lc->device, NULL);
 		if (!devno) {
-			DBG(lc, loopdev_debug("sysfs: failed devname to devno"));
+			DBG(CXT, ul_debugobj(lc, "sysfs: failed devname to devno"));
 			return NULL;
 		}
 		if (sysfs_init(&lc->sysfs, devno, NULL)) {
-			DBG(lc, loopdev_debug("sysfs: init failed"));
+			DBG(CXT, ul_debugobj(lc, "sysfs: init failed"));
 			return NULL;
 		}
 	}
@@ -289,10 +277,9 @@
 
 	if (lc->fd < 0) {
 		lc->mode = lc->flags & LOOPDEV_FL_RDWR ? O_RDWR : O_RDONLY;
-		lc->fd = open(lc->device, lc->mode);
-		DBG(lc, loopdev_debug("open %s [%s]: %s", lc->device,
-				lc->flags & LOOPDEV_FL_RDWR ? "rw" : "ro",
-				lc->fd < 0 ? "failed" : "ok"));
+		lc->fd = open(lc->device, lc->mode | O_CLOEXEC);
+		DBG(CXT, ul_debugobj(lc, "open %s [%s]: %m", lc->device,
+				lc->flags & LOOPDEV_FL_RDWR ? "rw" : "ro"));
 	}
 	return lc->fd;
 }
@@ -323,9 +310,9 @@
 	if (!lc)
 		return -EINVAL;
 
-	DBG(lc, loopdev_debug("iter: initialize"));
 
 	iter = &lc->iter;
+	DBG(ITER, ul_debugobj(iter, "initialize"));
 
 	/* always zeroize
 	 */
@@ -359,9 +346,8 @@
 	if (!lc)
 		return -EINVAL;
 
-	DBG(lc, loopdev_debug("iter: de-initialize"));
-
 	iter = &lc->iter;
+	DBG(ITER, ul_debugobj(iter, "de-initialize"));
 
 	free(iter->minors);
 	if (iter->proc)
@@ -394,6 +380,13 @@
 	    !(lc->iter.flags & LOOPITER_FL_FREE))
 		return 0;	/* caller does not care about device status */
 
+	if (!is_loopdev(lc->device)) {
+		DBG(ITER, ul_debugobj(&lc->iter, "%s does not exist", lc->device));
+		return -errno;
+	}
+
+	DBG(ITER, ul_debugobj(&lc->iter, "%s exist", lc->device));
+
 	used = loopcxt_get_offset(lc, NULL) == 0;
 
 	if ((lc->iter.flags & LOOPITER_FL_USED) && used)
@@ -402,7 +395,8 @@
 	if ((lc->iter.flags & LOOPITER_FL_FREE) && !used)
 		return 0;
 
-	DBG(lc, loopdev_debug("iter: unset device"));
+	DBG(ITER, ul_debugobj(&lc->iter, "failed to use %s device", lc->device));
+
 	ignore_result( loopcxt_set_device(lc, NULL) );
 	return 1;
 }
@@ -426,6 +420,9 @@
 
 	if (!dirname || !ary)
 		return 0;
+
+	DBG(ITER, ul_debug("scan dir: %s", dirname));
+
 	dir = opendir(dirname);
 	if (!dir)
 		return 0;
@@ -449,6 +446,7 @@
 			/* /dev/loop/<N> */
 			char *end = NULL;
 
+			errno = 0;
 			n = strtol(d->d_name, &end, 10);
 			if (d->d_name == end || (end && *end) || errno)
 				continue;
@@ -489,7 +487,7 @@
 	struct loopdev_iter *iter = &lc->iter;
 	char buf[BUFSIZ];
 
-	DBG(lc, loopdev_debug("iter: scan /proc/partitions"));
+	DBG(ITER, ul_debugobj(iter, "scan /proc/partitions"));
 
 	if (!iter->proc)
 		iter->proc = fopen(_PATH_PROC_PARTITIONS, "r");
@@ -505,7 +503,7 @@
 			   &m, name) != 2 || m != LOOPDEV_MAJOR)
 			continue;
 
-		DBG(lc, loopdev_debug("iter: check %s", name));
+		DBG(ITER, ul_debugobj(iter, "checking %s", name));
 
 		if (loopiter_set_device(lc, name) == 0)
 			return 0;
@@ -526,7 +524,7 @@
 	struct dirent *d;
 	int fd;
 
-	DBG(lc, loopdev_debug("iter: scan /sys/block"));
+	DBG(ITER, ul_debugobj(iter, "scanning /sys/block"));
 
 	if (!iter->sysblock)
 		iter->sysblock = opendir(_PATH_SYS_BLOCK);
@@ -540,7 +538,7 @@
 		char name[256];
 		struct stat st;
 
-		DBG(lc, loopdev_debug("iter: check %s", d->d_name));
+		DBG(ITER, ul_debugobj(iter, "check %s", d->d_name));
 
 		if (strcmp(d->d_name, ".") == 0
 		    || strcmp(d->d_name, "..") == 0
@@ -572,12 +570,13 @@
 	if (!lc)
 		return -EINVAL;
 
-	DBG(lc, loopdev_debug("iter: next"));
 
 	iter = &lc->iter;
 	if (iter->done)
 		return 1;
 
+	DBG(ITER, ul_debugobj(iter, "next"));
+
 	/* A) Look for used loop devices in /proc/partitions ("losetup -a" only)
 	 */
 	if (iter->flags & LOOPITER_FL_USED) {
@@ -596,7 +595,7 @@
 	 *    of loop devices). This is enough for 99% of all cases.
 	 */
 	if (iter->default_check) {
-		DBG(lc, loopdev_debug("iter: next: default check"));
+		DBG(ITER, ul_debugobj(iter, "next: default check"));
 		for (++iter->ncur; iter->ncur < LOOPDEV_DEFAULT_NNODES;
 							iter->ncur++) {
 			char name[16];
@@ -611,7 +610,7 @@
 	/* C) the worst possibility, scan whole /dev or /dev/loop/<N>
 	 */
 	if (!iter->minors) {
-		DBG(lc, loopdev_debug("iter: next: scan /dev"));
+		DBG(ITER, ul_debugobj(iter, "next: scanning /dev"));
 		iter->nminors = (lc->flags & LOOPDEV_FL_DEVSUBDIR) ?
 			loop_scandir(_PATH_DEV_LOOP, &iter->minors, 0) :
 			loop_scandir(_PATH_DEV, &iter->minors, 1);
@@ -653,8 +652,11 @@
 {
 	int fd;
 
-	if (!lc || lc->info_failed)
+	if (!lc || lc->info_failed) {
+		errno = EINVAL;
 		return NULL;
+	}
+	errno = 0;
 	if (lc->has_info)
 		return &lc->info;
 
@@ -665,13 +667,13 @@
 	if (ioctl(fd, LOOP_GET_STATUS64, &lc->info) == 0) {
 		lc->has_info = 1;
 		lc->info_failed = 0;
-		DBG(lc, loopdev_debug("reading loop_info64 OK"));
+		DBG(CXT, ul_debugobj(lc, "reading loop_info64 OK"));
 		return &lc->info;
-	} else {
-		lc->info_failed = 1;
-		DBG(lc, loopdev_debug("reading loop_info64 FAILED"));
 	}
 
+	lc->info_failed = 1;
+	DBG(CXT, ul_debugobj(lc, "reading loop_info64 FAILED"));
+
 	return NULL;
 }
 
@@ -703,7 +705,7 @@
 		}
 	}
 
-	DBG(lc, loopdev_debug("get_backing_file [%s]", res));
+	DBG(CXT, ul_debugobj(lc, "get_backing_file [%s]", res));
 	return res;
 }
 
@@ -727,10 +729,11 @@
 			if (offset)
 				*offset = lo->lo_offset;
 			rc = 0;
-		}
+		} else
+			rc = -errno;
 	}
 
-	DBG(lc, loopdev_debug("get_offset [rc=%d]", rc));
+	DBG(CXT, ul_debugobj(lc, "get_offset [rc=%d]", rc));
 	return rc;
 }
 
@@ -754,10 +757,11 @@
 			if (size)
 				*size = lo->lo_sizelimit;
 			rc = 0;
-		}
+		} else
+			rc = -errno;
 	}
 
-	DBG(lc, loopdev_debug("get_sizelimit [rc=%d]", rc));
+	DBG(CXT, ul_debugobj(lc, "get_sizelimit [rc=%d]", rc));
 	return rc;
 }
 
@@ -772,14 +776,17 @@
 int loopcxt_get_encrypt_type(struct loopdev_cxt *lc, uint32_t *type)
 {
 	struct loop_info64 *lo = loopcxt_get_info(lc);
-	int rc = -EINVAL;
+	int rc;
 
+	/* not provided by sysfs */
 	if (lo) {
 		if (type)
 			*type = lo->lo_encrypt_type;
 		rc = 0;
-	}
-	DBG(lc, loopdev_debug("get_encrypt_type [rc=%d]", rc));
+	} else
+		rc = -errno;
+
+	DBG(CXT, ul_debugobj(lc, "get_encrypt_type [rc=%d]", rc));
 	return rc;
 }
 
@@ -798,7 +805,7 @@
 	if (lo)
 		return (char *) lo->lo_crypt_name;
 
-	DBG(lc, loopdev_debug("get_crypt_name failed"));
+	DBG(CXT, ul_debugobj(lc, "get_crypt_name failed"));
 	return NULL;
 }
 
@@ -811,14 +818,16 @@
 int loopcxt_get_backing_devno(struct loopdev_cxt *lc, dev_t *devno)
 {
 	struct loop_info64 *lo = loopcxt_get_info(lc);
-	int rc = -EINVAL;
+	int rc;
 
 	if (lo) {
 		if (devno)
 			*devno = lo->lo_device;
 		rc = 0;
-	}
-	DBG(lc, loopdev_debug("get_backing_devno [rc=%d]", rc));
+	} else
+		rc = -errno;
+
+	DBG(CXT, ul_debugobj(lc, "get_backing_devno [rc=%d]", rc));
 	return rc;
 }
 
@@ -831,14 +840,16 @@
 int loopcxt_get_backing_inode(struct loopdev_cxt *lc, ino_t *ino)
 {
 	struct loop_info64 *lo = loopcxt_get_info(lc);
-	int rc = -EINVAL;
+	int rc;
 
 	if (lo) {
 		if (ino)
 			*ino = lo->lo_inode;
 		rc = 0;
-	}
-	DBG(lc, loopdev_debug("get_backing_inode [rc=%d]", rc));
+	} else
+		rc = -errno;
+
+	DBG(CXT, ul_debugobj(lc, "get_backing_inode [rc=%d]", rc));
 	return rc;
 }
 
@@ -969,7 +980,7 @@
 	if (!lc)
 		return 0;
 
-	DBG(lc, loopdev_debug("checking %s vs. %s",
+	DBG(CXT, ul_debugobj(lc, "checking %s vs. %s",
 				loopcxt_get_device(lc),
 				backing_file));
 
@@ -1012,7 +1023,7 @@
 		return -EINVAL;
 	lc->info.lo_offset = offset;
 
-	DBG(lc, loopdev_debug("set offset=%jd", offset));
+	DBG(CXT, ul_debugobj(lc, "set offset=%jd", offset));
 	return 0;
 }
 
@@ -1025,7 +1036,7 @@
 		return -EINVAL;
 	lc->info.lo_sizelimit = sizelimit;
 
-	DBG(lc, loopdev_debug("set sizelimit=%jd", sizelimit));
+	DBG(CXT, ul_debugobj(lc, "set sizelimit=%jd", sizelimit));
 	return 0;
 }
 
@@ -1043,7 +1054,7 @@
 		return -EINVAL;
 	lc->info.lo_flags = flags;
 
-	DBG(lc, loopdev_debug("set flags=%u", (unsigned) flags));
+	DBG(CXT, ul_debugobj(lc, "set flags=%u", (unsigned) flags));
 	return 0;
 }
 
@@ -1067,7 +1078,97 @@
 	strncpy((char *)lc->info.lo_file_name, lc->filename, LO_NAME_SIZE);
 	lc->info.lo_file_name[LO_NAME_SIZE- 1] = '\0';
 
-	DBG(lc, loopdev_debug("set backing file=%s", lc->info.lo_file_name));
+	DBG(CXT, ul_debugobj(lc, "set backing file=%s", lc->info.lo_file_name));
+	return 0;
+}
+
+/*
+ * In kernels prior to v3.9, if the offset or sizelimit options
+ * are used, the block device's size won't be synced automatically.
+ * blockdev --getsize64 and filesystems will use the backing
+ * file size until the block device has been re-opened or the
+ * LOOP_SET_CAPACITY ioctl is called to sync the sizes.
+ *
+ * Since mount -oloop uses the LO_FLAGS_AUTOCLEAR option and passes
+ * the open file descriptor to the mount system call, we need to use
+ * the ioctl. Calling losetup directly doesn't have this problem since
+ * it closes the device when it exits and whatever consumes the device
+ * next will re-open it, causing the resync.
+ */
+static int loopcxt_check_size(struct loopdev_cxt *lc, int file_fd)
+{
+	uint64_t size, expected_size;
+	int dev_fd;
+	struct stat st;
+
+	if (!lc->info.lo_offset && !lc->info.lo_sizelimit)
+		return 0;
+
+	if (fstat(file_fd, &st)) {
+		DBG(CXT, ul_debugobj(lc, "failed to fstat backing file"));
+		return -errno;
+	}
+	if (S_ISBLK(st.st_mode)) {
+		if (blkdev_get_size(file_fd,
+				(unsigned long long *) &expected_size)) {
+			DBG(CXT, ul_debugobj(lc, "failed to determine device size"));
+			return -errno;
+		}
+	} else
+		expected_size = st.st_size;
+
+	if (expected_size == 0 || expected_size <= lc->info.lo_offset) {
+		DBG(CXT, ul_debugobj(lc, "failed to determine expected size"));
+		return 0;	/* ignore this error */
+	}
+
+	if (lc->info.lo_offset > 0)
+		expected_size -= lc->info.lo_offset;
+
+	if (lc->info.lo_sizelimit > 0 && lc->info.lo_sizelimit < expected_size)
+		expected_size = lc->info.lo_sizelimit;
+
+	dev_fd = loopcxt_get_fd(lc);
+	if (dev_fd < 0) {
+		DBG(CXT, ul_debugobj(lc, "failed to get loop FD"));
+		return -errno;
+	}
+
+	if (blkdev_get_size(dev_fd, (unsigned long long *) &size)) {
+		DBG(CXT, ul_debugobj(lc, "failed to determine loopdev size"));
+		return -errno;
+	}
+
+	/* It's block device, so, align to 512-byte sectors */
+	if (expected_size % 512) {
+		DBG(CXT, ul_debugobj(lc, "expected size misaligned to 512-byte sectors"));
+		expected_size = (expected_size >> 9) << 9;
+	}
+
+	if (expected_size != size) {
+		DBG(CXT, ul_debugobj(lc, "warning: loopdev and expected "
+				      "size dismatch (%ju/%ju)",
+				      size, expected_size));
+
+		if (loopcxt_set_capacity(lc)) {
+			/* ioctl not available */
+			if (errno == ENOTTY || errno == EINVAL)
+				errno = ERANGE;
+			return -errno;
+		}
+
+		if (blkdev_get_size(dev_fd, (unsigned long long *) &size))
+			return -errno;
+
+		if (expected_size != size) {
+			errno = ERANGE;
+			DBG(CXT, ul_debugobj(lc, "failed to set loopdev size, "
+					"size: %ju, expected: %ju",
+					size, expected_size));
+			return -errno;
+		}
+	}
+
 	return 0;
 }
 
@@ -1091,12 +1192,12 @@
  */
 int loopcxt_setup_device(struct loopdev_cxt *lc)
 {
-	int file_fd, dev_fd, mode = O_RDWR, rc = -1;
+	int file_fd, dev_fd, mode = O_RDWR, rc = -1, cnt = 0;
 
 	if (!lc || !*lc->device || !lc->filename)
 		return -EINVAL;
 
-	DBG(lc, loopdev_debug("device setup requested"));
+	DBG(SETUP, ul_debugobj(lc, "device setup requested"));
 
 	/*
 	 * Open backing file and device
@@ -1104,19 +1205,19 @@
 	if (lc->info.lo_flags & LO_FLAGS_READ_ONLY)
 		mode = O_RDONLY;
 
-	if ((file_fd = open(lc->filename, mode)) < 0) {
+	if ((file_fd = open(lc->filename, mode | O_CLOEXEC)) < 0) {
 		if (mode != O_RDONLY && (errno == EROFS || errno == EACCES))
 			file_fd = open(lc->filename, mode = O_RDONLY);
 
 		if (file_fd < 0) {
-			DBG(lc, loopdev_debug("open backing file failed: %m"));
+			DBG(SETUP, ul_debugobj(lc, "open backing file failed: %m"));
 			return -errno;
 		}
 	}
-	DBG(lc, loopdev_debug("setup: backing file open: OK"));
+	DBG(SETUP, ul_debugobj(lc, "backing file open: OK"));
 
 	if (lc->fd != -1 && lc->mode != mode) {
-		DBG(lc, loopdev_debug("closing already open device (mode mismatch)"));
+		DBG(SETUP, ul_debugobj(lc, "closing already open device (mode mismatch)"));
 		close(lc->fd);
 		lc->fd = -1;
 		lc->mode = 0;
@@ -1131,51 +1232,83 @@
 		lc->flags &= ~LOOPDEV_FL_RDONLY;
 	}
 
-	dev_fd = loopcxt_get_fd(lc);
+	do {
+		errno = 0;
+		dev_fd = loopcxt_get_fd(lc);
+		if (dev_fd >= 0 || lc->control_ok == 0)
+			break;
+		if (errno != EACCES && errno != ENOENT)
+			break;
+		/* We have permissions to open /dev/loop-control, but open
+		 * /dev/loopN failed with EACCES, it's probably because udevd
+		 * does not applied chown yet. Let's wait a moment. */
+		usleep(25000);
+	} while (cnt++ < 16);
+
 	if (dev_fd < 0) {
 		rc = -errno;
 		goto err;
 	}
 
-	DBG(lc, loopdev_debug("setup: device open: OK"));
+	DBG(SETUP, ul_debugobj(lc, "device open: OK"));
 
 	/*
 	 * Set FD
 	 */
 	if (ioctl(dev_fd, LOOP_SET_FD, file_fd) < 0) {
 		rc = -errno;
-		DBG(lc, loopdev_debug("LOOP_SET_FD failed: %m"));
+		DBG(SETUP, ul_debugobj(lc, "LOOP_SET_FD failed: %m"));
 		goto err;
 	}
 
-	DBG(lc, loopdev_debug("setup: LOOP_SET_FD: OK"));
-
-	close(file_fd);
-	file_fd = -1;
+	DBG(SETUP, ul_debugobj(lc, "LOOP_SET_FD: OK"));
 
 	if (ioctl(dev_fd, LOOP_SET_STATUS64, &lc->info)) {
-		DBG(lc, loopdev_debug("LOOP_SET_STATUS64 failed: %m"));
+		DBG(SETUP, ul_debugobj(lc, "LOOP_SET_STATUS64 failed: %m"));
 		goto err;
 	}
 
-	DBG(lc, loopdev_debug("setup: LOOP_SET_STATUS64: OK"));
+	DBG(SETUP, ul_debugobj(lc, "LOOP_SET_STATUS64: OK"));
+
+	if ((rc = loopcxt_check_size(lc, file_fd)))
+		goto err;
+
+	close(file_fd);
 
 	memset(&lc->info, 0, sizeof(lc->info));
 	lc->has_info = 0;
 	lc->info_failed = 0;
 
-	DBG(lc, loopdev_debug("setup success [rc=0]"));
+	DBG(SETUP, ul_debugobj(lc, "success [rc=0]"));
 	return 0;
 err:
 	if (file_fd >= 0)
 		close(file_fd);
-	if (dev_fd >= 0)
+	if (dev_fd >= 0 && rc != -EBUSY)
 		ioctl(dev_fd, LOOP_CLR_FD, 0);
 
-	DBG(lc, loopdev_debug("setup failed [rc=%d]", rc));
+	DBG(SETUP, ul_debugobj(lc, "failed [rc=%d]", rc));
 	return rc;
 }
 
+int loopcxt_set_capacity(struct loopdev_cxt *lc)
+{
+	int fd = loopcxt_get_fd(lc);
+
+	if (fd < 0)
+		return -EINVAL;
+
+	/* Kernels prior to v2.6.30 don't support this ioctl */
+	if (ioctl(fd, LOOP_SET_CAPACITY, 0) < 0) {
+		int rc = -errno;
+		DBG(CXT, ul_debugobj(lc, "LOOP_SET_CAPACITY failed: %m"));
+		return rc;
+	}
+
+	DBG(CXT, ul_debugobj(lc, "capacity set"));
+	return 0;
+}
+
 int loopcxt_delete_device(struct loopdev_cxt *lc)
 {
 	int fd = loopcxt_get_fd(lc);
@@ -1184,14 +1317,45 @@
 		return -EINVAL;
 
 	if (ioctl(fd, LOOP_CLR_FD, 0) < 0) {
-		DBG(lc, loopdev_debug("LOOP_CLR_FD failed: %m"));
+		DBG(CXT, ul_debugobj(lc, "LOOP_CLR_FD failed: %m"));
 		return -errno;
 	}
 
-	DBG(lc, loopdev_debug("device removed"));
+	DBG(CXT, ul_debugobj(lc, "device removed"));
 	return 0;
 }
 
+int loopcxt_add_device(struct loopdev_cxt *lc)
+{
+	int rc = -EINVAL;
+	int ctl, nr = -1;
+	const char *p, *dev = loopcxt_get_device(lc);
+
+	if (!dev)
+		goto done;
+
+	if (!(lc->flags & LOOPDEV_FL_CONTROL)) {
+		rc = -ENOSYS;
+		goto done;
+	}
+
+	p = strrchr(dev, '/');
+	if (!p || (sscanf(p, "/loop%d", &nr) != 1 && sscanf(p, "/%d", &nr) != 1)
+	       || nr < 0)
+		goto done;
+
+	ctl = open(_PATH_DEV_LOOPCTL, O_RDWR|O_CLOEXEC);
+	if (ctl >= 0) {
+		DBG(CXT, ul_debugobj(lc, "add_device %d", nr));
+		rc = ioctl(ctl, LOOP_CTL_ADD, nr);
+		close(ctl);
+	}
+	lc->control_ok = rc >= 0 ? 1 : 0;
+done:
+	DBG(CXT, ul_debugobj(lc, "add_device done [rc=%d]", rc));
+	return rc;
+}
+
 /*
  * Note that LOOP_CTL_GET_FREE ioctl is supported since kernel 3.1. In older
  * kernels we have to check all loop devices to found unused one.
@@ -1202,10 +1366,10 @@
 {
 	int rc = -1;
 
-	DBG(lc, loopdev_debug("find_unused requested"));
+	DBG(CXT, ul_debugobj(lc, "find_unused requested"));
 
 	if (lc->flags & LOOPDEV_FL_CONTROL) {
-		int ctl = open(_PATH_DEV_LOOPCTL, O_RDWR);
+		int ctl = open(_PATH_DEV_LOOPCTL, O_RDWR|O_CLOEXEC);
 
 		if (ctl >= 0)
 			rc = ioctl(ctl, LOOP_CTL_GET_FREE);
@@ -1215,9 +1379,10 @@
 
 			rc = loopiter_set_device(lc, name);
 		}
+		lc->control_ok = ctl >= 0 && rc == 0 ? 1 : 0;
 		if (ctl >= 0)
 			close(ctl);
-		DBG(lc, loopdev_debug("find_unused by loop-control [rc=%d]", rc));
+		DBG(CXT, ul_debugobj(lc, "find_unused by loop-control [rc=%d]", rc));
 	}
 
 	if (rc < 0) {
@@ -1227,7 +1392,7 @@
 
 		rc = loopcxt_next(lc);
 		loopcxt_deinit_iterator(lc);
-		DBG(lc, loopdev_debug("find_unused by scan [rc=%d]", rc));
+		DBG(CXT, ul_debugobj(lc, "find_unused by scan [rc=%d]", rc));
 	}
 	return rc;
 }
@@ -1405,155 +1570,3 @@
 	return count;
 }
 
-
-#ifdef TEST_PROGRAM_LOOPDEV
-#include <errno.h>
-#include <err.h>
-
-static void test_loop_info(const char *device, int flags, int debug)
-{
-	struct loopdev_cxt lc;
-	char *p;
-	uint64_t u64;
-
-	if (loopcxt_init(&lc, flags))
-		return;
-	loopcxt_enable_debug(&lc, debug);
-
-	if (loopcxt_set_device(&lc, device))
-		err(EXIT_FAILURE, "failed to set device");
-
-	p = loopcxt_get_backing_file(&lc);
-	printf("\tBACKING FILE: %s\n", p);
-	free(p);
-
-	if (loopcxt_get_offset(&lc, &u64) == 0)
-		printf("\tOFFSET: %jd\n", u64);
-
-	if (loopcxt_get_sizelimit(&lc, &u64) == 0)
-		printf("\tSIZE LIMIT: %jd\n", u64);
-
-	printf("\tAUTOCLEAR: %s\n", loopcxt_is_autoclear(&lc) ? "YES" : "NOT");
-
-	loopcxt_deinit(&lc);
-}
-
-static void test_loop_scan(int flags, int debug)
-{
-	struct loopdev_cxt lc;
-	int rc;
-
-	if (loopcxt_init(&lc, 0))
-		return;
-	loopcxt_enable_debug(&lc, debug);
-
-	if (loopcxt_init_iterator(&lc, flags))
-		err(EXIT_FAILURE, "iterator initlization failed");
-
-	while((rc = loopcxt_next(&lc)) == 0) {
-		const char *device = loopcxt_get_device(&lc);
-
-		if (flags & LOOPITER_FL_USED) {
-			char *backing = loopcxt_get_backing_file(&lc);
-			printf("\t%s: %s\n", device, backing);
-			free(backing);
-		} else
-			printf("\t%s\n", device);
-	}
-
-	if (rc < 0)
-		err(EXIT_FAILURE, "loopdevs scanning failed");
-
-	loopcxt_deinit(&lc);
-}
-
-static int test_loop_setup(const char *filename, const char *device, int debug)
-{
-	struct loopdev_cxt lc;
-	int rc;
-
-	rc = loopcxt_init(&lc, 0);
-	if (rc)
-		return rc;
-	loopcxt_enable_debug(&lc, debug);
-
-	if (device) {
-		rc = loopcxt_set_device(&lc, device);
-		if (rc)
-			err(EXIT_FAILURE, "failed to set device: %s", device);
-	}
-
-	do {
-		if (!device) {
-			rc = loopcxt_find_unused(&lc);
-			if (rc)
-				err(EXIT_FAILURE, "failed to find unused device");
-			printf("Trying to use '%s'\n", loopcxt_get_device(&lc));
-		}
-
-		if (loopcxt_set_backing_file(&lc, filename))
-			err(EXIT_FAILURE, "failed to set backing file");
-
-		rc = loopcxt_setup_device(&lc);
-		if (rc == 0)
-			break;		/* success */
-
-		if (device || rc != -EBUSY)
-			err(EXIT_FAILURE, "failed to setup device for %s",
-					lc.filename);
-
-		printf("device stolen...trying again\n");
-	} while (1);
-
-	loopcxt_deinit(&lc);
-
-	return 0;
-}
-
-int main(int argc, char *argv[])
-{
-	int dbg;
-
-	if (argc < 2)
-		goto usage;
-
-	dbg = getenv("LOOPDEV_DEBUG") == NULL ? 0 : 1;
-
-	if (argc == 3 && strcmp(argv[1], "--info") == 0) {
-		printf("---sysfs & ioctl:---\n");
-		test_loop_info(argv[2], 0, dbg);
-		printf("---sysfs only:---\n");
-		test_loop_info(argv[2], LOOPDEV_FL_NOIOCTL, dbg);
-		printf("---ioctl only:---\n");
-		test_loop_info(argv[2], LOOPDEV_FL_NOSYSFS, dbg);
-
-	} else if (argc == 2 && strcmp(argv[1], "--used") == 0) {
-		printf("---all used devices---\n");
-		test_loop_scan(LOOPITER_FL_USED, dbg);
-
-	} else if (argc == 2 && strcmp(argv[1], "--free") == 0) {
-		printf("---all free devices---\n");
-		test_loop_scan(LOOPITER_FL_FREE, dbg);
-
-	} else if (argc >= 3 && strcmp(argv[1], "--setup") == 0) {
-		test_loop_setup(argv[2], argv[3], dbg);
-
-	} else if (argc == 3 && strcmp(argv[1], "--delete") == 0) {
-		if (loopdev_delete(argv[2]))
-			errx(EXIT_FAILURE, "failed to deinitialize device %s", argv[2]);
-	} else
-		goto usage;
-
-	return EXIT_SUCCESS;
-
-usage:
-	errx(EXIT_FAILURE, "usage: \n"
-			   "  %1$s --info <device>\n"
-			   "  %1$s --free\n"
-			   "  %1$s --used\n"
-			   "  %1$s --setup <filename> [<device>]\n"
-			   "  %1$s --delete\n",
-			   argv[0]);
-}
-
-#endif /* TEST_PROGRAM */
diff --git a/libblkid/mangle.c b/libblkid/lib/mangle.c
similarity index 100%
rename from libblkid/mangle.c
rename to libblkid/lib/mangle.c
diff --git a/libblkid/match.c b/libblkid/lib/match.c
similarity index 100%
rename from libblkid/match.c
rename to libblkid/lib/match.c
diff --git a/libblkid/mbsalign.c b/libblkid/lib/mbsalign.c
similarity index 65%
rename from libblkid/mbsalign.c
rename to libblkid/lib/mbsalign.c
index ea6851f..5e52e8f 100644
--- a/libblkid/mbsalign.c
+++ b/libblkid/lib/mbsalign.c
@@ -2,8 +2,8 @@
    Copyright (C) 2009-2010 Free Software Foundation, Inc.
 
    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 3 of the License, or
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 2.1 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -23,17 +23,193 @@
 #include <stdio.h>
 #include <stdbool.h>
 #include <limits.h>
+#include <ctype.h>
 
 #include "c.h"
 #include "mbsalign.h"
 #include "widechar.h"
 
-
 #ifdef HAVE_WIDECHAR
 /* Replace non printable chars.
    Note \t and \n etc. are non printable.
    Return 1 if replacement made, 0 otherwise.  */
 
+/*
+ * Counts number of cells in multibyte string. For all control and
+ * non-printable chars is the result width enlarged to store \x?? hex
+ * sequence. See mbs_safe_encode().
+ *
+ * Returns: number of cells, @sz returns number of bytes.
+ */
+size_t mbs_safe_nwidth(const char *buf, size_t bufsz, size_t *sz)
+{
+	mbstate_t st;
+	const char *p = buf, *last = buf;
+	size_t width = 0, bytes = 0;
+
+	memset(&st, 0, sizeof(st));
+
+	if (p && *p && bufsz)
+		last = p + (bufsz - 1);
+
+	while (p && *p && p <= last) {
+		if (iscntrl((unsigned char) *p)) {
+			width += 4, bytes += 4;		/* *p encoded to \x?? */
+			p++;
+		}
+#ifdef HAVE_WIDECHAR
+		else {
+			wchar_t wc;
+			size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st);
+
+			if (len == 0)
+				break;
+
+			if (len == (size_t) -1 || len == (size_t) -2) {
+				len = 1;
+				if (isprint((unsigned char) *p))
+					width += 1, bytes += 1;
+				else
+					width += 4, bytes += 4;
+
+			} else if (!iswprint(wc)) {
+				width += len * 4;	/* hex encode whole sequence */
+				bytes += len * 4;
+			} else {
+				width += wcwidth(wc);	/* number of cells */
+				bytes += len;		/* number of bytes */
+			}
+			p += len;
+		}
+#else
+		else if (!isprint((unsigned char) *p)) {
+			width += 4, bytes += 4;		/* *p encoded to \x?? */
+			p++;
+		} else {
+			width++, bytes++;
+			p++;
+		}
+#endif
+	}
+
+	if (sz)
+		*sz = bytes;
+	return width;
+}
+
+size_t mbs_safe_width(const char *s)
+{
+	if (!s || !*s)
+		return 0;
+	return mbs_safe_nwidth(s, strlen(s), NULL);
+}
+
+/*
+ * Copy @s to @buf and replace control and non-printable chars with
+ * \x?? hex sequence. The @width returns number of cells.
+ *
+ * The @buf has to be big enough to store mbs_safe_encode_size(strlen(s)))
+ * bytes.
+ */
+char *mbs_safe_encode_to_buffer(const char *s, size_t *width, char *buf)
+{
+	mbstate_t st;
+	const char *p = s;
+	char *r;
+	size_t sz = s ? strlen(s) : 0;
+
+	if (!sz || !buf)
+		return NULL;
+
+	memset(&st, 0, sizeof(st));
+
+	r = buf;
+	*width = 0;
+
+	while (p && *p) {
+		if (iscntrl((unsigned char) *p)) {
+			sprintf(r, "\\x%02x", (unsigned char) *p);
+			r += 4;
+			*width += 4;
+			p++;
+		}
+#ifdef HAVE_WIDECHAR
+		else {
+			wchar_t wc;
+			size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st);
+
+			if (len == 0)
+				break;		/* end of string */
+
+			if (len == (size_t) -1 || len == (size_t) -2) {
+				len = 1;
+				/*
+				 * Not valid multibyte sequence -- maybe it's
+				 * printable char according to the current locales.
+				 */
+				if (!isprint((unsigned char) *p)) {
+					sprintf(r, "\\x%02x", (unsigned char) *p);
+					r += 4;
+					*width += 4;
+				} else {
+					width++;
+					*r++ = *p;
+				}
+			} else if (!iswprint(wc)) {
+				size_t i;
+				for (i = 0; i < len; i++) {
+					sprintf(r, "\\x%02x", (unsigned char) *p);
+					r += 4;
+					*width += 4;
+				}
+			} else {
+				memcpy(r, p, len);
+				r += len;
+				*width += wcwidth(wc);
+			}
+			p += len;
+		}
+#else
+		else if (!isprint((unsigned char) *p)) {
+			sprintf(r, "\\x%02x", (unsigned char) *p);
+			p++;
+			r += 4;
+			*width += 4;
+		} else {
+			*r++ = *p++;
+			*width++;
+		}
+#endif
+	}
+
+	*r = '\0';
+
+	return buf;
+}
+
+size_t mbs_safe_encode_size(size_t bytes)
+{
+	return (bytes * 4) + 1;
+}
+
+/*
+ * Returns allocated string where all control and non-printable chars are
+ * replaced with \x?? hex sequence.
+ */
+char *mbs_safe_encode(const char *s, size_t *width)
+{
+	size_t sz = s ? strlen(s) : 0;
+	char *buf;
+
+	if (!sz)
+		return NULL;
+	buf = malloc(mbs_safe_encode_size(sz));
+	if (!buf)
+		return NULL;
+
+	return mbs_safe_encode_to_buffer(s, width, buf);
+}
+
 static bool
 wc_ensure_printable (wchar_t *wchars)
 {
@@ -143,7 +319,7 @@
 {
   /* FIXME: Should we pad with "figure space" (\u2007)
      if non ascii data present?  */
-  while (n_spaces-- && (dest < dest_end))
+  for (/* nothing */; n_spaces && (dest < dest_end); n_spaces--)
     *dest++ = ' ';
   *dest = '\0';
   return dest;
@@ -173,7 +349,7 @@
   const char *str_to_print = src;
   size_t n_cols = src_size - 1;
   size_t n_used_bytes = n_cols; /* Not including NUL */
-  size_t n_spaces = 0;
+  size_t n_spaces = 0, space_left;
   bool conversion = false;
   bool wc_enabled = false;
 
@@ -254,8 +430,8 @@
   if (dest_size != 0)
     {
       char *dest_end = dest + dest_size - 1;
-      size_t start_spaces = n_spaces / 2 + n_spaces % 2;
-      size_t end_spaces = n_spaces / 2;
+      size_t start_spaces;
+      size_t end_spaces;
 
       switch (align)
         {
@@ -276,9 +452,8 @@
         }
 
       dest = mbs_align_pad (dest, dest_end, start_spaces);
-      size_t space_left = dest_end - dest;
-      //dest = mempcpy (dest, str_to_print, min (n_used_bytes, space_left));
-      memcpy (dest, str_to_print, min (n_used_bytes, space_left));
+      space_left = dest_end - dest;
+      dest = memcpy (dest, str_to_print, min (n_used_bytes, space_left));
       mbs_align_pad (dest, dest_end, end_spaces);
     }
 
diff --git a/libblkid/md5.c b/libblkid/lib/md5.c
similarity index 100%
rename from libblkid/md5.c
rename to libblkid/lib/md5.c
diff --git a/libblkid/lib/monotonic.c b/libblkid/lib/monotonic.c
new file mode 100644
index 0000000..3d4a443
--- /dev/null
+++ b/libblkid/lib/monotonic.c
@@ -0,0 +1,68 @@
+/*
+ * Please, don't add this file to libcommon because clock_gettime() requires
+ * -lrt on systems with old libc.
+ */
+#include <time.h>
+#include <sys/sysinfo.h>
+#include <sys/time.h>
+
+#include "c.h"
+#include "nls.h"
+#include "monotonic.h"
+
+int get_boot_time(struct timeval *boot_time)
+{
+#ifdef CLOCK_BOOTTIME
+	struct timespec hires_uptime;
+	struct timeval lores_uptime;
+#endif
+	struct timeval now;
+#ifdef HAVE_SYSINFO
+	struct sysinfo info;
+#endif
+
+	if (gettimeofday(&now, NULL) != 0) {
+		warn(_("gettimeofday failed"));
+		return -errno;
+	}
+#ifdef CLOCK_BOOTTIME
+	if (clock_gettime(CLOCK_BOOTTIME, &hires_uptime) == 0) {
+		TIMESPEC_TO_TIMEVAL(&lores_uptime, &hires_uptime);
+		timersub(&now, &lores_uptime, boot_time);
+		return 0;
+	}
+#endif
+#ifdef HAVE_SYSINFO
+	/* fallback */
+	if (sysinfo(&info) != 0)
+		warn(_("sysinfo failed"));
+
+	boot_time->tv_sec = now.tv_sec - info.uptime;
+	boot_time->tv_usec = 0;
+	return 0;
+#else
+	return -ENOSYS;
+#endif
+}
+
+int gettime_monotonic(struct timeval *tv)
+{
+#ifdef CLOCK_MONOTONIC
+	/* Can slew only by ntp and adjtime */
+	int ret;
+	struct timespec ts;
+
+# ifdef CLOCK_MONOTONIC_RAW
+	/* Linux specific, cant slew */
+	if (!(ret = clock_gettime(CLOCK_MONOTONIC_RAW, &ts))) {
+# else
+	if (!(ret = clock_gettime(CLOCK_MONOTONIC, &ts))) {
+# endif
+		tv->tv_sec = ts.tv_sec;
+		tv->tv_usec = ts.tv_nsec / 1000;
+	}
+	return ret;
+#else
+	return gettimeofday(tv, NULL);
+#endif
+}
diff --git a/libblkid/pager.c b/libblkid/lib/pager.c
similarity index 90%
rename from libblkid/pager.c
rename to libblkid/lib/pager.c
index 5cf8c03..9e09cd5 100644
--- a/libblkid/pager.c
+++ b/libblkid/lib/pager.c
@@ -40,16 +40,6 @@
 	close(fd[1]);
 }
 
-static inline void dup_devnull(int to)
-{
-	int fd = open(NULL_DEVICE, O_RDWR);
-
-	if (fd < 0)
-		err(EXIT_FAILURE, _("cannot open %s"), NULL_DEVICE);
-	dup2(fd, to);
-	close(fd);
-}
-
 static int start_command(struct child_process *cmd)
 {
 	int need_in;
@@ -73,10 +63,10 @@
 	cmd->pid = fork();
 	if (!cmd->pid) {
 		if (need_in) {
-			dup2(fdin[0], 0);
+			dup2(fdin[0], STDIN_FILENO);
 			close_pair(fdin);
 		} else if (cmd->in > 0) {
-			dup2(cmd->in, 0);
+			dup2(cmd->in, STDIN_FILENO);
 			close(cmd->in);
 		}
 
@@ -144,7 +134,7 @@
 	fd_set in;
 
 	FD_ZERO(&in);
-	FD_SET(0, &in);
+	FD_SET(STDIN_FILENO, &in);
 	select(1, &in, NULL, &in, NULL);
 
 	setenv("LESS", "FRSX", 0);
@@ -155,8 +145,8 @@
 	fflush(stdout);
 	fflush(stderr);
 	/* signal EOF to pager */
-	close(1);
-	close(2);
+	close(STDOUT_FILENO);
+	close(STDERR_FILENO);
 	finish_command(&pager_process);
 }
 
@@ -170,7 +160,7 @@
 {
 	const char *pager = getenv("PAGER");
 
-	if (!isatty(1))
+	if (!isatty(STDOUT_FILENO))
 		return;
 
 	if (!pager)
@@ -188,9 +178,9 @@
 		return;
 
 	/* original process continues, but writes to the pipe */
-	dup2(pager_process.in, 1);
-	if (isatty(2))
-		dup2(pager_process.in, 2);
+	dup2(pager_process.in, STDOUT_FILENO);
+	if (isatty(STDERR_FILENO))
+		dup2(pager_process.in, STDERR_FILENO);
 	close(pager_process.in);
 
 	/* this makes sure that the parent terminates after the pager */
diff --git a/libblkid/path.c b/libblkid/lib/path.c
similarity index 91%
rename from libblkid/path.c
rename to libblkid/lib/path.c
index 4f955d9..fc90c0a 100644
--- a/libblkid/path.c
+++ b/libblkid/lib/path.c
@@ -49,6 +49,19 @@
 	return pathbuf;
 }
 
+char *
+path_strdup(const char *path, ...)
+{
+	const char *p;
+	va_list ap;
+
+	va_start(ap, path);
+	p = path_vcreate(path, ap);
+	va_end(ap);
+
+	return p ? strdup(p) : NULL;
+}
+
 static FILE *
 path_vfopen(const char *mode, int exit_on_error, const char *path, va_list ap)
 {
@@ -97,7 +110,7 @@
 	va_end(ap);
 
 	if (!fgets(result, len, fd))
-		err(EXIT_FAILURE, _("failed to read: %s"), pathbuf);
+		err(EXIT_FAILURE, _("cannot read %s"), pathbuf);
 	fclose(fd);
 
 	len = strlen(result);
@@ -118,7 +131,7 @@
 
 	if (fscanf(fd, "%d", &result) != 1) {
 		if (ferror(fd))
-			err(EXIT_FAILURE, _("failed to read: %s"), pathbuf);
+			err(EXIT_FAILURE, _("cannot read %s"), pathbuf);
 		else
 			errx(EXIT_FAILURE, _("parse error: %s"), pathbuf);
 	}
@@ -139,7 +152,7 @@
 
 	if (fscanf(fd, "%"SCNu64, &result) != 1) {
 		if (ferror(fd))
-			err(EXIT_FAILURE, _("failed to read: %s"), pathbuf);
+			err(EXIT_FAILURE, _("cannot read %s"), pathbuf);
 		else
 			errx(EXIT_FAILURE, _("parse error: %s"), pathbuf);
 	}
@@ -154,7 +167,7 @@
 	va_list ap;
 
 	va_start(ap, path);
-	fd = path_vopen(O_WRONLY, path, ap);
+	fd = path_vopen(O_WRONLY|O_CLOEXEC, path, ap);
 	va_end(ap);
 	result = write_all(fd, str, strlen(str));
 	close(fd);
@@ -187,7 +200,7 @@
 	fd = path_vfopen("r", 1, path, ap);
 
 	if (!fgets(buf, len, fd))
-		err(EXIT_FAILURE, _("failed to read: %s"), pathbuf);
+		err(EXIT_FAILURE, _("cannot read %s"), pathbuf);
 	fclose(fd);
 
 	len = strlen(buf);
diff --git a/libblkid/lib/procutils.c b/libblkid/lib/procutils.c
new file mode 100644
index 0000000..ef96941
--- /dev/null
+++ b/libblkid/lib/procutils.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2011 Davidlohr Bueso <dave@gnu.org>
+ *
+ * procutils.c: General purpose procfs parsing utilities
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library Public License as published by
+ * the Free Software Foundation; either version 2, 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 Library Public License for more details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <ctype.h>
+
+#include "procutils.h"
+#include "at.h"
+#include "c.h"
+
+/*
+ * @pid: process ID for which we want to obtain the threads group
+ *
+ * Returns: newly allocated tasks structure
+ */
+struct proc_tasks *proc_open_tasks(pid_t pid)
+{
+	struct proc_tasks *tasks;
+	char path[PATH_MAX];
+
+	sprintf(path, "/proc/%d/task/", pid);
+
+	tasks = malloc(sizeof(struct proc_tasks));
+	if (tasks) {
+		tasks->dir = opendir(path);
+		if (tasks->dir)
+			return tasks;
+	}
+
+	free(tasks);
+	return NULL;
+}
+
+/*
+ * @tasks: allocated tasks structure
+ *
+ * Returns: nothing
+ */
+void proc_close_tasks(struct proc_tasks *tasks)
+{
+	if (tasks && tasks->dir)
+		closedir(tasks->dir);
+	free(tasks);
+}
+
+/*
+ * @tasks: allocated task structure
+ * @tid: [output] one of the thread IDs belonging to the thread group
+ *        If when an error occurs, it is set to 0.
+ *
+ * Returns: 0 on success, 1 on end, -1 on failure or no more threads
+ */
+int proc_next_tid(struct proc_tasks *tasks, pid_t *tid)
+{
+	struct dirent *d;
+	char *end;
+
+	if (!tasks || !tid)
+		return -EINVAL;
+
+	*tid = 0;
+	errno = 0;
+
+	do {
+		d = readdir(tasks->dir);
+		if (!d)
+			return errno ? -1 : 1;		/* error or end-of-dir */
+
+		if (!isdigit((unsigned char) *d->d_name))
+			continue;
+		errno = 0;
+		*tid = (pid_t) strtol(d->d_name, &end, 10);
+		if (errno || d->d_name == end || (end && *end))
+			return -1;
+
+	} while (!*tid);
+
+	return 0;
+}
+
+struct proc_processes *proc_open_processes(void)
+{
+	struct proc_processes *ps;
+
+	ps = calloc(1, sizeof(struct proc_processes));
+	if (ps) {
+		ps->dir = opendir("/proc");
+		if (ps->dir)
+			return ps;
+	}
+
+	free(ps);
+	return NULL;
+}
+
+void proc_close_processes(struct proc_processes *ps)
+{
+	if (ps && ps->dir)
+		closedir(ps->dir);
+	free(ps);
+}
+
+void proc_processes_filter_by_name(struct proc_processes *ps, const char *name)
+{
+	ps->fltr_name = name;
+	ps->has_fltr_name = name ? 1 : 0;
+}
+
+void proc_processes_filter_by_uid(struct proc_processes *ps, uid_t uid)
+{
+	ps->fltr_uid = uid;
+	ps->has_fltr_uid = 1;
+}
+
+int proc_next_pid(struct proc_processes *ps, pid_t *pid)
+{
+	struct dirent *d;
+
+	if (!ps || !pid)
+		return -EINVAL;
+
+	*pid = 0;
+	errno = 0;
+
+	do {
+		char buf[BUFSIZ], *p;
+
+		d = readdir(ps->dir);
+		if (!d)
+			return errno ? -1 : 1;		/* error or end-of-dir */
+
+
+		if (!isdigit((unsigned char) *d->d_name))
+			continue;
+
+		/* filter out by UID */
+		if (ps->has_fltr_uid) {
+			struct stat st;
+
+			if (fstat_at(dirfd(ps->dir), "/proc", d->d_name, &st, 0))
+				continue;
+			if (ps->fltr_uid != st.st_uid)
+				continue;
+		}
+
+		/* filter out by NAME */
+		if (ps->has_fltr_name) {
+			char procname[256];
+			FILE *f;
+
+			snprintf(buf, sizeof(buf), "%s/stat", d->d_name);
+			f = fopen_at(dirfd(ps->dir), "/proc", buf,
+						O_CLOEXEC|O_RDONLY, "r");
+			if (!f)
+				continue;
+
+			p = fgets(buf, sizeof(buf), f);
+			fclose(f);
+			if (!p)
+				continue;
+
+			if (sscanf(buf, "%*d (%255[^)])", procname) != 1)
+				continue;
+
+			/* ok, we got the process name. */
+			if (strcmp(procname, ps->fltr_name) != 0)
+				continue;
+		}
+
+		p = NULL;
+		errno = 0;
+		*pid = (pid_t) strtol(d->d_name, &p, 10);
+		if (errno || d->d_name == p || (p && *p))
+			return errno ? -errno : -1;
+
+		return 0;
+	} while (1);
+
+	return 0;
+}
+
+#ifdef TEST_PROGRAM
+
+static int test_tasks(int argc, char *argv[])
+{
+	pid_t tid, pid;
+	struct proc_tasks *ts;
+
+	if (argc != 2)
+		return EXIT_FAILURE;
+
+	pid = strtol(argv[1], (char **) NULL, 10);
+	printf("PID=%d, TIDs:", pid);
+
+	ts = proc_open_tasks(pid);
+	if (!ts)
+		err(EXIT_FAILURE, "open list of tasks failed");
+
+	while (proc_next_tid(ts, &tid) == 0)
+		printf(" %d", tid);
+
+	printf("\n");
+        proc_close_tasks(ts);
+	return EXIT_SUCCESS;
+}
+
+static int test_processes(int argc, char *argv[])
+{
+	pid_t pid;
+	struct proc_processes *ps;
+
+	ps = proc_open_processes();
+	if (!ps)
+		err(EXIT_FAILURE, "open list of processes failed");
+
+	if (argc >= 3 && strcmp(argv[1], "--name") == 0)
+		proc_processes_filter_by_name(ps, argv[2]);
+
+	if (argc >= 3 && strcmp(argv[1], "--uid") == 0)
+		proc_processes_filter_by_uid(ps, (uid_t) atol(argv[2]));
+
+	while (proc_next_pid(ps, &pid) == 0)
+		printf(" %d", pid);
+
+	printf("\n");
+        proc_close_processes(ps);
+	return EXIT_SUCCESS;
+}
+
+int main(int argc, char *argv[])
+{
+	if (argc < 2) {
+		fprintf(stderr, "usage: %1$s --tasks <pid>\n"
+				"       %1$s --processes [---name <name>] [--uid <uid>]\n",
+				program_invocation_short_name);
+		return EXIT_FAILURE;
+	}
+
+	if (strcmp(argv[1], "--tasks") == 0)
+		return test_tasks(argc - 1, argv + 1);
+	if (strcmp(argv[1], "--processes") == 0)
+		return test_processes(argc - 1, argv + 1);
+
+	return EXIT_FAILURE;
+}
+#endif /* TEST_PROGRAM */
diff --git a/libblkid/randutils.c b/libblkid/lib/randutils.c
similarity index 84%
rename from libblkid/randutils.c
rename to libblkid/lib/randutils.c
index 80893d3..684ac0a 100644
--- a/libblkid/randutils.c
+++ b/libblkid/lib/randutils.c
@@ -15,7 +15,9 @@
 
 #include <sys/syscall.h>
 
+#include "c.h"
 #include "randutils.h"
+#include "nls.h"
 
 #ifdef HAVE_TLS
 #define THREAD_LOCAL static __thread
@@ -34,9 +36,9 @@
 	struct timeval	tv;
 
 	gettimeofday(&tv, 0);
-	fd = open("/dev/urandom", O_RDONLY);
+	fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
 	if (fd == -1)
-		fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
+		fd = open("/dev/random", O_RDONLY | O_NONBLOCK | O_CLOEXEC);
 	if (fd >= 0) {
 		i = fcntl(fd, F_GETFD);
 		if (i >= 0)
@@ -108,6 +110,26 @@
 	return;
 }
 
+
+/*
+ * Tell source of randomness.
+ */
+const char *random_tell_source(void)
+{
+	size_t i;
+	static const char *random_sources[] = {
+		"/dev/urandom",
+		"/dev/random"
+	};
+
+	for (i = 0; i < ARRAY_SIZE(random_sources); i++) {
+		if (!access(random_sources[i], R_OK))
+			return random_sources[i];
+	}
+
+	return _("libc pseudo-random functions");
+}
+
 #ifdef TEST_PROGRAM
 int main(int argc __attribute__ ((__unused__)),
          char *argv[] __attribute__ ((__unused__)))
diff --git a/libblkid/lib/readutmp.c b/libblkid/lib/readutmp.c
new file mode 100644
index 0000000..b11e9a4
--- /dev/null
+++ b/libblkid/lib/readutmp.c
@@ -0,0 +1,78 @@
+/* GNU's read utmp module.
+
+	 Copyright (C) 1992-2001, 2003-2006, 2009-2014 Free Software Foundation, Inc.
+
+	 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 3 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, see <http://www.gnu.org/licenses/>.	*/
+
+/* Written by jla; revised by djm */
+/* extracted for util-linux by ooprala */
+
+#include <errno.h>
+#include <stdio.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "xalloc.h"
+#include "readutmp.h"
+
+/* Read the utmp entries corresponding to file FILE into freshly-
+	 malloc'd storage, set *UTMP_BUF to that pointer, set *N_ENTRIES to
+	 the number of entries, and return zero.	If there is any error,
+	 return -1, setting errno, and don't modify the parameters.
+	 If OPTIONS & READ_UTMP_CHECK_PIDS is nonzero, omit entries whose
+	 process-IDs do not currently exist.	*/
+int
+read_utmp (char const *file, size_t *n_entries, struct utmp **utmp_buf)
+{
+	size_t n_read = 0;
+	size_t n_alloc = 0;
+	struct utmp *utmp = NULL;
+	struct utmp *u;
+
+	/* Ignore the return value for now.
+		 Solaris' utmpname returns 1 upon success -- which is contrary
+		 to what the GNU libc version does.	In addition, older GNU libc
+		 versions are actually void.	 */
+	utmpname(file);
+
+	setutent();
+
+	errno = 0;
+	while ((u = getutent()) != NULL) {
+		if (n_read == n_alloc) {
+			n_alloc += 32;
+			utmp = xrealloc(utmp, n_alloc * sizeof (struct utmp));
+			if (!utmp)
+				return -1;
+		}
+		utmp[n_read++] = *u;
+	}
+	if (!u && errno) {
+		free(utmp);
+		return -1;
+	}
+
+	endutent();
+
+	*n_entries = n_read;
+	*utmp_buf = utmp;
+
+	return 0;
+}
diff --git a/libblkid/setproctitle.c b/libblkid/lib/setproctitle.c
similarity index 100%
rename from libblkid/setproctitle.c
rename to libblkid/lib/setproctitle.c
diff --git a/libblkid/strutils.c b/libblkid/lib/strutils.c
similarity index 84%
rename from libblkid/strutils.c
rename to libblkid/lib/strutils.c
index 2337b07..9fe9481 100644
--- a/libblkid/strutils.c
+++ b/libblkid/lib/strutils.c
@@ -10,6 +10,7 @@
 #include <errno.h>
 #include <sys/stat.h>
 #include <string.h>
+#include <assert.h>
 
 #include "c.h"
 #include "nls.h"
@@ -20,7 +21,7 @@
 {
 	while (power--) {
 		if (UINTMAX_MAX / base < *x)
-			return -2;
+			return -ERANGE;
 		*x *= base;
 	}
 	return 0;
@@ -32,30 +33,43 @@
  * Supported suffixes:
  *
  * XiB or X for 2^N
- *     where X = {K,M,G,T,P,E,Y,Z}
+ *     where X = {K,M,G,T,P,E,Z,Y}
  *        or X = {k,m,g,t,p,e}  (undocumented for backward compatibility only)
  * for example:
  *		10KiB	= 10240
  *		10K	= 10240
  *
  * XB for 10^N
- *     where X = {K,M,G,T,P,E,Y,Z}
+ *     where X = {K,M,G,T,P,E,Z,Y}
  * for example:
  *		10KB	= 10000
  *
+ * The optinal 'power' variable returns number associated with used suffix
+ * {K,M,G,T,P,E,Z,Y}  = {1,2,3,4,5,6,7,8}.
+ *
+ * The function also supports decimal point, for example:
+ *              0.5MB   = 500000
+ *              0.5MiB  = 512000
+ *
  * Note that the function does not accept numbers with '-' (negative sign)
  * prefix.
  */
-int strtosize(const char *str, uintmax_t *res)
+int parse_size(const char *str, uintmax_t *res, int *power)
 {
 	char *p;
-	uintmax_t x;
-	int base = 1024, rc = 0;
+	uintmax_t x, frac = 0;
+	int base = 1024, rc = 0, pwr = 0, frac_zeros = 0;
+
+	static const char *suf  = "KMGTPEYZ";
+	static const char *suf2 = "kmgtpeyz";
+	const char *sp;
 
 	*res = 0;
 
-	if (!str || !*str)
+	if (!str || !*str) {
+		rc = -EINVAL;
 		goto err;
+	}
 
 	/* Only positive numbers are acceptable
 	 *
@@ -66,72 +80,108 @@
 	p = (char *) str;
 	while (isspace((unsigned char) *p))
 		p++;
-	if (*p == '-')
+	if (*p == '-') {
+		rc = -EINVAL;
 		goto err;
+	}
 	p = NULL;
 
 	errno = 0;
 	x = strtoumax(str, &p, 0);
 
 	if (p == str ||
-	    (errno != 0 && (x == UINTMAX_MAX || x == 0)))
+	    (errno != 0 && (x == UINTMAX_MAX || x == 0))) {
+		rc = errno ? -errno : -1;
 		goto err;
-
+	}
 	if (!p || !*p)
 		goto done;			/* without suffix */
 
 	/*
 	 * Check size suffixes
 	 */
+check_suffix:
 	if (*(p + 1) == 'i' && *(p + 2) == 'B' && !*(p + 3))
 		base = 1024;			/* XiB, 2^N */
 	else if (*(p + 1) == 'B' && !*(p + 2))
 		base = 1000;			/* XB, 10^N */
-	else if (*(p + 1))
-		goto err;			/* unexpected suffix */
+	else if (*(p + 1)) {
+		struct lconv const *l = localeconv();
+		char *dp = l ? l->decimal_point : NULL;
+		size_t dpsz = dp ? strlen(dp) : 0;
 
-	switch(*p) {
-	case 'K':
-	case 'k':
-		rc = do_scale_by_power(&x, base, 1);
-		break;
-	case 'M':
-	case 'm':
-		rc = do_scale_by_power(&x, base, 2);
-		break;
-	case 'G':
-	case 'g':
-		rc = do_scale_by_power(&x, base, 3);
-		break;
-	case 'T':
-	case 't':
-		rc = do_scale_by_power(&x, base, 4);
-		break;
-	case 'P':
-	case 'p':
-		rc = do_scale_by_power(&x, base, 5);
-		break;
-	case 'E':
-	case 'e':
-		rc = do_scale_by_power(&x, base, 6);
-		break;
-	case 'Z':
-		rc = do_scale_by_power(&x, base, 7);
-		break;
-	case 'Y':
-		rc = do_scale_by_power(&x, base, 8);
-		break;
-	default:
-		goto err;
+		if (frac == 0 && *p && dp && strncmp(dp, p, dpsz) == 0) {
+			char *fstr = p + dpsz;
+
+			for (p = fstr; *p && *p == '0'; p++)
+				frac_zeros++;
+			errno = 0, p = NULL;
+			frac = strtoumax(fstr, &p, 0);
+			if (p == fstr ||
+			    (errno != 0 && (frac == UINTMAX_MAX || frac == 0))) {
+				rc = errno ? -errno : -1;
+				goto err;
+			}
+			if (frac && (!p  || !*p)) {
+				rc = -EINVAL;
+				goto err;		/* without suffix, but with frac */
+			}
+			goto check_suffix;
+		}
+		rc = -EINVAL;
+		goto err;			/* unexpected suffix */
 	}
 
+	sp = strchr(suf, *p);
+	if (sp)
+		pwr = (sp - suf) + 1;
+	else {
+		sp = strchr(suf2, *p);
+		if (sp)
+			pwr = (sp - suf2) + 1;
+		else {
+			rc = -EINVAL;
+			goto err;
+		}
+	}
+
+	rc = do_scale_by_power(&x, base, pwr);
+	if (power)
+		*power = pwr;
+	if (frac && pwr) {
+		int zeros_in_pwr = frac_zeros % 3;
+		int frac_pwr = pwr - (frac_zeros / 3) - 1;
+		uintmax_t y = frac * (zeros_in_pwr == 0 ? 100 :
+				      zeros_in_pwr == 1 ?  10 : 1);
+
+		if (frac_pwr < 0) {
+			rc = -EINVAL;
+			goto err;
+		}
+		do_scale_by_power(&y, base, frac_pwr);
+		x += y;
+	}
 done:
 	*res = x;
-	return rc;
 err:
-	return -1;
+	return rc;
 }
 
+int strtosize(const char *str, uintmax_t *res)
+{
+	return parse_size(str, res, NULL);
+}
+
+int isdigit_string(const char *str)
+{
+	const char *p;
+
+	for (p = str; p && *p && isdigit((unsigned char) *p); p++);
+
+	return p && p > str && !*p;
+}
+
+
 #ifndef HAVE_MEMPCPY
 void *mempcpy(void *restrict dest, const void *restrict src, size_t n)
 {
@@ -332,9 +382,19 @@
 	errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
 }
 
+
+void strtotimeval_or_err(const char *str, struct timeval *tv, const char *errmesg)
+{
+	double user_input;
+
+	user_input = strtod_or_err(str, errmesg);
+	tv->tv_sec = (time_t) user_input;
+	tv->tv_usec = (long)((user_input - tv->tv_sec) * 1000000);
+}
+
 /*
  * Converts stat->st_mode to ls(1)-like mode string. The size of "str" must
- * be 10 bytes.
+ * be 11 bytes.
  */
 void strmode(mode_t mode, char *str)
 {
diff --git a/libblkid/lib/swapprober.c b/libblkid/lib/swapprober.c
new file mode 100644
index 0000000..5a4b112
--- /dev/null
+++ b/libblkid/lib/swapprober.c
@@ -0,0 +1,49 @@
+
+#include "c.h"
+#include "nls.h"
+
+#include "swapheader.h"
+#include "swapprober.h"
+
+blkid_probe get_swap_prober(const char *devname)
+{
+	blkid_probe pr;
+	int rc;
+	const char *version = NULL;
+	char *swap_filter[] = { "swap", NULL };
+
+	pr = blkid_new_probe_from_filename(devname);
+	if (!pr) {
+		warn(_("%s: unable to probe device"), devname);
+		return NULL;
+	}
+
+	blkid_probe_enable_superblocks(pr, TRUE);
+	blkid_probe_set_superblocks_flags(pr,
+			BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID |
+			BLKID_SUBLKS_VERSION);
+
+	blkid_probe_filter_superblocks_type(pr, BLKID_FLTR_ONLYIN, swap_filter);
+
+	rc = blkid_do_safeprobe(pr);
+	if (rc == -1)
+		warn(_("%s: unable to probe device"), devname);
+	else if (rc == -2)
+		warnx(_("%s: ambiguous probing result; use wipefs(8)"), devname);
+	else if (rc == 1)
+		warnx(_("%s: not a valid swap partition"), devname);
+
+	if (rc == 0) {
+		/* Only the SWAPSPACE2 is supported. */
+		if (blkid_probe_lookup_value(pr, "VERSION", &version, NULL) == 0
+		    && version
+		    && strcmp(version, stringify_value(SWAP_VERSION)))
+			warnx(_("%s: unsupported swap version '%s'"),
+						devname, version);
+		else
+			return pr;
+	}
+
+	blkid_free_probe(pr);
+	return NULL;
+}
diff --git a/libblkid/sysfs1.c b/libblkid/lib/sysfs.c
similarity index 74%
rename from libblkid/sysfs1.c
rename to libblkid/lib/sysfs.c
index fd4ec62..63a90dc 100644
--- a/libblkid/sysfs1.c
+++ b/libblkid/lib/sysfs.c
@@ -5,12 +5,13 @@
  * Written by Karel Zak <kzak@redhat.com>
  */
 #include <ctype.h>
-#include <fcntl.h>
-#include <unistd.h>
+
 #include "c.h"
 #include "at.h"
 #include "pathnames.h"
 #include "sysfs.h"
+#include "fileutils.h"
+#include "all-io.h"
 
 char *sysfs_devno_attribute_path(dev_t devno, char *buf,
 				 size_t bufsiz, const char *attr)
@@ -89,7 +90,7 @@
 		FILE *f;
 		int maj = 0, min = 0;
 
-		f = fopen(path, "r");
+		f = fopen(path, "r" UL_CLOEXECSTR);
 		if (!f)
 			return 0;
 
@@ -150,7 +151,7 @@
 	if (!sysfs_devno_path(devno, path, sizeof(path)))
 		goto err;
 
-	fd = open(path, O_RDONLY);
+	fd = open(path, O_RDONLY|O_CLOEXEC);
 	if (fd < 0)
 		goto err;
 	cxt->dir_fd = fd;
@@ -204,9 +205,9 @@
 	return sysfs_stat(cxt, attr, &st) == 0;
 }
 
-static int sysfs_open(struct sysfs_cxt *cxt, const char *attr)
+static int sysfs_open(struct sysfs_cxt *cxt, const char *attr, int flags)
 {
-	int fd = open_at(cxt->dir_fd, cxt->dir_path, attr, O_RDONLY);
+	int fd = open_at(cxt->dir_fd, cxt->dir_path, attr, flags);
 
 	if (fd == -1 && errno == ENOENT &&
 	    strncmp(attr, "queue/", 6) == 0 && cxt->parent) {
@@ -214,7 +215,7 @@
 		/* Exception for "queue/<attr>". These attributes are available
 		 * for parental devices only
 		 */
-		fd = open_at(cxt->parent->dir_fd, cxt->dir_path, attr, O_RDONLY);
+		fd = open_at(cxt->parent->dir_fd, cxt->dir_path, attr, flags);
 	}
 	return fd;
 }
@@ -238,7 +239,7 @@
 	int fd = -1;
 
 	if (attr)
-		fd = sysfs_open(cxt, attr);
+		fd = sysfs_open(cxt, attr, O_RDONLY|O_CLOEXEC);
 
 	else if (cxt->dir_fd >= 0)
 		/* request to open root of device in sysfs (/sys/block/<dev>)
@@ -263,9 +264,9 @@
 
 static FILE *sysfs_fopen(struct sysfs_cxt *cxt, const char *attr)
 {
-	int fd = sysfs_open(cxt, attr);
+	int fd = sysfs_open(cxt, attr, O_RDONLY|O_CLOEXEC);
 
-	return fd < 0 ? NULL : fdopen(fd, "r");
+	return fd < 0 ? NULL : fdopen(fd, "r" UL_CLOEXECSTR);
 }
 
 
@@ -290,7 +291,8 @@
 
 #ifdef _DIRENT_HAVE_D_TYPE
 	if (d->d_type != DT_DIR &&
-	    d->d_type != DT_LNK)
+	    d->d_type != DT_LNK &&
+	    d->d_type != DT_UNKNOWN)
 		return 0;
 #endif
 	if (parent_name) {
@@ -320,7 +322,7 @@
 	/* Cannot use /partition file, not supported on old sysfs */
 	snprintf(path, sizeof(path), "%s/start", d->d_name);
 
-	return access(path, R_OK) == 0;
+	return faccessat(dirfd(dir), path, R_OK, 0) == 0;
 }
 
 /*
@@ -417,6 +419,42 @@
 	return -1;
 }
 
+int sysfs_write_string(struct sysfs_cxt *cxt, const char *attr, const char *str)
+{
+	int fd = sysfs_open(cxt, attr, O_WRONLY|O_CLOEXEC);
+	int rc, errsv;
+
+	if (fd < 0)
+		return -errno;
+	rc = write_all(fd, str, strlen(str));
+
+	errsv = errno;
+	close(fd);
+	errno = errsv;
+	return rc;
+}
+
+int sysfs_write_u64(struct sysfs_cxt *cxt, const char *attr, uint64_t num)
+{
+	char buf[sizeof(stringify_value(ULLONG_MAX))];
+	int fd, rc = 0, len, errsv;
+
+	fd = sysfs_open(cxt, attr, O_WRONLY|O_CLOEXEC);
+	if (fd < 0)
+		return -errno;
+
+	len = snprintf(buf, sizeof(buf), "%ju", num);
+	if (len < 0 || (size_t) len + 1 > sizeof(buf))
+		rc = -errno;
+	else
+		rc = write_all(fd, buf, len);
+
+	errsv = errno;
+	close(fd);
+	errno = errsv;
+	return rc;
+}
+
 char *sysfs_strdup(struct sysfs_cxt *cxt, const char *attr)
 {
 	char buf[1024];
@@ -509,15 +547,144 @@
 	return buf;
 }
 
-/* returns basename and keeps dirname in the @path */
-static char *stripoff_last_component(char *path)
-{
-    char *p = strrchr(path, '/');
+#define SUBSYSTEM_LINKNAME	"/subsystem"
 
-    if (!p)
-        return NULL;
-    *p = '\0';
-    return ++p;
+/*
+ * For example:
+ *
+ * chain: /sys/dev/block/../../devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/ \
+ *                           1-1.2:1.0/host65/target65:0:0/65:0:0:0/block/sdb
+ *
+ * The function check if <chain>/subsystem symlink exists, if yes then returns
+ * basename of the readlink result, and remove the last subdirectory from the
+ * <chain> path.
+ */
+static char *get_subsystem(char *chain, char *buf, size_t bufsz)
+{
+	size_t len;
+	char *p;
+
+	if (!chain || !*chain)
+		return NULL;
+
+	len = strlen(chain);
+	if (len + sizeof(SUBSYSTEM_LINKNAME) > PATH_MAX)
+		return NULL;
+
+	do {
+		ssize_t sz;
+
+		/* append "/subsystem" to the path */
+		memcpy(chain + len, SUBSYSTEM_LINKNAME, sizeof(SUBSYSTEM_LINKNAME));
+
+		/* try if subsystem symlink exists */
+		sz = readlink(chain, buf, bufsz - 1);
+
+		/* remove last subsystem from chain */
+		chain[len] = '\0';
+		p = strrchr(chain, '/');
+		if (p) {
+			*p = '\0';
+			len = p - chain;
+		}
+
+		if (sz > 0) {
+			/* we found symlink to subsystem, return basename */
+			buf[sz] = '\0';
+			return basename(buf);
+		}
+
+	} while (p);
+
+	return NULL;
+}
+
+/*
+ * Returns complete path to the device, the patch contains all all sybsystems
+ * used for the device.
+ */
+char *sysfs_get_devchain(struct sysfs_cxt *cxt, char *buf, size_t bufsz)
+{
+	/* read /sys/dev/block/<maj>:<min> symlink */
+	size_t sz = sysfs_readlink(cxt, NULL, buf, bufsz);
+	if (sz <= 0 || sz + sizeof(_PATH_SYS_DEVBLOCK "/") > bufsz)
+		return NULL;
+
+	buf[sz++] = '\0';
+
+	/* create absolute patch from the link */
+	memmove(buf + sizeof(_PATH_SYS_DEVBLOCK "/") - 1, buf, sz);
+	memcpy(buf, _PATH_SYS_DEVBLOCK "/", sizeof(_PATH_SYS_DEVBLOCK "/") - 1);
+
+	return buf;
+}
+
+/*
+ * The @subsys returns the next subsystem in the chain. Function modifies
+ * @devchain string.
+ *
+ * Returns: 0 in success, <0 on error, 1 on end of chain
+ */
+int sysfs_next_subsystem(struct sysfs_cxt *cxt __attribute__((unused)),
+			 char *devchain, char **subsys)
+{
+	char subbuf[PATH_MAX];
+	char *sub;
+
+	if (!subsys || !devchain)
+		return -EINVAL;
+
+	while ((sub = get_subsystem(devchain, subbuf, sizeof(subbuf)))) {
+		*subsys = strdup(sub);
+		if (!*subsys)
+			return -ENOMEM;
+		return 0;
+	}
+
+	return 1;
+}
+
+
+static int is_hotpluggable_subsystem(const char *name)
+{
+	static const char * const hotplug_subsystems[] = {
+		"usb",
+		"ieee1394",
+		"pcmcia",
+		"mmc",
+		"ccw"
+	};
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(hotplug_subsystems); i++)
+		if (strcmp(name, hotplug_subsystems[i]) == 0)
+			return 1;
+
+	return 0;
+}
+
+int sysfs_is_hotpluggable(struct sysfs_cxt *cxt)
+{
+	char buf[PATH_MAX], *chain, *sub;
+	int rc = 0;
+
+
+	/* check /sys/dev/block/<maj>:<min>/removable attribute */
+	if (sysfs_read_int(cxt, "removable", &rc) == 0 && rc == 1)
+		return 1;
+
+	chain = sysfs_get_devchain(cxt, buf, sizeof(buf));
+
+	while (chain && sysfs_next_subsystem(cxt, chain, &sub) == 0) {
+		rc = is_hotpluggable_subsystem(sub);
+		if (rc) {
+			free(sub);
+			break;
+		}
+		free(sub);
+	}
+
+	return rc;
 }
 
 static int get_dm_wholedisk(struct sysfs_cxt *cxt, char *diskname,
@@ -548,6 +715,10 @@
     return rc;
 }
 
+/*
+ * Returns by @diskdevno whole disk device devno and (optionaly) by
+ * @diskname the whole disk device name.
+ */
 int sysfs_devno_to_wholedisk(dev_t dev, char *diskname,
             size_t len, dev_t *diskdevno)
 {
@@ -638,6 +809,48 @@
     return -1;
 }
 
+/*
+ * Returns 1 if the device is private LVM device.
+ */
+int sysfs_devno_is_lvm_private(dev_t devno)
+{
+	struct sysfs_cxt cxt = UL_SYSFSCXT_EMPTY;
+	char *uuid = NULL;
+	int rc = 0;
+
+	if (sysfs_init(&cxt, devno, NULL) != 0)
+		return 0;
+
+	uuid = sysfs_strdup(&cxt, "dm/uuid");
+
+	/* Private LVM devices use "LVM-<uuid>-<name>" uuid format (important
+	 * is the "LVM" prefix and "-<name>" postfix).
+	 */
+	if (uuid && strncmp(uuid, "LVM-", 4) == 0) {
+		char *p = strrchr(uuid + 4, '-');
+
+		if (p && *(p + 1))
+			rc = 1;
+	}
+
+	sysfs_deinit(&cxt);
+	free(uuid);
+	return rc;
+}
+
+/*
+ * Return 0 or 1, or < 0 in case of error
+ */
+int sysfs_devno_is_wholedisk(dev_t devno)
+{
+	dev_t disk;
+
+	if (sysfs_devno_to_wholedisk(devno, NULL, 0, &disk) != 0)
+		return -1;
+
+	return devno == disk;
+}
+
 
 int sysfs_scsi_get_hctl(struct sysfs_cxt *cxt, int *h, int *c, int *t, int *l)
 {
@@ -654,11 +867,12 @@
 		return len;
 
 	buf[len] = '\0';
-	hctl = strrchr(buf, '/') + 1;
+	hctl = strrchr(buf, '/');
 	if (!hctl)
 		return -1;
+	hctl++;
 
-	if (sscanf(hctl, "%d:%d:%d:%d", &cxt->scsi_host, &cxt->scsi_channel,
+	if (sscanf(hctl, "%u:%u:%u:%u", &cxt->scsi_host, &cxt->scsi_channel,
 				&cxt->scsi_target, &cxt->scsi_lun) != 4)
 		return -1;
 
@@ -706,7 +920,7 @@
 	    !sysfs_scsi_host_attribute_path(cxt, type, buf, sizeof(buf), attr))
 		return NULL;
 
-	if (!(f = fopen(buf, "r")))
+	if (!(f = fopen(buf, "r" UL_CLOEXECSTR)))
                 return NULL;
 
 	rc = fscanf(f, "%1023[^\n]", buf);
@@ -785,7 +999,7 @@
 	struct sysfs_cxt cxt = UL_SYSFSCXT_EMPTY;
 	char *devname;
 	dev_t devno;
-	char path[PATH_MAX];
+	char path[PATH_MAX], *sub, *chain;
 	int i, is_part;
 	uint64_t u64;
 	ssize_t len;
@@ -838,6 +1052,16 @@
 		printf("SECTOR: %d\n", i);
 
 	printf("DEVNAME: %s\n", sysfs_get_devname(&cxt, path, sizeof(path)));
+	printf("HOTPLUG: %s\n", sysfs_is_hotpluggable(&cxt) ? "yes" : "no");
+
+	chain = sysfs_get_devchain(&cxt, path, sizeof(path));
+	printf("SUBSUSTEMS:\n");
+
+	while (chain && sysfs_next_subsystem(&cxt, chain, &sub) == 0) {
+		printf("\t%s\n", sub);
+		free(sub);
+	}
+
 
 	sysfs_deinit(&cxt);
 	return EXIT_SUCCESS;
diff --git a/libblkid/lib/terminal-colors.d.5 b/libblkid/lib/terminal-colors.d.5
new file mode 100644
index 0000000..66ecf2c
--- /dev/null
+++ b/libblkid/lib/terminal-colors.d.5
@@ -0,0 +1,190 @@
+.\" terminal-colors.d.5 --
+.\" Copyright 2014 Ondrej Oprala <ooprala@redhat.com>
+.\" Copyright (C) 2014 Karel Zak <kzak@redhat.com>
+.\" Copyright 2014 Red Hat, Inc.
+.\" May be distributed under the GNU General Public License
+.TH "TERMINAL_COLORS.D" "5" "January 2014" "util-linux" "terminal-colors.d"
+.SH "NAME"
+terminal-colors.d \- Configure output colorization for various utilities
+.SH "SYNOPSIS"
+/etc/terminal-colors\&.d/[[\fIname\fR][@\fIterm\fR]\&.][\fItype\fR]
+.SH "DESCRIPTION"
+Files in this directory determine the default behavior for utilities
+when coloring output.
+
+The
+.I name
+is a utility name.  The name is optional and when none is specified then the
+file is used for all unspecified utilities.
+
+The
+.I term
+is a terminal identifier (the TERM environment variable).
+The terminal identifier is optional and when none is specified then the file
+is used for all unspecified terminals.
+
+The
+.I type
+is a file type.  Supported file types are:
+.TP
+.B disable
+Turns off output colorization for all compatible utilities.
+.TP
+.B enable
+Turns on output colorization; any matching
+.B disable
+files are ignored.
+.TP
+.B scheme
+Specifies colors used for output.  The file format may be specific to the utility,
+the default format is described below.
+.PP
+If there are more files that match for a utility, then the file with the more
+specific filename wins.  For example, the filename "@xterm.scheme" has less
+priority than "dmesg@xterm.scheme".  The lowest priority are those files without a
+utility name and terminal identifier (e.g. "disable").
+
+The user-specific
+.I $XDG_CONFIG_HOME/terminal-colors.d
+or
+.I $HOME/.config/terminal-colors.d
+overrides the global setting.
+
+.SH EXAMPLES
+Disable colors for all compatible utilities:
+.RS
+.br
+.B "touch /etc/terminal-colors.d/disable"
+.br
+.RE
+
+Disable colors for all compatible utils on a vt100 terminal:
+.RS
+.br
+.B "touch /etc/terminal-colors.d/@vt100.disable"
+.br
+.RE
+
+Disable colors for all compatible utils except dmesg(1):
+.RS
+.br
+.B "touch /etc/terminal-colors.d/disable"
+.sp
+.B "touch /etc/terminal-colors.d/dmesg.enable"
+.br
+.RE
+
+.SH DEFAULT SCHEME FILES FORMAT
+The following statement is recognized:
+
+.RS
+.br
+.B "name color-sequence"
+.br
+.RE
+
+The
+.B name
+is a logical name of color sequence (for example "error").  The names are
+specific to the utilities.  For more details always see the COLORS section
+in the man page for the utility.
+
+The
+.B color-sequence
+is a color name, ASCII color sequences or escape sequences.
+
+.SS Color names
+black, blue, brown, cyan, darkgray, gray, green, lightblue, lightcyan
+lightgray, lightgreen, lightmagenta, lightred, magenta, red and yellow
+.SS ANSI color sequences
+The color sequences are composed of sequences of numbers
+separated by semicolons.  The most common codes are:
+.sp
+.RS
+.TS
+l l.
+ 0	to restore default color
+ 1	for brighter colors
+ 4	for underlined text
+ 5	for flashing text
+30	for black foreground
+31	for red foreground
+32	for green foreground
+33	for yellow (or brown) foreground
+34	for blue foreground
+35	for purple foreground
+36	for cyan foreground
+37	for white (or gray) foreground
+40	for black background
+41	for red background
+42	for green background
+43	for yellow (or brown) background
+44	for blue background
+45	for purple background
+46	for cyan background
+47	for white (or gray) background
+.TE
+.RE
+.SS Escape sequences
+To specify control or blank characters in the color sequences,
+C-style \e-escaped notation can be used:
+.sp
+.RS
+.TS
+lb l.
+\ea	Bell (ASCII 7)
+\eb	Backspace (ASCII 8)
+\ee	Escape (ASCII 27)
+\ef	Form feed (ASCII 12)
+\en	Newline (ASCII 10)
+\er	Carriage Return (ASCII 13)
+\et	Tab (ASCII 9)
+\ev	Vertical Tab (ASCII 11)
+\e?	Delete (ASCII 127)
+\e_	Space
+\e\e	Backslash (\e)
+\e^	Caret (^)
+\e#	Hash mark (#)
+.TE
+.RE
+.sp
+Please note that escapes are necessary to enter a space, backslash,
+caret, or any control character anywhere in the string, as well as a
+hash mark as the first character.
+
+For example, to use a red background for alert messages in the output of
+.BR dmesg (1),
+use:
+
+.RS
+.br
+.B "echo 'alert 37;41' >> /etc/terminal-colors.d/dmesg.scheme"
+.br
+.RE
+
+.SS Comments
+Lines where the first non-blank character is a # (hash) are ignored.
+Any other use of the hash character is not interpreted as introducing
+a comment.
+
+.SH FILES
+.B $XDG_CONFIG_HOME/terminal-colors.d
+.br
+.B $HOME/.config/terminal-colors.d
+.br
+.B /etc/terminal-colors.d
+
+.SH ENVIRONMENT
+.IP TERMINAL_COLORS_DEBUG=all
+enables debug output.
+
+.SH COMPATIBILITY
+The terminal-colors.d functionality is currently supported by all util-linux
+utilities which provides colorized output.  For more details always see the
+COLORS section in the man page for the utility.
+
+.SH AVAILABILITY
+terminal-colors.d is part of the util-linux package and is available from
+.UR ftp://\:ftp.kernel.org\:/pub\:/linux\:/utils\:/util-linux/
+Linux Kernel Archive
+.UE .
diff --git a/libblkid/lib/timeutils.c b/libblkid/lib/timeutils.c
new file mode 100644
index 0000000..b811041
--- /dev/null
+++ b/libblkid/lib/timeutils.c
@@ -0,0 +1,342 @@
+/***
+  First set of functions in this file are part of systemd, and were
+  copied to util-linux at August 2013.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd 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
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with util-linux; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <assert.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/sysinfo.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "c.h"
+#include "nls.h"
+#include "strutils.h"
+#include "timeutils.h"
+
+#define WHITESPACE " \t\n\r"
+
+#define streq(a,b) (strcmp((a),(b)) == 0)
+
+static int parse_sec(const char *t, usec_t *usec)
+{
+	 static const struct {
+		const char *suffix;
+		usec_t usec;
+	 } table[] = {
+		{ "seconds",	USEC_PER_SEC },
+		{ "second",	USEC_PER_SEC },
+		{ "sec",	USEC_PER_SEC },
+		{ "s",		USEC_PER_SEC },
+		{ "minutes",	USEC_PER_MINUTE },
+		{ "minute",	USEC_PER_MINUTE },
+		{ "min",	USEC_PER_MINUTE },
+		{ "months",	USEC_PER_MONTH },
+		{ "month",	USEC_PER_MONTH },
+		{ "msec",	USEC_PER_MSEC },
+		{ "ms",		USEC_PER_MSEC },
+		{ "m",		USEC_PER_MINUTE },
+		{ "hours",	USEC_PER_HOUR },
+		{ "hour",	USEC_PER_HOUR },
+		{ "hr",		USEC_PER_HOUR },
+		{ "h",		USEC_PER_HOUR },
+		{ "days",	USEC_PER_DAY },
+		{ "day",	USEC_PER_DAY },
+		{ "d",		USEC_PER_DAY },
+		{ "weeks",	USEC_PER_WEEK },
+		{ "week",	USEC_PER_WEEK },
+		{ "w",		USEC_PER_WEEK },
+		{ "years",	USEC_PER_YEAR },
+		{ "year",	USEC_PER_YEAR },
+		{ "y",		USEC_PER_YEAR },
+		{ "usec",	1ULL },
+		{ "us",		1ULL },
+		{ "",		USEC_PER_SEC },	/* default is sec */
+	 };
+
+	const char *p;
+	usec_t r = 0;
+	int something = FALSE;
+
+	assert(t);
+	assert(usec);
+
+	p = t;
+	for (;;) {
+		long long l, z = 0;
+		char *e;
+		unsigned i, n = 0;
+
+		p += strspn(p, WHITESPACE);
+
+		if (*p == 0) {
+			if (!something)
+				return -EINVAL;
+
+			break;
+		}
+
+		errno = 0;
+		l = strtoll(p, &e, 10);
+
+		if (errno > 0)
+			return -errno;
+
+		if (l < 0)
+			return -ERANGE;
+
+		if (*e == '.') {
+			char *b = e + 1;
+
+			errno = 0;
+			z = strtoll(b, &e, 10);
+			if (errno > 0)
+				return -errno;
+
+			if (z < 0)
+				return -ERANGE;
+
+			if (e == b)
+				return -EINVAL;
+
+			n = e - b;
+
+		} else if (e == p)
+			return -EINVAL;
+
+		e += strspn(e, WHITESPACE);
+
+		for (i = 0; i < ARRAY_SIZE(table); i++)
+			if (startswith(e, table[i].suffix)) {
+				usec_t k = (usec_t) z * table[i].usec;
+
+				for (; n > 0; n--)
+					k /= 10;
+
+				r += (usec_t) l *table[i].usec + k;
+				p = e + strlen(table[i].suffix);
+
+				something = TRUE;
+				break;
+			}
+
+		if (i >= ARRAY_SIZE(table))
+			return -EINVAL;
+
+	}
+
+	*usec = r;
+
+	return 0;
+}
+
+int parse_timestamp(const char *t, usec_t *usec)
+{
+	 static const struct {
+		const char *name;
+		const int nr;
+	 } day_nr[] = {
+		{ "Sunday",	0 },
+		{ "Sun",	0 },
+		{ "Monday",	1 },
+		{ "Mon",	1 },
+		{ "Tuesday",	2 },
+		{ "Tue",	2 },
+		{ "Wednesday",	3 },
+		{ "Wed",	3 },
+		{ "Thursday",	4 },
+		{ "Thu",	4 },
+		{ "Friday",	5 },
+		{ "Fri",	5 },
+		{ "Saturday",	6 },
+		{ "Sat",	6 },
+	 };
+
+	const char *k;
+	struct tm tm, copy;
+	time_t x;
+	usec_t plus = 0, minus = 0, ret;
+	int r, weekday = -1;
+	unsigned i;
+
+	/*
+	 * Allowed syntaxes:
+	 *
+	 *   2012-09-22 16:34:22
+	 *   2012-09-22 16:34	  (seconds will be set to 0)
+	 *   2012-09-22		  (time will be set to 00:00:00)
+	 *   16:34:22		  (date will be set to today)
+	 *   16:34		  (date will be set to today, seconds to 0)
+	 *   now
+	 *   yesterday		  (time is set to 00:00:00)
+	 *   today		  (time is set to 00:00:00)
+	 *   tomorrow		  (time is set to 00:00:00)
+	 *   +5min
+	 *   -5days
+	 *
+	 */
+
+	assert(t);
+	assert(usec);
+
+	x = time(NULL);
+	localtime_r(&x, &tm);
+	tm.tm_isdst = -1;
+
+	if (streq(t, "now"))
+		goto finish;
+
+	else if (streq(t, "today")) {
+		tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+		goto finish;
+
+	} else if (streq(t, "yesterday")) {
+		tm.tm_mday--;
+		tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+		goto finish;
+
+	} else if (streq(t, "tomorrow")) {
+		tm.tm_mday++;
+		tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+		goto finish;
+
+	} else if (t[0] == '+') {
+
+		r = parse_sec(t + 1, &plus);
+		if (r < 0)
+			return r;
+
+		goto finish;
+	} else if (t[0] == '-') {
+
+		r = parse_sec(t + 1, &minus);
+		if (r < 0)
+			return r;
+
+		goto finish;
+
+	} else if (endswith(t, " ago")) {
+		char *z;
+
+		z = strndup(t, strlen(t) - 4);
+		if (!z)
+			return -ENOMEM;
+
+		r = parse_sec(z, &minus);
+		free(z);
+		if (r < 0)
+			return r;
+
+		goto finish;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(day_nr); i++) {
+		size_t skip;
+
+		if (!startswith_no_case(t, day_nr[i].name))
+			continue;
+
+		skip = strlen(day_nr[i].name);
+		if (t[skip] != ' ')
+			continue;
+
+		weekday = day_nr[i].nr;
+		t += skip + 1;
+		break;
+	}
+
+	copy = tm;
+	k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
+	if (k && *k == 0)
+		goto finish;
+
+	tm = copy;
+	k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
+	if (k && *k == 0)
+		goto finish;
+
+	tm = copy;
+	k = strptime(t, "%y-%m-%d %H:%M", &tm);
+	if (k && *k == 0) {
+		tm.tm_sec = 0;
+		goto finish;
+	}
+
+	tm = copy;
+	k = strptime(t, "%Y-%m-%d %H:%M", &tm);
+	if (k && *k == 0) {
+		tm.tm_sec = 0;
+		goto finish;
+	}
+
+	tm = copy;
+	k = strptime(t, "%y-%m-%d", &tm);
+	if (k && *k == 0) {
+		tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+		goto finish;
+	}
+
+	tm = copy;
+	k = strptime(t, "%Y-%m-%d", &tm);
+	if (k && *k == 0) {
+		tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+		goto finish;
+	}
+
+	tm = copy;
+	k = strptime(t, "%H:%M:%S", &tm);
+	if (k && *k == 0)
+		goto finish;
+
+	tm = copy;
+	k = strptime(t, "%H:%M", &tm);
+	if (k && *k == 0) {
+		tm.tm_sec = 0;
+		goto finish;
+	}
+
+	tm = copy;
+	k = strptime(t, "%Y%m%d%H%M%S", &tm);
+	if (k && *k == 0) {
+		tm.tm_sec = 0;
+		goto finish;
+	}
+
+	return -EINVAL;
+
+ finish:
+	x = mktime(&tm);
+	if (x == (time_t)-1)
+		return -EINVAL;
+
+	if (weekday >= 0 && tm.tm_wday != weekday)
+		return -EINVAL;
+
+	ret = (usec_t) x *USEC_PER_SEC;
+
+	ret += plus;
+	if (ret > minus)
+		ret -= minus;
+	else
+		ret = 0;
+
+	*usec = ret;
+
+	return 0;
+}
diff --git a/libblkid/ttyutils.c b/libblkid/lib/ttyutils.c
similarity index 85%
rename from libblkid/ttyutils.c
rename to libblkid/lib/ttyutils.c
index 3b5a68c..ea551e2 100644
--- a/libblkid/ttyutils.c
+++ b/libblkid/lib/ttyutils.c
@@ -20,11 +20,11 @@
         const char	*cp;
 
 #ifdef TIOCGSIZE
-	if (ioctl (0, TIOCGSIZE, &t_win) == 0)
+	if (ioctl (STDIN_FILENO, TIOCGSIZE, &t_win) == 0)
 		return t_win.ts_cols;
 #endif
 #ifdef TIOCGWINSZ
-	if (ioctl (0, TIOCGWINSZ, &w_win) == 0)
+	if (ioctl (STDIN_FILENO, TIOCGWINSZ, &w_win) == 0)
 		return w_win.ws_col;
 #endif
         cp = getenv("COLUMNS");
@@ -42,7 +42,8 @@
 	return 0;
 }
 
-int get_terminal_name(const char **path,
+int get_terminal_name(int fd,
+		      const char **path,
 		      const char **name,
 		      const char **number)
 {
@@ -56,7 +57,7 @@
 	if (number)
 		*number = NULL;
 
-	tty = ttyname(STDERR_FILENO);
+	tty = ttyname(fd);
 	if (!tty)
 		return -1;
 	if (path)
@@ -82,7 +83,7 @@
 {
 	const char *path, *name, *num;
 
-	if (get_terminal_name(&path, &name, &num) == 0) {
+	if (get_terminal_name(STDERR_FILENO, &path, &name, &num) == 0) {
 		fprintf(stderr, "tty path:   %s\n", path);
 		fprintf(stderr, "tty name:   %s\n", name);
 		fprintf(stderr, "tty number: %s\n", num);
diff --git a/libblkid/libblkid.3 b/libblkid/libblkid.3
new file mode 100644
index 0000000..58ca91c
--- /dev/null
+++ b/libblkid/libblkid.3
@@ -0,0 +1,79 @@
+.\" Copyright 2001 Andreas Dilger (adilger@turbolinux.com)
+.\"
+.\" This man page was created for libblkid.so.1.0 from e2fsprogs-1.24.
+.\"
+.\" This file may be copied under the terms of the GNU Lesser General Public
+.\" License.
+.\"
+.\" Created  Wed Sep 14 12:02:12 2001, Andreas Dilger
+.TH LIBBLKID 3 "May 2009" "util-linux" "Programmer's Manual"
+.SH NAME
+libblkid \- block device identification library
+.SH SYNOPSIS
+.B #include <blkid.h>
+.sp
+.B cc
+.I file.c
+.B \-lblkid
+.SH DESCRIPTION
+The
+.B libblkid
+library is used to identify block devices (disks) as to their content (e.g.
+filesystem type) as well as extracting additional information such as
+filesystem labels/volume names, unique identifiers/serial numbers.
+A common use is to allow use of LABEL= and UUID= tags instead of hard-coding
+specific block device names into configuration files.
+.P
+The low-level part of the library also allows to extract information about
+partitions and block device topology.
+.P
+The high-level part of the library keeps information about block devices in a
+cache file and is verified to still be valid before being returned to the user
+(if the user has read permission on the raw block device, otherwise not).
+The cache file also allows unprivileged users (normally anyone other
+than root, or those not in the "disk" group) to locate devices by label/id.
+The standard location of the cache file can be overridden by the
+environment variable BLKID_FILE.
+.P
+In situations where one is getting information about a single known device, it
+does not impact performance whether the cache is used or not (unless you are
+not able to read the block device directly).
+.P
+The high-level part of the library supports two methods to evaluate LABEL/UUID.
+It reads information directly from a block device or read information from
+/dev/disk/by-* udev symlinks.  The udev is preferred method by default.
+.P
+If you are dealing with
+multiple devices, use of the cache is highly recommended (even if empty) as
+devices will be scanned at most one time and the on-disk cache will be
+updated if possible.
+.P
+In some cases (modular kernels), block devices are not even visible until
+after they are accessed the first time, so it is critical that there is
+some way to locate these devices without enumerating only visible devices,
+so the use of the cache file is
+.B required
+in this situation.
+.SH CONFIGURATION FILE
+The standard location of the
+.I /etc/blkid.conf
+config file can be overridden by the environment variable BLKID_CONF.  For more
+details about the config file see
+.BR blkid (8)
+man page.
+.SH AUTHOR
+.B libblkid
+was written by Andreas Dilger for the ext2 filesystem utilties, with input
+from Ted Ts'o.  The library was subsequently heavily modified by Ted Ts'o.
+
+The low-level probing code was rewritten by Karel Zak.
+.SH COPYING
+.B libblkid
+is available under the terms of the GNU Library General Public License (LGPL),
+version 2 (or at your discretion any later version).
+.SH "SEE ALSO"
+.BR blkid (8),
+.BR findfs (8)
+.SH AVAILABILITY
+libblkid is part of the util-linux package since version 2.15 and is available from
+ftp://ftp.kernel.org/pub/linux/utils/util-linux/.
diff --git a/libblkid/libfdisk/COPYING b/libblkid/libfdisk/COPYING
new file mode 100644
index 0000000..be1a5b3
--- /dev/null
+++ b/libblkid/libfdisk/COPYING
@@ -0,0 +1,8 @@
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later
+version.
+
+The complete text of the license is available in the
+../Documentation/licenses/COPYING.LGPLv2.1 file.
diff --git a/libblkid/libfdisk/Makemodule.am b/libblkid/libfdisk/Makemodule.am
new file mode 100644
index 0000000..5d83341
--- /dev/null
+++ b/libblkid/libfdisk/Makemodule.am
@@ -0,0 +1,14 @@
+if BUILD_LIBFDISK
+
+include libfdisk/src/Makemodule.am
+
+if ENABLE_GTK_DOC
+# Docs uses separate Makefiles
+SUBDIRS += libfdisk/docs
+endif
+
+pkgconfig_DATA += libfdisk/fdisk.pc
+PATHFILES      += libfdisk/fdisk.pc
+EXTRA_DIST     += libfdisk/COPYING
+
+endif # BUILD_LIBFDISK
diff --git a/libblkid/libfdisk/docs/.gitignore b/libblkid/libfdisk/docs/.gitignore
new file mode 100644
index 0000000..f91f93d
--- /dev/null
+++ b/libblkid/libfdisk/docs/.gitignore
@@ -0,0 +1,18 @@
+*-decl-list.txt
+*-decl.txt
+*-overrides.txt
+*-undeclared.txt
+*-undocumented.txt
+*-unused.txt
+*.args
+*.bak
+*.hierarchy
+*.interfaces
+*.prerequisites
+*.signals
+*.stamp
+*.types
+html/*
+tmpl/*
+version.xml
+xml/*
diff --git a/libblkid/libfdisk/docs/Makefile.am b/libblkid/libfdisk/docs/Makefile.am
new file mode 100644
index 0000000..dc70979
--- /dev/null
+++ b/libblkid/libfdisk/docs/Makefile.am
@@ -0,0 +1,93 @@
+## Process this file with automake to produce Makefile.in
+
+# We require automake 1.10 at least.
+AUTOMAKE_OPTIONS = 1.10
+
+# This is a blank Makefile.am for using gtk-doc.
+# Copy this to your project's API docs directory and modify the variables to
+# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples
+# of using the various options.
+
+# The name of the module, e.g. 'glib'.
+DOC_MODULE=libfdisk
+
+# Uncomment for versioned docs and specify the version of the module, e.g. '2'.
+#DOC_MODULE_VERSION=2
+
+# The top-level SGML file. You can change this if you want to.
+DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml
+
+# The directory containing the source code. Relative to $(srcdir).
+# gtk-doc will search all .c & .h files beneath here for inline comments
+# documenting the functions and macros.
+# e.g. DOC_SOURCE_DIR=../../../gtk
+DOC_SOURCE_DIR=../src
+
+# Extra options to pass to gtkdoc-scangobj. Not normally needed.
+SCANGOBJ_OPTIONS=
+
+# Extra options to supply to gtkdoc-scan.
+# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
+SCAN_OPTIONS=
+
+# Extra options to supply to gtkdoc-mkdb.
+# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml
+MKDB_OPTIONS=--sgml-mode --output-format=xml --name-space fdisk
+
+# Extra options to supply to gtkdoc-mktmpl
+# e.g. MKTMPL_OPTIONS=--only-section-tmpl
+MKTMPL_OPTIONS=
+
+# Extra options to supply to gtkdoc-mkhtml
+MKHTML_OPTIONS=
+
+# Extra options to supply to gtkdoc-fixref. Not normally needed.
+# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html
+FIXXREF_OPTIONS=
+
+# Used for dependencies. The docs will be rebuilt if any of these change.
+# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h
+# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c
+HFILE_GLOB=$(top_builddir)/libfdisk/src/libfdisk.h
+CFILE_GLOB=$(top_srcdir)/libfdisk/src/*.c
+
+# Extra header to include when scanning, which are not under DOC_SOURCE_DIR
+# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h
+EXTRA_HFILES=
+
+# Header files to ignore when scanning. Use base file name, no paths
+# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h
+IGNORE_HFILES=fdiskP.h
+
+# Images to copy into HTML directory.
+# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
+HTML_IMAGES=
+
+# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
+# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
+content_files = $(builddir)/version.xml
+
+# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
+# These files must be listed here *and* in content_files
+# e.g. expand_content_files=running.sgml
+expand_content_files=
+
+# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
+# Only needed if you are using gtkdoc-scangobj to dynamically query widget
+# signals and properties.
+# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
+# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
+GTKDOC_CFLAGS=
+GTKDOC_LIBS=
+
+# This includes the standard gtk-doc make rules, copied by gtkdocize.
+include $(top_srcdir)/config/gtk-doc.make
+
+# Other files to distribute
+# e.g. EXTRA_DIST += version.xml.in
+EXTRA_DIST += version.xml.in
+
+# Files not to distribute
+# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
+# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
+DISTCLEANFILES += version.xml
diff --git a/libblkid/libfdisk/docs/libfdisk-docs.xml b/libblkid/libfdisk/docs/libfdisk-docs.xml
new file mode 100644
index 0000000..546d007
--- /dev/null
+++ b/libblkid/libfdisk/docs/libfdisk-docs.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
+               "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
+[
+  <!ENTITY version SYSTEM "version.xml">
+]>
+<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
+  <bookinfo>
+    <title>libfdisk Reference Manual</title>
+    <releaseinfo>for libfdisk version &version;</releaseinfo>
+    <copyright>
+      <year>2014</year>
+      <holder>Karel Zak &lt;kzak@redhat.com&gt;</holder>
+    </copyright>
+  </bookinfo>
+
+  <part id="over">
+    <title>libfdisk Overview</title>
+    <partintro>
+    <para>
+The libfdisk library is used for manipulating with partition tables.
+    </para>
+    <para>
+The library is part of the util-linux package since version 2.26 and is
+available from ftp://ftp.kernel.org/pub/linux/utils/util-linux/.
+    </para>
+  </partintro>
+ </part>
+
+  <part>
+    <title>Basic handlers and setting</title>
+    <xi:include href="xml/context.xml"/>
+    <xi:include href="xml/ask.xml"/>
+    <xi:include href="xml/alignment.xml"/>
+    <xi:include href="xml/script.xml"/>
+  </part>
+   <part>
+    <title>Partitining</title>
+    <xi:include href="xml/label.xml"/>
+    <xi:include href="xml/partition.xml"/>
+    <xi:include href="xml/table.xml"/>
+    <xi:include href="xml/parttype.xml"/>
+  </part>
+  <part>
+    <title>Label specific functions</title>
+    <xi:include href="xml/dos.xml"/>
+    <xi:include href="xml/gpt.xml"/>
+    <xi:include href="xml/sun.xml"/>
+    <xi:include href="xml/sgi.xml"/>
+    <xi:include href="xml/bsd.xml"/>
+  </part>
+  <part>
+    <title>Misc</title>
+    <xi:include href="xml/iter.xml"/>
+    <xi:include href="xml/utils.xml"/>
+    <xi:include href="xml/init.xml"/>
+  </part>
+  <index id="api-index-full">
+    <title>API Index</title>
+    <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
+  </index>
+</book>
diff --git a/libblkid/libfdisk/docs/libfdisk-sections.txt b/libblkid/libfdisk/docs/libfdisk-sections.txt
new file mode 100644
index 0000000..c0aaeae
--- /dev/null
+++ b/libblkid/libfdisk/docs/libfdisk-sections.txt
@@ -0,0 +1,303 @@
+<SECTION>
+<FILE>init</FILE>
+fdisk_init_debug
+</SECTION>
+
+<SECTION>
+<FILE>ask</FILE>
+fdisk_info
+fdisk_warn
+fdisk_warnx
+fdisk_set_ask
+<SUBSECTION>
+fdisk_ask
+fdisk_ask_get_query
+fdisk_ask_get_type
+fdisk_ask_menu_get_default
+fdisk_ask_menu_get_item
+fdisk_ask_menu_get_nitems
+fdisk_ask_menu_get_result
+fdisk_ask_menu_set_result
+fdisk_ask_number
+fdisk_ask_number_get_base
+fdisk_ask_number_get_default
+fdisk_ask_number_get_high
+fdisk_ask_number_get_low
+fdisk_ask_number_get_range
+fdisk_ask_number_get_result
+fdisk_ask_number_get_unit
+fdisk_ask_number_inchars
+fdisk_ask_number_set_relative
+fdisk_ask_number_set_result
+fdisk_ask_partnum
+fdisk_ask_print_get_errno
+fdisk_ask_print_get_mesg
+fdisk_ask_string
+fdisk_ask_string_get_result
+fdisk_ask_string_set_result
+fdisk_ask_yesno
+fdisk_ask_yesno_get_result
+fdisk_ask_yesno_set_result
+fdisk_ref_ask
+fdisk_unref_ask
+</SECTION>
+
+<SECTION>
+<FILE>alignment</FILE>
+fdisk_align_lba
+fdisk_align_lba_in_range
+fdisk_has_user_device_properties
+fdisk_lba_is_phy_aligned
+fdisk_override_geometry
+fdisk_reread_partition_table
+fdisk_reset_alignment
+fdisk_reset_device_properties
+fdisk_save_user_geometry
+fdisk_save_user_sector_size
+</SECTION>
+
+<SECTION>
+<FILE>label</FILE>
+fdisk_create_disklabel
+fdisk_list_disklabel
+fdisk_locate_disklabel
+fdisk_reorder_partitions
+fdisk_set_disklabel_id
+fdisk_set_partition_type
+fdisk_toggle_partition_flag
+fdisk_verify_disklabel
+fdisk_write_disklabel
+<SUBSECTION>
+fdisk_get_disklabel_id
+fdisk_get_label
+fdisk_get_nlabels
+fdisk_next_label
+fdisk_get_npartitions
+<SUBSECTION>
+fdisk_field
+fdisk_field_get_id
+fdisk_field_get_name
+fdisk_field_get_width
+fdisk_field_is_number
+<SUBSECTION>
+fdisk_label
+fdisk_label_get_field
+fdisk_label_get_field_by_name
+fdisk_label_get_fields_ids
+fdisk_label_get_name
+fdisk_label_get_nparttypes
+fdisk_label_get_parttype
+fdisk_label_get_parttype_from_code
+fdisk_label_get_parttype_from_string
+fdisk_label_get_type
+fdisk_label_has_code_parttypes
+fdisk_label_is_changed
+fdisk_label_is_disabled
+fdisk_label_parse_parttype
+fdisk_label_require_geometry
+fdisk_label_set_changed
+fdisk_label_set_disabled
+</SECTION>
+
+<SECTION>
+<FILE>script</FILE>
+fdisk_set_script
+fdisk_get_script
+<SUBSECTION>
+fdisk_apply_script
+fdisk_apply_script_headers
+<SUBSECTION>
+fdisk_script
+fdisk_new_script
+fdisk_new_script_from_file
+fdisk_ref_script
+fdisk_script_get_header
+fdisk_script_get_nlines
+fdisk_script_get_table
+fdisk_script_read_context
+fdisk_script_read_file
+fdisk_script_read_line
+fdisk_script_set_header
+fdisk_script_write_file
+fdisk_unref_script
+</SECTION>
+
+<SECTION>
+<FILE>bsd</FILE>
+fdisk_bsd_edit_disklabel
+fdisk_bsd_link_partition
+fdisk_bsd_write_bootstrap
+</SECTION>
+
+<SECTION>
+<FILE>partition</FILE>
+fdisk_add_partition
+fdisk_delete_all_partitions
+fdisk_delete_partition
+fdisk_get_partition
+fdisk_is_partition_used
+fdisk_set_partition
+<SUBSECTION>
+fdisk_partition
+fdisk_new_partition
+fdisk_partition_cmp_partno
+fdisk_partition_cmp_start
+fdisk_partition_end_follow_default
+fdisk_partition_end_is_default
+fdisk_partition_get_attrs
+fdisk_partition_get_end
+fdisk_partition_get_name
+fdisk_partition_get_parent
+fdisk_partition_get_partno
+fdisk_partition_get_size
+fdisk_partition_get_start
+fdisk_partition_get_type
+fdisk_partition_get_uuid
+fdisk_partition_has_end
+fdisk_partition_has_partno
+fdisk_partition_has_size
+fdisk_partition_has_start
+fdisk_partition_is_bootable
+fdisk_partition_is_container
+fdisk_partition_is_freespace
+fdisk_partition_is_nested
+fdisk_partition_is_used
+fdisk_partition_next_partno
+fdisk_partition_partno_follow_default
+fdisk_partition_set_attrs
+fdisk_partition_set_name
+fdisk_partition_set_partno
+fdisk_partition_set_size
+fdisk_partition_set_start
+fdisk_partition_set_type
+fdisk_partition_set_uuid
+fdisk_partition_size_explicit
+fdisk_partition_start_follow_default
+fdisk_partition_start_is_default
+fdisk_partition_to_string
+fdisk_partition_unset_partno
+fdisk_partition_unset_size
+fdisk_partition_unset_start
+fdisk_ref_partition
+fdisk_reset_partition
+fdisk_unref_partition
+</SECTION>
+
+<SECTION>
+<FILE>dos</FILE>
+fdisk_dos_enable_compatible
+fdisk_dos_is_compatible
+fdisk_dos_move_begin
+</SECTION>
+
+<SECTION>
+<FILE>sgi</FILE>
+fdisk_sgi_create_info
+fdisk_sgi_set_bootfile
+</SECTION>
+
+<SECTION>
+<FILE>gpt</FILE>
+fdisk_gpt_is_hybrid
+</SECTION>
+
+<SECTION>
+<FILE>sun</FILE>
+fdisk_sun_set_alt_cyl
+fdisk_sun_set_ilfact
+fdisk_sun_set_pcylcount
+fdisk_sun_set_rspeed
+fdisk_sun_set_xcyl
+</SECTION>
+
+<SECTION>
+<FILE>parttype</FILE>
+fdisk_parttype
+fdisk_copy_parttype
+fdisk_new_parttype
+fdisk_new_unknown_parttype
+fdisk_parttype_get_code
+fdisk_parttype_get_name
+fdisk_parttype_get_string
+fdisk_parttype_is_unknown
+fdisk_parttype_set_code
+fdisk_parttype_set_name
+fdisk_parttype_set_typestr
+fdisk_ref_parttype
+fdisk_unref_parttype
+</SECTION>
+
+<SECTION>
+<FILE>table</FILE>
+fdisk_get_freespaces
+fdisk_get_partitions
+<SUBSECTION>
+fdisk_table
+fdisk_apply_table
+fdisk_new_table
+fdisk_ref_table
+fdisk_reset_table
+fdisk_table_add_partition
+fdisk_table_get_nents
+fdisk_table_get_partition
+fdisk_table_is_empty
+fdisk_table_next_partition
+fdisk_table_remove_partition
+fdisk_table_sort_partitions
+fdisk_table_wrong_order
+fdisk_unref_table
+</SECTION>
+
+
+<SECTION>
+<FILE>context</FILE>
+fdisk_context
+fdisk_assign_device
+fdisk_deassign_device
+fdisk_enable_details
+fdisk_enable_listonly
+fdisk_get_alignment_offset
+fdisk_get_devfd
+fdisk_get_devname
+fdisk_get_first_lba
+fdisk_get_geom_cylinders
+fdisk_get_geom_heads
+fdisk_get_geom_sectors
+fdisk_get_grain_size
+fdisk_get_last_lba
+fdisk_get_minimal_iosize
+fdisk_get_nsectors
+fdisk_get_optimal_iosize
+fdisk_get_parent
+fdisk_get_physector_size
+fdisk_get_sector_size
+fdisk_get_unit
+fdisk_get_units_per_sector
+fdisk_has_label
+fdisk_has_user_device_properties
+fdisk_is_details
+fdisk_is_labeltype
+fdisk_is_listonly
+fdisk_is_readonly
+fdisk_new_context
+fdisk_new_nested_context
+fdisk_ref_context
+fdisk_set_first_lba
+fdisk_set_last_lba
+fdisk_set_unit
+fdisk_unref_context
+fdisk_use_cylinders
+</SECTION>
+
+<SECTION>
+<FILE>utils</FILE>
+fdisk_partname
+</SECTION>
+
+<SECTION>
+<FILE>iter</FILE>
+fdisk_free_iter
+fdisk_iter_get_direction
+fdisk_new_iter
+fdisk_reset_iter
+</SECTION>
diff --git a/libblkid/libfdisk/docs/version.xml.in b/libblkid/libfdisk/docs/version.xml.in
new file mode 100644
index 0000000..d78bda9
--- /dev/null
+++ b/libblkid/libfdisk/docs/version.xml.in
@@ -0,0 +1 @@
+@VERSION@
diff --git a/libblkid/libfdisk/fdisk.pc.in b/libblkid/libfdisk/fdisk.pc.in
new file mode 100644
index 0000000..bf81df0
--- /dev/null
+++ b/libblkid/libfdisk/fdisk.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@usrlib_execdir@
+includedir=@includedir@
+
+Name: fdisk
+Description: fdisk library
+Version: @LIBFDISK_VERSION@
+Requires.private: @LIBFDISK_PC_REQUIRES@
+Cflags: -I${includedir}/libfdisk
+Libs: -L${libdir} -lfdisk
diff --git a/libblkid/libfdisk/src/.gitignore b/libblkid/libfdisk/src/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libblkid/libfdisk/src/.gitignore
diff --git a/libblkid/libfdisk/src/Makemodule.am b/libblkid/libfdisk/src/Makemodule.am
new file mode 100644
index 0000000..18ddec7
--- /dev/null
+++ b/libblkid/libfdisk/src/Makemodule.am
@@ -0,0 +1,112 @@
+
+# libfdisk.h is generated, so it's stored in builddir!
+fdiskincdir = $(includedir)/libfdisk
+nodist_fdiskinc_HEADERS = $(top_builddir)/libfdisk/src/libfdisk.h
+
+usrlib_exec_LTLIBRARIES += libfdisk.la
+libfdisk_la_SOURCES = \
+	include/list.h \
+	\
+	libfdisk/src/fdiskP.h \
+	libfdisk/src/init.c \
+	libfdisk/src/test.c \
+	libfdisk/src/ask.c \
+	libfdisk/src/alignment.c \
+	libfdisk/src/label.c \
+	libfdisk/src/utils.c \
+	libfdisk/src/context.c \
+	libfdisk/src/parttype.c \
+	libfdisk/src/partition.c \
+	libfdisk/src/table.c \
+	libfdisk/src/iter.c \
+	libfdisk/src/script.c \
+	\
+	libfdisk/src/sun.c \
+	libfdisk/src/sgi.c \
+	libfdisk/src/dos.c \
+	libfdisk/src/bsd.c \
+	libfdisk/src/gpt.c \
+	$(nodist_fdiskinc_HEADERS)
+
+
+nodist_libfdisk_la_SOURCES = libfdisk/src/fdiskP.h
+
+libfdisk_la_LIBADD = libcommon.la libuuid.la
+
+libfdisk_la_CFLAGS = \
+	$(SOLIB_CFLAGS) \
+	-I$(ul_libuuid_incdir) \
+	-I$(ul_libfdisk_incdir) \
+	-I$(top_srcdir)/libfdisk/src
+
+libfdisk_la_DEPENDENCIES = \
+	libcommon.la \
+	libuuid.la \
+	libfdisk/src/libfdisk.sym \
+	libfdisk/src/libfdisk.h.in
+
+libfdisk_la_LDFLAGS = \
+	$(SOLIB_LDFLAGS) \
+	-Wl,--version-script=$(top_srcdir)/libfdisk/src/libfdisk.sym \
+	-version-info $(LIBFDISK_VERSION_INFO)
+
+if BUILD_LIBBLKID
+libfdisk_la_LIBADD += libblkid.la
+libfdisk_la_DEPENDENCIES += libblkid.la
+libfdisk_la_CFLAGS += -I$(ul_libblkid_incdir)
+endif
+
+EXTRA_DIST += \
+	libfdisk/src/libfdisk.sym \
+	libfdisk/src/libfdisk.h.in
+
+if BUILD_LIBFDISK_TESTS
+check_PROGRAMS += \
+	test_fdisk_ask \
+	test_fdisk_script \
+	test_fdisk_utils
+
+libfdisk_tests_cflags  = -DTEST_PROGRAM $(libfdisk_la_CFLAGS)
+libfdisk_tests_ldflags = libuuid.la -static
+libfdisk_tests_ldadd   = libfdisk.la $(UUID_LIBS)
+
+if BUILD_LIBBLKID
+libfdisk_tests_ldflags += libblkid.la
+endif
+
+test_fdisk_ask_SOURCES = libfdisk/src/ask.c
+test_fdisk_ask_CFLAGS = $(libfdisk_tests_cflags)
+test_fdisk_ask_LDFLAGS = $(libfdisk_tests_ldflags)
+test_fdisk_ask_LDADD = $(libfdisk_tests_ldadd)
+
+test_fdisk_utils_SOURCES = libfdisk/src/utils.c
+test_fdisk_utils_CFLAGS = $(libfdisk_tests_cflags)
+test_fdisk_utils_LDFLAGS = $(libfdisk_tests_ldflags)
+test_fdisk_utils_LDADD = $(libfdisk_tests_ldadd)
+
+test_fdisk_script_SOURCES = libfdisk/src/script.c
+test_fdisk_script_CFLAGS = $(libfdisk_tests_cflags)
+test_fdisk_script_LDFLAGS = $(libfdisk_tests_ldflags)
+test_fdisk_script_LDADD = $(libfdisk_tests_ldadd)
+
+endif # BUILD_LIBFDISK_TESTS
+
+
+# move lib from $(usrlib_execdir) to $(libdir) if needed
+install-exec-hook-libfdisk:
+	if test "$(usrlib_execdir)" != "$(libdir)" -a -f "$(DESTDIR)$(usrlib_execdir)/libfdisk.so"; then \
+		mkdir -p $(DESTDIR)$(libdir); \
+		mv $(DESTDIR)$(usrlib_execdir)/libfdisk.so.* $(DESTDIR)$(libdir); \
+		so_img_name=$$(readlink $(DESTDIR)$(usrlib_execdir)/libfdisk.so); \
+		so_img_rel_target=$$(echo $(usrlib_execdir) | sed 's,\(^/\|\)[^/][^/]*,..,g'); \
+		(cd $(DESTDIR)$(usrlib_execdir) && \
+			rm -f libfdisk.so && \
+			$(LN_S) $$so_img_rel_target$(libdir)/$$so_img_name libfdisk.so); \
+	fi
+
+uninstall-hook-libfdisk:
+	rm -f $(DESTDIR)$(libdir)/libfdisk.so*
+
+INSTALL_EXEC_HOOKS += install-exec-hook-libfdisk
+UNINSTALL_HOOKS += uninstall-hook-libfdisk
+
diff --git a/libblkid/libfdisk/src/alignment.c b/libblkid/libfdisk/src/alignment.c
new file mode 100644
index 0000000..67f1ddd
--- /dev/null
+++ b/libblkid/libfdisk/src/alignment.c
@@ -0,0 +1,654 @@
+
+#ifdef HAVE_LIBBLKID
+#include <blkid.h>
+#endif
+#include "blkdev.h"
+
+#include "fdiskP.h"
+
+/**
+ * SECTION: alignment
+ * @title: Alignment
+ * @short_description: functions to align partitions and work with disk topology and geometry
+ *
+ * The libfdisk aligns the end of the partitions to make it possible to align
+ * the next partition to the "grain" (see fdisk_get_grain()). The grain is
+ * usually 1MiB (or more for devices where optimal I/O is greater than 1MiB).
+ *
+ * It means that the library does not align strictly to physical sector size
+ * (or minimal or optimal I/O), but it uses greater granularity. It makes
+ * partition tables more portable. If you copy disk layout from 512-sector to
+ * 4K-sector device, all partitions are still aligned to physical sectors.
+ *
+ * This unified concept also makes partition tables more user friendly, all
+ * tables look same, LBA of the first partition is 2048 sectors everywhere, etc.
+ *
+ * It's recommended to not change any alignment or device properties. All is
+ * initialized by default by fdisk_assign_device().
+ *
+ * Note that terminology used by libfdisk is: 
+ *   - device properties: I/O limits (topology), geometry, sector size, ...
+ *   - alignment: first, last LBA, grain, ...
+ *
+ * The alignment setting may be modified by disk label driver.
+ */
+
+/*
+ * Alignment according to logical granularity (usually 1MiB)
+ */
+static int lba_is_aligned(struct fdisk_context *cxt, fdisk_sector_t lba)
+{
+	unsigned long granularity = max(cxt->phy_sector_size, cxt->min_io_size);
+	uintmax_t offset;
+
+	if (cxt->grain > granularity)
+		granularity = cxt->grain;
+	offset = (lba * cxt->sector_size) & (granularity - 1);
+
+	return !((granularity + cxt->alignment_offset - offset) & (granularity - 1));
+}
+
+/*
+ * Alignment according to physical device topology (usually minimal i/o size)
+ */
+static int lba_is_phy_aligned(struct fdisk_context *cxt, fdisk_sector_t lba)
+{
+	unsigned long granularity = max(cxt->phy_sector_size, cxt->min_io_size);
+	uintmax_t offset = (lba * cxt->sector_size) & (granularity - 1);
+
+	return !((granularity + cxt->alignment_offset - offset) & (granularity - 1));
+}
+
+/**
+ * fdisk_align_lba:
+ * @cxt: context
+ * @lba: address to align
+ * @direction: FDISK_ALIGN_{UP,DOWN,NEAREST}
+ *
+ * This function aligns @lba to the "grain" (see fdisk_get_grain()). If the
+ * device uses alignment offset then the result is moved according the offset
+ * to be on the physical boundary.
+ *
+ * Returns: alignment LBA.
+ */
+fdisk_sector_t fdisk_align_lba(struct fdisk_context *cxt, fdisk_sector_t lba, int direction)
+{
+	fdisk_sector_t res;
+
+	if (lba_is_aligned(cxt, lba))
+		res = lba;
+	else {
+		fdisk_sector_t sects_in_phy = cxt->grain / cxt->sector_size;
+
+		if (lba < cxt->first_lba)
+			res = cxt->first_lba;
+
+		else if (direction == FDISK_ALIGN_UP)
+			res = ((lba + sects_in_phy) / sects_in_phy) * sects_in_phy;
+
+		else if (direction == FDISK_ALIGN_DOWN)
+			res = (lba / sects_in_phy) * sects_in_phy;
+
+		else /* FDISK_ALIGN_NEAREST */
+			res = ((lba + sects_in_phy / 2) / sects_in_phy) * sects_in_phy;
+
+		if (cxt->alignment_offset && !lba_is_aligned(cxt, res) &&
+		    res > cxt->alignment_offset / cxt->sector_size) {
+			/*
+			 * apply alignment_offset
+			 *
+			 * On disk with alignment compensation physical blocks starts
+			 * at LBA < 0 (usually LBA -1). It means we have to move LBA
+			 * according the offset to be on the physical boundary.
+			 */
+			/* fprintf(stderr, "LBA: %llu apply alignment_offset\n", res); */
+			res -= (max(cxt->phy_sector_size, cxt->min_io_size) -
+					cxt->alignment_offset) / cxt->sector_size;
+
+			if (direction == FDISK_ALIGN_UP && res < lba)
+				res += sects_in_phy;
+		}
+	}
+
+	if (lba != res)
+		DBG(CXT, ul_debugobj(cxt, "LBA %ju -aligned-to-> %ju",
+				(uintmax_t) lba,
+				(uintmax_t) res));
+	return res;
+}
+
+/**
+ * fdisk_align_lba_in_range:
+ * @cxt: context
+ * @lba: LBA
+ * @start: range start
+ * @stop: range stop
+ *
+ * Align @lba, the result has to be between @start and @stop
+ *
+ * Returns: aligned LBA
+ */
+fdisk_sector_t fdisk_align_lba_in_range(struct fdisk_context *cxt,
+				  fdisk_sector_t lba, fdisk_sector_t start, fdisk_sector_t stop)
+{
+	fdisk_sector_t res;
+
+	start = fdisk_align_lba(cxt, start, FDISK_ALIGN_UP);
+	stop = fdisk_align_lba(cxt, stop, FDISK_ALIGN_DOWN);
+	lba = fdisk_align_lba(cxt, lba, FDISK_ALIGN_NEAREST);
+
+	if (lba < start)
+		res = start;
+	else if (lba > stop)
+		res = stop;
+	else
+		res = lba;
+
+	DBG(CXT, ul_debugobj(cxt, "LBA %ju range:<%ju..%ju>, result: %ju",
+				(uintmax_t) lba,
+				(uintmax_t) start,
+				(uintmax_t) stop,
+				(uintmax_t) res));
+	return res;
+}
+
+/**
+ * fdisk_lba_is_phy_aligned:
+ * @cxt: context
+ * @lba: LBA to check
+ *
+ * Check if the @lba is aligned to physical sector boundary.
+ *
+ * Returns: 1 if aligned.
+ */
+int fdisk_lba_is_phy_aligned(struct fdisk_context *cxt, fdisk_sector_t lba)
+{
+	return lba_is_phy_aligned(cxt, lba);
+}
+
+static unsigned long get_sector_size(int fd)
+{
+	int sect_sz;
+
+	if (!blkdev_get_sector_size(fd, &sect_sz))
+		return (unsigned long) sect_sz;
+	return DEFAULT_SECTOR_SIZE;
+}
+
+static void recount_geometry(struct fdisk_context *cxt)
+{
+	if (!cxt->geom.heads)
+		cxt->geom.heads = 255;
+	if (!cxt->geom.sectors)
+		cxt->geom.sectors = 63;
+
+	cxt->geom.cylinders = cxt->total_sectors /
+		(cxt->geom.heads * cxt->geom.sectors);
+}
+
+/**
+ * fdisk_override_geometry:
+ * @cxt: fdisk context
+ * @cylinders: user specified cylinders
+ * @heads: user specified heads
+ * @sectors: user specified sectors
+ *
+ * Overrides auto-discovery. The function fdisk_reset_device_properties()
+ * restores the original setting.
+ *
+ * The difference between fdisk_override_geometry() and fdisk_save_user_geometry()
+ * is that saved user geometry is persistent setting and it's applied always
+ * when device is assigned to the context or device properties are reseted.
+ *
+ * Returns: 0 on success, < 0 on error.
+ */
+int fdisk_override_geometry(struct fdisk_context *cxt,
+			    unsigned int cylinders,
+			    unsigned int heads,
+			    unsigned int sectors)
+{
+	if (!cxt)
+		return -EINVAL;
+	if (heads)
+		cxt->geom.heads = heads;
+	if (sectors)
+		cxt->geom.sectors = sectors;
+
+	if (cylinders)
+		cxt->geom.cylinders = cylinders;
+	else
+		recount_geometry(cxt);
+
+	fdisk_reset_alignment(cxt);
+
+	DBG(CXT, ul_debugobj(cxt, "override C/H/S: %u/%u/%u",
+		(unsigned) cxt->geom.cylinders,
+		(unsigned) cxt->geom.heads,
+		(unsigned) cxt->geom.sectors));
+
+	return 0;
+}
+
+/**
+ * fdisk_save_user_geometry:
+ * @cxt: context
+ * @cylinders: C
+ * @heads: H
+ * @sectors: S
+ *
+ * Save user defined geometry to use it for partitioning.
+ *
+ * The user properties are applied by fdisk_assign_device() or
+ * fdisk_reset_device_properties().
+
+ * Returns: <0 on error, 0 on success.
+ */
+int fdisk_save_user_geometry(struct fdisk_context *cxt,
+			    unsigned int cylinders,
+			    unsigned int heads,
+			    unsigned int sectors)
+{
+	if (!cxt)
+		return -EINVAL;
+
+	if (heads)
+		cxt->user_geom.heads = heads > 256 ? 0 : heads;
+	if (sectors)
+		cxt->user_geom.sectors = sectors >= 64 ? 0 : sectors;
+	if (cylinders)
+		cxt->user_geom.cylinders = cylinders;
+
+	DBG(CXT, ul_debugobj(cxt, "user C/H/S: %u/%u/%u",
+				(unsigned) cxt->user_geom.cylinders,
+				(unsigned) cxt->user_geom.heads,
+				(unsigned) cxt->user_geom.sectors));
+
+	return 0;
+}
+
+/**
+ * fdisk_save_user_sector_size:
+ * @cxt: context
+ * @phy: physical sector size
+ * @log: logicla sector size
+ *
+ * Save user defined sector sizes to use it for partitioning.
+ *
+ * The user properties are applied by fdisk_assign_device() or 
+ * fdisk_reset_device_properties().
+ *
+ * Returns: <0 on error, 0 on success.
+ */
+int fdisk_save_user_sector_size(struct fdisk_context *cxt,
+				unsigned int phy,
+				unsigned int log)
+{
+	if (!cxt)
+		return -EINVAL;
+
+	DBG(CXT, ul_debugobj(cxt, "user phy/log sector size: %u/%u", phy, log));
+
+	cxt->user_pyh_sector = phy;
+	cxt->user_log_sector = log;
+
+	return 0;
+}
+
+/**
+ * fdisk_has_user_device_properties:
+ * @cxt: context
+ *
+ * Returns: 1 if user specified any properties
+ */
+int fdisk_has_user_device_properties(struct fdisk_context *cxt)
+{
+	return (cxt->user_pyh_sector
+		    || cxt->user_log_sector
+		    || cxt->user_geom.heads
+		    || cxt->user_geom.sectors
+		    || cxt->user_geom.cylinders);
+}
+
+int fdisk_apply_user_device_properties(struct fdisk_context *cxt)
+{
+	if (!cxt)
+		return -EINVAL;
+
+	DBG(CXT, ul_debugobj(cxt, "appling user device properties"));
+
+	if (cxt->user_pyh_sector)
+		cxt->phy_sector_size = cxt->user_pyh_sector;
+	if (cxt->user_log_sector)
+		cxt->sector_size = cxt->min_io_size =
+			cxt->io_size = cxt->user_log_sector;
+
+	if (cxt->user_geom.heads)
+		cxt->geom.heads = cxt->user_geom.heads;
+	if (cxt->user_geom.sectors)
+		cxt->geom.sectors = cxt->user_geom.sectors;
+
+	if (cxt->user_geom.cylinders)
+		cxt->geom.cylinders = cxt->user_geom.cylinders;
+	else if (cxt->user_geom.heads || cxt->user_geom.sectors)
+		recount_geometry(cxt);
+
+	fdisk_reset_alignment(cxt);
+	if (cxt->firstsector_bufsz != cxt->sector_size)
+		fdisk_read_firstsector(cxt);
+
+	DBG(CXT, ul_debugobj(cxt, "new C/H/S: %u/%u/%u",
+		(unsigned) cxt->geom.cylinders,
+		(unsigned) cxt->geom.heads,
+		(unsigned) cxt->geom.sectors));
+	DBG(CXT, ul_debugobj(cxt, "new log/phy sector size: %u/%u",
+		(unsigned) cxt->sector_size,
+		(unsigned) cxt->phy_sector_size));
+
+	return 0;
+}
+
+void fdisk_zeroize_device_properties(struct fdisk_context *cxt)
+{
+	assert(cxt);
+
+	cxt->io_size = 0;
+	cxt->optimal_io_size = 0;
+	cxt->min_io_size = 0;
+	cxt->phy_sector_size = 0;
+	cxt->sector_size = 0;
+	cxt->alignment_offset = 0;
+	cxt->grain = 0;
+	cxt->first_lba = 0;
+	cxt->last_lba = 0;
+	cxt->total_sectors = 0;
+
+	memset(&cxt->geom, 0, sizeof(struct fdisk_geometry));
+}
+
+/**
+ * fdisk_reset_device_properties:
+ * @cxt: context
+ *
+ * Resets and discovery topology (I/O limits), geometry, re-read the first
+ * rector on the device if necessary and apply user device setting (geometry
+ * and sector size), then initialize alignment according to label driver (see
+ * fdisk_reset_alignment()).
+ *
+ * You don't have to use this function by default, fdisk_assign_device() is
+ * smart enough to initialize all necessary setting.
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_reset_device_properties(struct fdisk_context *cxt)
+{
+	int rc;
+
+	if (!cxt)
+		return -EINVAL;
+
+	DBG(CXT, ul_debugobj(cxt, "*** reseting device properties"));
+
+	fdisk_zeroize_device_properties(cxt);
+	fdisk_discover_topology(cxt);
+	fdisk_discover_geometry(cxt);
+
+	rc = fdisk_read_firstsector(cxt);
+	if (rc)
+		return rc;
+
+	fdisk_apply_user_device_properties(cxt);
+	return 0;
+}
+
+/*
+ * Generic (label independent) geometry
+ */
+int fdisk_discover_geometry(struct fdisk_context *cxt)
+{
+	fdisk_sector_t nsects;
+
+	assert(cxt);
+	assert(cxt->geom.heads == 0);
+
+	DBG(CXT, ul_debugobj(cxt, "%s: discovering geometry...", cxt->dev_path));
+
+	/* get number of 512-byte sectors, and convert it the real sectors */
+	if (!blkdev_get_sectors(cxt->dev_fd, (unsigned long long *) &nsects))
+		cxt->total_sectors = (nsects / (cxt->sector_size >> 9));
+
+	DBG(CXT, ul_debugobj(cxt, "total sectors: %ju (ioctl=%ju)",
+				(uintmax_t) cxt->total_sectors,
+				(uintmax_t) nsects));
+
+	/* what the kernel/bios thinks the geometry is */
+	blkdev_get_geometry(cxt->dev_fd, &cxt->geom.heads, (unsigned int *) &cxt->geom.sectors);
+
+	/* obtained heads and sectors */
+	recount_geometry(cxt);
+
+	DBG(CXT, ul_debugobj(cxt, "result: C/H/S: %u/%u/%u",
+			       (unsigned) cxt->geom.cylinders,
+			       (unsigned) cxt->geom.heads,
+			       (unsigned) cxt->geom.sectors));
+	return 0;
+}
+
+int fdisk_discover_topology(struct fdisk_context *cxt)
+{
+#ifdef HAVE_LIBBLKID
+	blkid_probe pr;
+#endif
+	assert(cxt);
+	assert(cxt->sector_size == 0);
+
+	DBG(CXT, ul_debugobj(cxt, "%s: discovering topology...", cxt->dev_path));
+#ifdef HAVE_LIBBLKID
+	DBG(CXT, ul_debugobj(cxt, "initialize libblkid prober"));
+
+	pr = blkid_new_probe();
+	if (pr && blkid_probe_set_device(pr, cxt->dev_fd, 0, 0) == 0) {
+		blkid_topology tp = blkid_probe_get_topology(pr);
+
+		if (tp) {
+			cxt->min_io_size = blkid_topology_get_minimum_io_size(tp);
+			cxt->optimal_io_size = blkid_topology_get_optimal_io_size(tp);
+			cxt->phy_sector_size = blkid_topology_get_physical_sector_size(tp);
+			cxt->alignment_offset = blkid_topology_get_alignment_offset(tp);
+
+			/* I/O size used by fdisk */
+			cxt->io_size = cxt->optimal_io_size;
+			if (!cxt->io_size)
+				/* optimal IO is optional, default to minimum IO */
+				cxt->io_size = cxt->min_io_size;
+		}
+	}
+	blkid_free_probe(pr);
+#endif
+
+	cxt->sector_size = get_sector_size(cxt->dev_fd);
+	if (!cxt->phy_sector_size) /* could not discover physical size */
+		cxt->phy_sector_size = cxt->sector_size;
+
+	/* no blkid or error, use default values */
+	if (!cxt->min_io_size)
+		cxt->min_io_size = cxt->sector_size;
+	if (!cxt->io_size)
+		cxt->io_size = cxt->sector_size;
+
+	DBG(CXT, ul_debugobj(cxt, "result: log/phy sector size: %ld/%ld",
+			cxt->sector_size, cxt->phy_sector_size));
+	DBG(CXT, ul_debugobj(cxt, "result: fdisk/min/optimal io: %ld/%ld/%ld",
+		       cxt->io_size, cxt->optimal_io_size, cxt->min_io_size));
+	return 0;
+}
+
+static int has_topology(struct fdisk_context *cxt)
+{
+	/*
+	 * Assume that the device provides topology info if
+	 * optimal_io_size is set or alignment_offset is set or
+	 * minimum_io_size is not power of 2.
+	 */
+	if (cxt &&
+	    (cxt->optimal_io_size ||
+	     cxt->alignment_offset ||
+	     !is_power_of_2(cxt->min_io_size)))
+		return 1;
+	return 0;
+}
+
+/*
+ * The LBA of the first partition is based on the device geometry and topology.
+ * This offset is generic (and recommended) for all labels.
+ *
+ * Returns: 0 on error or number of logical sectors.
+ */
+static fdisk_sector_t topology_get_first_lba(struct fdisk_context *cxt)
+{
+	fdisk_sector_t x = 0, res;
+
+	if (!cxt)
+		return 0;
+
+	if (!cxt->io_size)
+		fdisk_discover_topology(cxt);
+
+	/*
+	 * Align the begin of partitions to:
+	 *
+	 * a) topology
+	 *  a2) alignment offset
+	 *  a1) or physical sector (minimal_io_size, aka "grain")
+	 *
+	 * b) or default to 1MiB (2048 sectrors, Windows Vista default)
+	 *
+	 * c) or for very small devices use 1 phy.sector
+	 */
+	if (has_topology(cxt)) {
+		if (cxt->alignment_offset)
+			x = cxt->alignment_offset;
+		else if (cxt->io_size > 2048 * 512)
+			x = cxt->io_size;
+	}
+	/* default to 1MiB */
+	if (!x)
+		x = 2048 * 512;
+
+	res = x / cxt->sector_size;
+
+	/* don't use huge offset on small devices */
+	if (cxt->total_sectors <= res * 4)
+		res = cxt->phy_sector_size / cxt->sector_size;
+
+	return res;
+}
+
+static unsigned long topology_get_grain(struct fdisk_context *cxt)
+{
+	unsigned long res;
+
+	if (!cxt)
+		return 0;
+
+	if (!cxt->io_size)
+		fdisk_discover_topology(cxt);
+
+	res = cxt->io_size;
+
+	/* use 1MiB grain always when possible */
+	if (res < 2048 * 512)
+		res = 2048 * 512;
+
+	/* don't use huge grain on small devices */
+	if (cxt->total_sectors <= (res * 4 / cxt->sector_size))
+		res = cxt->phy_sector_size;
+
+	return res;
+}
+
+/**
+ * fdisk_reset_alignment:
+ * @cxt: fdisk context
+ *
+ * Resets alignment setting to the default and label specific values. This
+ * function does not change device properties (I/O limits, geometry etc.).
+ *
+ * Returns: 0 on success, < 0 in case of error.
+ */
+int fdisk_reset_alignment(struct fdisk_context *cxt)
+{
+	int rc = 0;
+
+	if (!cxt)
+		return -EINVAL;
+
+	DBG(CXT, ul_debugobj(cxt, "reseting alignment..."));
+
+	/* default */
+	cxt->grain = topology_get_grain(cxt);
+	cxt->first_lba = topology_get_first_lba(cxt);
+	cxt->last_lba = cxt->total_sectors - 1;
+
+	/* overwrite default by label stuff */
+	if (cxt->label && cxt->label->op->reset_alignment)
+		rc = cxt->label->op->reset_alignment(cxt);
+
+	DBG(CXT, ul_debugobj(cxt, "alignment reseted to: "
+			    "first LBA=%ju, last LBA=%ju, grain=%lu [rc=%d]",
+			    (uintmax_t) cxt->first_lba, (uintmax_t) cxt->last_lba,
+			    cxt->grain,	rc));
+	return rc;
+}
+
+
+fdisk_sector_t fdisk_scround(struct fdisk_context *cxt, fdisk_sector_t num)
+{
+	fdisk_sector_t un = fdisk_get_units_per_sector(cxt);
+	return (num + un - 1) / un;
+}
+
+fdisk_sector_t fdisk_cround(struct fdisk_context *cxt, fdisk_sector_t num)
+{
+	return fdisk_use_cylinders(cxt) ?
+			(num / fdisk_get_units_per_sector(cxt)) + 1 : num;
+}
+
+/**
+ * fdisk_reread_partition_table:
+ * @cxt: context
+ *
+ * Force *kernel* to re-read partition table on block devices.
+ *
+ * Returns: 0 on success, < 0 in case of error.
+ */
+int fdisk_reread_partition_table(struct fdisk_context *cxt)
+{
+	int i;
+	struct stat statbuf;
+
+	assert(cxt);
+	assert(cxt->dev_fd >= 0);
+
+	i = fstat(cxt->dev_fd, &statbuf);
+	if (i == 0 && S_ISBLK(statbuf.st_mode)) {
+		sync();
+#ifdef BLKRRPART
+		fdisk_info(cxt, _("Calling ioctl() to re-read partition table."));
+		i = ioctl(cxt->dev_fd, BLKRRPART);
+#else
+		errno = ENOSYS;
+		i = 1;
+#endif
+	}
+
+	if (i) {
+		fdisk_warn(cxt, _("Re-reading the partition table failed."));
+		fdisk_info(cxt,	_(
+			"The kernel still uses the old table. The "
+			"new table will be used at the next reboot "
+			"or after you run partprobe(8) or kpartx(8)."));
+		return -errno;
+	}
+
+	return 0;
+}
diff --git a/libblkid/libfdisk/src/ask.c b/libblkid/libfdisk/src/ask.c
new file mode 100644
index 0000000..7e0c3c2
--- /dev/null
+++ b/libblkid/libfdisk/src/ask.c
@@ -0,0 +1,1044 @@
+
+#include "strutils.h"
+#include "fdiskP.h"
+
+/**
+ * SECTION: ask
+ * @title: Ask
+ * @short_description: interface for dialog driven partitioning, warning and info messages
+ *
+ */
+
+static void fdisk_ask_menu_reset_items(struct fdisk_ask *ask);
+
+
+/**
+ * fdisk_set_ask:
+ * @cxt: context
+ * @ask_cb: callback
+ * @data: callback data
+ *
+ * Set callback for dialog driven partitioning and library warnings/errors.
+ *
+ * Returns: 0 on success, < 0 on error.
+ */
+int fdisk_set_ask(struct fdisk_context *cxt,
+		int (*ask_cb)(struct fdisk_context *, struct fdisk_ask *, void *),
+		void *data)
+{
+	assert(cxt);
+
+	cxt->ask_cb = ask_cb;
+	cxt->ask_data = data;
+	return 0;
+}
+
+struct fdisk_ask *fdisk_new_ask(void)
+{
+	struct fdisk_ask *ask = calloc(1, sizeof(struct fdisk_ask));
+	DBG(ASK, ul_debugobj(ask, "alloc"));
+	ask->refcount = 1;
+	return ask;
+}
+
+void fdisk_reset_ask(struct fdisk_ask *ask)
+{
+	int refcount;
+
+	assert(ask);
+	free(ask->query);
+
+	DBG(ASK, ul_debugobj(ask, "reset"));
+	refcount = ask->refcount;
+
+	if (fdisk_is_ask(ask, MENU))
+		fdisk_ask_menu_reset_items(ask);
+
+	memset(ask, 0, sizeof(*ask));
+	ask->refcount = refcount;
+}
+
+/**
+ * fdisk_ref_ask:
+ * @ask: ask instance
+ *
+ * Incremparts reference counter.
+ */
+void fdisk_ref_ask(struct fdisk_ask *ask)
+{
+	if (ask)
+		ask->refcount++;
+}
+
+
+/**
+ * fdisk_unref_ask:
+ * @ask: ask instance
+ *
+ * De-incremparts reference counter, on zero the @ask is automatically
+ * deallocated.
+ */
+void fdisk_unref_ask(struct fdisk_ask *ask)
+{
+	if (!ask)
+		return;
+	ask->refcount--;
+
+	if (ask->refcount <= 0) {
+		fdisk_reset_ask(ask);
+		DBG(ASK, ul_debugobj(ask, "free"));
+		free(ask);
+	}
+}
+
+/**
+ * fdisk_ask_get_query:
+ * @ask: ask instance
+ *
+ * Returns: pointer to dialog string.
+ */
+const char *fdisk_ask_get_query(struct fdisk_ask *ask)
+{
+	assert(ask);
+	return ask->query;
+}
+
+int fdisk_ask_set_query(struct fdisk_ask *ask, const char *str)
+{
+	assert(ask);
+	return !strdup_to_struct_member(ask, query, str) ? -ENOMEM : 0;
+}
+
+/**
+ * fdisk_ask_get_type:
+ * @ask: ask instance
+ *
+ * Returns: FDISK_ASKTYPE_*
+ */
+int fdisk_ask_get_type(struct fdisk_ask *ask)
+{
+	assert(ask);
+	return ask->type;
+}
+
+int fdisk_ask_set_type(struct fdisk_ask *ask, int type)
+{
+	assert(ask);
+	ask->type = type;
+	return 0;
+}
+
+int fdisk_do_ask(struct fdisk_context *cxt, struct fdisk_ask *ask)
+{
+	int rc;
+
+	assert(ask);
+	assert(cxt);
+
+	DBG(ASK, ul_debugobj(ask, "do_ask for '%s'",
+				ask->query ? ask->query :
+				ask->type == FDISK_ASKTYPE_INFO  ? "info" :
+				ask->type == FDISK_ASKTYPE_WARNX ? "warnx" :
+				ask->type == FDISK_ASKTYPE_WARN  ? "warn" :
+				"?nothing?"));
+
+	if (!cxt->ask_cb) {
+		DBG(ASK, ul_debugobj(ask, "no ask callback specified!"));
+		return -EINVAL;
+	}
+
+	rc = cxt->ask_cb(cxt, ask, cxt->ask_data);
+
+	DBG(ASK, ul_debugobj(ask, "do_ask done [rc=%d]", rc));
+	return rc;
+}
+
+#define is_number_ask(a)  (fdisk_is_ask(a, NUMBER) || fdisk_is_ask(a, OFFSET))
+
+/**
+ * fdisk_ask_number_get_range:
+ * @ask: ask instance
+ *
+ * Returns: string with range (e.g. "1,3,5-10")
+ */
+const char *fdisk_ask_number_get_range(struct fdisk_ask *ask)
+{
+	assert(ask);
+	assert(is_number_ask(ask));
+	return ask->data.num.range;
+}
+
+int fdisk_ask_number_set_range(struct fdisk_ask *ask, const char *range)
+{
+	assert(ask);
+	assert(is_number_ask(ask));
+	ask->data.num.range = range;
+	return 0;
+}
+
+/**
+ * fdisk_ask_number_get_default:
+ * @ask: ask instance
+ *
+ * Returns: default number
+ *
+ */
+uint64_t fdisk_ask_number_get_default(struct fdisk_ask *ask)
+{
+	assert(ask);
+	assert(is_number_ask(ask));
+	return ask->data.num.dfl;
+}
+
+int fdisk_ask_number_set_default(struct fdisk_ask *ask, uint64_t dflt)
+{
+	assert(ask);
+	ask->data.num.dfl = dflt;
+	return 0;
+}
+
+/**
+ * fdisk_ask_number_get_low:
+ * @ask: ask instance
+ *
+ * Returns: minimal possible number when ask for numbers in range
+ */
+uint64_t fdisk_ask_number_get_low(struct fdisk_ask *ask)
+{
+	assert(ask);
+	assert(is_number_ask(ask));
+	return ask->data.num.low;
+}
+
+int fdisk_ask_number_set_low(struct fdisk_ask *ask, uint64_t low)
+{
+	assert(ask);
+	ask->data.num.low = low;
+	return 0;
+}
+
+/**
+ * fdisk_ask_number_get_high:
+ * @ask: ask instance
+ *
+ * Returns: maximal possible number when ask for numbers in range
+ */
+uint64_t fdisk_ask_number_get_high(struct fdisk_ask *ask)
+{
+	assert(ask);
+	assert(is_number_ask(ask));
+	return ask->data.num.hig;
+}
+
+int fdisk_ask_number_set_high(struct fdisk_ask *ask, uint64_t high)
+{
+	assert(ask);
+	ask->data.num.hig = high;
+	return 0;
+}
+
+/**
+ * fdisk_ask_number_get_result:
+ * @ask: ask instance
+ *
+ * Returns: result
+ */
+uint64_t fdisk_ask_number_get_result(struct fdisk_ask *ask)
+{
+	assert(ask);
+	assert(is_number_ask(ask));
+	return ask->data.num.result;
+}
+
+/**
+ * fdisk_ask_number_set_result:
+ * @ask: ask instance
+ * @result: dialog result
+ *
+ * Returns: 0 on success, <0 on error
+ */
+int fdisk_ask_number_set_result(struct fdisk_ask *ask, uint64_t result)
+{
+	assert(ask);
+	ask->data.num.result = result;
+	return 0;
+}
+
+/**
+ * fdisk_ask_number_get_base:
+ * @ask: ask instance
+ *
+ * Returns: base when user specify number in relative notation (+size)
+ */
+uint64_t fdisk_ask_number_get_base(struct fdisk_ask *ask)
+{
+	assert(ask);
+	assert(is_number_ask(ask));
+	return ask->data.num.base;
+}
+
+int fdisk_ask_number_set_base(struct fdisk_ask *ask, uint64_t base)
+{
+	assert(ask);
+	ask->data.num.base = base;
+	return 0;
+}
+
+/**
+ * fdisk_ask_number_get_unit:
+ * @ask: ask instance
+ *
+ * Returns: number of bytes per the unit
+ */
+uint64_t fdisk_ask_number_get_unit(struct fdisk_ask *ask)
+{
+	assert(ask);
+	assert(is_number_ask(ask));
+	return ask->data.num.unit;
+}
+
+int fdisk_ask_number_set_unit(struct fdisk_ask *ask, uint64_t unit)
+{
+	assert(ask);
+	ask->data.num.unit = unit;
+	return 0;
+}
+
+int fdisk_ask_number_is_relative(struct fdisk_ask *ask)
+{
+	assert(ask);
+	assert(is_number_ask(ask));
+	return ask->data.num.relative;
+}
+
+/**
+ * fdisk_ask_number_set_relative
+ * @ask: ask instance
+ * @relative: 0 or 1
+ *
+ * Inform libfdisk that user specified number in relative notation rather than
+ * by explicit number. This info allows to fdisk do some optimization (e.g.
+ * align end of partiton, etc.)
+ *
+ * Returns: 0 on success, <0 on error
+ */
+int fdisk_ask_number_set_relative(struct fdisk_ask *ask, int relative)
+{
+	assert(ask);
+	ask->data.num.relative = relative ? 1 : 0;
+	return 0;
+}
+
+/**
+ * fdisk_ask_number_inchars:
+ * @ask: ask instance
+ *
+ * For example for BSD is normal to address partition by chars rather than by
+ * number (first partition is 'a').
+ *
+ * Returns: 1 if number should be presented as chars
+ *
+ */
+int fdisk_ask_number_inchars(struct fdisk_ask *ask)
+{
+	assert(ask);
+	assert(is_number_ask(ask));
+	return ask->data.num.inchars;
+}
+
+/*
+ * Generates string with list ranges (e.g. 1,2,5-8) for the 'cur'
+ */
+#define tochar(num)	((int) ('a' + num - 1))
+static char *mk_string_list(char *ptr, size_t *len, size_t *begin,
+			    size_t *run, ssize_t cur, int inchar)
+{
+	int rlen;
+
+	if (cur != -1) {
+		if (!*begin) {			/* begin of the list */
+			*begin = cur + 1;
+			return ptr;
+		}
+
+		if (*begin + *run == cur) {	/* no gap, continue */
+			(*run)++;
+			return ptr;
+		}
+	} else if (!*begin) {
+		*ptr = '\0';
+		return ptr;		/* end of empty list */
+	}
+
+					/* add to the list */
+	if (!*run)
+		rlen = inchar ? snprintf(ptr, *len, "%c,", tochar(*begin)) :
+				snprintf(ptr, *len, "%zu,", *begin);
+	else if (*run == 1)
+		rlen = inchar ?
+			snprintf(ptr, *len, "%c,%c,", tochar(*begin), tochar(*begin + 1)) :
+			snprintf(ptr, *len, "%zu,%zu,", *begin, *begin + 1);
+	else
+		rlen = inchar ?
+			snprintf(ptr, *len, "%c-%c,", tochar(*begin), tochar(*begin + *run)) :
+			snprintf(ptr, *len, "%zu-%zu,", *begin, *begin + *run);
+
+	if (rlen < 0 || (size_t) rlen + 1 > *len)
+		return NULL;
+
+	ptr += rlen;
+
+	if (rlen > 0 && *len > (size_t) rlen)
+		*len -= rlen;
+	else
+		*len = 0;
+
+	if (cur == -1 && *begin) {
+		/* end of the list */
+		*(ptr - 1) = '\0';	/* remove tailing ',' from the list */
+		return ptr;
+	}
+
+	*begin = cur + 1;
+	*run = 0;
+
+	return ptr;
+}
+
+/**
+ * fdisk_ask_partnum:
+ * @cxt: context
+ * @partnum: returns partition number
+ * @wantnew: 0|1
+ *
+ * High-level API to ask for used or unused partition number.
+ *
+ * Returns: 0 on success, < 0 on error, 1 if no free/used partition
+ */
+int fdisk_ask_partnum(struct fdisk_context *cxt, size_t *partnum, int wantnew)
+{
+	int rc = 0, inchar = 0;
+	char range[BUFSIZ], *ptr = range;
+	size_t i, len = sizeof(range), begin = 0, run = 0;
+	struct fdisk_ask *ask = NULL;
+	__typeof__(ask->data.num) *num;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(partnum);
+
+	if (cxt->label && cxt->label->flags & FDISK_LABEL_FL_INCHARS_PARTNO)
+		inchar = 1;
+
+	DBG(ASK, ul_debug("%s: asking for %s partition number "
+			  "(max: %zu, inchar: %s)",
+			cxt->label->name,
+			wantnew ? "new" : "used",
+			cxt->label->nparts_max,
+			inchar ? "yes" : "not"));
+
+	ask = fdisk_new_ask();
+	if (!ask)
+		return -ENOMEM;
+
+	fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER);
+	num = &ask->data.num;
+
+	ask->data.num.inchars = inchar ? 1 : 0;
+
+	for (i = 0; i < cxt->label->nparts_max; i++) {
+		int used = fdisk_is_partition_used(cxt, i);
+
+		if (wantnew && !used) {
+			ptr = mk_string_list(ptr, &len, &begin, &run, i, inchar);
+			if (!ptr) {
+				rc = -EINVAL;
+				break;
+			}
+			if (!num->low)
+				num->dfl = num->low = i + 1;
+			num->hig = i + 1;
+		} else if (!wantnew && used) {
+			ptr = mk_string_list(ptr, &len, &begin, &run, i, inchar);
+			if (!num->low)
+				num->low = i + 1;
+			num->dfl = num->hig = i + 1;
+		}
+	}
+
+	DBG(ASK, ul_debugobj(ask, "ask limits: low: %ju, high: %ju, default: %ju",
+				num->low, num->hig, num->dfl));
+
+	if (!rc && !wantnew && num->low == num->hig) {
+		if (num->low > 0) {
+			/* only one existing partiton, don't ask, return the number */
+			fdisk_ask_number_set_result(ask, num->low);
+			fdisk_info(cxt, _("Selected partition %ju"), num->low);
+
+		} else if (num->low == 0) {
+			fdisk_warnx(cxt, _("No partition is defined yet!"));
+			rc = 1;
+		}
+		goto dont_ask;
+	}
+	if (!rc && wantnew && num->low == num->hig) {
+		if (num->low > 0) {
+			/* only one free partition, don't ask, return the number */
+			fdisk_ask_number_set_result(ask, num->low);
+			fdisk_info(cxt, _("Selected partition %ju"), num->low);
+		}
+		if (num->low == 0) {
+			fdisk_warnx(cxt, _("No free partition available!"));
+			rc = 1;
+		}
+		goto dont_ask;
+	}
+	if (!rc) {
+		mk_string_list(ptr, &len, &begin, &run, -1, inchar);	/* terminate the list */
+		rc = fdisk_ask_number_set_range(ask, range);
+	}
+	if (!rc)
+		rc = fdisk_ask_set_query(ask, _("Partition number"));
+	if (!rc)
+		rc = fdisk_do_ask(cxt, ask);
+
+dont_ask:
+	if (!rc) {
+		*partnum = fdisk_ask_number_get_result(ask);
+		if (*partnum)
+			*partnum -= 1;
+	}
+	DBG(ASK, ul_debugobj(ask, "result: %ju [rc=%d]\n", fdisk_ask_number_get_result(ask), rc));
+	fdisk_unref_ask(ask);
+	return rc;
+}
+
+/**
+ * fdisk_ask_number:
+ * @cxt: context
+ * @low: minimal possible number
+ * @dflt: default suggestion
+ * @high: maximal possible number
+ * @query: question string
+ * @result: returns result
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_ask_number(struct fdisk_context *cxt,
+		     uintmax_t low,
+		     uintmax_t dflt,
+		     uintmax_t high,
+		     const char *query,
+		     uintmax_t *result)
+{
+	struct fdisk_ask *ask;
+	int rc;
+
+	assert(cxt);
+
+	ask = fdisk_new_ask();
+	if (!ask)
+		return -ENOMEM;
+
+	rc = fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER);
+	if (!rc)
+		fdisk_ask_number_set_low(ask, low);
+	if (!rc)
+		fdisk_ask_number_set_default(ask, dflt);
+	if (!rc)
+		fdisk_ask_number_set_high(ask, high);
+	if (!rc)
+		fdisk_ask_set_query(ask, query);
+	if (!rc)
+		rc = fdisk_do_ask(cxt, ask);
+	if (!rc)
+		*result = fdisk_ask_number_get_result(ask);
+
+	DBG(ASK, ul_debugobj(ask, "result: %ju [rc=%d]\n", *result, rc));
+	fdisk_unref_ask(ask);
+	return rc;
+}
+
+/**
+ * fdisk_ask_string_get_result:
+ * @ask: ask instance
+ *
+ * Returns: pointer to dialog result
+ */
+char *fdisk_ask_string_get_result(struct fdisk_ask *ask)
+{
+	assert(ask);
+	assert(fdisk_is_ask(ask, STRING));
+	return ask->data.str.result;
+}
+
+/**
+ * fdisk_ask_string_set_result:
+ * @ask: ask instance
+ * @result: pointer to allocated buffer with string
+ *
+ * You don't have to care about the @result deallocation, libfdisk is going to
+ * deallocate the result when destroy @ask instance.
+ *
+ * Returns: 0 on success, <0 on error
+ */
+int fdisk_ask_string_set_result(struct fdisk_ask *ask, char *result)
+{
+	assert(ask);
+	ask->data.str.result = result;
+	return 0;
+}
+
+/**
+ * fdisk_ask_string:
+ * @cxt: context:
+ * @query: question string
+ * @result: returns allocated buffer
+ *
+ * High-level API to ask for strings. Don't forget to deallocate the @result.
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_ask_string(struct fdisk_context *cxt,
+		     const char *query,
+		     char **result)
+{
+	struct fdisk_ask *ask;
+	int rc;
+
+	assert(cxt);
+
+	ask = fdisk_new_ask();
+	if (!ask)
+		return -ENOMEM;
+
+	rc = fdisk_ask_set_type(ask, FDISK_ASKTYPE_STRING);
+	if (!rc)
+		fdisk_ask_set_query(ask, query);
+	if (!rc)
+		rc = fdisk_do_ask(cxt, ask);
+	if (!rc)
+		*result = fdisk_ask_string_get_result(ask);
+
+	DBG(ASK, ul_debugobj(ask, "result: %s [rc=%d]\n", *result, rc));
+	fdisk_unref_ask(ask);
+	return rc;
+}
+
+/**
+ * fdisk_ask_yesno:
+ * @cxt: context
+ * @query: question string
+ * @result: returns 0 (no) or 1 (yes)
+ *
+ * Hight-level API to ask Yes/No questions
+ *
+ * Returns: 0 on success, <0 on error
+ */
+int fdisk_ask_yesno(struct fdisk_context *cxt,
+		     const char *query,
+		     int *result)
+{
+	struct fdisk_ask *ask;
+	int rc;
+
+	assert(cxt);
+
+	ask = fdisk_new_ask();
+	if (!ask)
+		return -ENOMEM;
+
+	rc = fdisk_ask_set_type(ask, FDISK_ASKTYPE_YESNO);
+	if (!rc)
+		fdisk_ask_set_query(ask, query);
+	if (!rc)
+		rc = fdisk_do_ask(cxt, ask);
+	if (!rc)
+		*result = fdisk_ask_yesno_get_result(ask) == 1 ? 1 : 0;
+
+	DBG(ASK, ul_debugobj(ask, "result: %d [rc=%d]\n", *result, rc));
+	fdisk_unref_ask(ask);
+	return rc;
+}
+
+/**
+ * fdisk_ask_yesno_get_result:
+ * @ask: ask instance
+ *
+ * Returns: 0 or 1
+ */
+int fdisk_ask_yesno_get_result(struct fdisk_ask *ask)
+{
+	assert(ask);
+	assert(fdisk_is_ask(ask, YESNO));
+	return ask->data.yesno.result;
+}
+
+/**
+ * fdisk_ask_yesno_set_result:
+ * @ask: ask instance
+ * @result: 1 or 0
+ *
+ * Returns: 0 on success, <0 on error
+ */
+int fdisk_ask_yesno_set_result(struct fdisk_ask *ask, int result)
+{
+	assert(ask);
+	ask->data.yesno.result = result;
+	return 0;
+}
+
+/*
+ * menu
+ */
+int fdisk_ask_menu_set_default(struct fdisk_ask *ask, int dfl)
+{
+	assert(ask);
+	assert(fdisk_is_ask(ask, MENU));
+	ask->data.menu.dfl = dfl;
+	return 0;
+}
+
+/**
+ * fdisk_ask_menu_get_default:
+ * @ask: ask instance
+ *
+ * Returns: default menu item key
+ */
+int fdisk_ask_menu_get_default(struct fdisk_ask *ask)
+{
+	assert(ask);
+	assert(fdisk_is_ask(ask, MENU));
+	return ask->data.menu.dfl;
+}
+
+/**
+ * fdisk_ask_menu_set_result:
+ * @ask: ask instance
+ * @key: result
+ *
+ * Returns: 0 on success, <0 on error
+ */
+int fdisk_ask_menu_set_result(struct fdisk_ask *ask, int key)
+{
+	assert(ask);
+	assert(fdisk_is_ask(ask, MENU));
+	ask->data.menu.result = key;
+	DBG(ASK, ul_debugobj(ask, "menu result: %c\n", key));
+	return 0;
+
+}
+
+/**
+ * fdisk_ask_menu_get_result:
+ * @ask: ask instance
+ * @key: returns selected menu item key
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_ask_menu_get_result(struct fdisk_ask *ask, int *key)
+{
+	assert(ask);
+	assert(fdisk_is_ask(ask, MENU));
+	if (key)
+		*key =  ask->data.menu.result;
+	return 0;
+}
+
+/**
+ * fdisk_ask_menu_get_item:
+ * @ask: ask menu instance
+ * @idx: wanted menu item index
+ * @key: returns key of the menu item
+ * @name: returns name of the menu item
+ * @desc: returns description of the menu item
+ *
+ * Returns: 0 on success, <0 on error, >0 if idx out-of-range
+ */
+int fdisk_ask_menu_get_item(struct fdisk_ask *ask, size_t idx, int *key,
+			    const char **name, const char **desc)
+{
+	size_t i;
+	struct ask_menuitem *mi;
+
+	assert(ask);
+	assert(fdisk_is_ask(ask, MENU));
+
+	for (i = 0, mi = ask->data.menu.first; mi; mi = mi->next, i++) {
+		if (i == idx)
+			break;
+	}
+
+	if (!mi)
+		return 1;	/* no more items */
+	if (key)
+		*key = mi->key;
+	if (name)
+		*name = mi->name;
+	if (desc)
+		*desc = mi->desc;
+	return 0;
+}
+
+static void fdisk_ask_menu_reset_items(struct fdisk_ask *ask)
+{
+	struct ask_menuitem *mi;
+
+	assert(ask);
+	assert(fdisk_is_ask(ask, MENU));
+
+	for (mi = ask->data.menu.first; mi; ) {
+		struct ask_menuitem *next = mi->next;
+		free(mi);
+		mi = next;
+	}
+}
+
+/**
+ * fdisk_ask_menu_get_nitems:
+ * @ask: ask instance
+ *
+ * Returns: number of menu items
+ */
+size_t fdisk_ask_menu_get_nitems(struct fdisk_ask *ask)
+{
+	struct ask_menuitem *mi;
+	size_t n;
+
+	assert(ask);
+	assert(fdisk_is_ask(ask, MENU));
+
+	for (n = 0, mi = ask->data.menu.first; mi; mi = mi->next, n++);
+
+	return n;
+}
+
+int fdisk_ask_menu_add_item(struct fdisk_ask *ask, int key,
+			const char *name, const char *desc)
+{
+	struct ask_menuitem *mi;
+
+	assert(ask);
+	assert(fdisk_is_ask(ask, MENU));
+
+	mi = calloc(1, sizeof(*mi));
+	if (!mi)
+		return -ENOMEM;
+	mi->key = key;
+	mi->name = name;
+	mi->desc = desc;
+
+	if (!ask->data.menu.first)
+		ask->data.menu.first = mi;
+	else {
+	        struct ask_menuitem *last = ask->data.menu.first;
+
+		while (last->next)
+			last = last->next;
+		last->next = mi;
+	}
+
+	DBG(ASK, ul_debugobj(ask, "new menu item: %c, \"%s\" (%s)\n", mi->key, mi->name, mi->desc));
+	return 0;
+}
+
+
+/*
+ * print-like
+ */
+
+#define is_print_ask(a) (fdisk_is_ask(a, WARN) || fdisk_is_ask(a, WARNX) || fdisk_is_ask(a, INFO))
+
+/**
+ * fdisk_ask_print_get_errno:
+ * @ask: ask instance
+ *
+ * Returns: error number for warning/error messages
+ */
+int fdisk_ask_print_get_errno(struct fdisk_ask *ask)
+{
+	assert(ask);
+	assert(is_print_ask(ask));
+	return ask->data.print.errnum;
+}
+
+int fdisk_ask_print_set_errno(struct fdisk_ask *ask, int errnum)
+{
+	assert(ask);
+	ask->data.print.errnum = errnum;
+	return 0;
+}
+
+/**
+ * fdisk_ask_print_get_mesg:
+ * @ask: ask instance
+ *
+ * Returns: pointer to message
+ */
+const char *fdisk_ask_print_get_mesg(struct fdisk_ask *ask)
+{
+	assert(ask);
+	assert(is_print_ask(ask));
+	return ask->data.print.mesg;
+}
+
+/* does not reallocate the message! */
+int fdisk_ask_print_set_mesg(struct fdisk_ask *ask, const char *mesg)
+{
+	assert(ask);
+	ask->data.print.mesg = mesg;
+	return 0;
+}
+
+static int do_vprint(struct fdisk_context *cxt, int errnum, int type,
+		     const char *fmt, va_list va)
+{
+	struct fdisk_ask *ask;
+	int rc;
+	char *mesg;
+
+	assert(cxt);
+
+	if (vasprintf(&mesg, fmt, va) < 0)
+		return -ENOMEM;
+
+	ask = fdisk_new_ask();
+	if (!ask) {
+		free(mesg);
+		return -ENOMEM;
+	}
+
+	fdisk_ask_set_type(ask, type);
+	fdisk_ask_print_set_mesg(ask, mesg);
+	if (errnum >= 0)
+		fdisk_ask_print_set_errno(ask, errnum);
+	rc = fdisk_do_ask(cxt, ask);
+
+	fdisk_unref_ask(ask);
+	free(mesg);
+	return rc;
+}
+
+/**
+ * fdisk_info:
+ * @cxt: context
+ * @fmt: printf-like formatted string
+ * @...: variable parametrs
+ *
+ * High-level API to print info messages,
+ *
+ * Returns: 0 on success, <0 on error
+ */
+int fdisk_info(struct fdisk_context *cxt, const char *fmt, ...)
+{
+	int rc;
+	va_list ap;
+
+	assert(cxt);
+	va_start(ap, fmt);
+	rc = do_vprint(cxt, -1, FDISK_ASKTYPE_INFO, fmt, ap);
+	va_end(ap);
+	return rc;
+}
+
+/**
+ * fdisk_info:
+ * @cxt: context
+ * @fmt: printf-like formatted string
+ * @...: variable parametrs
+ *
+ * High-level API to print warning message (errno expected)
+ *
+ * Returns: 0 on success, <0 on error
+ */
+int fdisk_warn(struct fdisk_context *cxt, const char *fmt, ...)
+{
+	int rc;
+	va_list ap;
+
+	assert(cxt);
+	va_start(ap, fmt);
+	rc = do_vprint(cxt, errno, FDISK_ASKTYPE_WARN, fmt, ap);
+	va_end(ap);
+	return rc;
+}
+
+/**
+ * fdisk_warnx:
+ * @cxt: context
+ * @fmt: printf-like formatted string
+ * @...: variable options
+ *
+ * High-level API to print warning message
+ *
+ * Returns: 0 on success, <0 on error
+ */
+int fdisk_warnx(struct fdisk_context *cxt, const char *fmt, ...)
+{
+	int rc;
+	va_list ap;
+
+	assert(cxt);
+	va_start(ap, fmt);
+	rc = do_vprint(cxt, -1, FDISK_ASKTYPE_WARNX, fmt, ap);
+	va_end(ap);
+	return rc;
+}
+
+int fdisk_info_new_partition(
+			struct fdisk_context *cxt,
+			int num, fdisk_sector_t start, fdisk_sector_t stop,
+			struct fdisk_parttype *t)
+{
+	int rc;
+	char *str = size_to_human_string(SIZE_SUFFIX_3LETTER | SIZE_SUFFIX_SPACE,
+				     (uint64_t)(stop - start + 1) * cxt->sector_size);
+
+	rc = fdisk_info(cxt,
+			_("Created a new partition %d of type '%s' and of size %s."),
+			num, t ? t->name : _("Unknown"), str);
+	free(str);
+	return rc;
+}
+
+#ifdef TEST_PROGRAM
+int test_ranges(struct fdisk_test *ts, int argc, char *argv[])
+{
+	/*                1  -  3,       6,    8, 9,   11    13 */
+	size_t nums[] = { 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1 };
+	size_t numx[] = { 0, 0, 0 };
+	char range[BUFSIZ], *ptr = range;
+	size_t i, len = sizeof(range), begin = 0, run = 0;
+
+	for (i = 0; i < ARRAY_SIZE(nums); i++) {
+		if (!nums[i])
+			continue;
+		ptr = mk_string_list(ptr, &len, &begin, &run, i, 0);
+	}
+	mk_string_list(ptr, &len, &begin, &run, -1, 0);
+	printf("list: '%s'\n", range);
+
+	ptr = range;
+	len = sizeof(range), begin = 0, run = 0;
+	for (i = 0; i < ARRAY_SIZE(numx); i++) {
+		if (!numx[i])
+			continue;
+		ptr = mk_string_list(ptr, &len, &begin, &run, i, 0);
+	}
+	mk_string_list(ptr, &len, &begin, &run, -1, 0);
+	printf("empty list: '%s'\n", range);
+
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	struct fdisk_test tss[] = {
+	{ "--ranges",  test_ranges,    "generates ranges" },
+	{ NULL }
+	};
+
+	return fdisk_run_test(tss, argc, argv);
+}
+
+#endif
diff --git a/libblkid/libfdisk/src/bsd.c b/libblkid/libfdisk/src/bsd.c
new file mode 100644
index 0000000..618a3ee
--- /dev/null
+++ b/libblkid/libfdisk/src/bsd.c
@@ -0,0 +1,992 @@
+/*
+ * Copyright (C) 2007-2013 Karel Zak <kzak@redhat.com>
+ *
+ * Based on the original code from fdisk
+ *    written by Bernhard Fastenrath (fasten@informatik.uni-bonn.de)
+ *    with code from the NetBSD disklabel command.
+ *
+ *    Arnaldo Carvalho de Melo <acme@conectiva.com.br>, March 1999
+ *    David Huggins-Daines <dhuggins@linuxcare.com>, January 2000
+ */
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/param.h>
+
+#include "nls.h"
+#include "blkdev.h"
+#include "fdiskP.h"
+#include "pt-mbr.h"
+#include "pt-bsd.h"
+#include "all-io.h"
+
+
+/**
+ * SECTION: bsd
+ * @title: BSD
+ * @short_description: disk label specific functions
+ *
+ */
+
+static const char *bsd_dktypenames[] = {
+	"unknown",
+	"SMD",
+	"MSCP",
+	"old DEC",
+	"SCSI",
+	"ESDI",
+	"ST506",
+	"HP-IB",
+	"HP-FL",
+	"type 9",
+	"floppy",
+	0
+};
+#define BSD_DKMAXTYPES	(ARRAY_SIZE(bsd_dktypenames) - 1)
+
+static struct fdisk_parttype bsd_fstypes[] = {
+        {BSD_FS_UNUSED, "unused"},
+	{BSD_FS_SWAP,   "swap"},
+	{BSD_FS_V6,     "Version 6"},
+	{BSD_FS_V7,     "Version 7"},
+	{BSD_FS_SYSV,   "System V"},
+	{BSD_FS_V71K,   "4.1BSD"},
+	{BSD_FS_V8,     "Eighth Edition"},
+	{BSD_FS_BSDFFS, "4.2BSD"},
+#ifdef __alpha__
+	{BSD_FS_EXT2,   "ext2"},
+#else
+	{BSD_FS_MSDOS,  "MS-DOS"},
+#endif
+	{BSD_FS_BSDLFS, "4.4LFS"},
+	{BSD_FS_OTHER,  "unknown"},
+	{BSD_FS_HPFS,   "HPFS"},
+	{BSD_FS_ISO9660,"ISO-9660"},
+	{BSD_FS_BOOT,   "boot"},
+	{BSD_FS_ADOS,   "ADOS"},
+	{BSD_FS_HFS,    "HFS"},
+	{BSD_FS_ADVFS,	"AdvFS"},
+	{ 0, NULL }
+};
+#define BSD_FSMAXTYPES (ARRAY_SIZE(bsd_fstypes)-1)
+
+/*
+ * in-memory fdisk BSD stuff
+ */
+struct fdisk_bsd_label {
+	struct fdisk_label	head;		/* generic part */
+
+	struct dos_partition *dos_part;		/* parent */
+	struct bsd_disklabel bsd;		/* on disk label */
+#if defined (__alpha__)
+	/* We access this through a u_int64_t * when checksumming */
+	char bsdbuffer[BSD_BBSIZE] __attribute__((aligned(8)));
+#else
+	char bsdbuffer[BSD_BBSIZE];
+#endif
+};
+
+static int bsd_list_disklabel(struct fdisk_context *cxt);
+static int bsd_initlabel(struct fdisk_context *cxt);
+static int bsd_readlabel(struct fdisk_context *cxt);
+static void sync_disks(struct fdisk_context *cxt);
+
+static inline struct fdisk_bsd_label *self_label(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, BSD));
+
+	return (struct fdisk_bsd_label *) cxt->label;
+}
+
+static inline struct bsd_disklabel *self_disklabel(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, BSD));
+
+	return &((struct fdisk_bsd_label *) cxt->label)->bsd;
+}
+
+static struct fdisk_parttype *bsd_partition_parttype(
+		struct fdisk_context *cxt,
+		struct bsd_partition *p)
+{
+	struct fdisk_parttype *t
+		= fdisk_label_get_parttype_from_code(cxt->label, p->p_fstype);
+	return t ? : fdisk_new_unknown_parttype(p->p_fstype, NULL);
+}
+
+
+#if defined (__alpha__)
+static void alpha_bootblock_checksum (char *boot)
+{
+	uint64_t *dp = (uint64_t *) boot, sum = 0;
+	int i;
+
+	for (i = 0; i < 63; i++)
+		sum += dp[i];
+	dp[63] = sum;
+}
+#endif /* __alpha__ */
+
+#define HIDDEN_MASK	0x10
+
+static int is_bsd_partition_type(int type)
+{
+	return (type == MBR_FREEBSD_PARTITION ||
+		type == (MBR_FREEBSD_PARTITION ^ HIDDEN_MASK) ||
+		type == MBR_NETBSD_PARTITION ||
+		type == (MBR_NETBSD_PARTITION ^ HIDDEN_MASK) ||
+		type == MBR_OPENBSD_PARTITION ||
+		type == (MBR_OPENBSD_PARTITION ^ HIDDEN_MASK));
+}
+
+/*
+ * look for DOS partition usable for nested BSD partition table
+ */
+static int bsd_assign_dos_partition(struct fdisk_context *cxt)
+{
+	struct fdisk_bsd_label *l = self_label(cxt);
+	size_t i;
+
+	for (i = 0; i < 4; i++) {
+		fdisk_sector_t ss;
+
+		l->dos_part = fdisk_dos_get_partition(cxt->parent, i);
+
+		if (!l->dos_part || !is_bsd_partition_type(l->dos_part->sys_ind))
+			continue;
+
+		ss = dos_partition_get_start(l->dos_part);
+		if (!ss) {
+			fdisk_warnx(cxt, _("Partition %zd: has invalid starting "
+					   "sector 0."), i + 1);
+			return -1;
+		}
+
+		if (cxt->parent->dev_path) {
+			free(cxt->dev_path);
+			cxt->dev_path = fdisk_partname(
+						cxt->parent->dev_path, i + 1);
+		}
+
+		DBG(LABEL, ul_debug("partition %zu assigned to BSD", i + 1));
+		return 0;
+	}
+
+	fdisk_warnx(cxt, _("There is no *BSD partition on %s."),
+				cxt->parent->dev_path);
+	free(cxt->dev_path);
+	cxt->dev_path = NULL;
+	l->dos_part = NULL;
+	return 1;
+}
+
+static int bsd_probe_label(struct fdisk_context *cxt)
+{
+	int rc = 0;
+
+	if (cxt->parent)
+		rc = bsd_assign_dos_partition(cxt);	/* nested BSD partiotn table */
+	if (!rc)
+		rc = bsd_readlabel(cxt);
+	if (!rc)
+		return 1;	/* found BSD */
+	return 0;		/* not found */
+}
+
+static int set_parttype(
+		struct fdisk_context *cxt,
+		size_t partnum,
+		struct fdisk_parttype *t)
+{
+	struct bsd_partition *p;
+	struct bsd_disklabel *d = self_disklabel(cxt);
+
+	if (partnum >= d->d_npartitions || !t || t->code > UINT8_MAX)
+		return -EINVAL;
+
+	p = &d->d_partitions[partnum];
+	if (t->code == p->p_fstype)
+		return 0;
+
+	p->p_fstype = t->code;
+	fdisk_label_set_changed(cxt->label, 1);
+	return 0;
+}
+
+static int bsd_add_partition(struct fdisk_context *cxt,
+			     struct fdisk_partition *pa,
+			     size_t *partno)
+{
+	struct fdisk_bsd_label *l = self_label(cxt);
+	struct bsd_disklabel *d = self_disklabel(cxt);
+	size_t i;
+	unsigned int begin = 0, end;
+	int rc = 0;
+
+	rc = fdisk_partition_next_partno(pa, cxt, &i);
+	if (rc)
+		return rc;
+	if (i >= BSD_MAXPARTITIONS)
+		return -ERANGE;
+	if (l->dos_part) {
+		begin = dos_partition_get_start(l->dos_part);
+		end = begin + dos_partition_get_size(l->dos_part) - 1;
+	} else
+		end = d->d_secperunit - 1;
+
+	/*
+	 * First sector
+	 */
+	if (pa && pa->start_follow_default)
+		;
+	else if (pa && fdisk_partition_has_start(pa)) {
+		if (pa->start < begin || pa->start > end)
+			return -ERANGE;
+		begin = pa->start;
+	} else {
+		struct fdisk_ask *ask = fdisk_new_ask();
+
+		if (!ask)
+			return -ENOMEM;
+		fdisk_ask_set_query(ask,
+			fdisk_use_cylinders(cxt) ?
+			_("First cylinder") : _("First sector"));
+		fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER);
+		fdisk_ask_number_set_low(ask, fdisk_cround(cxt, begin));
+		fdisk_ask_number_set_default(ask, fdisk_cround(cxt, begin));
+		fdisk_ask_number_set_high(ask, fdisk_cround(cxt, end));
+
+		rc = fdisk_do_ask(cxt, ask);
+		begin = fdisk_ask_number_get_result(ask);
+		fdisk_unref_ask(ask);
+		if (rc)
+			return rc;
+		if (fdisk_use_cylinders(cxt))
+			begin = (begin - 1) * d->d_secpercyl;
+	}
+
+	/*
+	 * Last sector
+	 */
+	if (pa && pa->end_follow_default)
+		;
+	else if (pa && fdisk_partition_has_size(pa)) {
+		if (begin + pa->size > end)
+			return -ERANGE;
+		end = begin + pa->size - 1ULL;
+	} else {
+		/* ask user by dialog */
+		struct fdisk_ask *ask = fdisk_new_ask();
+
+		if (!ask)
+			return -ENOMEM;
+		fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET);
+
+		if (fdisk_use_cylinders(cxt)) {
+			fdisk_ask_set_query(ask, _("Last cylinder, +cylinders or +size{K,M,G,T,P}"));
+			fdisk_ask_number_set_unit(ask,
+				     cxt->sector_size *
+				     fdisk_get_units_per_sector(cxt));
+		} else {
+			fdisk_ask_set_query(ask, _("Last sector, +sectors or +size{K,M,G,T,P}"));
+			fdisk_ask_number_set_unit(ask,cxt->sector_size);
+		}
+
+		fdisk_ask_number_set_low(ask, fdisk_cround(cxt, begin));
+		fdisk_ask_number_set_default(ask, fdisk_cround(cxt, end));
+		fdisk_ask_number_set_high(ask, fdisk_cround(cxt, end));
+		fdisk_ask_number_set_base(ask, fdisk_cround(cxt, begin));
+
+		rc = fdisk_do_ask(cxt, ask);
+		end = fdisk_ask_number_get_result(ask);
+		fdisk_unref_ask(ask);
+		if (rc)
+			return rc;
+		if (fdisk_use_cylinders(cxt))
+			end = end * d->d_secpercyl - 1;
+	}
+
+	d->d_partitions[i].p_size   = end - begin + 1;
+	d->d_partitions[i].p_offset = begin;
+	d->d_partitions[i].p_fstype = BSD_FS_UNUSED;
+
+	if (i >= d->d_npartitions)
+		d->d_npartitions = i + 1;
+	cxt->label->nparts_cur = d->d_npartitions;
+
+	if (pa && pa->type)
+		set_parttype(cxt, i, pa->type);
+
+	fdisk_label_set_changed(cxt->label, 1);
+	if (partno)
+		*partno = i;
+	return 0;
+}
+
+static int bsd_set_partition(struct fdisk_context *cxt, size_t n,
+			     struct fdisk_partition *pa)
+{
+	struct bsd_partition *p;
+	struct fdisk_bsd_label *l = self_label(cxt);
+	struct bsd_disklabel *d = self_disklabel(cxt);
+
+	if (n >= d->d_npartitions)
+		return -EINVAL;
+
+	p = &d->d_partitions[n];
+
+	/* we have to stay within parental DOS partition */
+	if (l->dos_part && (fdisk_partition_has_start(pa) ||
+			    fdisk_partition_has_size(pa))) {
+
+		fdisk_sector_t dosbegin = dos_partition_get_start(l->dos_part);
+		fdisk_sector_t dosend = dosbegin + dos_partition_get_size(l->dos_part) - 1;
+		fdisk_sector_t begin = fdisk_partition_has_start(pa) ? pa->start : p->p_offset;
+		fdisk_sector_t end = begin + (fdisk_partition_has_size(pa) ? pa->size : p->p_size) - 1;
+
+		if (begin < dosbegin || begin > dosend)
+			return -ERANGE;
+		if (end < dosbegin || end > dosend)
+			return -ERANGE;
+	}
+
+	if (pa->type) {
+		int rc = set_parttype(cxt, n, pa->type);
+		if (rc)
+			return rc;
+	}
+
+	if (fdisk_partition_has_start(pa))
+		d->d_partitions[n].p_offset = pa->start;
+	if (fdisk_partition_has_size(pa))
+		d->d_partitions[n].p_size = pa->size;
+
+	fdisk_label_set_changed(cxt->label, 1);
+	return 0;
+}
+
+
+/* Returns 0 on success, < 0 on error. */
+static int bsd_create_disklabel(struct fdisk_context *cxt)
+{
+	int rc, yes = 0;
+	struct bsd_disklabel *d = self_disklabel(cxt);
+
+	fdisk_info(cxt, _("The device %s does not contain BSD disklabel."), cxt->dev_path);
+	rc = fdisk_ask_yesno(cxt,
+			_("Do you want to create a BSD disklabel?"),
+			&yes);
+	if (rc)
+		return rc;
+	if (!yes)
+		return 1;
+	if (cxt->parent) {
+		rc = bsd_assign_dos_partition(cxt);
+		if (rc == 1)
+			/* not found DOS partition usable for BSD label */
+			rc = -EINVAL;
+	}
+	if (rc)
+		return rc;
+
+	rc = bsd_initlabel(cxt);
+	if (!rc) {
+		int org = fdisk_is_details(cxt);
+
+		cxt->label->nparts_cur = d->d_npartitions;
+		cxt->label->nparts_max = BSD_MAXPARTITIONS;
+
+		fdisk_enable_details(cxt, 1);
+		bsd_list_disklabel(cxt);
+		fdisk_enable_details(cxt, org);
+	}
+
+	return rc;
+}
+
+static int bsd_delete_part(
+		struct fdisk_context *cxt,
+		size_t partnum)
+{
+	struct bsd_disklabel *d = self_disklabel(cxt);
+
+	d->d_partitions[partnum].p_size   = 0;
+	d->d_partitions[partnum].p_offset = 0;
+	d->d_partitions[partnum].p_fstype = BSD_FS_UNUSED;
+
+	if (d->d_npartitions == partnum + 1)
+		while (!d->d_partitions[d->d_npartitions - 1].p_size)
+			d->d_npartitions--;
+
+	cxt->label->nparts_cur = d->d_npartitions;
+	fdisk_label_set_changed(cxt->label, 1);
+	return 0;
+}
+
+static int bsd_list_disklabel(struct fdisk_context *cxt)
+{
+	struct bsd_disklabel *d = self_disklabel(cxt);
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, BSD));
+
+	if (fdisk_is_details(cxt)) {
+		fdisk_info(cxt, "# %s:", cxt->dev_path);
+
+		if ((unsigned) d->d_type < BSD_DKMAXTYPES)
+			fdisk_info(cxt, _("type: %s"), bsd_dktypenames[d->d_type]);
+		else
+			fdisk_info(cxt, _("type: %d"), d->d_type);
+
+		fdisk_info(cxt, _("disk: %.*s"), (int) sizeof(d->d_typename), d->d_typename);
+		fdisk_info(cxt, _("label: %.*s"), (int) sizeof(d->d_packname), d->d_packname);
+
+		fdisk_info(cxt, _("flags: %s"),
+			d->d_flags & BSD_D_REMOVABLE ? _(" removable") :
+			d->d_flags & BSD_D_ECC ? _(" ecc") :
+			d->d_flags & BSD_D_BADSECT ? _(" badsect") : "");
+
+		/* On various machines the fields of *lp are short/int/long */
+		/* In order to avoid problems, we cast them all to long. */
+		fdisk_info(cxt, _("bytes/sector: %ld"), (long) d->d_secsize);
+		fdisk_info(cxt, _("sectors/track: %ld"), (long) d->d_nsectors);
+		fdisk_info(cxt, _("tracks/cylinder: %ld"), (long) d->d_ntracks);
+		fdisk_info(cxt, _("sectors/cylinder: %ld"), (long) d->d_secpercyl);
+		fdisk_info(cxt, _("cylinders: %ld"), (long) d->d_ncylinders);
+		fdisk_info(cxt, _("rpm: %d"), d->d_rpm);
+		fdisk_info(cxt, _("interleave: %d"), d->d_interleave);
+		fdisk_info(cxt, _("trackskew: %d"), d->d_trackskew);
+		fdisk_info(cxt, _("cylinderskew: %d"), d->d_cylskew);
+		fdisk_info(cxt, _("headswitch: %ld (milliseconds)"), (long) d->d_headswitch);
+		fdisk_info(cxt, _("track-to-track seek: %ld (milliseconds)"), (long) d->d_trkseek);
+	}
+
+	fdisk_info(cxt, _("partitions: %d"), d->d_npartitions);
+
+	return 0;
+}
+
+static int bsd_get_partition(struct fdisk_context *cxt, size_t n,
+			     struct fdisk_partition *pa)
+{
+	struct bsd_partition *p;
+	struct bsd_disklabel *d = self_disklabel(cxt);
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, BSD));
+
+	if (n >= d->d_npartitions)
+		return -EINVAL;
+
+	p = &d->d_partitions[n];
+
+	pa->used = p->p_size ? 1 : 0;
+	if (!pa->used)
+		return 0;
+
+	if (fdisk_use_cylinders(cxt) && d->d_secpercyl) {
+		pa->start_post = p->p_offset % d->d_secpercyl ? '*' : ' ';
+		pa->end_post = (p->p_offset + p->p_size) % d->d_secpercyl ? '*' : ' ';
+	}
+
+	pa->start = p->p_offset;
+	pa->size = p->p_size;
+	pa->type = bsd_partition_parttype(cxt, p);
+
+	if (p->p_fstype == BSD_FS_UNUSED || p->p_fstype == BSD_FS_BSDFFS) {
+		pa->fsize = p->p_fsize;
+		pa->bsize = p->p_fsize * p->p_frag;
+	}
+	if (p->p_fstype == BSD_FS_BSDFFS)
+		pa->cpg = p->p_cpg;
+
+	return 0;
+}
+
+static uint32_t ask_uint32(struct fdisk_context *cxt,
+		uint32_t dflt, char *mesg)
+{
+	uintmax_t res;
+
+	if (fdisk_ask_number(cxt, min(dflt, (uint32_t) 1), dflt,
+				UINT32_MAX, mesg, &res) == 0)
+		return res;
+	return dflt;
+}
+
+static uint16_t ask_uint16(struct fdisk_context *cxt,
+		uint16_t dflt, char *mesg)
+{
+	uintmax_t res;
+
+	if (fdisk_ask_number(cxt, min(dflt, (uint16_t) 1),
+				dflt, UINT16_MAX, mesg, &res) == 0)
+		return res;
+	return dflt;
+}
+
+/**
+ * fdisk_bsd_edit_disklabel:
+ * @cxt: context
+ *
+ * Edits fields in BSD disk label.
+ *
+ * Returns: 0 on success, <0 on error
+ */
+int fdisk_bsd_edit_disklabel(struct fdisk_context *cxt)
+{
+	struct bsd_disklabel *d = self_disklabel(cxt);
+	uintmax_t res;
+
+#if defined (__alpha__) || defined (__ia64__)
+	if (fdisk_ask_number(cxt, DEFAULT_SECTOR_SIZE, d->d_secsize,
+			     UINT32_MAX, _("bytes/sector"), &res) == 0)
+		d->d_secsize = res;
+
+	d->d_nsectors = ask_uint32(cxt, d->d_nsectors, _("sectors/track"));
+	d->d_ntracks = ask_uint32(cxt, d->d_ntracks, _("tracks/cylinder"));
+	d->d_ncylinders = ask_uint32(cxt, d->d_ncylinders  ,_("cylinders"));
+#endif
+	if (fdisk_ask_number(cxt, 1, d->d_nsectors * d->d_ntracks,
+			     d->d_nsectors * d->d_ntracks,
+			     _("sectors/cylinder"), &res) == 0)
+		d->d_secpercyl = res;
+
+	d->d_rpm = ask_uint16(cxt, d->d_rpm, _("rpm"));
+	d->d_interleave = ask_uint16(cxt, d->d_interleave, _("interleave"));
+	d->d_trackskew = ask_uint16(cxt, d->d_trackskew, _("trackskew"));
+	d->d_cylskew = ask_uint16(cxt, d->d_cylskew, _("cylinderskew"));
+
+	d->d_headswitch = ask_uint32(cxt, d->d_headswitch, _("headswitch"));
+	d->d_trkseek = ask_uint32(cxt, d->d_trkseek, _("track-to-track seek"));
+
+	d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
+	return 0;
+}
+
+static int bsd_get_bootstrap(struct fdisk_context *cxt,
+			char *path, void *ptr, int size)
+{
+	int fd;
+
+	if ((fd = open(path, O_RDONLY)) < 0) {
+		fdisk_warn(cxt, _("cannot open %s"), path);
+		return -errno;
+	}
+
+	if (read_all(fd, ptr, size) != size) {
+		fdisk_warn(cxt, _("cannot read %s"), path);
+		close(fd);
+		return -errno;
+	}
+
+	fdisk_info(cxt, _("The bootstrap file %s successfully loaded."), path);
+	close (fd);
+	return 0;
+}
+
+/**
+ * fdisk_bsd_write_bootstrap:
+ * @cxt: context
+ *
+ * Install bootstrap file to the BSD device
+ */
+int fdisk_bsd_write_bootstrap(struct fdisk_context *cxt)
+{
+	struct bsd_disklabel dl, *d = self_disklabel(cxt);
+	struct fdisk_bsd_label *l = self_label(cxt);
+	char *name = d->d_type == BSD_DTYPE_SCSI ? "sd" : "wd";
+	char buf[BUFSIZ];
+	char *res, *dp, *p;
+	int rc;
+	fdisk_sector_t sector;
+
+	snprintf(buf, sizeof(buf),
+		_("Bootstrap: %1$sboot -> boot%1$s (default %1$s)"),
+		name);
+	rc = fdisk_ask_string(cxt, buf, &res);
+	if (rc)
+		goto done;
+	if (res && *res)
+		name = res;
+
+	snprintf(buf, sizeof(buf), "%s/%sboot", BSD_LINUX_BOOTDIR, name);
+	rc = bsd_get_bootstrap(cxt, buf, l->bsdbuffer,	(int) d->d_secsize);
+	if (rc)
+		goto done;
+
+	/* We need a backup of the disklabel (might have changed). */
+	dp = &l->bsdbuffer[BSD_LABELSECTOR * DEFAULT_SECTOR_SIZE];
+	memmove(&dl, dp, sizeof(struct bsd_disklabel));
+
+	/* The disklabel will be overwritten by 0's from bootxx anyway */
+	memset(dp, 0, sizeof(struct bsd_disklabel));
+
+	snprintf(buf, sizeof(buf), "%s/boot%s", BSD_LINUX_BOOTDIR, name);
+	rc = bsd_get_bootstrap(cxt, buf,
+			&l->bsdbuffer[d->d_secsize],
+			(int) d->d_bbsize - d->d_secsize);
+	if (rc)
+		goto done;
+
+	/* check end of the bootstrap */
+	for (p = dp; p < dp + sizeof(struct bsd_disklabel); p++) {
+		if (!*p)
+			continue;
+		fdisk_warnx(cxt, _("Bootstrap overlaps with disklabel!"));
+		return -EINVAL;
+	}
+
+	/* move disklabel back */
+	memmove(dp, &dl, sizeof(struct bsd_disklabel));
+
+	sector = 0;
+	if (l->dos_part)
+		sector = dos_partition_get_start(l->dos_part);
+#if defined (__alpha__)
+	alpha_bootblock_checksum(l->bsdbuffer);
+#endif
+	if (lseek(cxt->dev_fd, (off_t) sector * DEFAULT_SECTOR_SIZE, SEEK_SET) == -1) {
+		fdisk_warn(cxt, _("seek on %s failed"), cxt->dev_path);
+		rc = -errno;
+		goto done;
+	}
+	if (write_all(cxt->dev_fd, l->bsdbuffer, BSD_BBSIZE)) {
+		fdisk_warn(cxt, _("cannot write %s"), cxt->dev_path);
+		rc = -errno;
+		goto done;
+	}
+
+	fdisk_info(cxt, _("Bootstrap installed on %s."), cxt->dev_path);
+	sync_disks(cxt);
+
+	rc = 0;
+done:
+	free(res);
+	return rc;
+}
+
+static unsigned short bsd_dkcksum (struct bsd_disklabel *lp)
+{
+	unsigned short *start, *end;
+	unsigned short sum = 0;
+
+	start = (unsigned short *) lp;
+	end = (unsigned short *) &lp->d_partitions[lp->d_npartitions];
+	while (start < end)
+		sum ^= *start++;
+	return sum;
+}
+
+static int bsd_initlabel (struct fdisk_context *cxt)
+{
+	struct fdisk_bsd_label *l = self_label(cxt);
+	struct bsd_disklabel *d = self_disklabel(cxt);
+	struct bsd_partition *pp;
+
+	memset (d, 0, sizeof (struct bsd_disklabel));
+
+	d -> d_magic = BSD_DISKMAGIC;
+
+	if (strncmp (cxt->dev_path, "/dev/sd", 7) == 0)
+		d -> d_type = BSD_DTYPE_SCSI;
+	else
+		d -> d_type = BSD_DTYPE_ST506;
+
+#if !defined (__alpha__)
+	d -> d_flags = BSD_D_DOSPART;
+#else
+	d -> d_flags = 0;
+#endif
+	d -> d_secsize = DEFAULT_SECTOR_SIZE;		/* bytes/sector  */
+	d -> d_nsectors = cxt->geom.sectors;		/* sectors/track */
+	d -> d_ntracks = cxt->geom.heads;		/* tracks/cylinder (heads) */
+	d -> d_ncylinders = cxt->geom.cylinders;
+	d -> d_secpercyl  = cxt->geom.sectors * cxt->geom.heads;/* sectors/cylinder */
+	if (d -> d_secpercyl == 0)
+		d -> d_secpercyl = 1;		/* avoid segfaults */
+	d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders;
+
+	d -> d_rpm = 3600;
+	d -> d_interleave = 1;
+	d -> d_trackskew = 0;
+	d -> d_cylskew = 0;
+	d -> d_headswitch = 0;
+	d -> d_trkseek = 0;
+
+	d -> d_magic2 = BSD_DISKMAGIC;
+	d -> d_bbsize = BSD_BBSIZE;
+	d -> d_sbsize = BSD_SBSIZE;
+
+	if (l->dos_part) {
+		d->d_npartitions = 4;
+
+		pp = &d->d_partitions[2];	/* Partition C should be the NetBSD partition */
+		pp->p_offset = dos_partition_get_start(l->dos_part);
+		pp->p_size   = dos_partition_get_size(l->dos_part);
+		pp->p_fstype = BSD_FS_UNUSED;
+
+		pp = &d -> d_partitions[3];	/* Partition D should be the whole disk */
+		pp->p_offset = 0;
+		pp->p_size   = d->d_secperunit;
+		pp->p_fstype = BSD_FS_UNUSED;
+	} else {
+		d->d_npartitions = 3;
+
+		pp = &d->d_partitions[2];	/* Partition C should be the whole disk */
+		pp->p_offset = 0;
+		pp->p_size   = d->d_secperunit;
+		pp->p_fstype = BSD_FS_UNUSED;
+	}
+
+	return 0;
+}
+
+/*
+ * Read a bsd_disklabel from sector 0 or from the starting sector of p.
+ * If it has the right magic, return 0.
+ */
+static int bsd_readlabel(struct fdisk_context *cxt)
+{
+	struct fdisk_bsd_label *l;
+	struct bsd_disklabel *d;
+	int t;
+	off_t offset = 0;
+
+	l = self_label(cxt);
+	d = self_disklabel(cxt);
+
+	if (l->dos_part)
+		/* BSD is nested within DOS partition, get the begin of the
+		 * partition. Note that DOS uses native sector size. */
+		offset = dos_partition_get_start(l->dos_part) * cxt->sector_size;
+
+	if (lseek(cxt->dev_fd, offset, SEEK_SET) == -1)
+		return -1;
+	if (read_all(cxt->dev_fd, l->bsdbuffer, sizeof(l->bsdbuffer)) < 0)
+		return errno ? -errno : -1;
+
+	/* The offset to begin of the disk label. Note that BSD uses
+	 * 512-byte (default) sectors. */
+	memmove(d, &l->bsdbuffer[BSD_LABELSECTOR * DEFAULT_SECTOR_SIZE
+			      + BSD_LABELOFFSET], sizeof(*d));
+
+	if (d->d_magic != BSD_DISKMAGIC || d->d_magic2 != BSD_DISKMAGIC) {
+		DBG(LABEL, ul_debug("not found magic"));
+		return -1;
+	}
+
+	for (t = d->d_npartitions; t < BSD_MAXPARTITIONS; t++) {
+		d->d_partitions[t].p_size   = 0;
+		d->d_partitions[t].p_offset = 0;
+		d->d_partitions[t].p_fstype = BSD_FS_UNUSED;
+	}
+
+	if (d->d_npartitions > BSD_MAXPARTITIONS)
+		fdisk_warnx(cxt, ("Too many partitions (%d, maximum is %d)."),
+				d->d_npartitions, BSD_MAXPARTITIONS);
+
+	/* let's follow in-PT geometry */
+	cxt->geom.sectors = d->d_nsectors;
+	cxt->geom.heads = d->d_ntracks;
+	cxt->geom.cylinders = d->d_ncylinders;
+
+	cxt->label->nparts_cur = d->d_npartitions;
+	cxt->label->nparts_max = BSD_MAXPARTITIONS;
+	DBG(LABEL, ul_debug("read BSD label"));
+	return 0;
+}
+
+static int bsd_write_disklabel(struct fdisk_context *cxt)
+{
+	off_t offset = 0;
+	struct fdisk_bsd_label *l = self_label(cxt);
+	struct bsd_disklabel *d = self_disklabel(cxt);
+
+
+	if (l->dos_part)
+		offset = dos_partition_get_start(l->dos_part) * cxt->sector_size;
+
+	d->d_checksum = 0;
+	d->d_checksum = bsd_dkcksum(d);
+
+	/* Update label within boot block. */
+	memmove(&l->bsdbuffer[BSD_LABELSECTOR * DEFAULT_SECTOR_SIZE
+			   + BSD_LABELOFFSET], d, sizeof(*d));
+
+#if defined (__alpha__) && BSD_LABELSECTOR == 0
+	/* Write the checksum to the end of the first sector. */
+	alpha_bootblock_checksum(l->bsdbuffer);
+#endif
+	if (lseek(cxt->dev_fd, offset, SEEK_SET) == -1) {
+		fdisk_warn(cxt, _("seek on %s failed"), cxt->dev_path);
+		return -errno;
+	}
+	if (write_all(cxt->dev_fd, l->bsdbuffer, sizeof(l->bsdbuffer))) {
+		fdisk_warn(cxt, _("cannot write %s"), cxt->dev_path);
+		return -errno;
+	}
+	sync_disks(cxt);
+
+	fdisk_info(cxt, _("Disklabel written to %s."), cxt->dev_path);
+	return 0;
+}
+
+static void sync_disks(struct fdisk_context *cxt)
+{
+	fdisk_info(cxt, _("Syncing disks."));
+	sync();
+}
+
+static int bsd_translate_fstype (int linux_type)
+{
+	switch (linux_type) {
+	case 0x01: /* DOS 12-bit FAT   */
+	case 0x04: /* DOS 16-bit <32M  */
+	case 0x06: /* DOS 16-bit >=32M */
+	case 0xe1: /* DOS access       */
+	case 0xe3: /* DOS R/O          */
+#if !defined (__alpha__)
+	case 0xf2: /* DOS secondary    */
+		return BSD_FS_MSDOS;
+#endif
+	case 0x07: /* OS/2 HPFS        */
+		return BSD_FS_HPFS;
+	default:
+		break;
+	}
+
+	return BSD_FS_OTHER;
+}
+
+/**
+ * fdisk_bsd_link_partition:
+ * @cxt: context
+ *
+ * Links partition from parent (DOS) to nested BSD partition table.
+ *
+ * Returns: 0 on success, <0 on error
+ */
+int fdisk_bsd_link_partition(struct fdisk_context *cxt)
+{
+	size_t k, i;
+	int rc;
+	struct dos_partition *p;
+	struct bsd_disklabel *d = self_disklabel(cxt);
+
+	if (!cxt->parent || !fdisk_is_label(cxt->parent, DOS)) {
+		fdisk_warnx(cxt, _("BSD label is not nested within a DOS partition."));
+		return -EINVAL;
+	}
+
+	/* ask for DOS partition */
+	rc = fdisk_ask_partnum(cxt->parent, &k, FALSE);
+	if (rc)
+		return rc;
+	/* ask for BSD partition */
+	rc = fdisk_ask_partnum(cxt, &i, TRUE);
+	if (rc)
+		return rc;
+
+	if (i >= BSD_MAXPARTITIONS)
+		return -EINVAL;
+
+	p = fdisk_dos_get_partition(cxt->parent, k);
+
+	d->d_partitions[i].p_size   = dos_partition_get_size(p);
+	d->d_partitions[i].p_offset = dos_partition_get_start(p);
+	d->d_partitions[i].p_fstype = bsd_translate_fstype(p->sys_ind);
+
+	if (i >= d->d_npartitions)
+		d->d_npartitions = i + 1;
+
+	cxt->label->nparts_cur = d->d_npartitions;
+	fdisk_label_set_changed(cxt->label, 1);
+
+	fdisk_info(cxt, _("BSD partition '%c' linked to DOS partition %zu."),
+			'a' + (int) i, k + 1);
+	return 0;
+}
+
+
+static int bsd_partition_is_used(
+		struct fdisk_context *cxt,
+		size_t partnum)
+{
+	struct bsd_disklabel *d = self_disklabel(cxt);
+
+	if (partnum >= BSD_MAXPARTITIONS)
+		return 0;
+
+	return d->d_partitions[partnum].p_size ? 1 : 0;
+}
+
+
+static const struct fdisk_label_operations bsd_operations =
+{
+	.probe		= bsd_probe_label,
+	.list		= bsd_list_disklabel,
+	.write		= bsd_write_disklabel,
+	.create		= bsd_create_disklabel,
+
+	.del_part	= bsd_delete_part,
+	.get_part	= bsd_get_partition,
+	.set_part	= bsd_set_partition,
+	.add_part	= bsd_add_partition,
+
+	.part_is_used   = bsd_partition_is_used,
+};
+
+static const struct fdisk_field bsd_fields[] =
+{
+	{ FDISK_FIELD_DEVICE,	N_("Slice"),	  1,	0 },
+	{ FDISK_FIELD_START,	N_("Start"),	  5,	FDISK_FIELDFL_NUMBER },
+	{ FDISK_FIELD_END,	N_("End"),	  5,	FDISK_FIELDFL_NUMBER },
+	{ FDISK_FIELD_SECTORS,	N_("Sectors"),    5,	FDISK_FIELDFL_NUMBER },
+	{ FDISK_FIELD_CYLINDERS,N_("Cylinders"),  5,	FDISK_FIELDFL_NUMBER },
+	{ FDISK_FIELD_SIZE,	N_("Size"),	  5,	FDISK_FIELDFL_NUMBER },
+	{ FDISK_FIELD_TYPE,	N_("Type"),	  8,	0 },
+	{ FDISK_FIELD_FSIZE,	N_("Fsize"),	  5,	FDISK_FIELDFL_NUMBER },
+	{ FDISK_FIELD_BSIZE,	N_("Bsize"),	  5,	FDISK_FIELDFL_NUMBER },
+	{ FDISK_FIELD_CPG,	N_("Cpg"),	  5,	FDISK_FIELDFL_NUMBER }
+};
+
+/*
+ * allocates BSD label driver
+ */
+struct fdisk_label *fdisk_new_bsd_label(struct fdisk_context *cxt)
+{
+	struct fdisk_label *lb;
+	struct fdisk_bsd_label *bsd;
+
+	assert(cxt);
+
+	bsd = calloc(1, sizeof(*bsd));
+	if (!bsd)
+		return NULL;
+
+	/* initialize generic part of the driver */
+	lb = (struct fdisk_label *) bsd;
+	lb->name = "bsd";
+	lb->id = FDISK_DISKLABEL_BSD;
+	lb->op = &bsd_operations;
+	lb->parttypes = bsd_fstypes;
+	lb->nparttypes = ARRAY_SIZE(bsd_fstypes) - 1;
+
+	lb->fields = bsd_fields;
+	lb->nfields = ARRAY_SIZE(bsd_fields);
+
+	lb->flags |= FDISK_LABEL_FL_INCHARS_PARTNO;
+	lb->flags |= FDISK_LABEL_FL_REQUIRE_GEOMETRY;
+
+	return lb;
+}
diff --git a/libblkid/libfdisk/src/context.c b/libblkid/libfdisk/src/context.c
new file mode 100644
index 0000000..2a4d377
--- /dev/null
+++ b/libblkid/libfdisk/src/context.c
@@ -0,0 +1,1017 @@
+#ifdef HAVE_LIBBLKID
+# include <blkid.h>
+#endif
+
+#include "fdiskP.h"
+
+
+/**
+ * SECTION: context
+ * @title: Context
+ * @short_description: stores info about device, labels etc.
+ *
+ * The library distinguish between three types of partitioning objects.
+ *
+ * on-disk data
+ *    - disk label specific
+ *    - probed and read  by disklabel drivers when assign device to the context
+ *      or when switch to another disk label type
+ *    - only fdisk_write_disklabel() modify on-disk data
+ *
+ * in-memory data
+ *    - generic data and disklabel specific data stored in struct fdisk_label
+ *    - all partitioning operations are based on in-memory data only
+ *
+ * struct fdisk_partition
+ *    - provides abstraction to present partitions to users
+ *    - fdisk_partition is possible to gather to fdisk_table container
+ *    - used as unified template for new partitions
+ *    - the struct fdisk_partition is always completely independent object and
+ *      any change to the object has no effect to in-memory (or on-disk) label data
+ */
+
+/**
+ * fdisk_new_context:
+ *
+ * Returns: newly allocated libfdisk handler
+ */
+struct fdisk_context *fdisk_new_context(void)
+{
+	struct fdisk_context *cxt;
+
+	cxt = calloc(1, sizeof(*cxt));
+	if (!cxt)
+		return NULL;
+
+	DBG(CXT, ul_debugobj(cxt, "alloc"));
+	cxt->dev_fd = -1;
+	cxt->refcount = 1;
+
+	/*
+	 * Allocate label specific structs.
+	 *
+	 * This is necessary (for example) to store label specific
+	 * context setting.
+	 */
+	cxt->labels[ cxt->nlabels++ ] = fdisk_new_gpt_label(cxt);
+	cxt->labels[ cxt->nlabels++ ] = fdisk_new_dos_label(cxt);
+	cxt->labels[ cxt->nlabels++ ] = fdisk_new_bsd_label(cxt);
+	cxt->labels[ cxt->nlabels++ ] = fdisk_new_sgi_label(cxt);
+	cxt->labels[ cxt->nlabels++ ] = fdisk_new_sun_label(cxt);
+
+	return cxt;
+}
+
+static int init_nested_from_parent(struct fdisk_context *cxt, int isnew)
+{
+	struct fdisk_context *parent;
+
+	assert(cxt);
+	assert(cxt->parent);
+
+	parent = cxt->parent;
+
+	cxt->alignment_offset = parent->alignment_offset;
+	cxt->ask_cb =		parent->ask_cb;
+	cxt->ask_data =		parent->ask_data;
+	cxt->dev_fd =		parent->dev_fd;
+	cxt->first_lba =        parent->first_lba;
+	cxt->firstsector_bufsz = parent->firstsector_bufsz;
+	cxt->firstsector =	parent->firstsector;
+	cxt->geom =		parent->geom;
+	cxt->grain =            parent->grain;
+	cxt->io_size =          parent->io_size;
+	cxt->last_lba =		parent->last_lba;
+	cxt->min_io_size =      parent->min_io_size;
+	cxt->optimal_io_size =  parent->optimal_io_size;
+	cxt->phy_sector_size =  parent->phy_sector_size;
+	cxt->readonly =		parent->readonly;
+	cxt->script =		parent->script;
+	fdisk_ref_script(cxt->script);
+	cxt->sector_size =      parent->sector_size;
+	cxt->total_sectors =    parent->total_sectors;
+	cxt->user_geom =	parent->user_geom;
+	cxt->user_log_sector =	parent->user_log_sector;
+	cxt->user_pyh_sector =  parent->user_pyh_sector;
+
+	/* parent <--> nested independent setting, initialize for new nested 
+	 * contexts only */
+	if (isnew) {
+		cxt->listonly =	parent->listonly;
+		cxt->display_details =	parent->display_details;
+		cxt->display_in_cyl_units = parent->display_in_cyl_units;
+	}
+
+	free(cxt->dev_path);
+	cxt->dev_path = NULL;
+
+	if (parent->dev_path) {
+		cxt->dev_path =	strdup(parent->dev_path);
+		if (!cxt->dev_path)
+			return -ENOMEM;
+	}
+
+	return 0;
+}
+
+/**
+ * fdisk_new_nested_context:
+ * @parent: parental context
+ * @name: optional label name (e.g. "bsd")
+ *
+ * Create a new nested fdisk context for nested disk labels (e.g. BSD or PMBR).
+ * The function also probes for the nested label on the device if device is
+ * already assigned to parent.
+ *
+ * The new context is initialized according to @parent and both context shares
+ * some settings and file descriptor to the device. The child propagate some
+ * changes (like fdisk_assign_device()) to parent, but it does not work
+ * vice-versa. The behavior is undefined if you assign another device to
+ * parent.
+ *
+ * Returns: new context for nested partition table.
+ */
+struct fdisk_context *fdisk_new_nested_context(struct fdisk_context *parent,
+				const char *name)
+{
+	struct fdisk_context *cxt;
+	struct fdisk_label *lb = NULL;
+
+	assert(parent);
+
+	cxt = calloc(1, sizeof(*cxt));
+	if (!cxt)
+		return NULL;
+
+	DBG(CXT, ul_debugobj(parent, "alloc nested [%p]", cxt));
+	cxt->refcount = 1;
+
+	fdisk_ref_context(parent);
+	cxt->parent = parent;
+
+	if (init_nested_from_parent(cxt, 1) != 0)
+		return NULL;
+
+	if (name) {
+		if (strcmp(name, "bsd") == 0)
+			lb = cxt->labels[ cxt->nlabels++ ] = fdisk_new_bsd_label(cxt);
+		else if (strcmp(name, "dos") == 0)
+			lb = cxt->labels[ cxt->nlabels++ ] = fdisk_new_dos_label(cxt);
+	}
+
+	if (lb && parent->dev_fd >= 0) {
+		DBG(CXT, ul_debugobj(cxt, "probing for nested %s", lb->name));
+
+		cxt->label = lb;
+
+		if (lb->op->probe(cxt) == 1)
+			__fdisk_switch_label(cxt, lb);
+		else {
+			DBG(CXT, ul_debugobj(cxt, "not found %s label", lb->name));
+			if (lb->op->deinit)
+				lb->op->deinit(lb);
+			cxt->label = NULL;
+		}
+	}
+
+	return cxt;
+}
+
+
+/**
+ * fdisk_ref_context:
+ * @cxt: context pointer
+ *
+ * Increments reference counter.
+ */
+void fdisk_ref_context(struct fdisk_context *cxt)
+{
+	if (cxt)
+		cxt->refcount++;
+}
+
+/**
+ * fdisk_get_label:
+ * @cxt: context instance
+ * @name: label name (e.g. "gpt")
+ *
+ * If no @name specified then returns the current context label.
+ *
+ * The label is allocated and maintained within the context #cxt. There is
+ * nothing like reference counting for labels, you cannot delallocate the
+ * label.
+ *
+ * Returns: label struct or NULL in case of error.
+ */
+struct fdisk_label *fdisk_get_label(struct fdisk_context *cxt, const char *name)
+{
+	size_t i;
+
+	assert(cxt);
+
+	if (!name)
+		return cxt->label;
+
+	for (i = 0; i < cxt->nlabels; i++)
+		if (cxt->labels[i]
+		    && strcmp(cxt->labels[i]->name, name) == 0)
+			return cxt->labels[i];
+
+	DBG(CXT, ul_debugobj(cxt, "failed to found %s label driver", name));
+	return NULL;
+}
+
+/**
+ * fdisk_next_label:
+ * @cxt: context instance
+ * @lb: returns pointer to the next label
+ *
+ * <informalexample>
+ *   <programlisting>
+ *      // print all supported labels
+ *	struct fdisk_context *cxt = fdisk_new_context();
+ *	struct fdisk_label *lb = NULL;
+ *
+ *	while (fdisk_next_label(cxt, &lb) == 0)
+ *		print("label name: %s\n", fdisk_label_get_name(lb));
+ *	fdisk_unref_context(cxt);
+ *   </programlisting>
+ * </informalexample>
+ *
+ * Returns: <0 in case of error, 0 on success, 1 at the end.
+ */
+int fdisk_next_label(struct fdisk_context *cxt, struct fdisk_label **lb)
+{
+	size_t i;
+	struct fdisk_label *res = NULL;
+
+	if (!lb || !cxt)
+		return -EINVAL;
+
+	if (!*lb)
+		res = cxt->labels[0];
+	else {
+		for (i = 1; i < cxt->nlabels; i++) {
+			if (*lb == cxt->labels[i - 1]) {
+				res = cxt->labels[i];
+				break;
+			}
+		}
+	}
+
+	*lb = res;
+	return res ? 0 : 1;
+}
+
+/**
+ * fdisk_get_nlabels:
+ * @cxt: context
+ *
+ * Returns: number of supported label types
+ */
+size_t fdisk_get_nlabels(struct fdisk_context *cxt)
+{
+	return cxt ? cxt->nlabels : 0;
+}
+
+int __fdisk_switch_label(struct fdisk_context *cxt, struct fdisk_label *lb)
+{
+	if (!lb || !cxt)
+		return -EINVAL;
+	if (lb->disabled) {
+		DBG(CXT, ul_debugobj(cxt, "*** attempt to switch to disabled label %s -- ignore!", lb->name));
+		return -EINVAL;
+	}
+	cxt->label = lb;
+	DBG(CXT, ul_debugobj(cxt, "--> switching context to %s!", lb->name));
+	return 0;
+}
+
+/**
+ * fdisk_has_label:
+ * @cxt: fdisk context
+ *
+ * Returns: return 1 if there is label on the device.
+ */
+int fdisk_has_label(struct fdisk_context *cxt)
+{
+	return cxt && cxt->label;
+}
+
+/**
+ * fdisk_get_npartitions:
+ * @cxt: context
+ *
+ * The maximal number of the partitions depends on disklabel and does not
+ * have to describe the real limit of PT.
+ *
+ * For example the limit for MBR without extend partition is 4, with extended
+ * partition it's unlimited (so the function returns the current number of all
+ * partitions in this case).
+ *
+ * And for example for GPT it depends on space allocated on disk for array of
+ * entry records (usually 128).
+ *
+ * It's fine to use fdisk_get_npartitions() in loops, but don't forget that
+ * partition may be unused (see fdisk_is_partition_used()).
+ *
+ * <informalexample>
+ *   <programlisting>
+ *	struct fdisk_partition *pa = NULL;
+ *	size_t i, nmax = fdisk_get_npartitions(cxt);
+ *
+ *	for (i = 0; i < nmax; i++) {
+ *		if (!fdisk_is_partition_used(cxt, i))
+ *			continue;
+ *		... do something ...
+ *	}
+ *   </programlisting>
+ * </informalexample>
+ *
+ * Note that the recommended way to list partitions is to use
+ * fdisk_get_partitions() and struct fdisk_table than ask disk driver for each
+ * individual partitions.
+ *
+ * Returns: maximal number of partitions for the current label.
+ */
+size_t fdisk_get_npartitions(struct fdisk_context *cxt)
+{
+	return cxt && cxt->label ? cxt->label->nparts_max : 0;
+}
+
+/**
+ * fdisk_is_labeltype:
+ * @cxt: fdisk context
+ * @id: FDISK_DISKLABEL_*
+ *
+ * See also fdisk_is_label() macro in libfdisk.h.
+ *
+ * Returns: return 1 if the current label is @id
+ */
+int fdisk_is_labeltype(struct fdisk_context *cxt, enum fdisk_labeltype id)
+{
+	assert(cxt);
+
+	return cxt->label && fdisk_label_get_type(cxt->label) == id;
+}
+
+/**
+ * fdisk_get_parent:
+ * @cxt: nested fdisk context
+ *
+ * Returns: pointer to parental context, or NULL
+ */
+struct fdisk_context *fdisk_get_parent(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	return cxt->parent;
+}
+
+static void reset_context(struct fdisk_context *cxt)
+{
+	size_t i;
+
+	DBG(CXT, ul_debugobj(cxt, "*** resetting context"));
+
+	/* reset drives' private data */
+	for (i = 0; i < cxt->nlabels; i++)
+		fdisk_deinit_label(cxt->labels[i]);
+
+	if (cxt->parent) {
+		/* the first sector may be independent on parent */
+		if (cxt->parent->firstsector != cxt->firstsector)
+			free(cxt->firstsector);
+	} else {
+		/* we close device only in primary context */
+		if (cxt->dev_fd > -1)
+			close(cxt->dev_fd);
+		free(cxt->firstsector);
+	}
+
+	free(cxt->dev_path);
+	cxt->dev_path = NULL;
+
+	cxt->dev_fd = -1;
+	cxt->firstsector = NULL;
+	cxt->firstsector_bufsz = 0;
+
+	fdisk_zeroize_device_properties(cxt);
+
+	fdisk_unref_script(cxt->script);
+	cxt->script = NULL;
+
+	cxt->label = NULL;
+}
+
+/*
+ * This function prints a warning if the device is not wiped (e.g. wipefs(8).
+ * Please don't call this function if there is already a PT.
+ *
+ * Returns: 0 if nothing found, < 0 on error, 1 if found a signature
+ */
+static int warn_wipe(struct fdisk_context *cxt)
+{
+#ifdef HAVE_LIBBLKID
+	blkid_probe pr;
+#endif
+	int rc = 0;
+
+	assert(cxt);
+
+	if (fdisk_has_label(cxt) || cxt->dev_fd < 0)
+		return -EINVAL;
+#ifdef HAVE_LIBBLKID
+	DBG(CXT, ul_debugobj(cxt, "wipe check: initialize libblkid prober"));
+
+	pr = blkid_new_probe();
+	if (!pr)
+		return -ENOMEM;
+	rc = blkid_probe_set_device(pr, cxt->dev_fd, 0, 0);
+	if (rc)
+		return rc;
+
+	blkid_probe_enable_superblocks(pr, 1);
+	blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_TYPE);
+	blkid_probe_enable_partitions(pr, 1);
+
+	/* we care about the first found FS/raid, so don't call blkid_do_probe()
+	 * in loop or don't use blkid_do_fullprobe() ... */
+	rc = blkid_do_probe(pr);
+	if (rc == 0) {
+		const char *name = NULL;
+
+		if (blkid_probe_lookup_value(pr, "TYPE", &name, 0) == 0 ||
+		    blkid_probe_lookup_value(pr, "PTTYPE", &name, 0) == 0) {
+			fdisk_warnx(cxt, _(
+				"%s: device contains a valid '%s' signature; it is "
+				"strongly recommended to wipe the device with "
+				"wipefs(8) if this is unexpected, in order to "
+				"avoid possible collisions"), cxt->dev_path, name);
+			rc = 1;
+		}
+	}
+
+	blkid_free_probe(pr);
+#endif
+	return rc;
+}
+
+/**
+ * fdisk_assign_device:
+ * @cxt: context
+ * @fname: path to the device to be handled
+ * @readonly: how to open the device
+ *
+ * Open the device, discovery topology, geometry, detect disklabel and switch
+ * the current label driver to reflect the probing result.
+ *
+ * Note that this function resets all generic setting in context. If the @cxt
+ * is nested context then the device is assigned to the parental context and
+ * necessary properties are copied to the @cxt. The change is propagated in
+ * child->parent direction only. It's impossible to use a different device for
+ * primary and nested contexts.
+ *
+ * Returns: 0 on success, < 0 on error.
+ */
+int fdisk_assign_device(struct fdisk_context *cxt,
+			const char *fname, int readonly)
+{
+	int fd;
+
+	DBG(CXT, ul_debugobj(cxt, "assigning device %s", fname));
+	assert(cxt);
+
+	/* redirect request to parent */
+	if (cxt->parent) {
+		int rc, org = fdisk_is_listonly(cxt->parent);
+
+		/* assign_device() is sensitive to "listonly" mode, so let's
+		 * follow the current context setting for the parent to avoid 
+		 * unwanted extra warnings. */
+		fdisk_enable_listonly(cxt->parent, fdisk_is_listonly(cxt));
+
+		rc = fdisk_assign_device(cxt->parent, fname, readonly);
+		fdisk_enable_listonly(cxt->parent, org);
+
+		if (!rc)
+			rc = init_nested_from_parent(cxt, 0);
+		if (!rc)
+			fdisk_probe_labels(cxt);
+		return rc;
+	}
+
+	reset_context(cxt);
+
+	fd = open(fname, (readonly ? O_RDONLY : O_RDWR ) | O_CLOEXEC);
+	if (fd < 0)
+		return -errno;
+
+	cxt->readonly = readonly;
+	cxt->dev_fd = fd;
+	cxt->dev_path = strdup(fname);
+	if (!cxt->dev_path)
+		goto fail;
+
+	fdisk_discover_topology(cxt);
+	fdisk_discover_geometry(cxt);
+
+	if (fdisk_read_firstsector(cxt) < 0)
+		goto fail;
+
+	/* detect labels and apply labes specific stuff (e.g geomery)
+	 * to the context */
+	fdisk_probe_labels(cxt);
+
+	/* let's apply user geometry *after* label prober
+	 * to make it possible to override in-label setting */
+	fdisk_apply_user_device_properties(cxt);
+
+	/* warn about obsolete stuff on the device if we aren't in
+	 * list-only mode and there is not PT yet */
+	if (!fdisk_is_listonly(cxt) && !fdisk_has_label(cxt))
+		warn_wipe(cxt);
+
+	DBG(CXT, ul_debugobj(cxt, "initialized for %s [%s]",
+			      fname, readonly ? "READ-ONLY" : "READ-WRITE"));
+	return 0;
+fail:
+	DBG(CXT, ul_debugobj(cxt, "failed to assign device"));
+	return -errno;
+}
+
+/**
+ * fdisk_deassign_device:
+ * @cxt: context
+ * @nosync: disable fsync()
+ *
+ * Close device and call fsync(). If the @cxt is nested context than the
+ * request is redirected to the parent.
+ *
+ * Returns: 0 on success, < 0 on error.
+ */
+int fdisk_deassign_device(struct fdisk_context *cxt, int nosync)
+{
+	assert(cxt);
+	assert(cxt->dev_fd >= 0);
+
+	if (cxt->parent) {
+		int rc = fdisk_deassign_device(cxt->parent, nosync);
+
+		if (!rc)
+			rc = init_nested_from_parent(cxt, 0);
+		return rc;
+	}
+
+	if (cxt->readonly)
+		close(cxt->dev_fd);
+	else {
+		if (fsync(cxt->dev_fd) || close(cxt->dev_fd)) {
+			fdisk_warn(cxt, _("%s: close device failed"),
+					cxt->dev_path);
+			return -errno;
+		}
+
+		if (!nosync) {
+			fdisk_info(cxt, _("Syncing disks."));
+			sync();
+		}
+	}
+
+	free(cxt->dev_path);
+	cxt->dev_path = NULL;
+
+	cxt->dev_fd = -1;
+
+	return 0;
+}
+
+/**
+ * fdisk_is_readonly:
+ * @cxt: context
+ *
+ * Returns: 1 if device open readonly
+ */
+int fdisk_is_readonly(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	return cxt->readonly;
+}
+
+/**
+ * fdisk_unref_context:
+ * @cxt: fdisk context
+ *
+ * Deallocates context struct.
+ */
+void fdisk_unref_context(struct fdisk_context *cxt)
+{
+	int i;
+
+	if (!cxt)
+		return;
+
+	cxt->refcount--;
+	if (cxt->refcount <= 0) {
+		DBG(CXT, ul_debugobj(cxt, "freeing context %p for %s", cxt, cxt->dev_path));
+
+		reset_context(cxt);	/* this is sensitive to parent<->child relationship! */
+
+		/* deallocate label's private stuff */
+		for (i = 0; i < cxt->nlabels; i++) {
+			if (!cxt->labels[i])
+				continue;
+			if (cxt->labels[i]->op->free)
+				cxt->labels[i]->op->free(cxt->labels[i]);
+			else
+				free(cxt->labels[i]);
+		}
+
+		fdisk_unref_context(cxt->parent);
+		cxt->parent = NULL;
+
+		free(cxt);
+	}
+}
+
+
+/**
+ * fdisk_enable_details:
+ * @cxt: context
+ * @enable: true/flase
+ *
+ * Enables or disables "details" display mode. This function has effect to
+ * fdisk_partition_to_string() function.
+ *
+ * Returns: 0 on success, < 0 on error.
+ */
+int fdisk_enable_details(struct fdisk_context *cxt, int enable)
+{
+	assert(cxt);
+	cxt->display_details = enable ? 1 : 0;
+	return 0;
+}
+
+/**
+ * fdisk_is_details:
+ * @cxt: context
+ *
+ * Returns: 1 if details are enabled
+ */
+int fdisk_is_details(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	return cxt->display_details == 1;
+}
+
+/**
+ * fdisk_enable_listonly:
+ * @cxt: context
+ * @enable: true/flase
+ *
+ * Just list partition only, don't care about another details, mistakes, ...
+ *
+ * Returns: 0 on success, < 0 on error.
+ */
+int fdisk_enable_listonly(struct fdisk_context *cxt, int enable)
+{
+	assert(cxt);
+	cxt->listonly = enable ? 1 : 0;
+	return 0;
+}
+
+/**
+ * fdisk_is_listonly:
+ * @cxt: context
+ *
+ * Returns: 1 if list-only mode enabled
+ */
+int fdisk_is_listonly(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	return cxt->listonly == 1;
+}
+
+
+/**
+ * fdisk_set_unit:
+ * @cxt: context
+ * @str: "cylinder" or "sector".
+ *
+ * This is pure shit, unfortunately for example Sun addresses begin of the
+ * partition by cylinders...
+ *
+ * Returns: 0 on succes, <0 on error.
+ */
+int fdisk_set_unit(struct fdisk_context *cxt, const char *str)
+{
+	assert(cxt);
+
+	cxt->display_in_cyl_units = 0;
+
+	if (!str)
+		return 0;
+
+	if (strcmp(str, "cylinder") == 0 || strcmp(str, "cylinders") == 0)
+		cxt->display_in_cyl_units = 1;
+
+	else if (strcmp(str, "sector") == 0 || strcmp(str, "sectors") == 0)
+		cxt->display_in_cyl_units = 0;
+
+	DBG(CXT, ul_debugobj(cxt, "display unit: %s", fdisk_get_unit(cxt, 0)));
+	return 0;
+}
+
+/**
+ * fdisk_get_unit:
+ * @cxt: context
+ * @n: FDISK_PLURAL or FDISK_SINGULAR
+ *
+ * Returns: unit name.
+ */
+const char *fdisk_get_unit(struct fdisk_context *cxt, int n)
+{
+	assert(cxt);
+
+	if (fdisk_use_cylinders(cxt))
+		return P_("cylinder", "cylinders", n);
+	return P_("sector", "sectors", n);
+}
+
+/**
+ * fdisk_use_cylinders:
+ * @cxt: context
+ *
+ * Returns: 1 if user wants to display in cylinders.
+ */
+int fdisk_use_cylinders(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	return cxt->display_in_cyl_units == 1;
+}
+
+/**
+ * fdisk_get_units_per_sector:
+ * @cxt: context
+ *
+ * This is necessary only for brain dead situations when we use "cylinders";
+ *
+ * Returns: number of "units" per sector, default is 1 if display unit is sector.
+ */
+unsigned int fdisk_get_units_per_sector(struct fdisk_context *cxt)
+{
+	assert(cxt);
+
+	if (fdisk_use_cylinders(cxt)) {
+		assert(cxt->geom.heads);
+		return cxt->geom.heads * cxt->geom.sectors;
+	}
+	return 1;
+}
+
+/**
+ * fdisk_get_optimal_iosize:
+ * @cxt: context
+ *
+ * The optimal I/O is optional and does not have to be provided by device,
+ * anyway libfdisk never returns zero. If the optimal I/O size is not provided
+ * then libfdisk returns minimal I/O size or sector size.
+ *
+ * Returns: optimal I/O size in bytes.
+ */
+unsigned long fdisk_get_optimal_iosize(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	return cxt->optimal_io_size ? cxt->optimal_io_size : cxt->io_size;
+}
+
+/**
+ * fdisk_get_minimal_iosize:
+ * @cxt: context
+ *
+ * Returns: minimal I/O size in bytes
+ */
+unsigned long fdisk_get_minimal_iosize(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	return cxt->min_io_size;
+}
+
+/**
+ * fdisk_get_physector_size:
+ * @cxt: context
+ *
+ * Returns: physical sector size in bytes
+ */
+unsigned long fdisk_get_physector_size(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	return cxt->phy_sector_size;
+}
+
+/**
+ * fdisk_get_sector_size:
+ * @cxt: context
+ *
+ * Returns: logical sector size in bytes
+ */
+unsigned long fdisk_get_sector_size(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	return cxt->sector_size;
+}
+
+/**
+ * fdisk_get_alignment_offset
+ * @cxt: context
+ *
+ * The alignment offset is offset between logical and physical sectors. For
+ * backward compatibility the first logical sector on 4K disks does no have to
+ * start on the same place like physical sectors.
+ *
+ * Returns: alignment offset in bytes
+ */
+unsigned long fdisk_get_alignment_offset(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	return cxt->alignment_offset;
+}
+
+/**
+ * fdisk_get_grain_size:
+ * @cxt: context
+ *
+ * Returns: grain in bytes used to align partitions (usually 1MiB)
+ */
+unsigned long fdisk_get_grain_size(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	return cxt->grain;
+}
+
+/**
+ * fdisk_get_first_lba:
+ * @cxt: context
+ *
+ * Returns: first possible LBA on disk for data partitions.
+ */
+fdisk_sector_t fdisk_get_first_lba(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	return cxt->first_lba;
+}
+
+/**
+ * fdisk_set_first_lba:
+ * @cxt: fdisk context
+ * @lba: first possible logical sector for data
+ *
+ * It's strongly recommended to use the default library setting. The first LBA
+ * is always reseted by fdisk_assign_device(), fdisk_override_geometry()
+ * and fdisk_reset_alignment(). This is very low level function and library
+ * does not check if your setting makes any sense.
+ *
+ * This function is necessary only when you want to work with very unusual
+ * partition tables like GPT protective MBR or hybrid partition tables on
+ * bootable media where the first partition may start on very crazy offsets.
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+fdisk_sector_t fdisk_set_first_lba(struct fdisk_context *cxt, fdisk_sector_t lba)
+{
+	assert(cxt);
+	DBG(CXT, ul_debugobj(cxt, "setting first LBA from %ju to %ju",
+			(uintmax_t) cxt->first_lba, (uintmax_t) lba));
+	cxt->first_lba = lba;
+	return 0;
+}
+
+/**
+ * fdisk_get_last_lba:
+ * @cxt: fdisk context
+ *
+ * Note that the device has to be already assigned.
+ *
+ * Returns: last possible LBA on device
+ */
+fdisk_sector_t fdisk_get_last_lba(struct fdisk_context *cxt)
+{
+	return cxt->last_lba;
+}
+
+/**
+ * fdisk_set_last_lba:
+ * @cxt: fdisk context
+ * @lba: last possible logical sector
+ *
+ * It's strongly recommended to use the default library setting. The last LBA
+ * is always reseted by fdisk_assign_device(), fdisk_override_geometry() and
+ * fdisk_reset_alignment().
+ *
+ * The default is number of sectors on the device, but maybe modified by the
+ * current disklabel driver (for example GPT uses and of disk for backup
+ * header, so last_lba is smaller than total number of sectors).
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+fdisk_sector_t fdisk_set_last_lba(struct fdisk_context *cxt, fdisk_sector_t lba)
+{
+	assert(cxt);
+
+	if (lba > cxt->total_sectors - 1 && lba < 1)
+		return -ERANGE;
+	cxt->last_lba = lba;
+	return 0;
+}
+
+
+/**
+ * fdisk_get_nsectors:
+ * @cxt: context
+ *
+ * Returns: size of the device in logical sectors.
+ */
+fdisk_sector_t fdisk_get_nsectors(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	return cxt->total_sectors;
+}
+
+/**
+ * fdisk_get_devname:
+ * @cxt: context
+ *
+ * Returns: device name.
+ */
+const char *fdisk_get_devname(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	return cxt->dev_path;
+}
+
+/**
+ * fdisk_get_devfd:
+ * @cxt: context
+ *
+ * Retruns: device file descriptor.
+ */
+int fdisk_get_devfd(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	return cxt->dev_fd;
+}
+
+/**
+ * fdisk_get_geom_heads:
+ * @cxt: context
+ *
+ * Returns: number of geometry heads.
+ */
+unsigned int fdisk_get_geom_heads(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	return cxt->geom.heads;
+}
+/**
+ * fdisk_get_geom_sectors:
+ * @cxt: context
+ *
+ * Returns: number of geometry sectors.
+ */
+fdisk_sector_t fdisk_get_geom_sectors(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	return cxt->geom.sectors;
+
+}
+
+/**
+ * fdisk_get_geom_cylinders:
+ * @cxt: context
+ *
+ * Returns: number of geometry cylinders
+ */
+fdisk_sector_t fdisk_get_geom_cylinders(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	return cxt->geom.cylinders;
+}
+
+int fdisk_missing_geometry(struct fdisk_context *cxt)
+{
+	int rc;
+
+	assert(cxt);
+
+	if (!cxt || !cxt->label)
+		return 0;
+
+	rc = (fdisk_label_require_geometry(cxt->label) &&
+		    (!cxt->geom.heads || !cxt->geom.sectors
+				      || !cxt->geom.cylinders));
+
+	if (rc && !fdisk_is_listonly(cxt))
+		fdisk_warnx(cxt, _("Incomplete geometry setting."));
+
+	return rc;
+}
+
diff --git a/libblkid/libfdisk/src/dos.c b/libblkid/libfdisk/src/dos.c
new file mode 100644
index 0000000..2a06707
--- /dev/null
+++ b/libblkid/libfdisk/src/dos.c
@@ -0,0 +1,2331 @@
+/*
+ *
+ * Copyright (C) 2007-2013 Karel Zak <kzak@redhat.com>
+ *                    2012 Davidlohr Bueso <dave@gnu.org>
+ *
+ * This is re-written version for libfdisk, the original was fdiskdoslabel.c
+ * from util-linux fdisk.
+ */
+#include "c.h"
+#include "nls.h"
+#include "randutils.h"
+#include "pt-mbr.h"
+#include "strutils.h"
+
+#include "fdiskP.h"
+
+#include <ctype.h>
+
+#define MAXIMUM_PARTS	60
+#define ACTIVE_FLAG     0x80
+
+/**
+ * SECTION: dos
+ * @title: DOS (MBR)
+ * @short_description: disk label specific functions
+ *
+ */
+
+
+#define IS_EXTENDED(i) \
+	((i) == MBR_DOS_EXTENDED_PARTITION \
+	 || (i) == MBR_W95_EXTENDED_PARTITION \
+	 || (i) == MBR_LINUX_EXTENDED_PARTITION)
+
+/*
+ * per partition table entry data
+ *
+ * The four primary partitions have the same sectorbuffer
+ * and have NULL ex_entry.
+ *
+ * Each logical partition table entry has two pointers, one for the
+ * partition and one link to the next one.
+ */
+struct pte {
+	struct dos_partition *pt_entry;	/* on-disk MBR entry */
+	struct dos_partition *ex_entry;	/* on-disk EBR entry */
+	fdisk_sector_t offset;	        /* disk sector number */
+	unsigned char *sectorbuffer;	/* disk sector contents */
+
+	unsigned int changed : 1,
+		     private_sectorbuffer : 1;
+};
+
+/*
+ * in-memory fdisk GPT stuff
+ */
+struct fdisk_dos_label {
+	struct fdisk_label	head;		/* generic part */
+
+	struct pte	ptes[MAXIMUM_PARTS];	/* partition */
+	fdisk_sector_t	ext_offset;		/* start of the ext.partition */
+	size_t		ext_index;		/* ext.partition index (if ext_offset is set) */
+	unsigned int	compatible : 1,		/* is DOS compatible? */
+			non_pt_changed : 1;	/* MBR, but no PT changed */
+};
+
+/*
+ * Partition types
+ */
+static struct fdisk_parttype dos_parttypes[] = {
+	#include "pt-mbr-partnames.h"
+};
+
+#define set_hsc(h,s,c,sector) { \
+		s = sector % cxt->geom.sectors + 1;			\
+		sector /= cxt->geom.sectors;				\
+		h = sector % cxt->geom.heads;				\
+		sector /= cxt->geom.heads;				\
+		c = sector & 0xff;					\
+		s |= (sector >> 2) & 0xc0;				\
+	}
+
+
+#define sector(s)	((s) & 0x3f)
+#define cylinder(s, c)	((c) | (((s) & 0xc0) << 2))
+
+#define alignment_required(_x)	((_x)->grain != (_x)->sector_size)
+
+#define is_dos_compatible(_x) \
+		   (fdisk_is_label(_x, DOS) && \
+                    fdisk_dos_is_compatible(fdisk_get_label(_x, NULL)))
+
+#define cround(c, n)	fdisk_cround(c, n)
+
+
+static inline struct fdisk_dos_label *self_label(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, DOS));
+
+	return (struct fdisk_dos_label *) cxt->label;
+}
+
+static inline struct pte *self_pte(struct fdisk_context *cxt, size_t i)
+{
+	struct fdisk_dos_label *l = self_label(cxt);
+
+	if (i >= ARRAY_SIZE(l->ptes))
+		return NULL;
+
+	return &l->ptes[i];
+}
+
+static inline struct dos_partition *self_partition(
+				struct fdisk_context *cxt,
+				size_t i)
+{
+	struct pte *pe = self_pte(cxt, i);
+	return pe ? pe->pt_entry : NULL;
+}
+
+struct dos_partition *fdisk_dos_get_partition(
+				struct fdisk_context *cxt,
+				size_t i)
+{
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, DOS));
+
+	return self_partition(cxt, i);
+}
+
+static struct fdisk_parttype *dos_partition_parttype(
+		struct fdisk_context *cxt,
+		struct dos_partition *p)
+{
+	struct fdisk_parttype *t
+		= fdisk_label_get_parttype_from_code(cxt->label, p->sys_ind);
+	return t ? : fdisk_new_unknown_parttype(p->sys_ind, NULL);
+}
+
+/*
+ * Linux kernel cares about partition size only. Things like
+ * partition type or so are completely irrelevant -- kzak Nov-2013
+ */
+static int is_used_partition(struct dos_partition *p)
+{
+	return p && dos_partition_get_size(p) != 0;
+}
+
+static void partition_set_changed(
+				struct fdisk_context *cxt,
+				size_t i,
+				int changed)
+{
+	struct pte *pe = self_pte(cxt, i);
+
+	if (!pe)
+		return;
+
+	DBG(LABEL, ul_debug("DOS: setting %zu partition to %s", i,
+				changed ? "changed" : "unchanged"));
+
+	pe->changed = changed ? 1 : 0;
+	if (changed)
+		fdisk_label_set_changed(cxt->label, 1);
+}
+
+static fdisk_sector_t get_abs_partition_start(struct pte *pe)
+{
+	assert(pe);
+	assert(pe->pt_entry);
+
+	return pe->offset + dos_partition_get_start(pe->pt_entry);
+}
+
+static fdisk_sector_t get_abs_partition_end(struct pte *pe)
+{
+	fdisk_sector_t size;
+
+	assert(pe);
+	assert(pe->pt_entry);
+
+	size = dos_partition_get_size(pe->pt_entry);
+	return get_abs_partition_start(pe) + size - (size ? 1 : 0);
+}
+
+static int is_cleared_partition(struct dos_partition *p)
+{
+	return !(!p || p->boot_ind || p->bh || p->bs || p->bc ||
+		 p->sys_ind || p->eh || p->es || p->ec ||
+		 dos_partition_get_start(p) || dos_partition_get_size(p));
+}
+
+static int get_partition_unused_primary(struct fdisk_context *cxt,
+					struct fdisk_partition *pa,
+					size_t *partno)
+{
+	size_t org, n;
+	int rc;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(partno);
+
+	org = cxt->label->nparts_max;
+
+	cxt->label->nparts_max = 4;
+	rc = fdisk_partition_next_partno(pa, cxt, &n);
+	cxt->label->nparts_max = org;
+
+	if (rc == 1) {
+		fdisk_info(cxt, _("All primary partitions have been defined already."));
+		rc = -1;
+	} else if (rc == 0)
+		*partno = n;
+	return rc;
+}
+
+static int seek_sector(struct fdisk_context *cxt, fdisk_sector_t secno)
+{
+	off_t offset = (off_t) secno * cxt->sector_size;
+
+	return lseek(cxt->dev_fd, offset, SEEK_SET) == (off_t) -1 ? -errno : 0;
+}
+
+static int read_sector(struct fdisk_context *cxt, fdisk_sector_t secno,
+			unsigned char *buf)
+{
+	int rc = seek_sector(cxt, secno);
+	ssize_t r;
+
+	if (rc < 0)
+		return rc;
+
+	r = read(cxt->dev_fd, buf, cxt->sector_size);
+	if (r == (ssize_t) cxt->sector_size)
+		return 0;
+	if (r < 0)
+		return -errno;
+	return -1;
+}
+
+/* Allocate a buffer and read a partition table sector */
+static int read_pte(struct fdisk_context *cxt, size_t pno, fdisk_sector_t offset)
+{
+	int rc;
+	unsigned char *buf;
+	struct pte *pe = self_pte(cxt, pno);
+
+	buf = calloc(1, cxt->sector_size);
+	if (!buf)
+		return -ENOMEM;
+
+	DBG(LABEL, ul_debug("DOS: reading EBR %zu: offset=%ju, buffer=%p",
+				pno, (uintmax_t) offset, buf));
+
+	pe->offset = offset;
+	pe->sectorbuffer = buf;
+	pe->private_sectorbuffer = 1;
+
+	rc = read_sector(cxt, offset, pe->sectorbuffer);
+	if (rc) {
+		fdisk_warn(cxt, _("Failed to read extended partition table "
+				"(offset=%ju)"), (uintmax_t) offset);
+		return rc;
+	}
+
+	pe->changed = 0;
+	pe->pt_entry = pe->ex_entry = NULL;
+	return 0;
+}
+
+
+static void clear_partition(struct dos_partition *p)
+{
+	if (!p)
+		return;
+	p->boot_ind = 0;
+	p->bh = 0;
+	p->bs = 0;
+	p->bc = 0;
+	p->sys_ind = 0;
+	p->eh = 0;
+	p->es = 0;
+	p->ec = 0;
+	dos_partition_set_start(p,0);
+	dos_partition_set_size(p,0);
+}
+
+static void dos_init(struct fdisk_context *cxt)
+{
+	struct fdisk_dos_label *l = self_label(cxt);
+	size_t i;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, DOS));
+
+	DBG(LABEL, ul_debug("DOS: initialize, first sector buffer %p", cxt->firstsector));
+
+	cxt->label->nparts_max = 4;	/* default, unlimited number of logical */
+
+	l->ext_index = 0;
+	l->ext_offset = 0;
+	l->non_pt_changed = 0;
+
+	memset(l->ptes, 0, sizeof(l->ptes));
+
+	for (i = 0; i < 4; i++) {
+		struct pte *pe = self_pte(cxt, i);
+
+		pe->pt_entry = mbr_get_partition(cxt->firstsector, i);
+		pe->ex_entry = NULL;
+		pe->offset = 0;
+		pe->sectorbuffer = cxt->firstsector;
+		pe->private_sectorbuffer = 0;
+		pe->changed = 0;
+	}
+
+	if (fdisk_is_listonly(cxt))
+		return;
+	/*
+	 * Various warnings...
+	 */
+	if (fdisk_missing_geometry(cxt))
+		fdisk_warnx(cxt, _("You can set geometry from the extra functions menu."));
+
+	if (is_dos_compatible(cxt)) {
+		fdisk_warnx(cxt, _("DOS-compatible mode is deprecated."));
+
+		if (cxt->sector_size != cxt->phy_sector_size)
+			fdisk_info(cxt, _(
+		"The device presents a logical sector size that is smaller than "
+		"the physical sector size. Aligning to a physical sector (or optimal "
+		"I/O) size boundary is recommended, or performance may be impacted."));
+	}
+
+	if (fdisk_use_cylinders(cxt))
+		fdisk_warnx(cxt, _("Cylinders as display units are deprecated."));
+
+	if (cxt->total_sectors > UINT_MAX) {
+		uint64_t bytes = cxt->total_sectors * cxt->sector_size;
+		char *szstr = size_to_human_string(SIZE_SUFFIX_SPACE
+					   | SIZE_SUFFIX_3LETTER, bytes);
+		fdisk_warnx(cxt,
+		_("The size of this disk is %s (%ju bytes). DOS "
+		  "partition table format can not be used on drives for "
+		  "volumes larger than %lu bytes for %lu-byte "
+		  "sectors. Use GUID partition table format (GPT)."),
+			szstr, bytes,
+			UINT_MAX * cxt->sector_size,
+			cxt->sector_size);
+		free(szstr);
+	}
+}
+
+/* callback called by libfdisk */
+static void dos_deinit(struct fdisk_label *lb)
+{
+	size_t i;
+	struct fdisk_dos_label *l = (struct fdisk_dos_label *) lb;
+
+	for (i = 0; i < ARRAY_SIZE(l->ptes); i++) {
+		struct pte *pe = &l->ptes[i];
+
+		if (pe->private_sectorbuffer && pe->sectorbuffer) {
+			DBG(LABEL, ul_debug("DOS: freeing pte %zu sector buffer %p",
+						i, pe->sectorbuffer));
+			free(pe->sectorbuffer);
+		}
+		pe->sectorbuffer = NULL;
+		pe->private_sectorbuffer = 0;
+	}
+
+	memset(l->ptes, 0, sizeof(l->ptes));
+}
+
+static void reset_pte(struct pte *pe)
+{
+	assert(pe);
+
+	if (pe->private_sectorbuffer) {
+		DBG(LABEL, ul_debug("  --> freeing pte sector buffer %p",
+					pe->sectorbuffer));
+		free(pe->sectorbuffer);
+	}
+	memset(pe, 0, sizeof(struct pte));
+}
+
+static int dos_delete_partition(struct fdisk_context *cxt, size_t partnum)
+{
+	struct fdisk_dos_label *l;
+	struct pte *pe;
+	struct dos_partition *p;
+	struct dos_partition *q;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, DOS));
+
+	pe = self_pte(cxt, partnum);
+	if (!pe)
+		return -EINVAL;
+
+	DBG(LABEL, ul_debug("DOS: delete partiton %zu (max=%zu)", partnum,
+				cxt->label->nparts_max));
+
+	l = self_label(cxt);
+	p = pe->pt_entry;
+	q = pe->ex_entry;
+
+	/* Note that for the fifth partition (partnum == 4) we don't actually
+	   decrement partitions. */
+	if (partnum < 4) {
+		DBG(LABEL, ul_debug("--> delete primary"));
+		if (IS_EXTENDED(p->sys_ind) && partnum == l->ext_index) {
+			cxt->label->nparts_max = 4;
+			l->ptes[l->ext_index].ex_entry = NULL;
+			l->ext_offset = 0;
+			l->ext_index = 0;
+		}
+		partition_set_changed(cxt, partnum, 1);
+		clear_partition(p);
+	} else if (!q->sys_ind && partnum > 4) {
+		DBG(LABEL, ul_debug("--> delete logical [last in the chain]"));
+		reset_pte(&l->ptes[partnum]);
+		--cxt->label->nparts_max;
+		--partnum;
+		/* clear link to deleted partition */
+		clear_partition(l->ptes[partnum].ex_entry);
+		partition_set_changed(cxt, partnum, 1);
+	} else {
+		DBG(LABEL, ul_debug("--> delete logical [move down]"));
+		if (partnum > 4) {
+			DBG(LABEL, ul_debug(" --> delete %zu logical link", partnum));
+			p = l->ptes[partnum - 1].ex_entry;
+			*p = *q;
+			dos_partition_set_start(p, dos_partition_get_start(q));
+			dos_partition_set_size(p, dos_partition_get_size(q));
+			partition_set_changed(cxt, partnum - 1, 1);
+
+		} else if (cxt->label->nparts_max > 5) {
+			DBG(LABEL, ul_debug(" --> delete first logical link"));
+			pe = &l->ptes[5];	/* second logical */
+
+			if (pe->pt_entry)	/* prevent SEGFAULT */
+				dos_partition_set_start(pe->pt_entry,
+					       get_abs_partition_start(pe) -
+					       l->ext_offset);
+			pe->offset = l->ext_offset;
+			partition_set_changed(cxt, 5, 1);
+		}
+
+		if (cxt->label->nparts_max > 5) {
+			DBG(LABEL, ul_debug(" --> move ptes"));
+			cxt->label->nparts_max--;
+			reset_pte(&l->ptes[partnum]);
+			while (partnum < cxt->label->nparts_max) {
+				DBG(LABEL, ul_debug("  --> moving pte %zu <-- %zu", partnum, partnum + 1));
+				l->ptes[partnum] = l->ptes[partnum + 1];
+				partnum++;
+			}
+			memset(&l->ptes[partnum], 0, sizeof(struct pte));
+		} else {
+			DBG(LABEL, ul_debug(" --> the only logical: clear only"));
+			clear_partition(l->ptes[partnum].pt_entry);
+			cxt->label->nparts_max--;
+
+			if (partnum == 4) {
+				DBG(LABEL, ul_debug("  --> clear last logical"));
+				reset_pte(&l->ptes[partnum]);
+				partition_set_changed(cxt, l->ext_index, 1);
+			}
+		}
+	}
+
+	fdisk_label_set_changed(cxt->label, 1);
+	return 0;
+}
+
+static void read_extended(struct fdisk_context *cxt, size_t ext)
+{
+	size_t i;
+	struct pte *pex, *pe;
+	struct dos_partition *p, *q;
+	struct fdisk_dos_label *l = self_label(cxt);
+
+	l->ext_index = ext;
+	pex = self_pte(cxt, ext);
+	pex->ex_entry = pex->pt_entry;
+
+	p = pex->pt_entry;
+	if (!dos_partition_get_start(p)) {
+		fdisk_warnx(cxt, _("Bad offset in primary extended partition."));
+		return;
+	}
+
+	DBG(LABEL, ul_debug("DOS: Reading extended %zu", ext));
+
+	while (IS_EXTENDED (p->sys_ind)) {
+		pe = self_pte(cxt, cxt->label->nparts_max);
+
+		if (cxt->label->nparts_max >= MAXIMUM_PARTS) {
+			/* This is not a Linux restriction, but
+			   this program uses arrays of size MAXIMUM_PARTS.
+			   Do not try to `improve' this test. */
+			struct pte *pre = self_pte(cxt,
+						cxt->label->nparts_max - 1);
+			fdisk_warnx(cxt,
+			_("Omitting partitions after #%zu. They will be deleted "
+			  "if you save this partition table."),
+				cxt->label->nparts_max);
+
+			clear_partition(pre->ex_entry);
+			partition_set_changed(cxt,
+					cxt->label->nparts_max - 1, 1);
+			return;
+		}
+
+		if (read_pte(cxt, cxt->label->nparts_max, l->ext_offset +
+						dos_partition_get_start(p)))
+			return;
+
+		if (!l->ext_offset)
+			l->ext_offset = dos_partition_get_start(p);
+
+		assert(pe->sectorbuffer);
+		q = p = mbr_get_partition(pe->sectorbuffer, 0);
+
+		for (i = 0; i < 4; i++, p++) {
+			if (!dos_partition_get_size(p))
+				continue;
+
+			if (IS_EXTENDED (p->sys_ind)) {
+				if (pe->ex_entry)
+					fdisk_warnx(cxt, _(
+					"Extra link pointer in partition "
+					"table %zu."),
+						cxt->label->nparts_max + 1);
+				else
+					pe->ex_entry = p;
+			} else if (p->sys_ind) {
+				if (pe->pt_entry)
+					fdisk_warnx(cxt, _(
+					"Ignoring extra data in partition "
+					"table %zu."),
+						cxt->label->nparts_max + 1);
+				else
+					pe->pt_entry = p;
+			}
+		}
+
+		/* very strange code here... */
+		if (!pe->pt_entry) {
+			if (q != pe->ex_entry)
+				pe->pt_entry = q;
+			else
+				pe->pt_entry = q + 1;
+		}
+		if (!pe->ex_entry) {
+			if (q != pe->pt_entry)
+				pe->ex_entry = q;
+			else
+				pe->ex_entry = q + 1;
+		}
+
+		p = pe->ex_entry;
+		cxt->label->nparts_cur = ++cxt->label->nparts_max;
+
+		DBG(LABEL, ul_debug("DOS: EBR[offset=%ju]: link: type=%x,  start=%u, size=%u; "
+				                         " data: type=%x, start=%u, size=%u",
+				    (uintmax_t) pe->offset,
+				    pe->ex_entry->sys_ind,
+				    dos_partition_get_start(pe->ex_entry),
+				    dos_partition_get_size(pe->ex_entry),
+				    pe->pt_entry->sys_ind,
+				    dos_partition_get_start(pe->pt_entry),
+				    dos_partition_get_size(pe->pt_entry)));
+
+	}
+
+	/* remove last empty EBR */
+	pe = self_pte(cxt, cxt->label->nparts_max - 1);
+	if (is_cleared_partition(pe->ex_entry) &&
+	    is_cleared_partition(pe->pt_entry)) {
+		DBG(LABEL, ul_debug("DOS: EBR[offset=%ju]: empty, remove", (uintmax_t) pe->offset));
+		reset_pte(pe);
+		cxt->label->nparts_max--;
+		cxt->label->nparts_cur--;
+	}
+
+	/* remove empty links */
+ remove:
+	q = self_partition(cxt, 4);
+	for (i = 4; i < cxt->label->nparts_max; i++) {
+		p = self_partition(cxt, i);
+
+		if (!dos_partition_get_size(p) &&
+		    (cxt->label->nparts_max > 5 || q->sys_ind)) {
+			fdisk_info(cxt, _("omitting empty partition (%zu)"), i+1);
+			dos_delete_partition(cxt, i);
+			goto remove; 	/* numbering changed */
+		}
+	}
+
+	DBG(LABEL, ul_debug("DOS: nparts_max: %zu", cxt->label->nparts_max));
+}
+
+static int dos_get_disklabel_id(struct fdisk_context *cxt, char **id)
+{
+	unsigned int num;
+
+	assert(cxt);
+	assert(id);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, DOS));
+
+	num = mbr_get_id(cxt->firstsector);
+	if (asprintf(id, "0x%08x", num) > 0)
+		return 0;
+
+	return -ENOMEM;
+}
+
+static int dos_create_disklabel(struct fdisk_context *cxt)
+{
+	unsigned int id = 0;
+	int rc, has_id = 0;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, DOS));
+
+	DBG(LABEL, ul_debug("DOS: creating new disklabel"));
+
+	if (cxt->script) {
+		char *end = NULL;
+		const char *s = fdisk_script_get_header(cxt->script, "label-id");
+
+		if (s) {
+			errno = 0;
+			id = strtol(s, &end, 16);
+			if (!errno && end && s < end)
+				has_id = 1;
+		}
+	}
+
+	/* random disk signature */
+	if (!has_id)
+		random_get_bytes(&id, sizeof(id));
+
+	dos_init(cxt);
+	rc = fdisk_init_firstsector_buffer(cxt);
+	if (rc)
+		return rc;
+	fdisk_label_set_changed(cxt->label, 1);
+
+	/* Generate an MBR ID for this disk */
+	mbr_set_id(cxt->firstsector, id);
+
+	/* Put MBR signature */
+	mbr_set_magic(cxt->firstsector);
+
+	fdisk_info(cxt, _("Created a new DOS disklabel with disk "
+			 "identifier 0x%08x."), id);
+	return 0;
+}
+
+static int dos_set_disklabel_id(struct fdisk_context *cxt)
+{
+	char *end = NULL, *str = NULL;
+	unsigned int id, old;
+	struct fdisk_dos_label *l;
+	int rc;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, DOS));
+
+	DBG(LABEL, ul_debug("DOS: setting Id"));
+
+	l = self_label(cxt);
+	old = mbr_get_id(cxt->firstsector);
+	rc = fdisk_ask_string(cxt,
+			_("Enter the new disk identifier"), &str);
+	if (rc)
+		return rc;
+
+	errno = 0;
+	id = strtoul(str, &end, 0);
+	if (errno || str == end || (end && *end)) {
+		fdisk_warnx(cxt, _("Incorrect value."));
+		return -EINVAL;
+	}
+
+
+	mbr_set_id(cxt->firstsector, id);
+	l->non_pt_changed = 1;
+	fdisk_label_set_changed(cxt->label, 1);
+
+	fdisk_info(cxt, _("Disk identifier changed from 0x%08x to 0x%08x."),
+			old, id);
+	return 0;
+}
+
+static void get_partition_table_geometry(struct fdisk_context *cxt,
+			unsigned int *ph, unsigned int *ps)
+{
+	unsigned char *bufp = cxt->firstsector;
+	struct dos_partition *p;
+	int i, h, s, hh, ss;
+	int first = 1;
+	int bad = 0;
+
+	hh = ss = 0;
+	for (i = 0; i < 4; i++) {
+		p = mbr_get_partition(bufp, i);
+		if (p->sys_ind != 0) {
+			h = p->eh + 1;
+			s = (p->es & 077);
+			if (first) {
+				hh = h;
+				ss = s;
+				first = 0;
+			} else if (hh != h || ss != s)
+				bad = 1;
+		}
+	}
+
+	if (!first && !bad) {
+		*ph = hh;
+		*ps = ss;
+	}
+
+	DBG(LABEL, ul_debug("DOS PT geometry: heads=%u, sectors=%u", *ph, *ps));
+}
+
+static int dos_reset_alignment(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, DOS));
+
+	/* overwrite necessary stuff by DOS deprecated stuff */
+	if (is_dos_compatible(cxt)) {
+		DBG(LABEL, ul_debug("DOS: reseting alignemnt for DOS-comaptiblem PT"));
+		if (cxt->geom.sectors)
+			cxt->first_lba = cxt->geom.sectors;	/* usually 63 */
+
+		cxt->grain = cxt->sector_size;			/* usually 512 */
+	}
+
+	return 0;
+}
+
+/* TODO: move to include/pt-dos.h and share with libblkid */
+#define AIX_MAGIC_STRING	"\xC9\xC2\xD4\xC1"
+#define AIX_MAGIC_STRLEN	(sizeof(AIX_MAGIC_STRING) - 1)
+
+static int dos_probe_label(struct fdisk_context *cxt)
+{
+	size_t i;
+	unsigned int h = 0, s = 0;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, DOS));
+
+	/* ignore disks with AIX magic number */
+	if (memcmp(cxt->firstsector, AIX_MAGIC_STRING, AIX_MAGIC_STRLEN) == 0)
+		return 0;
+
+	if (!mbr_is_valid_magic(cxt->firstsector))
+		return 0;
+
+	dos_init(cxt);
+
+	get_partition_table_geometry(cxt, &h, &s);
+	if (h && s) {
+		cxt->geom.heads = h;
+	        cxt->geom.sectors = s;
+	}
+
+	for (i = 0; i < 4; i++) {
+		struct pte *pe = self_pte(cxt, i);
+
+		if (is_used_partition(pe->pt_entry))
+			cxt->label->nparts_cur++;
+
+		if (IS_EXTENDED (pe->pt_entry->sys_ind)) {
+			if (cxt->label->nparts_max != 4)
+				fdisk_warnx(cxt, _(
+				"Ignoring extra extended partition %zu"),
+					i + 1);
+			else
+				read_extended(cxt, i);
+		}
+	}
+
+	for (i = 3; i < cxt->label->nparts_max; i++) {
+		struct pte *pe = self_pte(cxt, i);
+		struct fdisk_dos_label *l = self_label(cxt);
+
+		if (!mbr_is_valid_magic(pe->sectorbuffer)) {
+			fdisk_info(cxt, _(
+			"Invalid flag 0x%02x%02x of EBR (for partition %zu) will "
+			"be corrected by w(rite)."),
+				pe->sectorbuffer[510],
+				pe->sectorbuffer[511],
+				i + 1);
+			partition_set_changed(cxt, i, 1);
+
+			/* mark also extended as changed to update the first EBR
+			 * in situation that there is no logical partitions at all */
+			partition_set_changed(cxt, l->ext_index, 1);
+		}
+	}
+
+	return 1;
+}
+
+static void set_partition(struct fdisk_context *cxt,
+			  int i, int doext, fdisk_sector_t start,
+			  fdisk_sector_t stop, int sysid, int boot)
+{
+	struct pte *pe = self_pte(cxt, i);
+	struct dos_partition *p;
+	fdisk_sector_t offset;
+
+	assert(!FDISK_IS_UNDEF(start));
+	assert(!FDISK_IS_UNDEF(stop));
+
+	if (doext) {
+		struct fdisk_dos_label *l = self_label(cxt);
+		p = pe->ex_entry;
+		offset = l->ext_offset;
+	} else {
+		p = pe->pt_entry;
+		offset = pe->offset;
+	}
+
+	DBG(LABEL, ul_debug("DOS: setting partition %d%s, offset=%zu, start=%zu, stop=%zu, sysid=%02x",
+				i, doext ? " [extended]" : "",
+				(size_t) offset,
+				(size_t) (start -  offset),
+				(size_t) (stop - start + 1),
+				sysid));
+
+	p->boot_ind = boot ? ACTIVE_FLAG : 0;
+	p->sys_ind = sysid;
+	dos_partition_set_start(p, start - offset);
+	dos_partition_set_size(p, stop - start + 1);
+
+	if (is_dos_compatible(cxt) && (start/(cxt->geom.sectors*cxt->geom.heads) > 1023))
+		start = cxt->geom.heads*cxt->geom.sectors*1024 - 1;
+	set_hsc(p->bh, p->bs, p->bc, start);
+	if (is_dos_compatible(cxt) && (stop/(cxt->geom.sectors*cxt->geom.heads) > 1023))
+		stop = cxt->geom.heads*cxt->geom.sectors*1024 - 1;
+	set_hsc(p->eh, p->es, p->ec, stop);
+	partition_set_changed(cxt, i, 1);
+}
+
+static fdisk_sector_t get_unused_start(struct fdisk_context *cxt,
+				 int part_n, fdisk_sector_t start,
+				 fdisk_sector_t first[], fdisk_sector_t last[])
+{
+	size_t i;
+
+	for (i = 0; i < cxt->label->nparts_max; i++) {
+		fdisk_sector_t lastplusoff;
+		struct pte *pe = self_pte(cxt, i);
+
+		if (start == pe->offset)
+			start += cxt->first_lba;
+		lastplusoff = last[i] + ((part_n < 4) ? 0 : cxt->first_lba);
+		if (start >= first[i] && start <= lastplusoff)
+			start = lastplusoff + 1;
+	}
+
+	return start;
+}
+
+static void fill_bounds(struct fdisk_context *cxt,
+			fdisk_sector_t *first, fdisk_sector_t *last)
+{
+	size_t i;
+	struct pte *pe = self_pte(cxt, 0);
+	struct dos_partition *p;
+
+	for (i = 0; i < cxt->label->nparts_max; pe++,i++) {
+		p = pe->pt_entry;
+		if (is_cleared_partition(p) || IS_EXTENDED (p->sys_ind)) {
+			first[i] = 0xffffffff;
+			last[i] = 0;
+		} else {
+			first[i] = get_abs_partition_start(pe);
+			last[i]  = get_abs_partition_end(pe);
+		}
+	}
+}
+
+static int get_start_from_user(	struct fdisk_context *cxt,
+				fdisk_sector_t *start,
+				fdisk_sector_t low,
+				fdisk_sector_t dflt,
+				fdisk_sector_t limit,
+				struct fdisk_partition *pa)
+{
+	assert(start);
+
+	/* try to use tepmlate from 'pa' */
+	if (pa && pa->start_follow_default)
+		*start = dflt;
+
+	else if (pa && fdisk_partition_has_start(pa)) {
+		DBG(LABEL, ul_debug("DOS: start: wanted=%ju, low=%ju, limit=%ju",
+				(uintmax_t) pa->start, (uintmax_t) low, (uintmax_t) limit));
+		*start = pa->start;
+		if (*start < low || *start > limit) {
+			fdisk_warnx(cxt, _("Start sector %ju out of range."),
+					(uintmax_t) *start);
+			return -ERANGE;
+		}
+	} else {
+		/* ask user by dialog */
+		struct fdisk_ask *ask = fdisk_new_ask();
+		int rc;
+
+		if (!ask)
+			return -ENOMEM;
+		fdisk_ask_set_query(ask,
+			fdisk_use_cylinders(cxt) ?
+				_("First cylinder") : _("First sector"));
+		fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER);
+		fdisk_ask_number_set_low(ask, fdisk_cround(cxt, low));
+		fdisk_ask_number_set_default(ask, fdisk_cround(cxt, dflt));
+		fdisk_ask_number_set_high(ask, fdisk_cround(cxt, limit));
+
+		rc = fdisk_do_ask(cxt, ask);
+		*start = fdisk_ask_number_get_result(ask);
+		fdisk_unref_ask(ask);
+		if (rc)
+			return rc;
+		if (fdisk_use_cylinders(cxt)) {
+		        *start = (*start - 1)
+				* fdisk_get_units_per_sector(cxt);
+			if (*start < low)
+				*start = low;
+		}
+	}
+
+	DBG(LABEL, ul_debug("DOS: start is %ju", (uintmax_t) *start));
+	return 0;
+}
+
+static fdisk_sector_t get_possible_last(struct fdisk_context *cxt, size_t n)
+{
+	fdisk_sector_t limit;
+
+	if (n >= 4) {
+		/* logical partitions */
+		struct fdisk_dos_label *l = self_label(cxt);
+		struct pte *ext_pe = l->ext_offset ? self_pte(cxt, l->ext_index) : NULL;
+
+		if (!ext_pe)
+			return 0;
+		limit = get_abs_partition_end(ext_pe);
+	} else {
+		/* primary partitions */
+		if (fdisk_use_cylinders(cxt) || !cxt->total_sectors)
+			limit = cxt->geom.heads * cxt->geom.sectors * cxt->geom.cylinders - 1;
+		else
+			limit = cxt->total_sectors - 1;
+
+		if (limit > UINT_MAX)
+			limit = UINT_MAX;
+	}
+
+	DBG(LABEL, ul_debug("DOS: last possible sector for #%zu is %ju",
+				n, (uintmax_t) limit));
+	return limit;
+}
+
+/* returns last free sector for area addressed by @start, the first[] and
+ * last[] are fill_bounds() results */
+static fdisk_sector_t get_unused_last(struct fdisk_context *cxt, size_t n,
+				fdisk_sector_t start,
+				fdisk_sector_t first[], fdisk_sector_t last[])
+{
+	size_t i;
+	fdisk_sector_t limit = get_possible_last(cxt, n);
+
+	for (i = 0; i < cxt->label->nparts_max; i++) {
+		struct pte *pe = self_pte(cxt, i);
+
+		if (start < pe->offset && limit >= pe->offset)
+			limit = pe->offset - 1;
+		if (start < first[i] && limit >= first[i])
+			limit = first[i] - 1;
+	}
+
+	DBG(LABEL, ul_debug("DOS: unused sector for #%zu is %ju",
+				n, (uintmax_t) limit));
+	return limit;
+}
+
+static int add_partition(struct fdisk_context *cxt, size_t n,
+			 struct fdisk_partition *pa)
+{
+	int sys, read = 0, rc, isrel = 0;
+	size_t i;
+	struct fdisk_dos_label *l = self_label(cxt);
+	struct dos_partition *p = self_partition(cxt, n);
+	struct pte *ext_pe = l->ext_offset ? self_pte(cxt, l->ext_index) : NULL;
+
+	fdisk_sector_t start, stop = 0, limit, temp,
+		first[cxt->label->nparts_max],
+		last[cxt->label->nparts_max];
+
+	DBG(LABEL, ul_debug("DOS: adding partition %zu", n));
+
+	sys = pa && pa->type ? pa->type->code : MBR_LINUX_DATA_PARTITION;
+
+	if (is_used_partition(p)) {
+		fdisk_warnx(cxt, _("Partition %zu is already defined.  "
+			           "Delete it before re-adding it."),
+				n + 1);
+		return -EINVAL;
+	}
+	fill_bounds(cxt, first, last);
+	limit = get_possible_last(cxt, n);
+
+	if (n < 4) {
+		if (cxt->parent && fdisk_is_label(cxt->parent, GPT))
+			start = 1;		/* Bad boy modifies hybrid MBR */
+		else {
+			if (cxt->script && pa && fdisk_partition_has_start(pa)
+			    && pa->start < cxt->first_lba
+			    && pa->start >= 1)
+				fdisk_set_first_lba(cxt, 1);
+
+			start = cxt->first_lba;
+		}
+
+		if (l->ext_offset) {
+			assert(ext_pe);
+			first[l->ext_index] = l->ext_offset;
+			last[l->ext_index] = get_abs_partition_end(ext_pe);
+		}
+	} else {
+		assert(ext_pe);
+
+		if (cxt->script && pa && fdisk_partition_has_start(pa)
+		    && pa->start >= l->ext_offset
+		    && pa->start < l->ext_offset + cxt->first_lba)
+			fdisk_set_first_lba(cxt, 1);
+
+		start = l->ext_offset + cxt->first_lba;
+	}
+
+	if (fdisk_use_cylinders(cxt))
+		for (i = 0; i < cxt->label->nparts_max; i++) {
+			first[i] = (fdisk_cround(cxt, first[i]) - 1)
+				* fdisk_get_units_per_sector(cxt);
+		}
+
+	/*
+	 * Ask for first sector
+	 */
+	do {
+		fdisk_sector_t dflt, aligned;
+
+		temp = start;
+		dflt = start = get_unused_start(cxt, n, start, first, last);
+
+		if (n >= 4 && pa && fdisk_partition_has_start(pa) && cxt->script
+		    && cxt->first_lba > 1
+		    && temp == start - cxt->first_lba) {
+			fdisk_set_first_lba(cxt, 1);
+			start = pa->start;
+		}
+
+		/* the default sector should be aligned and unused */
+		do {
+			aligned = fdisk_align_lba_in_range(cxt, dflt, dflt, limit);
+			dflt = get_unused_start(cxt, n, aligned, first, last);
+		} while (dflt != aligned && dflt > aligned && dflt < limit);
+
+		if (dflt >= limit)
+			dflt = start;
+		if (start > limit)
+			break;
+		if (start >= temp + fdisk_get_units_per_sector(cxt)
+		    && read) {
+			fdisk_info(cxt, _("Sector %llu is already allocated."),
+					temp);
+			temp = start;
+			read = 0;
+			if (pa && (fdisk_partition_has_start(pa) ||
+				   pa->start_follow_default))
+				break;
+		}
+
+		if (!read && start == temp) {
+			rc = get_start_from_user(cxt, &start, temp, dflt, limit, pa);
+			if (rc)
+				return rc;
+			read = 1;
+		}
+	} while (start != temp || !read);
+
+	if (n == 4) {
+		/* The first EBR is stored at begin of the extended partition */
+		struct pte *pe = self_pte(cxt, n);
+		pe->offset = l->ext_offset;
+
+	} else if (n > 4) {
+		/* The second (and another) EBR */
+		struct pte *pe = self_pte(cxt, n);
+
+		pe->offset = start - cxt->first_lba;
+		if (pe->offset == l->ext_offset) { /* must be corrected */
+			pe->offset++;
+			if (cxt->first_lba == 1)
+				start++;
+		}
+	}
+
+	limit = get_unused_last(cxt, n, start, first, last);
+
+	if (start > limit) {
+		fdisk_info(cxt, _("No free sectors available."));
+		if (n > 4)
+			cxt->label->nparts_max--;
+		return -ENOSPC;
+	}
+
+	/*
+	 * Ask for last sector
+	 */
+	if (fdisk_cround(cxt, start) == fdisk_cround(cxt, limit))
+		stop = limit;
+	else if (pa && pa->end_follow_default)
+		stop = limit;
+	else if (pa && fdisk_partition_has_size(pa)) {
+		stop = start + pa->size - 1;
+		isrel = pa->size_explicit ? 0 : 1;
+	} else {
+		/* ask user by dialog */
+		struct fdisk_ask *ask = fdisk_new_ask();
+
+		if (!ask)
+			return -ENOMEM;
+		fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET);
+
+		if (fdisk_use_cylinders(cxt)) {
+			fdisk_ask_set_query(ask, _("Last cylinder, +cylinders or +size{K,M,G,T,P}"));
+			fdisk_ask_number_set_unit(ask,
+				     cxt->sector_size *
+				     fdisk_get_units_per_sector(cxt));
+		} else {
+			fdisk_ask_set_query(ask, _("Last sector, +sectors or +size{K,M,G,T,P}"));
+			fdisk_ask_number_set_unit(ask,cxt->sector_size);
+		}
+
+		fdisk_ask_number_set_low(ask, fdisk_cround(cxt, start));
+		fdisk_ask_number_set_default(ask, fdisk_cround(cxt, limit));
+		fdisk_ask_number_set_high(ask, fdisk_cround(cxt, limit));
+		fdisk_ask_number_set_base(ask, fdisk_cround(cxt, start));	/* base for relative input */
+
+		rc = fdisk_do_ask(cxt, ask);
+		stop = fdisk_ask_number_get_result(ask);
+		isrel = fdisk_ask_number_is_relative(ask);
+		fdisk_unref_ask(ask);
+		if (rc)
+			return rc;
+		if (fdisk_use_cylinders(cxt)) {
+			stop = stop * fdisk_get_units_per_sector(cxt) - 1;
+			if (stop >limit)
+				stop = limit;
+		}
+	}
+
+	DBG(LABEL, ul_debug("DOS: raw stop: %ju", (uintmax_t) stop));
+
+	if (stop > limit)
+		stop = limit;
+
+	if (stop < limit) {
+		if (isrel && alignment_required(cxt)) {
+			/* the last sector has not been exactly requested (but
+			 * defined by +size{K,M,G} convention), so be smart and
+			 * align the end of the partition. The next partition
+			 * will start at phy.block boundary.
+			 */
+			stop = fdisk_align_lba_in_range(cxt, stop, start, limit) - 1;
+			if (stop > limit)
+				stop = limit;
+		}
+	}
+
+	set_partition(cxt, n, 0, start, stop, sys, pa && pa->boot == 1 ? 1 : 0);
+	if (n > 4) {
+		struct pte *pe = self_pte(cxt, n);
+		set_partition(cxt, n - 1, 1, pe->offset, stop,
+					MBR_DOS_EXTENDED_PARTITION, 0);
+	}
+
+	/* report */
+	{
+		struct fdisk_parttype *t =
+			fdisk_label_get_parttype_from_code(cxt->label, sys);
+		fdisk_info_new_partition(cxt, n + 1, start, stop, t);
+		fdisk_unref_parttype(t);
+	}
+
+
+	if (IS_EXTENDED(sys)) {
+		struct pte *pen = self_pte(cxt, n);
+
+		l->ext_index = n;
+		l->ext_offset = start;
+		pen->ex_entry = p;
+	}
+
+	fdisk_label_set_changed(cxt->label, 1);
+	return 0;
+}
+
+static int add_logical(struct fdisk_context *cxt,
+		       struct fdisk_partition *pa,
+		       size_t *partno)
+{
+	struct pte *pe;
+	int rc;
+
+	assert(cxt);
+	assert(partno);
+	assert(cxt->label);
+	assert(self_label(cxt)->ext_offset);
+
+	DBG(LABEL, ul_debug("DOS: nparts max: %zu", cxt->label->nparts_max));
+	pe = self_pte(cxt, cxt->label->nparts_max);
+
+	if (!pe->sectorbuffer) {
+		pe->sectorbuffer = calloc(1, cxt->sector_size);
+		if (!pe->sectorbuffer)
+			return -ENOMEM;
+		DBG(LABEL, ul_debug("DOS: logical: %zu: new EBR sector buffer %p",
+					cxt->label->nparts_max, pe->sectorbuffer));
+		pe->private_sectorbuffer = 1;
+	}
+	pe->pt_entry = mbr_get_partition(pe->sectorbuffer, 0);
+	pe->ex_entry = pe->pt_entry + 1;
+	pe->offset = 0;
+	partition_set_changed(cxt, cxt->label->nparts_max, 1);
+
+	cxt->label->nparts_max++;
+
+	/* this message makes sense only when we use extended/primary/logical
+	 * dialog. The dialog is disable for scripts, see dos_add_partition() */
+	if (!cxt->script)
+		fdisk_info(cxt, _("Adding logical partition %zu"),
+				cxt->label->nparts_max);
+	*partno = cxt->label->nparts_max - 1;
+	rc = add_partition(cxt, *partno, pa);
+
+	if (rc) {
+		/* reset on error */
+		cxt->label->nparts_max--;
+		pe->pt_entry = NULL;
+		pe->ex_entry = NULL;
+		pe->offset = 0;
+		pe->changed = 0;
+	}
+
+	return rc;
+}
+
+static void check(struct fdisk_context *cxt, size_t n,
+	   unsigned int h, unsigned int s, unsigned int c,
+	   unsigned int start)
+{
+	unsigned int total, real_s, real_c;
+
+	if (!is_dos_compatible(cxt))
+		return;
+
+	real_s = sector(s) - 1;
+	real_c = cylinder(s, c);
+	total = (real_c * cxt->geom.heads + h) * cxt->geom.sectors + real_s;
+
+	if (!total)
+		fdisk_warnx(cxt, _("Partition %zu: contains sector 0"), n);
+	if (h >= cxt->geom.heads)
+		fdisk_warnx(cxt, _("Partition %zu: head %d greater than "
+				   "maximum %d"), n, h + 1, cxt->geom.heads);
+	if (real_s >= cxt->geom.sectors)
+		fdisk_warnx(cxt, _("Partition %zu: sector %d greater than "
+				   "maximum %llu"), n, s, cxt->geom.sectors);
+	if (real_c >= cxt->geom.cylinders)
+		fdisk_warnx(cxt, _("Partition %zu: cylinder %d greater than "
+				   "maximum %llu"),
+				n, real_c + 1,
+				cxt->geom.cylinders);
+
+	if (cxt->geom.cylinders <= 1024 && start != total)
+		fdisk_warnx(cxt, _("Partition %zu: previous sectors %u "
+				   "disagrees with total %u"), n, start, total);
+}
+
+/* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
+ * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
+ * Jan.  1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
+ * Lubkin Oct.  1991). */
+
+static void
+long2chs(struct fdisk_context *cxt, unsigned long ls,
+	 unsigned int *c, unsigned int *h, unsigned int *s) {
+	int spc = cxt->geom.heads * cxt->geom.sectors;
+
+	*c = ls / spc;
+	ls = ls % spc;
+	*h = ls / cxt->geom.sectors;
+	*s = ls % cxt->geom.sectors + 1;	/* sectors count from 1 */
+}
+
+static void check_consistency(struct fdisk_context *cxt, struct dos_partition *p,
+			      size_t partition)
+{
+	unsigned int pbc, pbh, pbs;	/* physical beginning c, h, s */
+	unsigned int pec, peh, pes;	/* physical ending c, h, s */
+	unsigned int lbc, lbh, lbs;	/* logical beginning c, h, s */
+	unsigned int lec, leh, les;	/* logical ending c, h, s */
+
+	if (!is_dos_compatible(cxt))
+		return;
+
+	if (!cxt->geom.heads || !cxt->geom.sectors || (partition >= 4))
+		return;		/* do not check extended partitions */
+
+	/* physical beginning c, h, s */
+	pbc = (p->bc & 0xff) | ((p->bs << 2) & 0x300);
+	pbh = p->bh;
+	pbs = p->bs & 0x3f;
+
+	/* physical ending c, h, s */
+	pec = (p->ec & 0xff) | ((p->es << 2) & 0x300);
+	peh = p->eh;
+	pes = p->es & 0x3f;
+
+	/* compute logical beginning (c, h, s) */
+	long2chs(cxt, dos_partition_get_start(p), &lbc, &lbh, &lbs);
+
+	/* compute logical ending (c, h, s) */
+	long2chs(cxt, dos_partition_get_start(p) + dos_partition_get_size(p) - 1, &lec, &leh, &les);
+
+	/* Same physical / logical beginning? */
+	if (cxt->geom.cylinders <= 1024
+	    && (pbc != lbc || pbh != lbh || pbs != lbs)) {
+		fdisk_warnx(cxt, _("Partition %zu: different physical/logical "
+			"beginnings (non-Linux?): "
+			"phys=(%d, %d, %d), logical=(%d, %d, %d)"),
+			partition + 1,
+			pbc, pbh, pbs,
+			lbc, lbh, lbs);
+	}
+
+	/* Same physical / logical ending? */
+	if (cxt->geom.cylinders <= 1024
+	    && (pec != lec || peh != leh || pes != les)) {
+		fdisk_warnx(cxt, _("Partition %zu: different physical/logical "
+			"endings: phys=(%d, %d, %d), logical=(%d, %d, %d)"),
+			partition + 1,
+			pec, peh, pes,
+			lec, leh, les);
+	}
+
+	/* Ending on cylinder boundary? */
+	if (peh != (cxt->geom.heads - 1) || pes != cxt->geom.sectors) {
+		fdisk_warnx(cxt, _("Partition %zu: does not end on "
+				   "cylinder boundary."),
+			partition + 1);
+	}
+}
+
+static int dos_verify_disklabel(struct fdisk_context *cxt)
+{
+	size_t i, j;
+	fdisk_sector_t total = 1, n_sectors = cxt->total_sectors;
+	fdisk_sector_t first[cxt->label->nparts_max],
+		       last[cxt->label->nparts_max];
+	struct dos_partition *p;
+	struct fdisk_dos_label *l = self_label(cxt);
+
+	assert(fdisk_is_label(cxt, DOS));
+
+	fill_bounds(cxt, first, last);
+	for (i = 0; i < cxt->label->nparts_max; i++) {
+		struct pte *pe = self_pte(cxt, i);
+
+		p = self_partition(cxt, i);
+		if (is_used_partition(p) && !IS_EXTENDED(p->sys_ind)) {
+			check_consistency(cxt, p, i);
+			if (get_abs_partition_start(pe) < first[i])
+				fdisk_warnx(cxt, _(
+					"Partition %zu: bad start-of-data."),
+					 i + 1);
+
+			check(cxt, i + 1, p->eh, p->es, p->ec, last[i]);
+			total += last[i] + 1 - first[i];
+
+			if (i == 0)
+				total += get_abs_partition_start(pe) - 1;
+
+			for (j = 0; j < i; j++) {
+				if ((first[i] >= first[j] && first[i] <= last[j])
+				    || ((last[i] <= last[j] && last[i] >= first[j]))) {
+
+					fdisk_warnx(cxt, _("Partition %zu: "
+						"overlaps partition %zu."),
+						j + 1, i + 1);
+
+					total += first[i] >= first[j] ?
+						first[i] : first[j];
+					total -= last[i] <= last[j] ?
+						last[i] : last[j];
+				}
+			}
+		}
+	}
+
+	if (l->ext_offset) {
+		fdisk_sector_t e_last;
+		struct pte *ext_pe = self_pte(cxt, l->ext_index);
+
+		e_last = get_abs_partition_end(ext_pe);
+
+		for (i = 4; i < cxt->label->nparts_max; i++) {
+			total++;
+			p = self_partition(cxt, i);
+
+			if (!p->sys_ind) {
+				if (i != 4 || i + 1 < cxt->label->nparts_max)
+					fdisk_warnx(cxt,
+						_("Partition %zu: empty."),
+						i + 1);
+			} else if (first[i] < l->ext_offset
+				   || last[i] > e_last) {
+
+				fdisk_warnx(cxt, _("Logical partition %zu: "
+					"not entirely in partition %zu."),
+					i + 1, l->ext_index + 1);
+			}
+		}
+	}
+
+	if (total > n_sectors)
+		fdisk_warnx(cxt, _("Total allocated sectors %llu greater "
+			"than the maximum %llu."), total, n_sectors);
+	else if (total < n_sectors)
+		fdisk_warnx(cxt, _("Remaining %lld unallocated %ld-byte "
+			"sectors."), n_sectors - total, cxt->sector_size);
+
+	return 0;
+}
+
+/*
+ * Ask the user for new partition type information (logical, extended).
+ * This function calls the actual partition adding logic - add_partition.
+ *
+ * API callback.
+ */
+static int dos_add_partition(struct fdisk_context *cxt,
+			     struct fdisk_partition *pa,
+			     size_t *partno)
+{
+	size_t i, free_primary = 0, free_sectors = 0;
+	fdisk_sector_t last = 0, grain;
+	int rc = 0;
+	struct fdisk_dos_label *l;
+	struct pte *ext_pe;
+	size_t res;		/* partno */
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, DOS));
+
+	DBG(LABEL, ul_debug("DOS: new partition wanted"));
+
+	l = self_label(cxt);
+	ext_pe = l->ext_offset ? self_pte(cxt, l->ext_index) : NULL;
+
+	/*
+	 * partition template (@pa) based partitioning
+	 */
+
+	/* pa specifies start within extended partition, add logical */
+	if (pa && fdisk_partition_has_start(pa) && ext_pe
+	    && pa->start >= l->ext_offset
+	    && pa->start <= get_abs_partition_end(ext_pe)) {
+		DBG(LABEL, ul_debug("DOS: pa template %p: add logical", pa));
+		rc = add_logical(cxt, pa, &res);
+		goto done;
+
+	/* pa specifies that extended partition is wanted */
+	} else if (pa && pa->type && pa->type->code == MBR_DOS_EXTENDED_PARTITION) {
+		DBG(LABEL, ul_debug("DOS: pa template %p: add extened", pa));
+		if (l->ext_offset) {
+			fdisk_warnx(cxt, _("Extended partition already exists."));
+			return -EINVAL;
+		}
+		rc = get_partition_unused_primary(cxt, pa, &res);
+		if (rc == 0) {
+			rc = add_partition(cxt, res, pa);
+			goto done;
+		}
+
+	/* pa specifies start, but outside extended partition */
+	} else if (pa && fdisk_partition_has_start(pa) && l->ext_offset) {
+		DBG(LABEL, ul_debug("DOS: pa template %p: add primary", pa));
+		rc = get_partition_unused_primary(cxt, pa, &res);
+		if (rc == 0) {
+			rc = add_partition(cxt, res, pa);
+			goto done;
+		}
+	}
+
+	/*
+	 * dialog driven partitioning (it does not mean that @pa template is
+	 * completely ignored!)
+	 */
+
+	/* check if there is space for primary partition */
+	grain = cxt->grain > cxt->sector_size ? cxt->grain / cxt->sector_size : 1;
+	last = cxt->first_lba;
+
+	for (i = 0; i < 4; i++) {
+		struct dos_partition *p = self_partition(cxt, i);
+
+		if (is_used_partition(p)) {
+			fdisk_sector_t start = dos_partition_get_start(p);
+			if (last + grain <= start)
+				free_sectors = 1;
+			last = start + dos_partition_get_size(p);
+		} else
+			free_primary++;
+	}
+	if (last + grain < cxt->total_sectors - 1)
+		free_sectors = 1;
+
+	if (!free_primary && cxt->label->nparts_max >= MAXIMUM_PARTS) {
+		fdisk_info(cxt, _("The maximum number of partitions has "
+				  "been created."));
+		return -EINVAL;
+	}
+	rc = 1;
+
+	if (!free_primary || !free_sectors) {
+		DBG(LABEL, ul_debug("DOS: primary impossible, add logical"));
+		if (l->ext_offset) {
+			if (!pa || fdisk_partition_has_start(pa)) {
+				if (!free_primary)
+					fdisk_info(cxt, _("All primary partitions are in use."));
+				else if (!free_sectors)
+					fdisk_info(cxt, _("All space for primary partitions is in use."));
+			}
+			rc = add_logical(cxt, pa, &res);
+		} else {
+			fdisk_info(cxt,
+			     _(	"Impossible to create another primary partition. "
+				"If you want to create more partitions, you must "
+				"replace a primary partition with an extended "
+				"partition first."));
+			return -EINVAL;
+		}
+	} else if (cxt->label->nparts_max >= MAXIMUM_PARTS) {
+		fdisk_info(cxt, _("All logical partitions are in use. "
+				  "Adding a primary partition."));
+		rc = get_partition_unused_primary(cxt, pa, &res);
+		if (rc == 0)
+			rc = add_partition(cxt, res, pa);
+	} else {
+		char hint[BUFSIZ];
+		struct fdisk_ask *ask;
+		int c;
+
+		/* the default layout for scripts is to create primary partitions */
+		if (cxt->script) {
+			rc = get_partition_unused_primary(cxt, pa, &res);
+			if (rc == 0)
+				rc = add_partition(cxt, res, pa);
+			goto done;
+		}
+
+		ask = fdisk_new_ask();
+		if (!ask)
+			return -ENOMEM;
+		fdisk_ask_set_type(ask, FDISK_ASKTYPE_MENU);
+		fdisk_ask_set_query(ask, _("Partition type"));
+		fdisk_ask_menu_set_default(ask, free_primary == 1
+						&& !l->ext_offset ? 'e' : 'p');
+		snprintf(hint, sizeof(hint),
+				_("%zu primary, %d extended, %zu free"),
+				4 - (l->ext_offset ? 1 : 0) - free_primary,
+				l->ext_offset ? 1 : 0,
+				free_primary);
+
+		fdisk_ask_menu_add_item(ask, 'p', _("primary"), hint);
+		if (!l->ext_offset)
+			fdisk_ask_menu_add_item(ask, 'e', _("extended"), _("container for logical partitions"));
+		else
+			fdisk_ask_menu_add_item(ask, 'l', _("logical"), _("numbered from 5"));
+
+		rc = fdisk_do_ask(cxt, ask);
+		if (rc)
+			return rc;
+		fdisk_ask_menu_get_result(ask, &c);
+		fdisk_unref_ask(ask);
+
+		if (c == 'p') {
+			rc = get_partition_unused_primary(cxt, pa, &res);
+			if (rc == 0)
+				rc = add_partition(cxt, res, pa);
+			goto done;
+		} else if (c == 'l' && l->ext_offset) {
+			rc = add_logical(cxt, pa, &res);
+			goto done;
+		} else if (c == 'e' && !l->ext_offset) {
+			rc = get_partition_unused_primary(cxt, pa, &res);
+			if (rc == 0) {
+				struct fdisk_partition *xpa = NULL;
+				struct fdisk_parttype *t;
+
+				t = fdisk_label_get_parttype_from_code(cxt->label,
+						MBR_DOS_EXTENDED_PARTITION);
+				if (!pa) {
+					pa = xpa = fdisk_new_partition();
+					if (!xpa)
+						return -ENOMEM;
+				}
+				fdisk_partition_set_type(pa, t);
+				rc = add_partition(cxt, res, pa);
+				if (xpa) {
+					fdisk_unref_partition(xpa);
+					pa = NULL;
+				}
+			}
+			goto done;
+		} else
+			fdisk_warnx(cxt, _("Invalid partition type `%c'."), c);
+	}
+done:
+	if (rc == 0) {
+		cxt->label->nparts_cur++;
+		if (partno)
+			*partno = res;
+	}
+	return rc;
+}
+
+static int write_sector(struct fdisk_context *cxt, fdisk_sector_t secno,
+			       unsigned char *buf)
+{
+	int rc;
+
+	rc = seek_sector(cxt, secno);
+	if (rc != 0) {
+		fdisk_warn(cxt, _("Cannot write sector %jd: seek failed"),
+				(uintmax_t) secno);
+		return rc;
+	}
+
+	DBG(LABEL, ul_debug("DOS: writting to sector %ju", (uintmax_t) secno));
+
+	if (write(cxt->dev_fd, buf, cxt->sector_size) != (ssize_t) cxt->sector_size)
+		return -errno;
+	return 0;
+}
+
+static int dos_write_disklabel(struct fdisk_context *cxt)
+{
+	struct fdisk_dos_label *l = self_label(cxt);
+	size_t i;
+	int rc = 0, mbr_changed = 0;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, DOS));
+
+	mbr_changed = l->non_pt_changed;
+
+	/* MBR (primary partitions) */
+	if (!mbr_changed) {
+		for (i = 0; i < 4; i++) {
+			struct pte *pe = self_pte(cxt, i);
+			if (pe->changed)
+				mbr_changed = 1;
+		}
+	}
+	if (mbr_changed) {
+		mbr_set_magic(cxt->firstsector);
+		rc = write_sector(cxt, 0, cxt->firstsector);
+		if (rc)
+			goto done;
+	}
+
+	if (cxt->label->nparts_max <= 4 && l->ext_offset) {
+		/* we have empty extended partition, check if the partition has
+		 * been modified and then cleanup possible remaining EBR  */
+		struct pte *pe = self_pte(cxt, l->ext_index);
+		unsigned char empty[512] = { 0 };
+		fdisk_sector_t off = pe ? get_abs_partition_start(pe) : 0;
+
+		if (off && pe->changed) {
+			mbr_set_magic(empty);
+			write_sector(cxt, off, empty);
+		}
+	}
+
+	/* EBR (logical partitions) */
+	for (i = 4; i < cxt->label->nparts_max; i++) {
+		struct pte *pe = self_pte(cxt, i);
+
+		if (!pe->changed || !pe->offset || !pe->sectorbuffer)
+			continue;
+
+		mbr_set_magic(pe->sectorbuffer);
+		rc = write_sector(cxt, pe->offset, pe->sectorbuffer);
+		if (rc)
+			goto done;
+	}
+
+done:
+	return rc;
+}
+
+static int dos_locate_disklabel(struct fdisk_context *cxt, int n,
+		const char **name, off_t *offset, size_t *size)
+{
+	assert(cxt);
+
+	*name = NULL;
+	*offset = 0;
+	*size = 0;
+
+	switch (n) {
+	case 0:
+		*name = "MBR";
+		*offset = 0;
+		*size = 512;
+		break;
+	default:
+		/* extended partitions */
+		if (n - 1 + 4 < cxt->label->nparts_max) {
+			struct pte *pe = self_pte(cxt, n - 1 + 4);
+
+			assert(pe->private_sectorbuffer);
+
+			*name = "EBR";
+			*offset = pe->offset * cxt->sector_size;
+			*size = 512;
+		} else
+			return 1;
+		break;
+	}
+
+	return 0;
+}
+
+/*
+ * Check whether partition entries are ordered by their starting positions.
+ * Return 0 if OK. Return i if partition i should have been earlier.
+ * Two separate checks: primary and logical partitions.
+ */
+static int wrong_p_order(struct fdisk_context *cxt, size_t *prev)
+{
+	size_t last_p_start_pos = 0, p_start_pos;
+	size_t i, last_i = 0;
+
+	for (i = 0 ; i < cxt->label->nparts_max; i++) {
+
+		struct pte *pe = self_pte(cxt, i);
+		struct dos_partition *p = pe->pt_entry;
+
+		if (i == 4) {
+			last_i = 4;
+			last_p_start_pos = 0;
+		}
+		if (is_used_partition(p)) {
+			p_start_pos = get_abs_partition_start(pe);
+
+			if (last_p_start_pos > p_start_pos) {
+				if (prev)
+					*prev = last_i;
+				return i;
+			}
+
+			last_p_start_pos = p_start_pos;
+			last_i = i;
+		}
+	}
+	return 0;
+}
+
+static int dos_list_disklabel(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, DOS));
+
+	return 0;
+}
+
+static int dos_get_partition(struct fdisk_context *cxt, size_t n,
+			     struct fdisk_partition *pa)
+{
+	struct dos_partition *p;
+	struct pte *pe;
+	struct fdisk_dos_label *lb;
+
+	assert(cxt);
+	assert(pa);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, DOS));
+
+	lb = self_label(cxt);
+	pe = self_pte(cxt, n);
+	p = pe->pt_entry;
+	pa->used = !is_cleared_partition(p);
+	if (!pa->used)
+		return 0;
+
+	pa->type = dos_partition_parttype(cxt, p);
+	pa->boot = p->boot_ind == ACTIVE_FLAG ? 1 : 0;
+	pa->start = get_abs_partition_start(pe);
+	pa->size = dos_partition_get_size(p);
+	pa->container = lb->ext_offset && n == lb->ext_index;
+
+	if (n >= 4)
+		pa->parent_partno = lb->ext_index;
+
+	if (p->boot_ind && asprintf(&pa->attrs, "%02x", p->boot_ind) < 0)
+		return -ENOMEM;
+
+	/* start C/H/S */
+	if (asprintf(&pa->start_chs, "%d/%d/%d",
+				cylinder(p->bs, p->bc),
+				sector(p->bs),
+				p->bh) < 0)
+		return -ENOMEM;
+
+	/* end C/H/S */
+	if (asprintf(&pa->end_chs, "%d/%d/%d",
+				cylinder(p->es, p->ec),
+				sector(p->es),
+				p->eh) < 0)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int dos_set_partition(struct fdisk_context *cxt, size_t n,
+			     struct fdisk_partition *pa)
+{
+	struct fdisk_dos_label *l;
+	struct dos_partition *p;
+	struct pte *pe;
+	fdisk_sector_t start, size;
+
+	assert(cxt);
+	assert(pa);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, DOS));
+
+	if (n >= cxt->label->nparts_max)
+		return -EINVAL;
+
+	if (pa->type && IS_EXTENDED(pa->type->code)) {
+		fdisk_warnx(cxt, _("You cannot change a partition into an "
+			"extended one or vice versa. Delete it first."));
+		return -EINVAL;
+	}
+
+	if (pa->type && !pa->type->code)
+		fdisk_warnx(cxt, _("Type 0 means free space to many systems. "
+				   "Having partitions of type 0 is probably unwise."));
+	l = self_label(cxt);
+	p = self_partition(cxt, n);
+	pe = self_pte(cxt, n);
+
+	FDISK_INIT_UNDEF(start);
+	FDISK_INIT_UNDEF(size);
+
+	if (fdisk_partition_has_start(pa))
+		start = pa->start;
+	if (fdisk_partition_has_size(pa))
+		size = pa->size;
+
+	if (pa->end_follow_default) {
+		fdisk_sector_t first[cxt->label->nparts_max],
+			 last[cxt->label->nparts_max],
+			 xlast;
+		struct pte *ext = l->ext_offset ? self_pte(cxt, l->ext_index) : NULL; 
+
+		fill_bounds(cxt, first, last);
+
+		if (ext && l->ext_offset) {
+			first[l->ext_index] = l->ext_offset;
+			last[l->ext_index] = get_abs_partition_end(ext);
+		}
+		if (FDISK_IS_UNDEF(start))
+			start = get_abs_partition_start(pe);
+
+		DBG(LABEL, ul_debug("DOS: #%zu    now %ju +%ju sectors",
+			n, (uintmax_t) start, (uintmax_t) dos_partition_get_size(p)));
+
+		xlast = get_unused_last(cxt, n, start, first, last);
+		size = xlast ? xlast - start + 1: dos_partition_get_size(p);
+
+		DBG(LABEL, ul_debug("DOS: #%zu wanted %ju +%ju sectors",
+			n, (uintmax_t) start, (uintmax_t) size));
+	}
+
+	if (!FDISK_IS_UNDEF(start) || !FDISK_IS_UNDEF(size)) {
+		DBG(LABEL, ul_debug("DOS: resize partition"));
+
+		if (FDISK_IS_UNDEF(start))
+			start = get_abs_partition_start(pe);
+		if (FDISK_IS_UNDEF(size))
+			size = dos_partition_get_size(p);
+
+		set_partition(cxt, n, 0, start, start + size - 1,
+				pa->type  ? pa->type->code : p->sys_ind,
+				pa->boot == 1);
+	} else {
+		DBG(LABEL, ul_debug("DOS: keep size, modify properties"));
+		if (pa->type)
+			p->sys_ind = pa->type->code;
+		if (!FDISK_IS_UNDEF(pa->boot))
+			p->boot_ind = pa->boot == 1 ? ACTIVE_FLAG : 0;
+	}
+
+	partition_set_changed(cxt, n, 1);
+	return 0;
+}
+
+static void print_chain_of_logicals(struct fdisk_context *cxt)
+{
+	size_t i;
+	struct fdisk_dos_label *l = self_label(cxt);
+
+	fputc('\n', stdout);
+
+	for (i = 4; i < cxt->label->nparts_max; i++) {
+		struct pte *pe = self_pte(cxt, i);
+
+		fprintf(stderr, "#%02zu EBR [%10ju], "
+			"data[start=%10ju (%10ju), size=%10ju], "
+			"link[start=%10ju (%10ju), size=%10ju]\n",
+			i, (uintmax_t) pe->offset,
+			/* data */
+			(uintmax_t) dos_partition_get_start(pe->pt_entry),
+			(uintmax_t) get_abs_partition_start(pe),
+			(uintmax_t) dos_partition_get_size(pe->pt_entry),
+			/* link */
+			(uintmax_t) dos_partition_get_start(pe->ex_entry),
+			(uintmax_t) l->ext_offset + dos_partition_get_start(pe->ex_entry),
+			(uintmax_t) dos_partition_get_size(pe->ex_entry));
+	}
+}
+
+static int cmp_ebr_offsets(const void *a, const void *b)
+{
+	struct pte *ae = (struct pte *) a,
+		   *be = (struct pte *) b;
+
+	if (ae->offset == 0 && be->offset == 0)
+		return 0;
+	if (ae->offset == 0)
+		return 1;
+	if (be->offset == 0)
+		return -1;
+
+	return cmp_numbers(ae->offset, be->offset);
+}
+
+/*
+ * Fix the chain of logicals.
+ *
+ * The function does not modify data partitions within EBR tables
+ * (pte->pt_entry). It sorts the chain by EBR offsets and then update links
+ * (pte->ex_entry) between EBR tables.
+ *
+ */
+static void fix_chain_of_logicals(struct fdisk_context *cxt)
+{
+	struct fdisk_dos_label *l = self_label(cxt);
+	struct pte *last;
+	size_t i;
+
+	DBG(LABEL, print_chain_of_logicals(cxt));
+
+	/* Sort chain by EBR offsets */
+	qsort(&l->ptes[4], cxt->label->nparts_max - 4, sizeof(struct pte),
+			cmp_ebr_offsets);
+
+again:
+	/* Sort data partitions by start */
+	for (i = 4; i < cxt->label->nparts_max - 1; i++) {
+		struct pte *cur = self_pte(cxt, i),
+			   *nxt = self_pte(cxt, i + 1);
+
+		if (get_abs_partition_start(cur) >
+		    get_abs_partition_start(nxt)) {
+
+			struct dos_partition tmp = *cur->pt_entry;
+			fdisk_sector_t cur_start = get_abs_partition_start(cur),
+				 nxt_start = get_abs_partition_start(nxt);
+
+			/* swap data partitions */
+			*cur->pt_entry = *nxt->pt_entry;
+			*nxt->pt_entry = tmp;
+
+			/* Recount starts according to EBR offsets, the absolute
+			 * address tas to be still the same! */
+			dos_partition_set_start(cur->pt_entry, nxt_start - cur->offset);
+			dos_partition_set_start(nxt->pt_entry, cur_start - nxt->offset);
+
+			partition_set_changed(cxt, i, 1);
+			partition_set_changed(cxt, i + 1, 1);
+			goto again;
+		}
+	}
+
+	/* Update EBR links */
+	for (i = 4; i < cxt->label->nparts_max - 1; i++) {
+		struct pte *cur = self_pte(cxt, i),
+			   *nxt = self_pte(cxt, i + 1);
+
+		fdisk_sector_t noff = nxt->offset - l->ext_offset,
+			 ooff = dos_partition_get_start(cur->ex_entry);
+
+		if (noff == ooff)
+			continue;
+
+		DBG(LABEL, ul_debug("DOS: fix EBR [%10ju] link %ju -> %ju",
+			(uintmax_t) cur->offset,
+			(uintmax_t) ooff, (uintmax_t) noff));
+
+		set_partition(cxt, i, 1, nxt->offset,
+				get_abs_partition_end(nxt),
+				MBR_DOS_EXTENDED_PARTITION, 0);
+	}
+
+	/* always terminate the chain ! */
+	last = self_pte(cxt, cxt->label->nparts_max - 1);
+	if (last) {
+		clear_partition(last->ex_entry);
+		partition_set_changed(cxt, cxt->label->nparts_max - 1, 1);
+	}
+
+	DBG(LABEL, print_chain_of_logicals(cxt));
+}
+
+static int dos_reorder(struct fdisk_context *cxt)
+{
+	struct pte *pei, *pek;
+	size_t i,k;
+
+	if (!wrong_p_order(cxt, NULL)) {
+		fdisk_info(cxt, _("Nothing to do. Ordering is correct already."));
+		return 0;
+	}
+
+	while ((i = wrong_p_order(cxt, &k)) != 0 && i < 4) {
+		/* partition i should have come earlier, move it */
+		/* We have to move data in the MBR */
+		struct dos_partition *pi, *pk, *pe, pbuf;
+		pei = self_pte(cxt, i);
+		pek = self_pte(cxt, k);
+
+		pe = pei->ex_entry;
+		pei->ex_entry = pek->ex_entry;
+		pek->ex_entry = pe;
+
+		pi = pei->pt_entry;
+		pk = pek->pt_entry;
+
+		memmove(&pbuf, pi, sizeof(struct dos_partition));
+		memmove(pi, pk, sizeof(struct dos_partition));
+		memmove(pk, &pbuf, sizeof(struct dos_partition));
+
+		partition_set_changed(cxt, i, 1);
+		partition_set_changed(cxt, k, 1);
+	}
+
+	if (i)
+		fix_chain_of_logicals(cxt);
+
+	fdisk_info(cxt, _("Done."));
+	return 0;
+}
+
+/* TODO: use fdisk_set_partition() API */
+int fdisk_dos_move_begin(struct fdisk_context *cxt, size_t i)
+{
+	struct pte *pe;
+	struct dos_partition *p;
+	unsigned int new, free_start, curr_start, last;
+	uintmax_t res = 0;
+	size_t x;
+	int rc;
+
+	assert(cxt);
+	assert(fdisk_is_label(cxt, DOS));
+
+	pe = self_pte(cxt, i);
+	p = pe->pt_entry;
+
+	if (!is_used_partition(p) || IS_EXTENDED (p->sys_ind)) {
+		fdisk_warnx(cxt, _("Partition %zu: no data area."), i + 1);
+		return 0;
+	}
+
+	/* the default start is at the second sector of the disk or at the
+	 * second sector of the extended partition
+	 */
+	free_start = pe->offset ? pe->offset + 1 : 1;
+
+	curr_start = get_abs_partition_start(pe);
+
+	/* look for a free space before the current start of the partition */
+	for (x = 0; x < cxt->label->nparts_max; x++) {
+		unsigned int end;
+		struct pte *prev_pe = self_pte(cxt, x);
+		struct dos_partition *prev_p = prev_pe->pt_entry;
+
+		if (!prev_p)
+			continue;
+		end = get_abs_partition_start(prev_pe)
+		      + dos_partition_get_size(prev_p);
+
+		if (is_used_partition(prev_p) &&
+		    end > free_start && end <= curr_start)
+			free_start = end;
+	}
+
+	last = get_abs_partition_end(pe);
+
+	rc = fdisk_ask_number(cxt, free_start, curr_start, last,
+			_("New beginning of data"), &res);
+	if (rc)
+		return rc;
+
+	new = res - pe->offset;
+
+	if (new != dos_partition_get_size(p)) {
+		unsigned int sects = dos_partition_get_size(p)
+				+ dos_partition_get_start(p) - new;
+
+		dos_partition_set_size(p, sects);
+		dos_partition_set_start(p, new);
+
+		partition_set_changed(cxt, i, 1);
+	}
+
+	return rc;
+}
+
+static int dos_partition_is_used(
+		struct fdisk_context *cxt,
+		size_t i)
+{
+	struct dos_partition *p;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, DOS));
+
+	if (i >= cxt->label->nparts_max)
+		return 0;
+
+	p = self_partition(cxt, i);
+
+	return p && !is_cleared_partition(p);
+}
+
+static int dos_toggle_partition_flag(
+		struct fdisk_context *cxt,
+		size_t i,
+		unsigned long flag)
+{
+	struct dos_partition *p;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, DOS));
+
+	if (i >= cxt->label->nparts_max)
+		return -EINVAL;
+
+	p = self_partition(cxt, i);
+
+	switch (flag) {
+	case DOS_FLAG_ACTIVE:
+		if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
+			fdisk_warnx(cxt, _("Partition %zu: is an extended "
+					"partition."), i + 1);
+
+		p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
+		partition_set_changed(cxt, i, 1);
+		fdisk_info(cxt,	p->boot_ind ?
+			_("The bootable flag on partition %zu is enabled now.") :
+			_("The bootable flag on partition %zu is disabled now."),
+			i + 1);
+		break;
+	default:
+		return 1;
+	}
+
+	return 0;
+}
+
+static const struct fdisk_field dos_fields[] =
+{
+	/* basic */
+	{ FDISK_FIELD_DEVICE,	N_("Device"),	 10,	0 },
+	{ FDISK_FIELD_BOOT,	N_("Boot"),	  1,	0 },
+	{ FDISK_FIELD_START,	N_("Start"),	  5,	FDISK_FIELDFL_NUMBER },
+	{ FDISK_FIELD_END,	N_("End"),	  5,	FDISK_FIELDFL_NUMBER },
+	{ FDISK_FIELD_SECTORS,	N_("Sectors"),	  5,	FDISK_FIELDFL_NUMBER },
+	{ FDISK_FIELD_CYLINDERS,N_("Cylinders"),  5,	FDISK_FIELDFL_NUMBER },
+	{ FDISK_FIELD_SIZE,	N_("Size"),	  5,	FDISK_FIELDFL_NUMBER | FDISK_FIELDFL_EYECANDY },
+	{ FDISK_FIELD_TYPEID,	N_("Id"),	  2,	FDISK_FIELDFL_NUMBER },
+	{ FDISK_FIELD_TYPE,	N_("Type"),	0.1,	0 },
+
+	/* expert mode */
+	{ FDISK_FIELD_SADDR,	N_("Start-C/H/S"), 1,   FDISK_FIELDFL_NUMBER | FDISK_FIELDFL_DETAIL },
+	{ FDISK_FIELD_EADDR,	N_("End-C/H/S"),   1,   FDISK_FIELDFL_NUMBER | FDISK_FIELDFL_DETAIL },
+	{ FDISK_FIELD_ATTR,	N_("Attrs"),	   2,   FDISK_FIELDFL_NUMBER | FDISK_FIELDFL_DETAIL }
+
+};
+
+static const struct fdisk_label_operations dos_operations =
+{
+	.probe		= dos_probe_label,
+	.write		= dos_write_disklabel,
+	.verify		= dos_verify_disklabel,
+	.create		= dos_create_disklabel,
+	.locate		= dos_locate_disklabel,
+	.list		= dos_list_disklabel,
+	.reorder	= dos_reorder,
+	.get_id		= dos_get_disklabel_id,
+	.set_id		= dos_set_disklabel_id,
+
+	.get_part	= dos_get_partition,
+	.set_part	= dos_set_partition,
+	.add_part	= dos_add_partition,
+	.del_part	= dos_delete_partition,
+
+	.part_toggle_flag = dos_toggle_partition_flag,
+	.part_is_used	= dos_partition_is_used,
+
+	.reset_alignment = dos_reset_alignment,
+
+	.deinit		= dos_deinit,
+};
+
+/*
+ * allocates DOS in-memory stuff
+ */
+struct fdisk_label *fdisk_new_dos_label(struct fdisk_context *cxt)
+{
+	struct fdisk_label *lb;
+	struct fdisk_dos_label *dos;
+
+	assert(cxt);
+
+	dos = calloc(1, sizeof(*dos));
+	if (!dos)
+		return NULL;
+
+	/* initialize generic part of the driver */
+	lb = (struct fdisk_label *) dos;
+	lb->name = "dos";
+	lb->id = FDISK_DISKLABEL_DOS;
+	lb->op = &dos_operations;
+	lb->parttypes = dos_parttypes;
+	lb->nparttypes = ARRAY_SIZE(dos_parttypes) - 1;
+	lb->fields = dos_fields;
+	lb->nfields = ARRAY_SIZE(dos_fields);
+
+	return lb;
+}
+
+/**
+ * fdisk_dos_enable_compatible:
+ * @lb: DOS label (see fdisk_get_label())
+ * @enable: 0 or 1
+ *
+ * Enables deprecated DOS compatible mode, in this mode library checks for
+ * cylinders boundary, cases about CHS addressing and another obscure things.
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_dos_enable_compatible(struct fdisk_label *lb, int enable)
+{
+	struct fdisk_dos_label *dos = (struct fdisk_dos_label *) lb;
+
+	if (!lb)
+		return -EINVAL;
+
+	dos->compatible = enable;
+	if (enable)
+		lb->flags |= FDISK_LABEL_FL_REQUIRE_GEOMETRY;
+	return 0;
+}
+
+/**
+ * fdisk_dos_is_compatible:
+ * @lb: DOS label
+ *
+ * Returns: 0 if DOS compatibility disabled, 1 if enabled
+ */
+int fdisk_dos_is_compatible(struct fdisk_label *lb)
+{
+	return ((struct fdisk_dos_label *) lb)->compatible;
+}
diff --git a/libblkid/libfdisk/src/fdiskP.h b/libblkid/libfdisk/src/fdiskP.h
new file mode 100644
index 0000000..b169a9f
--- /dev/null
+++ b/libblkid/libfdisk/src/fdiskP.h
@@ -0,0 +1,438 @@
+/*
+ * fdiskP.h - private library header file
+ *
+ * Copyright (C) 2012 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+#ifndef _LIBFDISK_PRIVATE_H
+#define _LIBFDISK_PRIVATE_H
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+
+#include "c.h"
+#include "libfdisk.h"
+
+#include "nls.h"		/* temporary before dialog API will be implamented */
+#include "list.h"
+#include "debug.h"
+#include <stdio.h>
+#include <stdarg.h>
+
+/* features */
+#define CONFIG_LIBFDISK_ASSERT
+
+#ifdef CONFIG_LIBFDISK_ASSERT
+#include <assert.h>
+#endif
+
+/*
+ * Debug
+ */
+#define LIBFDISK_DEBUG_HELP	(1 << 0)
+#define LIBFDISK_DEBUG_INIT	(1 << 1)
+#define LIBFDISK_DEBUG_CXT	(1 << 2)
+#define LIBFDISK_DEBUG_LABEL    (1 << 3)
+#define LIBFDISK_DEBUG_ASK      (1 << 4)
+#define LIBFDISK_DEBUG_PART	(1 << 6)
+#define LIBFDISK_DEBUG_PARTTYPE	(1 << 7)
+#define LIBFDISK_DEBUG_TAB	(1 << 8)
+#define LIBFDISK_DEBUG_SCRIPT	(1 << 9)
+#define LIBFDISK_DEBUG_ALL	0xFFFF
+
+UL_DEBUG_DECLARE_MASK(libfdisk);
+#define DBG(m, x)	__UL_DBG(libfdisk, LIBFDISK_DEBUG_, m, x)
+#define ON_DBG(m, x)	__UL_DBG_CALL(libfdisk, LIBFDISK_DEBUG_, m, x)
+#define DBG_FLUSH	__UL_DBG_FLUSH(libfdisk, LIBFDISK_DEBUG_)
+
+#ifdef TEST_PROGRAM
+struct fdisk_test {
+	const char	*name;
+	int		(*body)(struct fdisk_test *ts, int argc, char *argv[]);
+	const char	*usage;
+};
+
+/* test.c */
+extern int fdisk_run_test(struct fdisk_test *tests, int argc, char *argv[]);
+#endif
+
+
+/*
+ * Generic iterator
+ */
+struct fdisk_iter {
+        struct list_head        *p;		/* current position */
+        struct list_head        *head;		/* start position */
+	int			direction;	/* FDISK_ITER_{FOR,BACK}WARD */
+};
+
+#define IS_ITER_FORWARD(_i)	((_i)->direction == FDISK_ITER_FORWARD)
+#define IS_ITER_BACKWARD(_i)	((_i)->direction == FDISK_ITER_BACKWARD)
+
+#define FDISK_ITER_INIT(itr, list) \
+	do { \
+		(itr)->p = IS_ITER_FORWARD(itr) ? \
+				(list)->next : (list)->prev; \
+		(itr)->head = (list); \
+	} while(0)
+
+#define FDISK_ITER_ITERATE(itr, res, restype, member) \
+	do { \
+		res = list_entry((itr)->p, restype, member); \
+		(itr)->p = IS_ITER_FORWARD(itr) ? \
+				(itr)->p->next : (itr)->p->prev; \
+	} while(0)
+
+/*
+ * Partition types
+ */
+struct fdisk_parttype {
+	unsigned int	code;		/* type as number or zero */
+	char		*name;		/* description */
+	char		*typestr;	/* type as string or NULL */
+
+	unsigned int	flags;		/* FDISK_PARTTYPE_* flags */
+	int		refcount;	/* reference counter for allocated types */
+};
+
+enum {
+	FDISK_PARTTYPE_UNKNOWN		= (1 << 1),
+	FDISK_PARTTYPE_INVISIBLE	= (1 << 2),
+	FDISK_PARTTYPE_ALLOCATED	= (1 << 3)
+};
+
+#define fdisk_parttype_is_invisible(_x)	((_x) && ((_x)->flags & FDISK_PARTTYPE_INVISIBLE))
+#define fdisk_parttype_is_allocated(_x)	((_x) && ((_x)->flags & FDISK_PARTTYPE_ALLOCATED))
+
+struct fdisk_partition {
+	int		refcount;		/* reference counter */
+
+	size_t		partno;			/* partition number */
+	size_t		parent_partno;		/* for logical partitions */
+
+	fdisk_sector_t	start;			/* first sectors */
+	fdisk_sector_t	size;			/* size in sectors */
+
+	char		*name;			/* partition name */
+	char		*uuid;			/* partition UUID */
+	char		*attrs;			/* partition flags/attributes converted to string */
+	struct fdisk_parttype	*type;		/* partition type */
+
+	struct list_head	parts;		/* list of partitions */
+
+	/* extra fields for partition_to_string() */
+	char		start_post;		/* start postfix  (e.g. '+') */
+	char		end_post;		/* end postfix */
+	char		size_post;		/* size postfix */
+
+	uint64_t	fsize;			/* bsd junk */
+	uint64_t	bsize;
+	uint64_t	cpg;
+
+	char		*start_chs;		/* start C/H/S in string */
+	char		*end_chs;		/* end C/H/S in string */
+
+	unsigned int	boot;			/* MBR: bootable */
+
+	unsigned int	container : 1,			/* container partition (e.g. extended partition) */
+			end_follow_default : 1,		/* use default end */
+			freespace : 1,			/* this is free space */
+			partno_follow_default : 1,	/* use default partno */
+			size_explicit : 1,		/* don't align the size */
+			start_follow_default : 1,	/* use default start */
+			used : 1,			/* partition already used */
+			wholedisk : 1;			/* special system partition */
+};
+
+#define FDISK_INIT_UNDEF(_x)	((_x) = (__typeof__(_x)) -1)
+#define FDISK_IS_UNDEF(_x)	((_x) == (__typeof__(_x)) -1)
+
+struct fdisk_table {
+	struct list_head	parts;		/* partitions */
+	int			refcount;
+	size_t			nents;		/* number of partitions */
+};
+
+/*
+ * Legacy CHS based geometry
+ */
+struct fdisk_geometry {
+	unsigned int heads;
+	fdisk_sector_t sectors;
+	fdisk_sector_t cylinders;
+};
+
+/*
+ * Label specific operations
+ */
+struct fdisk_label_operations {
+	/* probe disk label */
+	int (*probe)(struct fdisk_context *cxt);
+	/* write in-memory changes to disk */
+	int (*write)(struct fdisk_context *cxt);
+	/* verify the partition table */
+	int (*verify)(struct fdisk_context *cxt);
+	/* create new disk label */
+	int (*create)(struct fdisk_context *cxt);
+	/* list disklabel details */
+	int (*list)(struct fdisk_context *cxt);
+	/* returns offset and size of the 'n' part of the PT */
+	int (*locate)(struct fdisk_context *cxt, int n, const char **name, off_t *offset, size_t *size);
+	/* reorder partitions */
+	int (*reorder)(struct fdisk_context *cxt);
+
+	/* get disk label ID */
+	int (*get_id)(struct fdisk_context *cxt, char **id);
+	/* set disk label ID */
+	int (*set_id)(struct fdisk_context *cxt);
+
+
+	/* new partition */
+	int (*add_part)(struct fdisk_context *cxt, struct fdisk_partition *pa,
+						size_t *partno);
+	/* delete partition */
+	int (*del_part)(struct fdisk_context *cxt, size_t partnum);
+
+	/* fill in partition struct */
+	int (*get_part)(struct fdisk_context *cxt, size_t n,
+						struct fdisk_partition *pa);
+	/* modify partition */
+	int (*set_part)(struct fdisk_context *cxt, size_t n,
+						struct fdisk_partition *pa);
+
+	/* return state of the partition */
+	int (*part_is_used)(struct fdisk_context *cxt, size_t partnum);
+
+	int (*part_toggle_flag)(struct fdisk_context *cxt, size_t i, unsigned long flag);
+
+	/* refresh alignment setting */
+	int (*reset_alignment)(struct fdisk_context *cxt);
+
+	/* free in-memory label stuff */
+	void (*free)(struct fdisk_label *lb);
+
+	/* deinit in-memory label stuff */
+	void (*deinit)(struct fdisk_label *lb);
+};
+
+/*
+ * The fields describes how to display libfdisk_partition
+ */
+struct fdisk_field {
+	int		id;		/* FDISK_FIELD_* */
+	const char	*name;		/* field name */
+	double		width;		/* field width (compatible with libsmartcols whint) */
+	int		flags;		/* FDISK_FIELDFL_* */
+};
+
+/* note that the defauls is to display a column always */
+enum {
+	FDISK_FIELDFL_DETAIL	= (1 << 1),	/* only display if fdisk_is_details() */
+	FDISK_FIELDFL_EYECANDY	= (1 << 2),	/* don't display if fdisk_is_details() */
+	FDISK_FIELDFL_NUMBER	= (1 << 3),	/* column display numbers */
+};
+
+/*
+ * Generic label
+ */
+struct fdisk_label {
+	const char		*name;		/* label name */
+	enum fdisk_labeltype	id;		/* FDISK_DISKLABEL_* */
+	struct fdisk_parttype	*parttypes;	/* supported partitions types */
+	size_t			nparttypes;	/* number of items in parttypes[] */
+
+	size_t			nparts_max;	/* maximal number of partitions */
+	size_t			nparts_cur;	/* number of currently used partitions */
+
+	int			flags;		/* FDISK_LABEL_FL_* flags */
+
+	unsigned int		changed:1,	/* label has been modified */
+				disabled:1;	/* this driver is disabled at all */
+
+	const struct fdisk_field *fields;	/* all possible fields */
+	size_t			nfields;
+
+	const struct fdisk_label_operations *op;
+};
+
+
+/* label driver flags */
+enum {
+	FDISK_LABEL_FL_REQUIRE_GEOMETRY = (1 << 2),
+	FDISK_LABEL_FL_INCHARS_PARTNO   = (1 << 3)
+};
+
+/* label allocators */
+extern struct fdisk_label *fdisk_new_gpt_label(struct fdisk_context *cxt);
+extern struct fdisk_label *fdisk_new_dos_label(struct fdisk_context *cxt);
+extern struct fdisk_label *fdisk_new_bsd_label(struct fdisk_context *cxt);
+extern struct fdisk_label *fdisk_new_sgi_label(struct fdisk_context *cxt);
+extern struct fdisk_label *fdisk_new_sun_label(struct fdisk_context *cxt);
+
+
+struct ask_menuitem {
+	char	key;
+	const char	*name;
+	const char	*desc;
+
+	struct ask_menuitem *next;
+};
+
+/* fdisk dialog -- note that nothing from this stuff will be directly exported,
+ * we will have get/set() function for everything.
+ */
+struct fdisk_ask {
+	int		type;		/* FDISK_ASKTYPE_* */
+	char		*query;
+
+	int		refcount;
+
+	union {
+		/* FDISK_ASKTYPE_{NUMBER,OFFSET} */
+		struct ask_number {
+			uint64_t	hig;		/* high limit */
+			uint64_t	low;		/* low limit */
+			uint64_t	dfl;		/* default */
+			uint64_t	result;
+			uint64_t	base;		/* for relative results */
+			uint64_t	unit;		/* unit for offsets */
+			const char	*range;		/* by library generated list */
+			unsigned int	relative :1,
+					inchars  :1;
+		} num;
+		/* FDISK_ASKTYPE_{WARN,WARNX,..} */
+		struct ask_print {
+			const char	*mesg;
+			int		errnum;		/* errno */
+		} print;
+		/* FDISK_ASKTYPE_YESNO */
+		struct ask_yesno {
+			int		result;		/* TRUE or FALSE */
+		} yesno;
+		/* FDISK_ASKTYPE_STRING */
+		struct ask_string {
+			char		*result;	/* allocated */
+		} str;
+		/* FDISK_ASKTYPE_MENU */
+		struct ask_menu {
+			int		dfl;		/* default meni item */
+			int		result;
+			struct ask_menuitem *first;
+		} menu;
+	} data;
+};
+
+struct fdisk_context {
+	int dev_fd;         /* device descriptor */
+	char *dev_path;     /* device path */
+	int refcount;
+
+	unsigned char *firstsector; /* buffer with master boot record */
+	unsigned long firstsector_bufsz;
+
+	/* topology */
+	unsigned long io_size;		/* I/O size used by fdisk */
+	unsigned long optimal_io_size;	/* optional I/O returned by device */
+	unsigned long min_io_size;	/* minimal I/O size */
+	unsigned long phy_sector_size;	/* physical size */
+	unsigned long sector_size;	/* logical size */
+	unsigned long alignment_offset;
+
+	unsigned int readonly : 1,		/* don't write to the device */
+		     display_in_cyl_units : 1,	/* for obscure labels */
+		     display_details : 1,	/* expert display mode */
+		     listonly : 1;		/* list partition, nothing else */
+
+	/* alignment */
+	unsigned long grain;		/* alignment unit */
+	fdisk_sector_t first_lba;		/* recommended begin of the first partition */
+	fdisk_sector_t last_lba;		/* recomennded end of last partition */
+
+	/* geometry */
+	fdisk_sector_t total_sectors;	/* in logical sectors */
+	struct fdisk_geometry geom;
+
+	/* user setting to overwrite device default */
+	struct fdisk_geometry user_geom;
+	unsigned long user_pyh_sector;
+	unsigned long user_log_sector;
+
+	struct fdisk_label *label;	/* current label, pointer to labels[] */
+
+	size_t nlabels;			/* number of initialized label drivers */
+	struct fdisk_label *labels[8];	/* all supported labels,
+					 * FIXME: use any enum rather than hardcoded number */
+
+	int	(*ask_cb)(struct fdisk_context *, struct fdisk_ask *, void *);	/* fdisk dialogs callback */
+	void	*ask_data;		/* ask_cb() data */
+
+	struct fdisk_context	*parent;	/* for nested PT */
+	struct fdisk_script	*script;	/* what we want to follow */
+};
+
+/* partition.c */
+int fdisk_partition_next_partno(struct fdisk_partition *pa,
+				       struct fdisk_context *cxt,
+				       size_t *n);
+
+/* context.c */
+extern int __fdisk_switch_label(struct fdisk_context *cxt,
+				    struct fdisk_label *lb);
+extern int fdisk_missing_geometry(struct fdisk_context *cxt);
+
+/* alignment.c */
+fdisk_sector_t fdisk_scround(struct fdisk_context *cxt, fdisk_sector_t num);
+fdisk_sector_t fdisk_cround(struct fdisk_context *cxt, fdisk_sector_t num);
+
+extern int fdisk_discover_geometry(struct fdisk_context *cxt);
+extern int fdisk_discover_topology(struct fdisk_context *cxt);
+
+extern int fdisk_apply_user_device_properties(struct fdisk_context *cxt);
+extern void fdisk_zeroize_device_properties(struct fdisk_context *cxt);
+
+/* utils.c */
+extern int fdisk_init_firstsector_buffer(struct fdisk_context *cxt);
+extern int fdisk_read_firstsector(struct fdisk_context *cxt);
+extern char *fdisk_partname(const char *dev, size_t partno);
+
+/* label.c */
+extern int fdisk_probe_labels(struct fdisk_context *cxt);
+extern void fdisk_deinit_label(struct fdisk_label *lb);
+
+/* ask.c */
+struct fdisk_ask *fdisk_new_ask(void);
+void fdisk_reset_ask(struct fdisk_ask *ask);
+int fdisk_ask_set_query(struct fdisk_ask *ask, const char *str);
+int fdisk_ask_set_type(struct fdisk_ask *ask, int type);
+int fdisk_do_ask(struct fdisk_context *cxt, struct fdisk_ask *ask);
+int fdisk_ask_number_set_range(struct fdisk_ask *ask, const char *range);
+int fdisk_ask_number_set_default(struct fdisk_ask *ask, uint64_t dflt);
+int fdisk_ask_number_set_low(struct fdisk_ask *ask, uint64_t low);
+int fdisk_ask_number_set_high(struct fdisk_ask *ask, uint64_t high);
+int fdisk_ask_number_set_base(struct fdisk_ask *ask, uint64_t base);
+int fdisk_ask_number_set_unit(struct fdisk_ask *ask, uint64_t unit);
+int fdisk_ask_number_is_relative(struct fdisk_ask *ask);
+int fdisk_ask_menu_set_default(struct fdisk_ask *ask, int dfl);
+int fdisk_ask_menu_add_item(struct fdisk_ask *ask, int key,
+			const char *name, const char *desc);
+int fdisk_ask_print_set_errno(struct fdisk_ask *ask, int errnum);
+int fdisk_ask_print_set_mesg(struct fdisk_ask *ask, const char *mesg);
+int fdisk_info_new_partition(
+			struct fdisk_context *cxt,
+			int num, fdisk_sector_t start, fdisk_sector_t stop,
+			struct fdisk_parttype *t);
+
+/* dos.c */
+extern struct dos_partition *fdisk_dos_get_partition(
+				struct fdisk_context *cxt,
+				size_t i);
+
+#endif /* _LIBFDISK_PRIVATE_H */
diff --git a/libblkid/libfdisk/src/gpt.c b/libblkid/libfdisk/src/gpt.c
new file mode 100644
index 0000000..8c1c96c
--- /dev/null
+++ b/libblkid/libfdisk/src/gpt.c
@@ -0,0 +1,2565 @@
+/*
+ * Copyright (C) 2007 Karel Zak <kzak@redhat.com>
+ * Copyright (C) 2012 Davidlohr Bueso <dave@gnu.org>
+ *
+ * GUID Partition Table (GPT) support. Based on UEFI Specs 2.3.1
+ * Chapter 5: GUID Partition Table (GPT) Disk Layout (Jun 27th, 2012).
+ * Some ideas and inspiration from GNU parted and gptfdisk.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+#include <uuid.h>
+
+#include "fdiskP.h"
+
+#include "nls.h"
+#include "crc32.h"
+#include "blkdev.h"
+#include "bitops.h"
+#include "strutils.h"
+#include "all-io.h"
+
+/**
+ * SECTION: gpt
+ * @title: UEFI GPT
+ * @short_description: specific functionality
+ */
+
+#define GPT_HEADER_SIGNATURE 0x5452415020494645LL /* EFI PART */
+#define GPT_HEADER_REVISION_V1_02 0x00010200
+#define GPT_HEADER_REVISION_V1_00 0x00010000
+#define GPT_HEADER_REVISION_V0_99 0x00009900
+#define GPT_HEADER_MINSZ          92 /* bytes */
+
+#define GPT_PMBR_LBA        0
+#define GPT_MBR_PROTECTIVE  1
+#define GPT_MBR_HYBRID      2
+
+#define GPT_PRIMARY_PARTITION_TABLE_LBA 0x00000001
+
+#define EFI_PMBR_OSTYPE     0xEE
+#define MSDOS_MBR_SIGNATURE 0xAA55
+#define GPT_PART_NAME_LEN   (72 / sizeof(uint16_t))
+#define GPT_NPARTITIONS     128
+
+/* Globally unique identifier */
+struct gpt_guid {
+	uint32_t   time_low;
+	uint16_t   time_mid;
+	uint16_t   time_hi_and_version;
+	uint8_t    clock_seq_hi;
+	uint8_t    clock_seq_low;
+	uint8_t    node[6];
+};
+
+
+/* only checking that the GUID is 0 is enough to verify an empty partition. */
+#define GPT_UNUSED_ENTRY_GUID						\
+	((struct gpt_guid) { 0x00000000, 0x0000, 0x0000, 0x00, 0x00,	\
+			     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }})
+
+/* Linux native partition type */
+#define GPT_DEFAULT_ENTRY_TYPE "0FC63DAF-8483-4772-8E79-3D69D8477DE4"
+
+/*
+ * Attribute bits
+ */
+enum {
+	/* UEFI specific */
+	GPT_ATTRBIT_REQ      = 0,
+	GPT_ATTRBIT_NOBLOCK  = 1,
+	GPT_ATTRBIT_LEGACY   = 2,
+
+	/* GUID specific (range 48..64)*/
+	GPT_ATTRBIT_GUID_FIRST	= 48,
+	GPT_ATTRBIT_GUID_COUNT	= 16
+};
+
+#define GPT_ATTRSTR_REQ		"RequiredPartiton"
+#define GPT_ATTRSTR_NOBLOCK	"NoBlockIOProtocol"
+#define GPT_ATTRSTR_LEGACY	"LegacyBIOSBootable"
+
+/* The GPT Partition entry array contains an array of GPT entries. */
+struct gpt_entry {
+	struct gpt_guid     type; /* purpose and type of the partition */
+	struct gpt_guid     partition_guid;
+	uint64_t            lba_start;
+	uint64_t            lba_end;
+	uint64_t            attrs;
+	uint16_t            name[GPT_PART_NAME_LEN];
+}  __attribute__ ((packed));
+
+/* GPT header */
+struct gpt_header {
+	uint64_t            signature; /* header identification */
+	uint32_t            revision; /* header version */
+	uint32_t            size; /* in bytes */
+	uint32_t            crc32; /* header CRC checksum */
+	uint32_t            reserved1; /* must be 0 */
+	uint64_t            my_lba; /* LBA of block that contains this struct (LBA 1) */
+	uint64_t            alternative_lba; /* backup GPT header */
+	uint64_t            first_usable_lba; /* first usable logical block for partitions */
+	uint64_t            last_usable_lba; /* last usable logical block for partitions */
+	struct gpt_guid     disk_guid; /* unique disk identifier */
+	uint64_t            partition_entry_lba; /* LBA of start of partition entries array */
+	uint32_t            npartition_entries; /* total partition entries - normally 128 */
+	uint32_t            sizeof_partition_entry; /* bytes for each GUID pt */
+	uint32_t            partition_entry_array_crc32; /* partition CRC checksum */
+	uint8_t             reserved2[512 - 92]; /* must all be 0 */
+} __attribute__ ((packed));
+
+struct gpt_record {
+	uint8_t             boot_indicator; /* unused by EFI, set to 0x80 for bootable */
+	uint8_t             start_head; /* unused by EFI, pt start in CHS */
+	uint8_t             start_sector; /* unused by EFI, pt start in CHS */
+	uint8_t             start_track;
+	uint8_t             os_type; /* EFI and legacy non-EFI OS types */
+	uint8_t             end_head; /* unused by EFI, pt end in CHS */
+	uint8_t             end_sector; /* unused by EFI, pt end in CHS */
+	uint8_t             end_track; /* unused by EFI, pt end in CHS */
+	uint32_t            starting_lba; /* used by EFI - start addr of the on disk pt */
+	uint32_t            size_in_lba; /* used by EFI - size of pt in LBA */
+} __attribute__ ((packed));
+
+/* Protected MBR and legacy MBR share same structure */
+struct gpt_legacy_mbr {
+	uint8_t             boot_code[440];
+	uint32_t            unique_mbr_signature;
+	uint16_t            unknown;
+	struct gpt_record   partition_record[4];
+	uint16_t            signature;
+} __attribute__ ((packed));
+
+/*
+ * Here be dragons!
+ * See: http://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_type_GUIDs
+ */
+#define DEF_GUID(_u, _n) \
+	{ \
+		.typestr = (_u), \
+		.name = (_n),    \
+	}
+
+static struct fdisk_parttype gpt_parttypes[] =
+{
+	/* Generic OS */
+	DEF_GUID("C12A7328-F81F-11D2-BA4B-00A0C93EC93B", N_("EFI System")),
+
+	DEF_GUID("024DEE41-33E7-11D3-9D69-0008C781F39F", N_("MBR partition scheme")),
+	DEF_GUID("D3BFE2DE-3DAF-11DF-BA40-E3A556D89593", N_("Intel Fast Flash")),
+
+	/* Hah!IdontneedEFI */
+	DEF_GUID("21686148-6449-6E6F-744E-656564454649", N_("BIOS boot")),
+
+	/* Windows */
+	DEF_GUID("E3C9E316-0B5C-4DB8-817D-F92DF00215AE", N_("Microsoft reserved")),
+	DEF_GUID("EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", N_("Microsoft basic data")),
+	DEF_GUID("5808C8AA-7E8F-42E0-85D2-E1E90434CFB3", N_("Microsoft LDM metadata")),
+	DEF_GUID("AF9B60A0-1431-4F62-BC68-3311714A69AD", N_("Microsoft LDM data")),
+	DEF_GUID("DE94BBA4-06D1-4D40-A16A-BFD50179D6AC", N_("Windows recovery environment")),
+	DEF_GUID("37AFFC90-EF7D-4E96-91C3-2D7AE055B174", N_("IBM General Parallel Fs")),
+	DEF_GUID("E75CAF8F-F680-4CEE-AFA3-B001E56EFC2D", N_("Microsoft Storage Spaces")),
+
+	/* HP-UX */
+	DEF_GUID("75894C1E-3AEB-11D3-B7C1-7B03A0000000", N_("HP-UX data")),
+	DEF_GUID("E2A1E728-32E3-11D6-A682-7B03A0000000", N_("HP-UX service")),
+
+	/* Linux (http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec) */
+	DEF_GUID("0657FD6D-A4AB-43C4-84E5-0933C84B4F4F", N_("Linux swap")),
+	DEF_GUID("0FC63DAF-8483-4772-8E79-3D69D8477DE4", N_("Linux filesystem")),
+	DEF_GUID("3B8F8425-20E0-4F3B-907F-1A25A76F98E8", N_("Linux server data")),
+	DEF_GUID("44479540-F297-41B2-9AF7-D131D5F0458A", N_("Linux root (x86)")),
+	DEF_GUID("4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709", N_("Linux root (x86-64)")),
+	DEF_GUID("8DA63339-0007-60C0-C436-083AC8230908", N_("Linux reserved")),
+	DEF_GUID("933AC7E1-2EB4-4F13-B844-0E14E2AEF915", N_("Linux home")),
+	DEF_GUID("A19D880F-05FC-4D3B-A006-743F0F84911E", N_("Linux RAID")),
+	DEF_GUID("BC13C2FF-59E6-4262-A352-B275FD6F7172", N_("Linux extended boot")),
+	DEF_GUID("E6D6D379-F507-44C2-A23C-238F2A3DF928", N_("Linux LVM")),
+
+	/* FreeBSD */
+	DEF_GUID("516E7CB4-6ECF-11D6-8FF8-00022D09712B", N_("FreeBSD data")),
+	DEF_GUID("83BD6B9D-7F41-11DC-BE0B-001560B84F0F", N_("FreeBSD boot")),
+	DEF_GUID("516E7CB5-6ECF-11D6-8FF8-00022D09712B", N_("FreeBSD swap")),
+	DEF_GUID("516E7CB6-6ECF-11D6-8FF8-00022D09712B", N_("FreeBSD UFS")),
+	DEF_GUID("516E7CBA-6ECF-11D6-8FF8-00022D09712B", N_("FreeBSD ZFS")),
+	DEF_GUID("516E7CB8-6ECF-11D6-8FF8-00022D09712B", N_("FreeBSD Vinum")),
+
+	/* Apple OSX */
+	DEF_GUID("48465300-0000-11AA-AA11-00306543ECAC", N_("Apple HFS/HFS+")),
+	DEF_GUID("55465300-0000-11AA-AA11-00306543ECAC", N_("Apple UFS")),
+	DEF_GUID("52414944-0000-11AA-AA11-00306543ECAC", N_("Apple RAID")),
+	DEF_GUID("52414944-5F4F-11AA-AA11-00306543ECAC", N_("Apple RAID offline")),
+	DEF_GUID("426F6F74-0000-11AA-AA11-00306543ECAC", N_("Apple boot")),
+	DEF_GUID("4C616265-6C00-11AA-AA11-00306543ECAC", N_("Apple label")),
+	DEF_GUID("5265636F-7665-11AA-AA11-00306543ECAC", N_("Apple TV recovery")),
+	DEF_GUID("53746F72-6167-11AA-AA11-00306543ECAC", N_("Apple Core storage")),
+
+	/* Solaris */
+	DEF_GUID("6A82CB45-1DD2-11B2-99A6-080020736631", N_("Solaris boot")),
+	DEF_GUID("6A85CF4D-1DD2-11B2-99A6-080020736631", N_("Solaris root")),
+	/* same as Apple ZFS */
+	DEF_GUID("6A898CC3-1DD2-11B2-99A6-080020736631", N_("Solaris /usr & Apple ZFS")),
+	DEF_GUID("6A87C46F-1DD2-11B2-99A6-080020736631", N_("Solaris swap")),
+	DEF_GUID("6A8B642B-1DD2-11B2-99A6-080020736631", N_("Solaris backup")),
+	DEF_GUID("6A8EF2E9-1DD2-11B2-99A6-080020736631", N_("Solaris /var")),
+	DEF_GUID("6A90BA39-1DD2-11B2-99A6-080020736631", N_("Solaris /home")),
+	DEF_GUID("6A9283A5-1DD2-11B2-99A6-080020736631", N_("Solaris alternate sector")),
+	DEF_GUID("6A945A3B-1DD2-11B2-99A6-080020736631", N_("Solaris reserved 1")),
+	DEF_GUID("6A9630D1-1DD2-11B2-99A6-080020736631", N_("Solaris reserved 2")),
+	DEF_GUID("6A980767-1DD2-11B2-99A6-080020736631", N_("Solaris reserved 3")),
+	DEF_GUID("6A96237F-1DD2-11B2-99A6-080020736631", N_("Solaris reserved 4")),
+	DEF_GUID("6A8D2AC7-1DD2-11B2-99A6-080020736631", N_("Solaris reserved 5")),
+
+	/* NetBSD */
+	DEF_GUID("49F48D32-B10E-11DC-B99B-0019D1879648", N_("NetBSD swap")),
+	DEF_GUID("49F48D5A-B10E-11DC-B99B-0019D1879648", N_("NetBSD FFS")),
+	DEF_GUID("49F48D82-B10E-11DC-B99B-0019D1879648", N_("NetBSD LFS")),
+	DEF_GUID("2DB519C4-B10E-11DC-B99B-0019D1879648", N_("NetBSD concatenated")),
+	DEF_GUID("2DB519EC-B10E-11DC-B99B-0019D1879648", N_("NetBSD encrypted")),
+	DEF_GUID("49F48DAA-B10E-11DC-B99B-0019D1879648", N_("NetBSD RAID")),
+
+	/* ChromeOS */
+	DEF_GUID("FE3A2A5D-4F32-41A7-B725-ACCC3285A309", N_("ChromeOS kernel")),
+	DEF_GUID("3CB8E202-3B7E-47DD-8A3C-7FF2A13CFCEC", N_("ChromeOS root fs")),
+	DEF_GUID("2E0A753D-9E48-43B0-8337-B15192CB1B5E", N_("ChromeOS reserved")),
+
+	/* MidnightBSD */
+	DEF_GUID("85D5E45A-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD data")),
+	DEF_GUID("85D5E45E-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD boot")),
+	DEF_GUID("85D5E45B-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD swap")),
+	DEF_GUID("0394Ef8B-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD UFS")),
+	DEF_GUID("85D5E45D-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD ZFS")),
+	DEF_GUID("85D5E45C-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD Vinum")),
+};
+
+/* gpt_entry macros */
+#define gpt_partition_start(_e)		le64_to_cpu((_e)->lba_start)
+#define gpt_partition_end(_e)		le64_to_cpu((_e)->lba_end)
+
+/*
+ * in-memory fdisk GPT stuff
+ */
+struct fdisk_gpt_label {
+	struct fdisk_label	head;		/* generic part */
+
+	/* gpt specific part */
+	struct gpt_header	*pheader;	/* primary header */
+	struct gpt_header	*bheader;	/* backup header */
+	struct gpt_entry	*ents;		/* entries (partitions) */
+};
+
+static void gpt_deinit(struct fdisk_label *lb);
+
+static inline struct fdisk_gpt_label *self_label(struct fdisk_context *cxt)
+{
+	return (struct fdisk_gpt_label *) cxt->label;
+}
+
+/*
+ * Returns the partition length, or 0 if end is before beginning.
+ */
+static uint64_t gpt_partition_size(const struct gpt_entry *e)
+{
+	uint64_t start = gpt_partition_start(e);
+	uint64_t end = gpt_partition_end(e);
+
+	return start > end ? 0 : end - start + 1ULL;
+}
+
+/* prints UUID in the real byte order! */
+static void gpt_debug_uuid(const char *mesg, struct gpt_guid *guid)
+{
+	const unsigned char *uuid = (unsigned char *) guid;
+
+	fprintf(stderr, "%s: "
+		"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
+		mesg,
+		uuid[0], uuid[1], uuid[2], uuid[3],
+		uuid[4], uuid[5],
+		uuid[6], uuid[7],
+		uuid[8], uuid[9],
+		uuid[10], uuid[11], uuid[12], uuid[13], uuid[14],uuid[15]);
+}
+
+/*
+ * UUID is traditionally 16 byte big-endian array, except Intel EFI
+ * specification where the UUID is a structure of little-endian fields.
+ */
+static void swap_efi_guid(struct gpt_guid *uid)
+{
+	uid->time_low = swab32(uid->time_low);
+	uid->time_mid = swab16(uid->time_mid);
+	uid->time_hi_and_version = swab16(uid->time_hi_and_version);
+}
+
+static int string_to_guid(const char *in, struct gpt_guid *guid)
+{
+	if (uuid_parse(in, (unsigned char *) guid))	/* BE */
+		return -1;
+	swap_efi_guid(guid);				/* LE */
+	return 0;
+}
+
+static char *guid_to_string(const struct gpt_guid *guid, char *out)
+{
+	struct gpt_guid u = *guid;	/* LE */
+
+	swap_efi_guid(&u);		/* BE */
+	uuid_unparse_upper((unsigned char *) &u, out);
+
+	return out;
+}
+
+static struct fdisk_parttype *gpt_partition_parttype(
+		struct fdisk_context *cxt,
+		const struct gpt_entry *e)
+{
+	struct fdisk_parttype *t;
+	char str[37];
+
+	guid_to_string(&e->type, str);
+	t = fdisk_label_get_parttype_from_string(cxt->label, str);
+	return t ? : fdisk_new_unknown_parttype(0, str);
+}
+
+static void gpt_entry_set_type(struct gpt_entry *e, struct gpt_guid *uuid)
+{
+	e->type = *uuid;
+	DBG(LABEL, gpt_debug_uuid("new type", &(e->type)));
+}
+
+static void gpt_entry_set_name(struct gpt_entry *e, char *str)
+{
+	char name[GPT_PART_NAME_LEN] = { 0 };
+	size_t i, sz = strlen(str);
+
+	if (sz) {
+		if (sz > GPT_PART_NAME_LEN)
+			sz = GPT_PART_NAME_LEN;
+		memcpy(name, str, sz);
+	}
+
+	for (i = 0; i < GPT_PART_NAME_LEN; i++)
+		e->name[i] = cpu_to_le16((uint16_t) name[i]);
+}
+
+static int gpt_entry_set_uuid(struct gpt_entry *e, char *str)
+{
+	struct gpt_guid uuid;
+	int rc;
+
+	rc = string_to_guid(str, &uuid);
+	if (rc)
+		return rc;
+
+	e->partition_guid = uuid;
+	return 0;
+}
+
+
+static const char *gpt_get_header_revstr(struct gpt_header *header)
+{
+	if (!header)
+		goto unknown;
+
+	switch (header->revision) {
+	case GPT_HEADER_REVISION_V1_02:
+		return "1.2";
+	case GPT_HEADER_REVISION_V1_00:
+		return "1.0";
+	case GPT_HEADER_REVISION_V0_99:
+		return "0.99";
+	default:
+		goto unknown;
+	}
+
+unknown:
+	return "unknown";
+}
+
+static inline int partition_unused(const struct gpt_entry *e)
+{
+	return !memcmp(&e->type, &GPT_UNUSED_ENTRY_GUID,
+			sizeof(struct gpt_guid));
+}
+
+/*
+ * Builds a clean new valid protective MBR - will wipe out any existing data.
+ * Returns 0 on success, otherwise < 0 on error.
+ */
+static int gpt_mknew_pmbr(struct fdisk_context *cxt)
+{
+	struct gpt_legacy_mbr *pmbr = NULL;
+	int rc;
+
+	if (!cxt || !cxt->firstsector)
+		return -ENOSYS;
+
+	rc = fdisk_init_firstsector_buffer(cxt);
+	if (rc)
+		return rc;
+
+	pmbr = (struct gpt_legacy_mbr *) cxt->firstsector;
+
+	pmbr->signature = cpu_to_le16(MSDOS_MBR_SIGNATURE);
+	pmbr->partition_record[0].os_type      = EFI_PMBR_OSTYPE;
+	pmbr->partition_record[0].start_sector = 1;
+	pmbr->partition_record[0].end_head     = 0xFE;
+	pmbr->partition_record[0].end_sector   = 0xFF;
+	pmbr->partition_record[0].end_track    = 0xFF;
+	pmbr->partition_record[0].starting_lba = cpu_to_le32(1);
+	pmbr->partition_record[0].size_in_lba  =
+		cpu_to_le32(min((uint32_t) cxt->total_sectors - 1, 0xFFFFFFFF));
+
+	return 0;
+}
+
+/* some universal differences between the headers */
+static void gpt_mknew_header_common(struct fdisk_context *cxt,
+				    struct gpt_header *header, uint64_t lba)
+{
+	if (!cxt || !header)
+		return;
+
+	header->my_lba = cpu_to_le64(lba);
+
+	if (lba == GPT_PRIMARY_PARTITION_TABLE_LBA) { /* primary */
+		header->alternative_lba = cpu_to_le64(cxt->total_sectors - 1);
+		header->partition_entry_lba = cpu_to_le64(2);
+	} else { /* backup */
+		uint64_t esz = le32_to_cpu(header->npartition_entries) * sizeof(struct gpt_entry);
+		uint64_t esects = (esz + cxt->sector_size - 1) / cxt->sector_size;
+
+		header->alternative_lba = cpu_to_le64(GPT_PRIMARY_PARTITION_TABLE_LBA);
+		header->partition_entry_lba = cpu_to_le64(cxt->total_sectors - 1 - esects);
+	}
+}
+
+/*
+ * Builds a new GPT header (at sector lba) from a backup header2.
+ * If building a primary header, then backup is the secondary, and vice versa.
+ *
+ * Always pass a new (zeroized) header to build upon as we don't
+ * explicitly zero-set some values such as CRCs and reserved.
+ *
+ * Returns 0 on success, otherwise < 0 on error.
+ */
+static int gpt_mknew_header_from_bkp(struct fdisk_context *cxt,
+				     struct gpt_header *header,
+				     uint64_t lba,
+				     struct gpt_header *header2)
+{
+	if (!cxt || !header || !header2)
+		return -ENOSYS;
+
+	header->signature              = header2->signature;
+	header->revision               = header2->revision;
+	header->size                   = header2->size;
+	header->npartition_entries     = header2->npartition_entries;
+	header->sizeof_partition_entry = header2->sizeof_partition_entry;
+	header->first_usable_lba       = header2->first_usable_lba;
+	header->last_usable_lba        = header2->last_usable_lba;
+
+	memcpy(&header->disk_guid,
+	       &header2->disk_guid, sizeof(header2->disk_guid));
+	gpt_mknew_header_common(cxt, header, lba);
+
+	return 0;
+}
+
+static struct gpt_header *gpt_copy_header(struct fdisk_context *cxt,
+			   struct gpt_header *src)
+{
+	struct gpt_header *res;
+
+	if (!cxt || !src)
+		return NULL;
+
+	res = calloc(1, sizeof(*res));
+	if (!res) {
+		fdisk_warn(cxt, _("failed to allocate GPT header"));
+		return NULL;
+	}
+
+	res->my_lba                 = src->alternative_lba;
+	res->alternative_lba        = src->my_lba;
+
+	res->signature              = src->signature;
+	res->revision               = src->revision;
+	res->size                   = src->size;
+	res->npartition_entries     = src->npartition_entries;
+	res->sizeof_partition_entry = src->sizeof_partition_entry;
+	res->first_usable_lba       = src->first_usable_lba;
+	res->last_usable_lba        = src->last_usable_lba;
+
+	memcpy(&res->disk_guid, &src->disk_guid, sizeof(src->disk_guid));
+
+
+	if (res->my_lba == GPT_PRIMARY_PARTITION_TABLE_LBA)
+		res->partition_entry_lba = cpu_to_le64(2);
+	else {
+		uint64_t esz = le32_to_cpu(src->npartition_entries) * sizeof(struct gpt_entry);
+		uint64_t esects = (esz + cxt->sector_size - 1) / cxt->sector_size;
+
+		res->partition_entry_lba = cpu_to_le64(cxt->total_sectors - 1 - esects);
+	}
+
+	return res;
+}
+
+static void count_first_last_lba(struct fdisk_context *cxt,
+				 uint64_t *first, uint64_t *last)
+{
+	uint64_t esz = 0;
+
+	assert(cxt);
+
+	esz = sizeof(struct gpt_entry) * GPT_NPARTITIONS / cxt->sector_size;
+	*last = cxt->total_sectors - 2 - esz;
+	*first = esz + 2;
+
+	if (*first < cxt->first_lba && cxt->first_lba < *last)
+		/* Align according to topology */
+		*first = cxt->first_lba;
+}
+
+/*
+ * Builds a clean new GPT header (currently under revision 1.0).
+ *
+ * Always pass a new (zeroized) header to build upon as we don't
+ * explicitly zero-set some values such as CRCs and reserved.
+ *
+ * Returns 0 on success, otherwise < 0 on error.
+ */
+static int gpt_mknew_header(struct fdisk_context *cxt,
+			    struct gpt_header *header, uint64_t lba)
+{
+	uint64_t first, last;
+	int has_id = 0;
+
+	if (!cxt || !header)
+		return -ENOSYS;
+
+	header->signature = cpu_to_le64(GPT_HEADER_SIGNATURE);
+	header->revision  = cpu_to_le32(GPT_HEADER_REVISION_V1_00);
+	header->size      = cpu_to_le32(sizeof(struct gpt_header));
+
+	/*
+	 * 128 partitions are the default. It can go beyond that, but
+	 * we're creating a de facto header here, so no funny business.
+	 */
+	header->npartition_entries     = cpu_to_le32(GPT_NPARTITIONS);
+	header->sizeof_partition_entry = cpu_to_le32(sizeof(struct gpt_entry));
+
+	count_first_last_lba(cxt, &first, &last);
+	header->first_usable_lba = cpu_to_le64(first);
+	header->last_usable_lba  = cpu_to_le64(last);
+
+	gpt_mknew_header_common(cxt, header, lba);
+
+	if (cxt->script) {
+		const char *id = fdisk_script_get_header(cxt->script, "label-id");
+		if (id && string_to_guid(id, &header->disk_guid) == 0)
+			has_id = 1;
+	}
+
+	if (!has_id) {
+		uuid_generate_random((unsigned char *) &header->disk_guid);
+		swap_efi_guid(&header->disk_guid);
+	}
+	return 0;
+}
+
+/*
+ * Checks if there is a valid protective MBR partition table.
+ * Returns 0 if it is invalid or failure. Otherwise, return
+ * GPT_MBR_PROTECTIVE or GPT_MBR_HYBRID, depeding on the detection.
+ */
+static int valid_pmbr(struct fdisk_context *cxt)
+{
+	int i, part = 0, ret = 0; /* invalid by default */
+	struct gpt_legacy_mbr *pmbr = NULL;
+	uint32_t sz_lba = 0;
+
+	if (!cxt->firstsector)
+		goto done;
+
+	pmbr = (struct gpt_legacy_mbr *) cxt->firstsector;
+
+	if (le16_to_cpu(pmbr->signature) != MSDOS_MBR_SIGNATURE)
+		goto done;
+
+	/* LBA of the GPT partition header */
+	if (pmbr->partition_record[0].starting_lba !=
+	    cpu_to_le32(GPT_PRIMARY_PARTITION_TABLE_LBA))
+		goto done;
+
+	/* seems like a valid MBR was found, check DOS primary partitions */
+	for (i = 0; i < 4; i++) {
+		if (pmbr->partition_record[i].os_type == EFI_PMBR_OSTYPE) {
+			/*
+			 * Ok, we at least know that there's a protective MBR,
+			 * now check if there are other partition types for
+			 * hybrid MBR.
+			 */
+			part = i;
+			ret = GPT_MBR_PROTECTIVE;
+			goto check_hybrid;
+		}
+	}
+
+	if (ret != GPT_MBR_PROTECTIVE)
+		goto done;
+check_hybrid:
+	for (i = 0 ; i < 4; i++) {
+		if ((pmbr->partition_record[i].os_type != EFI_PMBR_OSTYPE) &&
+		    (pmbr->partition_record[i].os_type != 0x00))
+			ret = GPT_MBR_HYBRID;
+	}
+
+	/*
+	 * Protective MBRs take up the lesser of the whole disk
+	 * or 2 TiB (32bit LBA), ignoring the rest of the disk.
+	 * Some partitioning programs, nonetheless, choose to set
+	 * the size to the maximum 32-bit limitation, disregarding
+	 * the disk size.
+	 *
+	 * Hybrid MBRs do not necessarily comply with this.
+	 *
+	 * Consider a bad value here to be a warning to support dd-ing
+	 * an image from a smaller disk to a bigger disk.
+	 */
+	if (ret == GPT_MBR_PROTECTIVE) {
+		sz_lba = le32_to_cpu(pmbr->partition_record[part].size_in_lba);
+		if (sz_lba != (uint32_t) cxt->total_sectors - 1 && sz_lba != 0xFFFFFFFF) {
+			fdisk_warnx(cxt, _("GPT PMBR size mismatch (%u != %u) "
+					   "will be corrected by w(rite)."),
+					sz_lba,
+					(uint32_t) cxt->total_sectors - 1);
+			fdisk_label_set_changed(cxt->label, 1);
+		}
+	}
+done:
+	return ret;
+}
+
+static uint64_t last_lba(struct fdisk_context *cxt)
+{
+	struct stat s;
+	uint64_t sectors = 0;
+
+	memset(&s, 0, sizeof(s));
+	if (fstat(cxt->dev_fd, &s) == -1) {
+		fdisk_warn(cxt, _("gpt: stat() failed"));
+		return 0;
+	}
+
+	if (S_ISBLK(s.st_mode))
+		sectors = cxt->total_sectors - 1;
+	else if (S_ISREG(s.st_mode))
+		sectors = ((uint64_t) s.st_size /
+			   (uint64_t) cxt->sector_size) - 1ULL;
+	else
+		fdisk_warnx(cxt, _("gpt: cannot handle files with mode %o"), s.st_mode);
+
+	DBG(LABEL, ul_debug("GPT last LBA: %ju", sectors));
+	return sectors;
+}
+
+static ssize_t read_lba(struct fdisk_context *cxt, uint64_t lba,
+			void *buffer, const size_t bytes)
+{
+	off_t offset = lba * cxt->sector_size;
+
+	if (lseek(cxt->dev_fd, offset, SEEK_SET) == (off_t) -1)
+		return -1;
+	return read(cxt->dev_fd, buffer, bytes) != bytes;
+}
+
+
+/* Returns the GPT entry array */
+static struct gpt_entry *gpt_read_entries(struct fdisk_context *cxt,
+					 struct gpt_header *header)
+{
+	ssize_t sz;
+	struct gpt_entry *ret = NULL;
+	off_t offset;
+
+	assert(cxt);
+	assert(header);
+
+	sz = le32_to_cpu(header->npartition_entries) *
+	     le32_to_cpu(header->sizeof_partition_entry);
+
+	ret = calloc(1, sz);
+	if (!ret)
+		return NULL;
+	offset = le64_to_cpu(header->partition_entry_lba) *
+		       cxt->sector_size;
+
+	if (offset != lseek(cxt->dev_fd, offset, SEEK_SET))
+		goto fail;
+	if (sz != read(cxt->dev_fd, ret, sz))
+		goto fail;
+
+	return ret;
+
+fail:
+	free(ret);
+	return NULL;
+}
+
+static inline uint32_t count_crc32(const unsigned char *buf, size_t len)
+{
+	return (crc32(~0L, buf, len) ^ ~0L);
+}
+
+/*
+ * Recompute header and partition array 32bit CRC checksums.
+ * This function does not fail - if there's corruption, then it
+ * will be reported when checksuming it again (ie: probing or verify).
+ */
+static void gpt_recompute_crc(struct gpt_header *header, struct gpt_entry *ents)
+{
+	uint32_t crc = 0;
+	size_t entry_sz = 0;
+
+	if (!header)
+		return;
+
+	/* header CRC */
+	header->crc32 = 0;
+	crc = count_crc32((unsigned char *) header, le32_to_cpu(header->size));
+	header->crc32 = cpu_to_le32(crc);
+
+	/* partition entry array CRC */
+	header->partition_entry_array_crc32 = 0;
+	entry_sz = le32_to_cpu(header->npartition_entries) *
+		le32_to_cpu(header->sizeof_partition_entry);
+
+	crc = count_crc32((unsigned char *) ents, entry_sz);
+	header->partition_entry_array_crc32 = cpu_to_le32(crc);
+}
+
+/*
+ * Compute the 32bit CRC checksum of the partition table header.
+ * Returns 1 if it is valid, otherwise 0.
+ */
+static int gpt_check_header_crc(struct gpt_header *header, struct gpt_entry *ents)
+{
+	uint32_t crc, orgcrc = le32_to_cpu(header->crc32);
+
+	header->crc32 = 0;
+	crc = count_crc32((unsigned char *) header, le32_to_cpu(header->size));
+	header->crc32 = cpu_to_le32(orgcrc);
+
+	if (crc == le32_to_cpu(header->crc32))
+		return 1;
+
+	/*
+	 * If we have checksum mismatch it may be due to stale data,
+	 * like a partition being added or deleted. Recompute the CRC again
+	 * and make sure this is not the case.
+	 */
+	if (ents) {
+		gpt_recompute_crc(header, ents);
+		orgcrc = le32_to_cpu(header->crc32);
+		header->crc32 = 0;
+		crc = count_crc32((unsigned char *) header, le32_to_cpu(header->size));
+		header->crc32 = cpu_to_le32(orgcrc);
+
+		return crc == le32_to_cpu(header->crc32);
+	}
+
+	return 0;
+}
+
+/*
+ * It initializes the partition entry array.
+ * Returns 1 if the checksum is valid, otherwise 0.
+ */
+static int gpt_check_entryarr_crc(struct gpt_header *header,
+				  struct gpt_entry *ents)
+{
+	int ret = 0;
+	ssize_t entry_sz;
+	uint32_t crc;
+
+	if (!header || !ents)
+		goto done;
+
+	entry_sz = le32_to_cpu(header->npartition_entries) *
+		   le32_to_cpu(header->sizeof_partition_entry);
+
+	if (!entry_sz)
+		goto done;
+
+	crc = count_crc32((unsigned char *) ents, entry_sz);
+	ret = (crc == le32_to_cpu(header->partition_entry_array_crc32));
+done:
+	return ret;
+}
+
+static int gpt_check_lba_sanity(struct fdisk_context *cxt, struct gpt_header *header)
+{
+	int ret = 0;
+	uint64_t lu, fu, lastlba = last_lba(cxt);
+
+	fu = le64_to_cpu(header->first_usable_lba);
+	lu = le64_to_cpu(header->last_usable_lba);
+
+	/* check if first and last usable LBA make sense */
+	if (lu < fu) {
+		DBG(LABEL, ul_debug("error: header last LBA is before first LBA"));
+		goto done;
+	}
+
+	/* check if first and last usable LBAs with the disk's last LBA */
+	if (fu > lastlba || lu > lastlba) {
+		DBG(LABEL, ul_debug("error: header LBAs are after the disk's last LBA"));
+		goto done;
+	}
+
+	/* the header has to be outside usable range */
+	if (fu < GPT_PRIMARY_PARTITION_TABLE_LBA &&
+	    GPT_PRIMARY_PARTITION_TABLE_LBA < lu) {
+		DBG(LABEL, ul_debug("error: header outside of usable range"));
+		goto done;
+	}
+
+	ret = 1; /* sane */
+done:
+	return ret;
+}
+
+/* Check if there is a valid header signature */
+static int gpt_check_signature(struct gpt_header *header)
+{
+	return header->signature == cpu_to_le64(GPT_HEADER_SIGNATURE);
+}
+
+/*
+ * Return the specified GPT Header, or NULL upon failure/invalid.
+ * Note that all tests must pass to ensure a valid header,
+ * we do not rely on only testing the signature for a valid probe.
+ */
+static struct gpt_header *gpt_read_header(struct fdisk_context *cxt,
+					  uint64_t lba,
+					  struct gpt_entry **_ents)
+{
+	struct gpt_header *header = NULL;
+	struct gpt_entry *ents = NULL;
+	uint32_t hsz;
+
+	if (!cxt)
+		return NULL;
+
+	header = calloc(1, sizeof(*header));
+	if (!header)
+		return NULL;
+
+	/* read and verify header */
+	if (read_lba(cxt, lba, header, sizeof(struct gpt_header)) != 0)
+		goto invalid;
+
+	if (!gpt_check_signature(header))
+		goto invalid;
+
+	if (!gpt_check_header_crc(header, NULL))
+		goto invalid;
+
+	/* read and verify entries */
+	ents = gpt_read_entries(cxt, header);
+	if (!ents)
+		goto invalid;
+
+	if (!gpt_check_entryarr_crc(header, ents))
+		goto invalid;
+
+	if (!gpt_check_lba_sanity(cxt, header))
+		goto invalid;
+
+	/* valid header must be at MyLBA */
+	if (le64_to_cpu(header->my_lba) != lba)
+		goto invalid;
+
+	/* make sure header size is between 92 and sector size bytes */
+	hsz = le32_to_cpu(header->size);
+	if (hsz < GPT_HEADER_MINSZ || hsz > cxt->sector_size)
+		goto invalid;
+
+	if (_ents)
+		*_ents = ents;
+	else
+		free(ents);
+
+	DBG(LABEL, ul_debug("found valid GPT Header on LBA %ju", lba));
+	return header;
+invalid:
+	free(header);
+	free(ents);
+
+	DBG(LABEL, ul_debug("read GPT Header on LBA %ju failed", lba));
+	return NULL;
+}
+
+
+static int gpt_locate_disklabel(struct fdisk_context *cxt, int n,
+		const char **name, off_t *offset, size_t *size)
+{
+	struct fdisk_gpt_label *gpt;
+
+	assert(cxt);
+
+	*name = NULL;
+	*offset = 0;
+	*size = 0;
+
+	switch (n) {
+	case 0:
+		*name = "PMBR";
+		*offset = 0;
+		*size = 512;
+		break;
+	case 1:
+		*name = _("GPT Header");
+		*offset = GPT_PRIMARY_PARTITION_TABLE_LBA * cxt->sector_size;
+		*size = sizeof(struct gpt_header);
+		break;
+	case 2:
+		*name = _("GPT Entries");
+		gpt = self_label(cxt);
+		*offset = le64_to_cpu(gpt->pheader->partition_entry_lba) * cxt->sector_size;
+		*size = le32_to_cpu(gpt->pheader->npartition_entries) *
+			 le32_to_cpu(gpt->pheader->sizeof_partition_entry);
+		break;
+	default:
+		return 1;			/* no more chunks */
+	}
+
+	return 0;
+}
+
+
+
+/*
+ * Returns the number of partitions that are in use.
+ */
+static unsigned partitions_in_use(struct gpt_header *header,
+				  struct gpt_entry *ents)
+{
+	uint32_t i, used = 0;
+
+	if (!header || ! ents)
+		return 0;
+
+	for (i = 0; i < le32_to_cpu(header->npartition_entries); i++)
+		if (!partition_unused(&ents[i]))
+			used++;
+	return used;
+}
+
+
+/*
+ * Check if a partition is too big for the disk (sectors).
+ * Returns the faulting partition number, otherwise 0.
+ */
+static uint32_t check_too_big_partitions(struct gpt_header *header,
+				   struct gpt_entry *ents, uint64_t sectors)
+{
+	uint32_t i;
+
+	for (i = 0; i < le32_to_cpu(header->npartition_entries); i++) {
+		if (partition_unused(&ents[i]))
+			continue;
+		if (gpt_partition_end(&ents[i]) >= sectors)
+			return i + 1;
+	}
+
+	return 0;
+}
+
+/*
+ * Check if a partition ends before it begins
+ * Returns the faulting partition number, otherwise 0.
+ */
+static uint32_t check_start_after_end_paritions(struct gpt_header *header,
+						struct gpt_entry *ents)
+{
+	uint32_t i;
+
+	for (i = 0; i < le32_to_cpu(header->npartition_entries); i++) {
+		if (partition_unused(&ents[i]))
+			continue;
+		if (gpt_partition_start(&ents[i]) > gpt_partition_end(&ents[i]))
+			return i + 1;
+	}
+
+	return 0;
+}
+
+/*
+ * Check if partition e1 overlaps with partition e2.
+ */
+static inline int partition_overlap(struct gpt_entry *e1, struct gpt_entry *e2)
+{
+	uint64_t start1 = gpt_partition_start(e1);
+	uint64_t end1   = gpt_partition_end(e1);
+	uint64_t start2 = gpt_partition_start(e2);
+	uint64_t end2   = gpt_partition_end(e2);
+
+	return (start1 && start2 && (start1 <= end2) != (end1 < start2));
+}
+
+/*
+ * Find any partitions that overlap.
+ */
+static uint32_t check_overlap_partitions(struct gpt_header *header,
+					 struct gpt_entry *ents)
+{
+	uint32_t i, j;
+
+	for (i = 0; i < le32_to_cpu(header->npartition_entries); i++)
+		for (j = 0; j < i; j++) {
+			if (partition_unused(&ents[i]) ||
+			    partition_unused(&ents[j]))
+				continue;
+			if (partition_overlap(&ents[i], &ents[j])) {
+				DBG(LABEL, ul_debug("GPT partitions overlap detected [%u vs. %u]", i, j));
+				return i + 1;
+			}
+		}
+
+	return 0;
+}
+
+/*
+ * Find the first available block after the starting point; returns 0 if
+ * there are no available blocks left, or error. From gdisk.
+ */
+static uint64_t find_first_available(struct gpt_header *header,
+				     struct gpt_entry *ents, uint64_t start)
+{
+	uint64_t first;
+	uint32_t i, first_moved = 0;
+
+	uint64_t fu, lu;
+
+	if (!header || !ents)
+		return 0;
+
+	fu = le64_to_cpu(header->first_usable_lba);
+	lu = le64_to_cpu(header->last_usable_lba);
+
+	/*
+	 * Begin from the specified starting point or from the first usable
+	 * LBA, whichever is greater...
+	 */
+	first = start < fu ? fu : start;
+
+	/*
+	 * Now search through all partitions; if first is within an
+	 * existing partition, move it to the next sector after that
+	 * partition and repeat. If first was moved, set firstMoved
+	 * flag; repeat until firstMoved is not set, so as to catch
+	 * cases where partitions are out of sequential order....
+	 */
+	do {
+		first_moved = 0;
+		for (i = 0; i < le32_to_cpu(header->npartition_entries); i++) {
+			if (partition_unused(&ents[i]))
+				continue;
+			if (first < gpt_partition_start(&ents[i]))
+				continue;
+			if (first <= gpt_partition_end(&ents[i])) {
+				first = gpt_partition_end(&ents[i]) + 1;
+				first_moved = 1;
+			}
+		}
+	} while (first_moved == 1);
+
+	if (first > lu)
+		first = 0;
+
+	return first;
+}
+
+
+/* Returns last available sector in the free space pointed to by start. From gdisk. */
+static uint64_t find_last_free(struct gpt_header *header,
+			       struct gpt_entry *ents, uint64_t start)
+{
+	uint32_t i;
+	uint64_t nearest_start;
+
+	if (!header || !ents)
+		return 0;
+
+	nearest_start = le64_to_cpu(header->last_usable_lba);
+
+	for (i = 0; i < le32_to_cpu(header->npartition_entries); i++) {
+		uint64_t ps = gpt_partition_start(&ents[i]);
+
+		if (nearest_start > ps && ps > start)
+			nearest_start = ps - 1;
+	}
+
+	return nearest_start;
+}
+
+/* Returns the last free sector on the disk. From gdisk. */
+static uint64_t find_last_free_sector(struct gpt_header *header,
+				      struct gpt_entry *ents)
+{
+	uint32_t i, last_moved;
+	uint64_t last = 0;
+
+	if (!header || !ents)
+		goto done;
+
+	/* start by assuming the last usable LBA is available */
+	last = le64_to_cpu(header->last_usable_lba);
+	do {
+		last_moved = 0;
+		for (i = 0; i < le32_to_cpu(header->npartition_entries); i++) {
+			if ((last >= gpt_partition_start(&ents[i])) &&
+			    (last <= gpt_partition_end(&ents[i]))) {
+				last = gpt_partition_start(&ents[i]) - 1;
+				last_moved = 1;
+			}
+		}
+	} while (last_moved == 1);
+done:
+	return last;
+}
+
+/*
+ * Finds the first available sector in the largest block of unallocated
+ * space on the disk. Returns 0 if there are no available blocks left.
+ * From gdisk.
+ */
+static uint64_t find_first_in_largest(struct gpt_header *header,
+				      struct gpt_entry *ents)
+{
+	uint64_t start = 0, first_sect, last_sect;
+	uint64_t segment_size, selected_size = 0, selected_segment = 0;
+
+	if (!header || !ents)
+		goto done;
+
+	do {
+		first_sect =  find_first_available(header, ents, start);
+		if (first_sect != 0) {
+			last_sect = find_last_free(header, ents, first_sect);
+			segment_size = last_sect - first_sect + 1;
+
+			if (segment_size > selected_size) {
+				selected_size = segment_size;
+				selected_segment = first_sect;
+			}
+			start = last_sect + 1;
+		}
+	} while (first_sect != 0);
+
+done:
+	return selected_segment;
+}
+
+/*
+ * Find the total number of free sectors, the number of segments in which
+ * they reside, and the size of the largest of those segments. From gdisk.
+ */
+static uint64_t get_free_sectors(struct fdisk_context *cxt, struct gpt_header *header,
+				 struct gpt_entry *ents, uint32_t *nsegments,
+				 uint64_t *largest_segment)
+{
+	uint32_t num = 0;
+	uint64_t first_sect, last_sect;
+	uint64_t largest_seg = 0, segment_sz;
+	uint64_t totfound = 0, start = 0; /* starting point for each search */
+
+	if (!cxt->total_sectors)
+		goto done;
+
+	do {
+		first_sect = find_first_available(header, ents, start);
+		if (first_sect) {
+			last_sect = find_last_free(header, ents, first_sect);
+			segment_sz = last_sect - first_sect + 1;
+
+			if (segment_sz > largest_seg)
+				largest_seg = segment_sz;
+			totfound += segment_sz;
+			num++;
+			start = last_sect + 1;
+		}
+	} while (first_sect);
+
+done:
+	if (nsegments)
+		*nsegments = num;
+	if (largest_segment)
+		*largest_segment = largest_seg;
+
+	return totfound;
+}
+
+static int gpt_probe_label(struct fdisk_context *cxt)
+{
+	int mbr_type;
+	struct fdisk_gpt_label *gpt;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, GPT));
+
+	gpt = self_label(cxt);
+
+	/* TODO: it would be nice to support scenario when GPT headers are OK,
+	 *       but PMBR is corrupt */
+	mbr_type = valid_pmbr(cxt);
+	if (!mbr_type)
+		goto failed;
+
+	DBG(LABEL, ul_debug("found a %s MBR", mbr_type == GPT_MBR_PROTECTIVE ?
+			    "protective" : "hybrid"));
+
+	/* primary header */
+	gpt->pheader = gpt_read_header(cxt, GPT_PRIMARY_PARTITION_TABLE_LBA,
+				       &gpt->ents);
+
+	if (gpt->pheader)
+		/* primary OK, try backup from alternative LBA */
+		gpt->bheader = gpt_read_header(cxt,
+					le64_to_cpu(gpt->pheader->alternative_lba),
+					NULL);
+	else
+		/* primary corrupted -- try last LBA */
+		gpt->bheader = gpt_read_header(cxt, last_lba(cxt), &gpt->ents);
+
+	if (!gpt->pheader && !gpt->bheader)
+		goto failed;
+
+	/* primary OK, backup corrupted -- recovery */
+	if (gpt->pheader && !gpt->bheader) {
+		fdisk_warnx(cxt, _("The backup GPT table is corrupt, but the "
+				  "primary appears OK, so that will be used."));
+		gpt->bheader = gpt_copy_header(cxt, gpt->pheader);
+		if (!gpt->bheader)
+			goto failed;
+		gpt_recompute_crc(gpt->bheader, gpt->ents);
+
+	/* primary corrupted, backup OK -- recovery */
+	} else if (!gpt->pheader && gpt->bheader) {
+		fdisk_warnx(cxt, _("The primary GPT table is corrupt, but the "
+				  "backup appears OK, so that will be used."));
+		gpt->pheader = gpt_copy_header(cxt, gpt->bheader);
+		if (!gpt->pheader)
+			goto failed;
+		gpt_recompute_crc(gpt->pheader, gpt->ents);
+	}
+
+	cxt->label->nparts_max = le32_to_cpu(gpt->pheader->npartition_entries);
+	cxt->label->nparts_cur = partitions_in_use(gpt->pheader, gpt->ents);
+	return 1;
+failed:
+	DBG(LABEL, ul_debug("GPT probe failed"));
+	gpt_deinit(cxt->label);
+	return 0;
+}
+
+/*
+ * Stolen from libblkid - can be removed once partition semantics
+ * are added to the fdisk API.
+ */
+static char *encode_to_utf8(unsigned char *src, size_t count)
+{
+	uint16_t c;
+	char *dest;
+	size_t i, j, len = count;
+
+	dest = calloc(1, count);
+	if (!dest)
+		return NULL;
+
+	for (j = i = 0; i + 2 <= count; i += 2) {
+		/* always little endian */
+		c = (src[i+1] << 8) | src[i];
+		if (c == 0) {
+			dest[j] = '\0';
+			break;
+		} else if (c < 0x80) {
+			if (j+1 >= len)
+				break;
+			dest[j++] = (uint8_t) c;
+		} else if (c < 0x800) {
+			if (j+2 >= len)
+				break;
+			dest[j++] = (uint8_t) (0xc0 | (c >> 6));
+			dest[j++] = (uint8_t) (0x80 | (c & 0x3f));
+		} else {
+			if (j+3 >= len)
+				break;
+			dest[j++] = (uint8_t) (0xe0 | (c >> 12));
+			dest[j++] = (uint8_t) (0x80 | ((c >> 6) & 0x3f));
+			dest[j++] = (uint8_t) (0x80 | (c & 0x3f));
+		}
+	}
+	dest[j] = '\0';
+
+	return dest;
+}
+
+static int gpt_entry_attrs_to_string(struct gpt_entry *e, char **res)
+{
+	unsigned int n, count = 0;
+	size_t l;
+	char *bits, *p;
+	uint64_t attrs;
+
+	assert(e);
+	assert(res);
+
+	*res = NULL;
+	attrs = le64_to_cpu(e->attrs);
+	if (!attrs)
+		return 0;	/* no attributes at all */
+
+	bits = (char *) &attrs;
+
+	/* Note that sizeof() is correct here, we need separators between
+	 * the strings so also count \0 is correct */
+	*res = calloc(1, sizeof(GPT_ATTRSTR_NOBLOCK) +
+			 sizeof(GPT_ATTRSTR_REQ) +
+			 sizeof(GPT_ATTRSTR_LEGACY) +
+			 sizeof("GUID:") + (GPT_ATTRBIT_GUID_COUNT * 3));
+	if (!*res)
+		return -errno;
+
+	p = *res;
+	if (isset(bits, GPT_ATTRBIT_REQ)) {
+		memcpy(p, GPT_ATTRSTR_REQ, (l = sizeof(GPT_ATTRSTR_REQ)));
+		p += l - 1;
+	}
+	if (isset(bits, GPT_ATTRBIT_NOBLOCK)) {
+		if (p > *res)
+			*p++ = ' ';
+		memcpy(p, GPT_ATTRSTR_NOBLOCK, (l = sizeof(GPT_ATTRSTR_NOBLOCK)));
+		p += l - 1;
+	}
+	if (isset(bits, GPT_ATTRBIT_LEGACY)) {
+		if (p > *res)
+			*p++ = ' ';
+		memcpy(p, GPT_ATTRSTR_LEGACY, (l = sizeof(GPT_ATTRSTR_LEGACY)));
+		p += l - 1;
+	}
+
+	for (n = GPT_ATTRBIT_GUID_FIRST;
+	     n < GPT_ATTRBIT_GUID_FIRST + GPT_ATTRBIT_GUID_COUNT; n++) {
+
+		if (!isset(bits, n))
+			continue;
+		if (!count) {
+			if (p > *res)
+				*p++ = ' ';
+			p += sprintf(p, "GUID:%u", n);
+		} else
+			p += sprintf(p, ",%u", n);
+		count++;
+	}
+
+	return 0;
+}
+
+static int gpt_entry_attrs_from_string(
+			struct fdisk_context *cxt,
+			struct gpt_entry *e,
+			const char *str)
+{
+	const char *p = str;
+	uint64_t attrs = 0;
+	char *bits;
+
+	assert(e);
+	assert(p);
+
+	DBG(LABEL, ul_debug("GPT: parsing string attributes '%s'", p));
+
+	bits = (char *) &attrs;
+
+	while (p && *p) {
+		int bit = -1;
+
+		while (isblank(*p)) p++;
+		if (!*p)
+			break;
+
+		DBG(LABEL, ul_debug(" parsing item '%s'", p));
+
+		if (strncmp(p, "GUID:", 5) == 0) {
+			p += 5;
+			continue;
+		} else if (strncmp(p, GPT_ATTRSTR_REQ,
+					sizeof(GPT_ATTRSTR_REQ) - 1) == 0) {
+			bit = GPT_ATTRBIT_REQ;
+			p += sizeof(GPT_ATTRSTR_REQ) - 1;
+		} else if (strncmp(p, GPT_ATTRSTR_LEGACY,
+					sizeof(GPT_ATTRSTR_LEGACY) - 1) == 0) {
+			bit = GPT_ATTRBIT_LEGACY;
+			p += sizeof(GPT_ATTRSTR_LEGACY) - 1;
+		} else if (strncmp(p, GPT_ATTRSTR_NOBLOCK,
+					sizeof(GPT_ATTRSTR_NOBLOCK) - 1) == 0) {
+			bit = GPT_ATTRBIT_NOBLOCK;
+			p += sizeof(GPT_ATTRSTR_NOBLOCK) - 1;
+		} else if (isdigit((unsigned int) *p)) {
+			char *end = NULL;
+
+			errno = 0;
+			bit = strtol(p, &end, 0);
+			if (errno || !end || end == str
+			    || bit < GPT_ATTRBIT_GUID_FIRST
+			    || bit >= GPT_ATTRBIT_GUID_FIRST + GPT_ATTRBIT_GUID_COUNT)
+				bit = -1;
+			else
+				p = end;
+		}
+
+		if (bit < 0) {
+			fdisk_warnx(cxt, _("unssuported GPT attribute bit '%s'"), p);
+			return -EINVAL;
+		}
+
+		setbit(bits, bit);
+
+		while (isblank(*p)) p++;
+		if (*p == ',')
+			p++;
+	}
+
+	e->attrs = cpu_to_le64(attrs);
+	return 0;
+}
+
+static int gpt_get_partition(struct fdisk_context *cxt, size_t n,
+			     struct fdisk_partition *pa)
+{
+	struct fdisk_gpt_label *gpt;
+	struct gpt_entry *e;
+	char u_str[37];
+	int rc = 0;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, GPT));
+
+	gpt = self_label(cxt);
+
+	if ((uint32_t) n >= le32_to_cpu(gpt->pheader->npartition_entries))
+		return -EINVAL;
+
+	gpt = self_label(cxt);
+	e = &gpt->ents[n];
+
+	pa->used = !partition_unused(e) || gpt_partition_start(e);
+	if (!pa->used)
+		return 0;
+
+	pa->start = gpt_partition_start(e);
+	pa->size = gpt_partition_size(e);
+	pa->type = gpt_partition_parttype(cxt, e);
+
+	if (guid_to_string(&e->partition_guid, u_str)) {
+		pa->uuid = strdup(u_str);
+		if (!pa->uuid) {
+			rc = -errno;
+			goto done;
+		}
+	} else
+		pa->uuid = NULL;
+
+	rc = gpt_entry_attrs_to_string(e, &pa->attrs);
+	if (rc)
+		goto done;
+
+	pa->name = encode_to_utf8((unsigned char *)e->name, sizeof(e->name));
+	return 0;
+done:
+	fdisk_reset_partition(pa);
+	return rc;
+}
+
+
+static int gpt_set_partition(struct fdisk_context *cxt, size_t n,
+			     struct fdisk_partition *pa)
+{
+	struct fdisk_gpt_label *gpt;
+	struct gpt_entry *e;
+	int rc = 0;
+	uint64_t start, end;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, GPT));
+
+	gpt = self_label(cxt);
+
+	if ((uint32_t) n >= le32_to_cpu(gpt->pheader->npartition_entries))
+		return -EINVAL;
+
+	FDISK_INIT_UNDEF(start);
+	FDISK_INIT_UNDEF(end);
+
+	gpt = self_label(cxt);
+	e = &gpt->ents[n];
+
+	if (pa->uuid) {
+		char new_u[37], old_u[37];
+
+		guid_to_string(&e->partition_guid, old_u);
+		rc = gpt_entry_set_uuid(e, pa->uuid);
+		if (rc)
+			return rc;
+		guid_to_string(&e->partition_guid, new_u);
+		fdisk_info(cxt, _("Partition UUID changed from %s to %s."),
+			old_u, new_u);
+	}
+
+	if (pa->name) {
+		char *old = encode_to_utf8((unsigned char *)e->name, sizeof(e->name));
+		gpt_entry_set_name(e, pa->name);
+
+		fdisk_info(cxt, _("Partition name changed from '%s' to '%.*s'."),
+			old, (int) GPT_PART_NAME_LEN, pa->name);
+		free(old);
+	}
+
+	if (pa->type && pa->type->typestr) {
+		struct gpt_guid typeid;
+
+		rc = string_to_guid(pa->type->typestr, &typeid);
+		if (rc)
+			return rc;
+		gpt_entry_set_type(e, &typeid);
+	}
+	if (pa->attrs) {
+		rc = gpt_entry_attrs_from_string(cxt, e, pa->attrs);
+		if (rc)
+			return rc;
+	}
+
+	if (fdisk_partition_has_start(pa))
+		start = pa->start;
+	if (fdisk_partition_has_size(pa))
+		end = gpt_partition_start(e) + pa->size - 1ULL;
+
+	if (pa->end_follow_default) {
+		/* enlarge */
+		if (!FDISK_IS_UNDEF(start))
+			start = gpt_partition_start(e);
+		end = find_last_free(gpt->bheader, gpt->ents, start);
+		if (!end)
+			FDISK_INIT_UNDEF(end);
+	}
+
+	if (!FDISK_IS_UNDEF(start))
+		e->lba_start = cpu_to_le64(start);
+	if (!FDISK_IS_UNDEF(end))
+		e->lba_end = cpu_to_le64(end);
+
+	gpt_recompute_crc(gpt->pheader, gpt->ents);
+	gpt_recompute_crc(gpt->bheader, gpt->ents);
+
+	fdisk_label_set_changed(cxt->label, 1);
+	return rc;
+}
+
+
+/*
+ * List label partitions.
+ */
+static int gpt_list_disklabel(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, GPT));
+
+	if (fdisk_is_details(cxt)) {
+		struct gpt_header *h = self_label(cxt)->pheader;
+
+		fdisk_info(cxt, _("First LBA: %ju"), h->first_usable_lba);
+		fdisk_info(cxt, _("Last LBA: %ju"), h->last_usable_lba);
+		/* TRANSLATORS: The LBA (Logical Block Address) of the backup GPT header. */
+		fdisk_info(cxt, _("Alternative LBA: %ju"), h->alternative_lba);
+		/* TRANSLATORS: The start of the array of partition entries. */
+		fdisk_info(cxt, _("Partition entries LBA: %ju"), h->partition_entry_lba);
+		fdisk_info(cxt, _("Allocated partition entries: %u"), h->npartition_entries);
+	}
+
+	return 0;
+}
+
+/*
+ * Write partitions.
+ * Returns 0 on success, or corresponding error otherwise.
+ */
+static int gpt_write_partitions(struct fdisk_context *cxt,
+				struct gpt_header *header, struct gpt_entry *ents)
+{
+	off_t offset = le64_to_cpu(header->partition_entry_lba) * cxt->sector_size;
+	uint32_t nparts = le32_to_cpu(header->npartition_entries);
+	uint32_t totwrite = nparts * le32_to_cpu(header->sizeof_partition_entry);
+	ssize_t rc;
+
+	if (offset != lseek(cxt->dev_fd, offset, SEEK_SET))
+		goto fail;
+
+	rc = write(cxt->dev_fd, ents, totwrite);
+	if (rc > 0 && totwrite == (uint32_t) rc)
+		return 0;
+fail:
+	return -errno;
+}
+
+/*
+ * Write a GPT header to a specified LBA
+ * Returns 0 on success, or corresponding error otherwise.
+ */
+static int gpt_write_header(struct fdisk_context *cxt,
+			    struct gpt_header *header, uint64_t lba)
+{
+	off_t offset = lba * cxt->sector_size;
+
+	if (offset != lseek(cxt->dev_fd, offset, SEEK_SET))
+		goto fail;
+	if (cxt->sector_size ==
+	    (size_t) write(cxt->dev_fd, header, cxt->sector_size))
+		return 0;
+fail:
+	return -errno;
+}
+
+/*
+ * Write the protective MBR.
+ * Returns 0 on success, or corresponding error otherwise.
+ */
+static int gpt_write_pmbr(struct fdisk_context *cxt)
+{
+	off_t offset;
+	struct gpt_legacy_mbr *pmbr = NULL;
+
+	assert(cxt);
+	assert(cxt->firstsector);
+
+	pmbr = (struct gpt_legacy_mbr *) cxt->firstsector;
+
+	/* zero out the legacy partitions */
+	memset(pmbr->partition_record, 0, sizeof(pmbr->partition_record));
+
+	pmbr->signature = cpu_to_le16(MSDOS_MBR_SIGNATURE);
+	pmbr->partition_record[0].os_type      = EFI_PMBR_OSTYPE;
+	pmbr->partition_record[0].start_sector = 1;
+	pmbr->partition_record[0].end_head     = 0xFE;
+	pmbr->partition_record[0].end_sector   = 0xFF;
+	pmbr->partition_record[0].end_track    = 0xFF;
+	pmbr->partition_record[0].starting_lba = cpu_to_le32(1);
+
+	/*
+	 * Set size_in_lba to the size of the disk minus one. If the size of the disk
+	 * is too large to be represented by a 32bit LBA (2Tb), set it to 0xFFFFFFFF.
+	 */
+	if (cxt->total_sectors - 1 > 0xFFFFFFFFULL)
+		pmbr->partition_record[0].size_in_lba = cpu_to_le32(0xFFFFFFFF);
+	else
+		pmbr->partition_record[0].size_in_lba =
+			cpu_to_le32(cxt->total_sectors - 1UL);
+
+	offset = GPT_PMBR_LBA * cxt->sector_size;
+	if (offset != lseek(cxt->dev_fd, offset, SEEK_SET))
+		goto fail;
+
+	/* pMBR covers the first sector (LBA) of the disk */
+	if (write_all(cxt->dev_fd, pmbr, cxt->sector_size))
+		goto fail;
+	return 0;
+fail:
+	return -errno;
+}
+
+/*
+ * Writes in-memory GPT and pMBR data to disk.
+ * Returns 0 if successful write, otherwise, a corresponding error.
+ * Any indication of error will abort the operation.
+ */
+static int gpt_write_disklabel(struct fdisk_context *cxt)
+{
+	struct fdisk_gpt_label *gpt;
+	int mbr_type;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, GPT));
+
+	gpt = self_label(cxt);
+	mbr_type = valid_pmbr(cxt);
+
+	/* check that disk is big enough to handle the backup header */
+	if (le64_to_cpu(gpt->pheader->alternative_lba) > cxt->total_sectors)
+		goto err0;
+
+	/* check that the backup header is properly placed */
+	if (le64_to_cpu(gpt->pheader->alternative_lba) < cxt->total_sectors - 1)
+		/* TODO: correct this (with user authorization) and write */
+		goto err0;
+
+	if (check_overlap_partitions(gpt->pheader, gpt->ents))
+		goto err0;
+
+	/* recompute CRCs for both headers */
+	gpt_recompute_crc(gpt->pheader, gpt->ents);
+	gpt_recompute_crc(gpt->bheader, gpt->ents);
+
+	/*
+	 * UEFI requires writing in this specific order:
+	 *   1) backup partition tables
+	 *   2) backup GPT header
+	 *   3) primary partition tables
+	 *   4) primary GPT header
+	 *   5) protective MBR
+	 *
+	 * If any write fails, we abort the rest.
+	 */
+	if (gpt_write_partitions(cxt, gpt->bheader, gpt->ents) != 0)
+		goto err1;
+	if (gpt_write_header(cxt, gpt->bheader,
+			     le64_to_cpu(gpt->pheader->alternative_lba)) != 0)
+		goto err1;
+	if (gpt_write_partitions(cxt, gpt->pheader, gpt->ents) != 0)
+		goto err1;
+	if (gpt_write_header(cxt, gpt->pheader, GPT_PRIMARY_PARTITION_TABLE_LBA) != 0)
+		goto err1;
+
+	if (mbr_type == GPT_MBR_HYBRID)
+		fdisk_warnx(cxt, _("The device contains hybrid MBR -- writing GPT only. "
+				   "You have to sync the MBR manually."));
+	else if (gpt_write_pmbr(cxt) != 0)
+		goto err1;
+
+	DBG(LABEL, ul_debug("GPT write success"));
+	return 0;
+err0:
+	DBG(LABEL, ul_debug("GPT write failed: incorrect input"));
+	errno = EINVAL;
+	return -EINVAL;
+err1:
+	DBG(LABEL, ul_debug("GPT write failed: %m"));
+	return -errno;
+}
+
+/*
+ * Verify data integrity and report any found problems for:
+ *   - primary and backup header validations
+ *   - paritition validations
+ */
+static int gpt_verify_disklabel(struct fdisk_context *cxt)
+{
+	int nerror = 0;
+	unsigned int ptnum;
+	struct fdisk_gpt_label *gpt;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, GPT));
+
+	gpt = self_label(cxt);
+
+	if (!gpt || !gpt->bheader) {
+		nerror++;
+		fdisk_warnx(cxt, _("Disk does not contain a valid backup header."));
+	}
+
+	if (!gpt_check_header_crc(gpt->pheader, gpt->ents)) {
+		nerror++;
+		fdisk_warnx(cxt, _("Invalid primary header CRC checksum."));
+	}
+	if (gpt->bheader && !gpt_check_header_crc(gpt->bheader, gpt->ents)) {
+		nerror++;
+		fdisk_warnx(cxt, _("Invalid backup header CRC checksum."));
+	}
+
+	if (!gpt_check_entryarr_crc(gpt->pheader, gpt->ents)) {
+		nerror++;
+		fdisk_warnx(cxt, _("Invalid partition entry checksum."));
+	}
+
+	if (!gpt_check_lba_sanity(cxt, gpt->pheader)) {
+		nerror++;
+		fdisk_warnx(cxt, _("Invalid primary header LBA sanity checks."));
+	}
+	if (gpt->bheader && !gpt_check_lba_sanity(cxt, gpt->bheader)) {
+		nerror++;
+		fdisk_warnx(cxt, _("Invalid backup header LBA sanity checks."));
+	}
+
+	if (le64_to_cpu(gpt->pheader->my_lba) != GPT_PRIMARY_PARTITION_TABLE_LBA) {
+		nerror++;
+		fdisk_warnx(cxt, _("MyLBA mismatch with real position at primary header."));
+	}
+	if (gpt->bheader && le64_to_cpu(gpt->bheader->my_lba) != last_lba(cxt)) {
+		nerror++;
+		fdisk_warnx(cxt, _("MyLBA mismatch with real position at backup header."));
+
+	}
+	if (le64_to_cpu(gpt->pheader->alternative_lba) >= cxt->total_sectors) {
+		nerror++;
+		fdisk_warnx(cxt, _("Disk is too small to hold all data."));
+	}
+
+	/*
+	 * if the GPT is the primary table, check the alternateLBA
+	 * to see if it is a valid GPT
+	 */
+	if (gpt->bheader && (le64_to_cpu(gpt->pheader->my_lba) !=
+			     le64_to_cpu(gpt->bheader->alternative_lba))) {
+		nerror++;
+		fdisk_warnx(cxt, _("Primary and backup header mismatch."));
+	}
+
+	ptnum = check_overlap_partitions(gpt->pheader, gpt->ents);
+	if (ptnum) {
+		nerror++;
+		fdisk_warnx(cxt, _("Partition %u overlaps with partition %u."),
+				ptnum, ptnum+1);
+	}
+
+	ptnum = check_too_big_partitions(gpt->pheader, gpt->ents, cxt->total_sectors);
+	if (ptnum) {
+		nerror++;
+		fdisk_warnx(cxt, _("Partition %u is too big for the disk."),
+				ptnum);
+	}
+
+	ptnum = check_start_after_end_paritions(gpt->pheader, gpt->ents);
+	if (ptnum) {
+		nerror++;
+		fdisk_warnx(cxt, _("Partition %u ends before it starts."),
+				ptnum);
+	}
+
+	if (!nerror) { /* yay :-) */
+		uint32_t nsegments = 0;
+		uint64_t free_sectors = 0, largest_segment = 0;
+		char *strsz = NULL;
+
+		fdisk_info(cxt, _("No errors detected."));
+		fdisk_info(cxt, _("Header version: %s"), gpt_get_header_revstr(gpt->pheader));
+		fdisk_info(cxt, _("Using %u out of %d partitions."),
+		       partitions_in_use(gpt->pheader, gpt->ents),
+		       le32_to_cpu(gpt->pheader->npartition_entries));
+
+		free_sectors = get_free_sectors(cxt, gpt->pheader, gpt->ents,
+						&nsegments, &largest_segment);
+		if (largest_segment)
+			strsz = size_to_human_string(SIZE_SUFFIX_SPACE | SIZE_SUFFIX_3LETTER,
+					largest_segment * cxt->sector_size);
+
+		fdisk_info(cxt,
+			   P_("A total of %ju free sectors is available in %u segment.",
+			      "A total of %ju free sectors is available in %u segments "
+			      "(the largest is %s).", nsegments),
+			   free_sectors, nsegments, strsz);
+		free(strsz);
+
+	} else
+		fdisk_warnx(cxt,
+			P_("%d error detected.", "%d errors detected.", nerror),
+			nerror);
+
+	return 0;
+}
+
+/* Delete a single GPT partition, specified by partnum. */
+static int gpt_delete_partition(struct fdisk_context *cxt,
+				size_t partnum)
+{
+	struct fdisk_gpt_label *gpt;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, GPT));
+
+	gpt = self_label(cxt);
+
+	if (partnum >= cxt->label->nparts_max
+	    ||  partition_unused(&gpt->ents[partnum]))
+		return -EINVAL;
+
+	/* hasta la vista, baby! */
+	memset(&gpt->ents[partnum], 0, sizeof(struct gpt_entry));
+	if (!partition_unused(&gpt->ents[partnum]))
+		return -EINVAL;
+	else {
+		gpt_recompute_crc(gpt->pheader, gpt->ents);
+		gpt_recompute_crc(gpt->bheader, gpt->ents);
+		cxt->label->nparts_cur--;
+		fdisk_label_set_changed(cxt->label, 1);
+	}
+
+	return 0;
+}
+
+
+/* Performs logical checks to add a new partition entry */
+static int gpt_add_partition(
+		struct fdisk_context *cxt,
+		struct fdisk_partition *pa,
+		size_t *partno)
+{
+	uint64_t user_f, user_l;	/* user input ranges for first and last sectors */
+	uint64_t disk_f, disk_l;	/* first and last available sector ranges on device*/
+	uint64_t dflt_f, dflt_l;	/* largest segment (default) */
+	struct gpt_guid typeid;
+	struct fdisk_gpt_label *gpt;
+	struct gpt_header *pheader;
+	struct gpt_entry *e, *ents;
+	struct fdisk_ask *ask = NULL;
+	size_t partnum;
+	int rc;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, GPT));
+
+	gpt = self_label(cxt);
+	pheader = gpt->pheader;
+	ents = gpt->ents;
+
+	rc = fdisk_partition_next_partno(pa, cxt, &partnum);
+	if (rc) {
+		DBG(LABEL, ul_debug("GPT failed to get next partno"));
+		return rc;
+	}
+	if (!partition_unused(&ents[partnum])) {
+		fdisk_warnx(cxt, _("Partition %zu is already defined.  "
+			           "Delete it before re-adding it."), partnum +1);
+		return -ERANGE;
+	}
+	if (le32_to_cpu(pheader->npartition_entries) ==
+			partitions_in_use(pheader, ents)) {
+		fdisk_warnx(cxt, _("All partitions are already in use."));
+		return -ENOSPC;
+	}
+	if (!get_free_sectors(cxt, pheader, ents, NULL, NULL)) {
+		fdisk_warnx(cxt, _("No free sectors available."));
+		return -ENOSPC;
+	}
+
+	string_to_guid(pa && pa->type && pa->type->typestr ?
+				pa->type->typestr:
+				GPT_DEFAULT_ENTRY_TYPE, &typeid);
+
+	disk_f = find_first_available(pheader, ents, pheader->first_usable_lba);
+
+	/* if first sector no explicitly defined then ignore small gaps before
+	 * the first partition */
+	if ((!pa || !fdisk_partition_has_start(pa))
+	    && !partition_unused(&ents[0])
+	    && disk_f < gpt_partition_start(&ents[0])) {
+
+		do {
+			uint64_t x;
+			DBG(LABEL, ul_debug("testing first sector %ju", disk_f));
+			disk_f = find_first_available(pheader, ents, disk_f);
+			if (!disk_f)
+				break;
+			x = find_last_free(pheader, ents, disk_f);
+			if (x - disk_f >= cxt->grain / cxt->sector_size)
+				break;
+			DBG(LABEL, ul_debug("first sector %ju addresses to small space, continue...", disk_f));
+			disk_f = x + 1;
+		} while(1);
+
+		if (disk_f == 0)
+			disk_f = find_first_available(pheader, ents, pheader->first_usable_lba);
+	}
+
+	disk_l = find_last_free_sector(pheader, ents);
+
+	/* the default is the largest free space */
+	dflt_f = find_first_in_largest(pheader, ents);
+	dflt_l = find_last_free(pheader, ents, dflt_f);
+
+	/* align the default in range <dflt_f,dflt_l>*/
+	dflt_f = fdisk_align_lba_in_range(cxt, dflt_f, dflt_f, dflt_l);
+
+	/* first sector */
+	if (pa && pa->start_follow_default) {
+		user_f = dflt_f;
+
+	} else if (pa && fdisk_partition_has_start(pa)) {
+		DBG(LABEL, ul_debug("first sector defined: %ju", pa->start));
+		if (pa->start != find_first_available(pheader, ents, pa->start)) {
+			fdisk_warnx(cxt, _("Sector %ju already used."), pa->start);
+			return -ERANGE;
+		}
+		user_f = pa->start;
+	} else {
+		/*  ask by dialog */
+		for (;;) {
+			if (!ask)
+				ask = fdisk_new_ask();
+			else
+				fdisk_reset_ask(ask);
+
+			/* First sector */
+			fdisk_ask_set_query(ask, _("First sector"));
+			fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER);
+			fdisk_ask_number_set_low(ask,     disk_f);	/* minimal */
+			fdisk_ask_number_set_default(ask, dflt_f);	/* default */
+			fdisk_ask_number_set_high(ask,    disk_l);	/* maximal */
+
+			rc = fdisk_do_ask(cxt, ask);
+			if (rc)
+				goto done;
+
+			user_f = fdisk_ask_number_get_result(ask);
+			if (user_f != find_first_available(pheader, ents, user_f)) {
+				fdisk_warnx(cxt, _("Sector %ju already used."), user_f);
+				continue;
+			}
+			break;
+		}
+	}
+
+
+	/* Last sector */
+	dflt_l = find_last_free(pheader, ents, user_f);
+
+	if (pa && pa->end_follow_default) {
+		user_l = dflt_l;
+
+	} else if (pa && fdisk_partition_has_size(pa)) {
+		user_l = user_f + pa->size - 1;
+		DBG(LABEL, ul_debug("size defined: %ju, end: %ju (last possible: %ju)",
+					pa->size, user_l, dflt_l));
+		if (user_l != dflt_l && !pa->size_explicit)
+			user_l = fdisk_align_lba_in_range(cxt, user_l, user_f, dflt_l) - 1;
+
+	} else {
+		for (;;) {
+			if (!ask)
+				ask = fdisk_new_ask();
+			else
+				fdisk_reset_ask(ask);
+
+			fdisk_ask_set_query(ask, _("Last sector, +sectors or +size{K,M,G,T,P}"));
+			fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET);
+			fdisk_ask_number_set_low(ask,     user_f);	/* minimal */
+			fdisk_ask_number_set_default(ask, dflt_l);	/* default */
+			fdisk_ask_number_set_high(ask,    dflt_l);	/* maximal */
+			fdisk_ask_number_set_base(ask,    user_f);	/* base for relative input */
+			fdisk_ask_number_set_unit(ask,    cxt->sector_size);
+
+			rc = fdisk_do_ask(cxt, ask);
+			if (rc)
+				goto done;
+
+			user_l = fdisk_ask_number_get_result(ask);
+			if (fdisk_ask_number_is_relative(ask)) {
+				user_l = fdisk_align_lba_in_range(cxt, user_l, user_f, dflt_l) - 1;
+
+				/* no space for anything useful, use all space
+				if (user_l + (cxt->grain / cxt->sector_size) > dflt_l)
+					user_l = dflt_l;
+				*/
+			}
+
+			if (user_l > user_f && user_l <= disk_l)
+				break;
+		}
+	}
+
+
+	if (user_f > user_l || partnum >= cxt->label->nparts_max) {
+		fdisk_warnx(cxt, _("Could not create partition %zu"), partnum + 1);
+		rc = -EINVAL;
+		goto done;
+	}
+
+	assert(!FDISK_IS_UNDEF(user_l));
+	assert(!FDISK_IS_UNDEF(user_f));
+
+	e = &ents[partnum];
+	e->lba_end = cpu_to_le64(user_l);
+	e->lba_start = cpu_to_le64(user_f);
+
+	gpt_entry_set_type(e, &typeid);
+
+	if (pa && pa->uuid) {
+		/* Sometimes it's necessary to create a copy of the PT and
+		 * reuse already defined UUID
+		 */
+		rc = gpt_entry_set_uuid(e, pa->uuid);
+		if (rc)
+			goto done;
+	} else {
+		/* Any time a new partition entry is created a new GUID must be
+		 * generated for that partition, and every partition is guaranteed
+		 * to have a unique GUID.
+		 */
+		uuid_generate_random((unsigned char *) &e->partition_guid);
+		swap_efi_guid(&e->partition_guid);
+	}
+
+	if (pa && pa->name && *pa->name)
+		gpt_entry_set_name(e, pa->name);
+	if (pa && pa->attrs)
+		gpt_entry_attrs_from_string(cxt, e, pa->attrs);
+
+	DBG(LABEL, ul_debug("GPT new partition: partno=%zu, start=%ju, end=%ju, size=%ju",
+				partnum,
+				gpt_partition_start(e),
+				gpt_partition_end(e),
+				gpt_partition_size(e)));
+
+	gpt_recompute_crc(gpt->pheader, ents);
+	gpt_recompute_crc(gpt->bheader, ents);
+
+	/* report result */
+	{
+		struct fdisk_parttype *t;
+
+		cxt->label->nparts_cur++;
+		fdisk_label_set_changed(cxt->label, 1);
+
+		t = gpt_partition_parttype(cxt, &ents[partnum]);
+		fdisk_info_new_partition(cxt, partnum + 1, user_f, user_l, t);
+		fdisk_unref_parttype(t);
+	}
+
+	rc = 0;
+	if (partno)
+		*partno = partnum;
+done:
+	fdisk_unref_ask(ask);
+	return rc;
+}
+
+/*
+ * Create a new GPT disklabel - destroys any previous data.
+ */
+static int gpt_create_disklabel(struct fdisk_context *cxt)
+{
+	int rc = 0;
+	ssize_t esz = 0;
+	char str[37];
+	struct fdisk_gpt_label *gpt;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, GPT));
+
+	gpt = self_label(cxt);
+
+	/* label private stuff has to be empty, see gpt_deinit() */
+	assert(gpt->pheader == NULL);
+	assert(gpt->bheader == NULL);
+
+	/*
+	 * When no header, entries or pmbr is set, we're probably
+	 * dealing with a new, empty disk - so always allocate memory
+	 * to deal with the data structures whatever the case is.
+	 */
+	rc = gpt_mknew_pmbr(cxt);
+	if (rc < 0)
+		goto done;
+
+	/* primary */
+	gpt->pheader = calloc(1, sizeof(*gpt->pheader));
+	if (!gpt->pheader) {
+		rc = -ENOMEM;
+		goto done;
+	}
+	rc = gpt_mknew_header(cxt, gpt->pheader, GPT_PRIMARY_PARTITION_TABLE_LBA);
+	if (rc < 0)
+		goto done;
+
+	/* backup ("copy" primary) */
+	gpt->bheader = calloc(1, sizeof(*gpt->bheader));
+	if (!gpt->bheader) {
+		rc = -ENOMEM;
+		goto done;
+	}
+	rc = gpt_mknew_header_from_bkp(cxt, gpt->bheader,
+			last_lba(cxt), gpt->pheader);
+	if (rc < 0)
+		goto done;
+
+	esz = le32_to_cpu(gpt->pheader->npartition_entries) *
+	      le32_to_cpu(gpt->pheader->sizeof_partition_entry);
+	gpt->ents = calloc(1, esz);
+	if (!gpt->ents) {
+		rc = -ENOMEM;
+		goto done;
+	}
+	gpt_recompute_crc(gpt->pheader, gpt->ents);
+	gpt_recompute_crc(gpt->bheader, gpt->ents);
+
+	cxt->label->nparts_max = le32_to_cpu(gpt->pheader->npartition_entries);
+	cxt->label->nparts_cur = 0;
+
+	guid_to_string(&gpt->pheader->disk_guid, str);
+	fdisk_label_set_changed(cxt->label, 1);
+	fdisk_info(cxt, _("Created a new GPT disklabel (GUID: %s)."), str);
+done:
+	return rc;
+}
+
+static int gpt_get_disklabel_id(struct fdisk_context *cxt, char **id)
+{
+	struct fdisk_gpt_label *gpt;
+	char str[37];
+
+	assert(cxt);
+	assert(id);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, GPT));
+
+	gpt = self_label(cxt);
+	guid_to_string(&gpt->pheader->disk_guid, str);
+
+	*id = strdup(str);
+	if (!*id)
+		return -ENOMEM;
+	return 0;
+}
+
+static int gpt_set_disklabel_id(struct fdisk_context *cxt)
+{
+	struct fdisk_gpt_label *gpt;
+	struct gpt_guid uuid;
+	char *str, *old, *new;
+	int rc;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, GPT));
+
+	gpt = self_label(cxt);
+	if (fdisk_ask_string(cxt,
+			_("Enter new disk UUID (in 8-4-4-4-12 format)"), &str))
+		return -EINVAL;
+
+	rc = string_to_guid(str, &uuid);
+	free(str);
+
+	if (rc) {
+		fdisk_warnx(cxt, _("Failed to parse your UUID."));
+		return rc;
+	}
+
+	gpt_get_disklabel_id(cxt, &old);
+
+	gpt->pheader->disk_guid = uuid;
+	gpt->bheader->disk_guid = uuid;
+
+	gpt_recompute_crc(gpt->pheader, gpt->ents);
+	gpt_recompute_crc(gpt->bheader, gpt->ents);
+
+	gpt_get_disklabel_id(cxt, &new);
+
+	fdisk_info(cxt, _("Disk identifier changed from %s to %s."), old, new);
+
+	free(old);
+	free(new);
+	fdisk_label_set_changed(cxt->label, 1);
+	return 0;
+}
+
+static int gpt_part_is_used(struct fdisk_context *cxt, size_t i)
+{
+	struct fdisk_gpt_label *gpt;
+	struct gpt_entry *e;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, GPT));
+
+	gpt = self_label(cxt);
+
+	if ((uint32_t) i >= le32_to_cpu(gpt->pheader->npartition_entries))
+		return 0;
+	e = &gpt->ents[i];
+
+	return !partition_unused(e) || gpt_partition_start(e);
+}
+
+/**
+ * fdisk_gpt_is_hybrid:
+ * @cxt: context
+ *
+ * The regular GPT contains PMBR (dummy protective MBR) where the protective
+ * MBR does not address any partitions.
+ *
+ * Hybrid GPT contains regular MBR where this partition table addresses the
+ * same partitions as GPT. It's recommended to not use hybrid GPT due to MBR
+ * limits.
+ *
+ * The libfdisk does not provide functionality to sync GPT and MBR, you have to
+ * directly access and modify (P)MBR (see fdisk_new_nested_context()).
+ *
+ * Returns: 1 if partition table detected as hybrid otherwise return 0
+ */
+int fdisk_gpt_is_hybrid(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	return valid_pmbr(cxt) == GPT_MBR_HYBRID;
+}
+
+static int gpt_toggle_partition_flag(
+		struct fdisk_context *cxt,
+		size_t i,
+		unsigned long flag)
+{
+	struct fdisk_gpt_label *gpt;
+	uint64_t attrs, tmp;
+	char *bits;
+	const char *name = NULL;
+	int bit = -1, rc;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, GPT));
+
+	DBG(LABEL, ul_debug("GPT entry attribute change requested partno=%zu", i));
+	gpt = self_label(cxt);
+
+	if ((uint32_t) i >= le32_to_cpu(gpt->pheader->npartition_entries))
+		return -EINVAL;
+
+	attrs = le64_to_cpu(gpt->ents[i].attrs);
+	bits = (char *) &attrs;
+
+	switch (flag) {
+	case GPT_FLAG_REQUIRED:
+		bit = GPT_ATTRBIT_REQ;
+		name = GPT_ATTRSTR_REQ;
+		break;
+	case GPT_FLAG_NOBLOCK:
+		bit = GPT_ATTRBIT_NOBLOCK;
+		name = GPT_ATTRSTR_NOBLOCK;
+		break;
+	case GPT_FLAG_LEGACYBOOT:
+		bit = GPT_ATTRBIT_LEGACY;
+		name = GPT_ATTRSTR_LEGACY;
+		break;
+	case GPT_FLAG_GUIDSPECIFIC:
+		rc = fdisk_ask_number(cxt, 48, 48, 63, _("Enter GUID specific bit"), &tmp);
+		if (rc)
+			return rc;
+		bit = tmp;
+		break;
+	default:
+		/* already specified PT_FLAG_GUIDSPECIFIC bit */
+		if (flag >= 48 && flag <= 63) {
+			bit = flag;
+			flag = GPT_FLAG_GUIDSPECIFIC;
+		}
+		break;
+	}
+
+	if (bit < 0) {
+		fdisk_warnx(cxt, _("failed to toggle unsupported bit %lu"), flag);
+		return -EINVAL;
+	}
+
+	if (!isset(bits, bit))
+		setbit(bits, bit);
+	else
+		clrbit(bits, bit);
+
+	gpt->ents[i].attrs = cpu_to_le64(attrs);
+
+	if (flag == GPT_FLAG_GUIDSPECIFIC)
+		fdisk_info(cxt, isset(bits, bit) ?
+			_("The GUID specific bit %d on partition %zu is enabled now.") :
+			_("The GUID specific bit %d on partition %zu is disabled now."),
+			bit, i + 1);
+	else
+		fdisk_info(cxt, isset(bits, bit) ?
+			_("The %s flag on partition %zu is enabled now.") :
+			_("The %s flag on partition %zu is disabled now."),
+			name, i + 1);
+
+	gpt_recompute_crc(gpt->pheader, gpt->ents);
+	gpt_recompute_crc(gpt->bheader, gpt->ents);
+	fdisk_label_set_changed(cxt->label, 1);
+	return 0;
+}
+
+static int gpt_entry_cmp_start(const void *a, const void *b)
+{
+	struct gpt_entry *ae = (struct gpt_entry *) a,
+			 *be = (struct gpt_entry *) b;
+	int au = partition_unused(ae),
+	    bu = partition_unused(be);
+
+	if (au && bu)
+		return 0;
+	if (au)
+		return 1;
+	if (bu)
+		return -1;
+
+	return cmp_numbers(gpt_partition_start(ae), gpt_partition_start(be));
+}
+
+/* sort partition by start sector */
+static int gpt_reorder(struct fdisk_context *cxt)
+{
+	struct fdisk_gpt_label *gpt;
+	size_t nparts;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, GPT));
+
+	gpt = self_label(cxt);
+	nparts = le32_to_cpu(gpt->pheader->npartition_entries);
+
+	qsort(gpt->ents, nparts, sizeof(struct gpt_entry),
+			gpt_entry_cmp_start);
+
+	gpt_recompute_crc(gpt->pheader, gpt->ents);
+	gpt_recompute_crc(gpt->bheader, gpt->ents);
+	fdisk_label_set_changed(cxt->label, 1);
+
+	fdisk_info(cxt, _("Done."));
+	return 0;
+}
+
+static int gpt_reset_alignment(struct fdisk_context *cxt)
+{
+	struct fdisk_gpt_label *gpt;
+	struct gpt_header *h;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, GPT));
+
+	gpt = self_label(cxt);
+	h = gpt ? gpt->pheader : NULL;
+
+	if (h) {
+		/* always follow existing table */
+		cxt->first_lba = h->first_usable_lba;
+		cxt->last_lba  = h->last_usable_lba;
+	} else {
+		/* estimate ranges for GPT */
+		uint64_t first, last;
+
+		count_first_last_lba(cxt, &first, &last);
+
+		if (cxt->first_lba < first)
+			cxt->first_lba = first;
+		if (cxt->last_lba > last)
+			cxt->last_lba = last;
+	}
+
+	return 0;
+}
+/*
+ * Deinitialize fdisk-specific variables
+ */
+static void gpt_deinit(struct fdisk_label *lb)
+{
+	struct fdisk_gpt_label *gpt = (struct fdisk_gpt_label *) lb;
+
+	if (!gpt)
+		return;
+
+	free(gpt->ents);
+	free(gpt->pheader);
+	free(gpt->bheader);
+
+	gpt->ents = NULL;
+	gpt->pheader = NULL;
+	gpt->bheader = NULL;
+}
+
+static const struct fdisk_label_operations gpt_operations =
+{
+	.probe		= gpt_probe_label,
+	.write		= gpt_write_disklabel,
+	.verify		= gpt_verify_disklabel,
+	.create		= gpt_create_disklabel,
+	.list		= gpt_list_disklabel,
+	.locate		= gpt_locate_disklabel,
+	.reorder	= gpt_reorder,
+	.get_id		= gpt_get_disklabel_id,
+	.set_id		= gpt_set_disklabel_id,
+
+	.get_part	= gpt_get_partition,
+	.set_part	= gpt_set_partition,
+	.add_part	= gpt_add_partition,
+	.del_part	= gpt_delete_partition,
+
+	.part_is_used	= gpt_part_is_used,
+	.part_toggle_flag = gpt_toggle_partition_flag,
+
+	.deinit		= gpt_deinit,
+
+	.reset_alignment = gpt_reset_alignment
+};
+
+static const struct fdisk_field gpt_fields[] =
+{
+	/* basic */
+	{ FDISK_FIELD_DEVICE,	N_("Device"),	 10,	0 },
+	{ FDISK_FIELD_START,	N_("Start"),	  5,	FDISK_FIELDFL_NUMBER },
+	{ FDISK_FIELD_END,	N_("End"),	  5,	FDISK_FIELDFL_NUMBER },
+	{ FDISK_FIELD_SECTORS,	N_("Sectors"),	  5,	FDISK_FIELDFL_NUMBER },
+	{ FDISK_FIELD_SIZE,	N_("Size"),	  5,	FDISK_FIELDFL_NUMBER | FDISK_FIELDFL_EYECANDY },
+	{ FDISK_FIELD_TYPE,	N_("Type"),	0.1,	FDISK_FIELDFL_EYECANDY },
+	/* expert */
+	{ FDISK_FIELD_TYPEID,	N_("Type-UUID"), 36,	FDISK_FIELDFL_DETAIL },
+	{ FDISK_FIELD_UUID,	N_("UUID"),	 36,	FDISK_FIELDFL_DETAIL },
+	{ FDISK_FIELD_NAME,	N_("Name"),	0.2,	FDISK_FIELDFL_DETAIL },
+	{ FDISK_FIELD_ATTR,	N_("Attrs"),	  0,	FDISK_FIELDFL_DETAIL }
+};
+
+/*
+ * allocates GPT in-memory stuff
+ */
+struct fdisk_label *fdisk_new_gpt_label(struct fdisk_context *cxt)
+{
+	struct fdisk_label *lb;
+	struct fdisk_gpt_label *gpt;
+
+	assert(cxt);
+
+	gpt = calloc(1, sizeof(*gpt));
+	if (!gpt)
+		return NULL;
+
+	/* initialize generic part of the driver */
+	lb = (struct fdisk_label *) gpt;
+	lb->name = "gpt";
+	lb->id = FDISK_DISKLABEL_GPT;
+	lb->op = &gpt_operations;
+	lb->parttypes = gpt_parttypes;
+	lb->nparttypes = ARRAY_SIZE(gpt_parttypes);
+
+	lb->fields = gpt_fields;
+	lb->nfields = ARRAY_SIZE(gpt_fields);
+
+	return lb;
+}
diff --git a/libblkid/libfdisk/src/init.c b/libblkid/libfdisk/src/init.c
new file mode 100644
index 0000000..61acb0a
--- /dev/null
+++ b/libblkid/libfdisk/src/init.c
@@ -0,0 +1,55 @@
+
+#include "fdiskP.h"
+
+
+/**
+ * SECTION: init
+ * @title: Library initialization
+ * @short_description: initialize debug stuff
+ *
+ */
+
+UL_DEBUG_DEFINE_MASK(libfdisk);
+UL_DEBUG_DEFINE_MASKNAMES(libfdisk) =
+{
+	{ "all",	LIBFDISK_DEBUG_ALL,	"info about all subsystems" },
+	{ "ask",	LIBFDISK_DEBUG_ASK,	"fdisk dialogs" },
+	{ "help",	LIBFDISK_DEBUG_HELP,	"this help" },
+	{ "cxt",	LIBFDISK_DEBUG_CXT,	"library context (handler)" },
+	{ "label",	LIBFDISK_DEBUG_LABEL,	"disk label utils" },
+	{ "part",	LIBFDISK_DEBUG_PART,	"partition utils" },
+	{ "parttype",	LIBFDISK_DEBUG_PARTTYPE,"partition type utils" },
+	{ "script",	LIBFDISK_DEBUG_SCRIPT,	"sfdisk-like scripts" },
+	{ "tab",	LIBFDISK_DEBUG_TAB,	"table utils"},
+	{ NULL, 0 }
+};
+
+/**
+ * fdisk_init_debug:
+ * @mask: debug mask (0xffff to enable full debuging)
+ *
+ * If the @mask is not specified then this function reads
+ * LIBFDISK_DEBUG environment variable to get the mask.
+ *
+ * Already initialized debugging stuff cannot be changed. It does not
+ * have effect to call this function twice.
+ *
+ * It's strongly recommended to use fdisk_init_debug(0) in your code.
+ */
+void fdisk_init_debug(int mask)
+{
+	if (libfdisk_debug_mask)
+		return;
+
+	__UL_INIT_DEBUG(libfdisk, LIBFDISK_DEBUG_, mask, LIBFDISK_DEBUG);
+
+
+	if (libfdisk_debug_mask != LIBFDISK_DEBUG_INIT
+	    && libfdisk_debug_mask != (LIBFDISK_DEBUG_HELP|LIBFDISK_DEBUG_INIT)) {
+
+		DBG(INIT, ul_debug("library debug mask: 0x%04x", libfdisk_debug_mask));
+	}
+
+	ON_DBG(HELP, ul_debug_print_masks("LIBFDISK_DEBUG",
+				UL_DEBUG_MASKNAMES(libfdisk)));
+}
diff --git a/libblkid/libfdisk/src/iter.c b/libblkid/libfdisk/src/iter.c
new file mode 100644
index 0000000..9a0b080
--- /dev/null
+++ b/libblkid/libfdisk/src/iter.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+/**
+ * SECTION: iter
+ * @title: Iterator
+ * @short_description: unified iterator
+ *
+ * The iterator keeps the direction and the last position for access to the
+ * internal library tables/lists.
+ *
+ * It's very unusual to use the same iterator on multiple places in your
+ * application or share the same iterator, for this purpose libfdisk does not
+ * provide reference counting for this object. It's recommended to initialize
+ * the iterator by fdisk_new_iter() at begin of your function and then
+ * fdisk_free_iter() before you return from the function. 
+ *
+ * Don't forget to call fdisk_reset_iter() if you want to use the iterator more
+ * than once.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "fdiskP.h"
+
+/**
+ * fdisk_new_iter:
+ * @direction: FDISK_INTER_{FOR,BACK}WARD direction
+ *
+ * Returns: newly allocated generic libmount iterator.
+ */
+struct fdisk_iter *fdisk_new_iter(int direction)
+{
+	struct fdisk_iter *itr = calloc(1, sizeof(*itr));
+	if (!itr)
+		return NULL;
+	itr->direction = direction;
+	return itr;
+}
+
+/**
+ * fdisk_free_iter:
+ * @itr: iterator pointer
+ *
+ * Deallocates the iterator.
+ */
+void fdisk_free_iter(struct fdisk_iter *itr)
+{
+	free(itr);
+}
+
+/**
+ * fdisk_reset_iter:
+ * @itr: iterator pointer
+ * @direction: FDISK_INTER_{FOR,BACK}WARD or -1 to keep the direction unchanged
+ *
+ * Resets the iterator.
+ */
+void fdisk_reset_iter(struct fdisk_iter *itr, int direction)
+{
+	if (direction == -1)
+		direction = itr->direction;
+
+	memset(itr, 0, sizeof(*itr));
+	itr->direction = direction;
+}
+
+/**
+ * fdisk_iter_get_direction:
+ * @itr: iterator pointer
+ *
+ * Returns: FDISK_INTER_{FOR,BACK}WARD
+ */
+int fdisk_iter_get_direction(struct fdisk_iter *itr)
+{
+	return itr->direction;
+}
diff --git a/libblkid/libfdisk/src/label.c b/libblkid/libfdisk/src/label.c
new file mode 100644
index 0000000..750cfca
--- /dev/null
+++ b/libblkid/libfdisk/src/label.c
@@ -0,0 +1,569 @@
+
+#include "fdiskP.h"
+
+
+/**
+ * SECTION: label
+ * @title: Label
+ * @short_description: disk label (PT) specific data and functions
+ *
+ * The fdisk_new_context() initializes all label drivers, and allocate
+ * per-label specific data struct. This concept allows to store label specific
+ * settings to the label driver independently on the currently active label
+ * driver. Note that label struct cannot be deallocated, so there is no
+ * reference counting for fdisk_label objects. All is destroyed by
+ * fdisk_unref_context() only.
+ *
+ * Anyway, all label drives share in-memory first sector. The function
+ * fdisk_create_disklabel() overwrites the sector. But it's possible that
+ * label driver also uses another buffers, for example GPT uses more than only
+ * the first sector.
+ *
+ * All label operations are in-memory only, except fdisk_write_disklabel().
+ *
+ * All functions that use "struct fdisk_context" rather than "struct
+ * fdisk_label" use the currently active label driver.
+ */
+
+
+int fdisk_probe_labels(struct fdisk_context *cxt)
+{
+	size_t i;
+
+	cxt->label = NULL;
+
+	for (i = 0; i < cxt->nlabels; i++) {
+		struct fdisk_label *lb = cxt->labels[i];
+		struct fdisk_label *org = fdisk_get_label(cxt, NULL);
+		int rc;
+
+		if (!lb->op->probe)
+			continue;
+		if (lb->disabled) {
+			DBG(CXT, ul_debugobj(cxt, "%s: disabled -- ignore", lb->name));
+			continue;
+		}
+		DBG(CXT, ul_debugobj(cxt, "probing for %s", lb->name));
+
+		cxt->label = lb;
+		rc = lb->op->probe(cxt);
+		cxt->label = org;
+
+		if (rc != 1) {
+			if (lb->op->deinit)
+				lb->op->deinit(lb);	/* for sure */
+			continue;
+		}
+
+		__fdisk_switch_label(cxt, lb);
+		return 0;
+	}
+
+	DBG(CXT, ul_debugobj(cxt, "no label found"));
+	return 1; /* not found */
+}
+
+/**
+ * fdisk_label_get_name:
+ * @lb: label
+ *
+ * Returns: label name
+ */
+const char *fdisk_label_get_name(const struct fdisk_label *lb)
+{
+	return lb ? lb->name : NULL;
+}
+
+/**
+ * fdisk_label_is_labeltype:
+ * @lb: label
+ *
+ * Returns: FDISK_DISKLABEL_*.
+ */
+int fdisk_label_get_type(const struct fdisk_label *lb)
+{
+	return lb->id;
+}
+
+/**
+ * fdisk_label_require_geometry:
+ * @lb: label
+ *
+ * Returns: 1 if label requires CHS geometry
+ */
+int fdisk_label_require_geometry(const struct fdisk_label *lb)
+{
+	assert(lb);
+
+	return lb->flags & FDISK_LABEL_FL_REQUIRE_GEOMETRY ? 1 : 0;
+}
+
+/**
+ * fdisk_label_get_fields_ids
+ * @lb: label (or NULL for the current label)
+ * @cxt: context
+ * @ids: returns allocated array with FDISK_FIELD_* IDs
+ * @nids: returns number of items in fields
+ *
+ * This function returns the default fields for the label.
+ *
+ * Note that the set of the default fields depends on fdisk_enable_details()
+ * function. If the details are enabled then this function usually returns more
+ * fields.
+ *
+ * Returns: 0 on success, otherwise, a corresponding error.
+ */
+int fdisk_label_get_fields_ids(
+		const struct fdisk_label *lb,
+		struct fdisk_context *cxt,
+		int **ids, size_t *nids)
+{
+	size_t i, n;
+	int *c;
+
+	assert(cxt);
+
+	if (!lb)
+		lb = cxt->label;
+	if (!lb)
+		return -EINVAL;
+	if (!lb->fields || !lb->nfields)
+		return -ENOSYS;
+	c = calloc(lb->nfields, sizeof(int));
+	if (!c)
+		return -ENOMEM;
+	for (n = 0, i = 0; i < lb->nfields; i++) {
+		int id = lb->fields[i].id;
+
+		if ((fdisk_is_details(cxt) &&
+				(lb->fields[i].flags & FDISK_FIELDFL_EYECANDY))
+		     || (!fdisk_is_details(cxt) &&
+				(lb->fields[i].flags & FDISK_FIELDFL_DETAIL))
+		     || (id == FDISK_FIELD_SECTORS &&
+			         fdisk_use_cylinders(cxt))
+		     || (id == FDISK_FIELD_CYLINDERS &&
+			         !fdisk_use_cylinders(cxt)))
+			continue;
+
+		c[n++] = id;
+	}
+	if (ids)
+		*ids = c;
+	else
+		free(c);
+	if (nids)
+		*nids = n;
+	return 0;
+}
+
+/**
+ * fdisk_label_get_field:
+ * @lb: label
+ * @id: FDISK_FIELD_*
+ *
+ * The field struct describes data stored in struct fdisk_partition. The info
+ * about data is usable for example to generate human readable output (e.g.
+ * fdisk 'p'rint command). See fdisk_partition_to_stirng() and fdisk code.
+ *
+ * Returns: pointer to static instance of the field.
+ */
+const struct fdisk_field *fdisk_label_get_field(const struct fdisk_label *lb, int id)
+{
+	size_t i;
+
+	assert(lb);
+	assert(id > 0);
+
+	for (i = 0; i < lb->nfields; i++) {
+		if (lb->fields[i].id == id)
+			return &lb->fields[i];
+	}
+
+	return NULL;
+}
+
+/**
+ * fdisk_label_get_field_by_name
+ * @lb: label
+ * @name: field name
+ *
+ * Returns: pointer to static instance of the field.
+ */
+const struct fdisk_field *fdisk_label_get_field_by_name(
+				const struct fdisk_label *lb,
+				const char *name)
+{
+	size_t i;
+
+	assert(lb);
+	assert(name);
+
+	for (i = 0; i < lb->nfields; i++) {
+		if (lb->fields[i].name && strcasecmp(lb->fields[i].name, name) == 0)
+			return &lb->fields[i];
+	}
+
+	return NULL;
+}
+
+
+/**
+ * fdisk_field_get_id:
+ * @field: field instance
+ *
+ * Returns: field Id (FDISK_FIELD_*)
+ */
+int fdisk_field_get_id(const struct fdisk_field *field)
+{
+	return field ? field->id : -EINVAL;
+}
+
+/**
+ * fdisk_field_get_name:
+ * @field: field instance
+ *
+ * Returns: field name
+ */
+const char *fdisk_field_get_name(const struct fdisk_field *field)
+{
+	return field ? field->name : NULL;
+}
+
+/**
+ * fdisk_field_get_width:
+ * @field: field instance
+ *
+ * Returns: libsmartcols compatible width.
+ */
+double fdisk_field_get_width(const struct fdisk_field *field)
+{
+	return field ? field->width : -EINVAL;
+}
+
+/**
+ * fdisk_field_is_number:
+ * @field: field instance
+ *
+ * Returns: 1 if field represent number
+ */
+int fdisk_field_is_number(const struct fdisk_field *field)
+{
+	return field->flags ? field->flags & FDISK_FIELDFL_NUMBER : 0;
+}
+
+
+/**
+ * fdisk_write_disklabel:
+ * @cxt: fdisk context
+ *
+ * Write in-memory changes to disk. Be careful!
+ *
+ * Returns: 0 on success, otherwise, a corresponding error.
+ */
+int fdisk_write_disklabel(struct fdisk_context *cxt)
+{
+	if (!cxt || !cxt->label || cxt->readonly)
+		return -EINVAL;
+	if (!cxt->label->op->write)
+		return -ENOSYS;
+	return cxt->label->op->write(cxt);
+}
+
+/**
+ * fdisk_verify_disklabel:
+ * @cxt: fdisk context
+ *
+ * Verifies the partition table.
+ *
+ * Returns: 0 on success, otherwise, a corresponding error.
+ */
+int fdisk_verify_disklabel(struct fdisk_context *cxt)
+{
+	if (!cxt || !cxt->label)
+		return -EINVAL;
+	if (!cxt->label->op->verify)
+		return -ENOSYS;
+	if (fdisk_missing_geometry(cxt))
+		return -EINVAL;
+
+	return cxt->label->op->verify(cxt);
+}
+
+/**
+ * fdisk_list_disklabel:
+ * @cxt: fdisk context
+ *
+ * Lists details about disklabel, but no partitions.
+ *
+ * This function uses libfdisk ASK interface to print data. The details about
+ * partitions table are printed by FDISK_ASKTYPE_INFO.
+ *
+ * Returns: 0 on success, otherwise, a corresponding error.
+ */
+int fdisk_list_disklabel(struct fdisk_context *cxt)
+{
+	if (!cxt || !cxt->label)
+		return -EINVAL;
+	if (!cxt->label->op->list)
+		return -ENOSYS;
+
+	return cxt->label->op->list(cxt);
+}
+
+/**
+ * fdisk_create_disklabel:
+ * @cxt: fdisk context
+ * @name: label name
+ *
+ * Creates a new disk label of type @name. If @name is NULL, then it will
+ * create a default system label type, either SUN or DOS. The function
+ * automaticaly switches the current label driver to @name. The function
+ * fdisk_get_label() returns the current label driver.
+ *
+ * The function modifies in-memory data only.
+ *
+ * Returns: 0 on success, otherwise, a corresponding error.
+ */
+int fdisk_create_disklabel(struct fdisk_context *cxt, const char *name)
+{
+	int haslabel = 0;
+	struct fdisk_label *lb;
+
+	if (!cxt)
+		return -EINVAL;
+
+	if (!name) { /* use default label creation */
+#ifdef __sparc__
+		name = "sun";
+#else
+		name = "dos";
+#endif
+	}
+
+	if (cxt->label) {
+		fdisk_deinit_label(cxt->label);
+		haslabel = 1;
+	}
+
+	lb = fdisk_get_label(cxt, name);
+	if (!lb || lb->disabled)
+		return -EINVAL;
+	if (!lb->op->create)
+		return -ENOSYS;
+
+	__fdisk_switch_label(cxt, lb);
+
+	if (haslabel && !cxt->parent)
+		fdisk_reset_device_properties(cxt);
+
+	DBG(CXT, ul_debugobj(cxt, "create a new %s label", lb->name));
+	return cxt->label->op->create(cxt);
+}
+
+/**
+ * fdisk_locate_disklabel:
+ * @cxt: context
+ * @n: N item
+ * @name: return item name
+ * @offset: return offset where is item
+ * @size: of the item
+ *
+ * Locate disklabel and returns info about @n item of the label. For example
+ * GPT is composed from two items, PMBR and GPT, n=0 return offset to PMBR and n=1
+ * return offset to GPT. For more details see 'D' expect fdisk command.
+ *
+ * Returns: 0 on succes, <0 on error, 1 no more items.
+ */
+int fdisk_locate_disklabel(struct fdisk_context *cxt, int n, const char **name,
+			   off_t *offset, size_t *size)
+{
+	if (!cxt || !cxt->label)
+		return -EINVAL;
+	if (!cxt->label->op->locate)
+		return -ENOSYS;
+
+	DBG(CXT, ul_debugobj(cxt, "locating %d chunk of %s.", n, cxt->label->name));
+	return cxt->label->op->locate(cxt, n, name, offset, size);
+}
+
+
+/**
+ * fdisk_get_disklabel_id:
+ * @cxt: fdisk context
+ * @id: returns pointer to allocated string (MBR Id or GPT dirk UUID)
+ *
+ * Returns: 0 on success, otherwise, a corresponding error.
+ */
+int fdisk_get_disklabel_id(struct fdisk_context *cxt, char **id)
+{
+	if (!cxt || !cxt->label)
+		return -EINVAL;
+	if (!cxt->label->op->get_id)
+		return -ENOSYS;
+
+	DBG(CXT, ul_debugobj(cxt, "asking for disk %s ID", cxt->label->name));
+	return cxt->label->op->get_id(cxt, id);
+}
+
+/**
+ * fdisk_set_disklabel_id:
+ * @cxt: fdisk context
+ *
+ * Returns: 0 on success, otherwise, a corresponding error.
+ */
+int fdisk_set_disklabel_id(struct fdisk_context *cxt)
+{
+	if (!cxt || !cxt->label)
+		return -EINVAL;
+	if (!cxt->label->op->set_id)
+		return -ENOSYS;
+
+	DBG(CXT, ul_debugobj(cxt, "setting %s disk ID", cxt->label->name));
+	return cxt->label->op->set_id(cxt);
+}
+
+/**
+ * fdisk_set_partition_type:
+ * @cxt: fdisk context
+ * @partnum: partition number
+ * @t: new type
+ *
+ * Returns: 0 on success, < 0 on error.
+ */
+int fdisk_set_partition_type(struct fdisk_context *cxt,
+			     size_t partnum,
+			     struct fdisk_parttype *t)
+{
+	if (!cxt || !cxt->label || !t)
+		return -EINVAL;
+
+
+	if (cxt->label->op->set_part) {
+		struct fdisk_partition *pa = fdisk_new_partition();
+		int rc;
+
+		if (!pa)
+			return -ENOMEM;
+		fdisk_partition_set_type(pa, t);
+
+		DBG(CXT, ul_debugobj(cxt, "partition: %zd: set type", partnum));
+		rc = cxt->label->op->set_part(cxt, partnum, pa);
+		fdisk_unref_partition(pa);
+		return rc;
+	}
+
+	return -ENOSYS;
+}
+
+
+/**
+ * fdisk_toggle_partition_flag:
+ * @cxt: fdisk context
+ * @partnum: partition number
+ * @flag: flag ID
+ *
+ * Returns: 0 on success, otherwise, a corresponding error.
+ */
+int fdisk_toggle_partition_flag(struct fdisk_context *cxt,
+			       size_t partnum,
+			       unsigned long flag)
+{
+	int rc;
+
+	if (!cxt || !cxt->label)
+		return -EINVAL;
+	if (!cxt->label->op->part_toggle_flag)
+		return -ENOSYS;
+
+	rc = cxt->label->op->part_toggle_flag(cxt, partnum, flag);
+
+	DBG(CXT, ul_debugobj(cxt, "partition: %zd: toggle: 0x%04lx [rc=%d]", partnum, flag, rc));
+	return rc;
+}
+
+/**
+ * fdisk_reorder_partitions
+ * @cxt: fdisk context
+ *
+ * Sort partitions according to the partition start sector.
+ *
+ * Returns: 0 on success, otherwise, a corresponding error.
+ */
+int fdisk_reorder_partitions(struct fdisk_context *cxt)
+{
+	if (!cxt || !cxt->label)
+		return -EINVAL;
+	if (!cxt->label->op->reorder)
+		return -ENOSYS;
+
+	return cxt->label->op->reorder(cxt);
+}
+
+/*
+ * Resets the current used label driver to initial state
+ */
+void fdisk_deinit_label(struct fdisk_label *lb)
+{
+	assert(lb);
+
+	/* private label information */
+	if (lb->op->deinit)
+		lb->op->deinit(lb);
+}
+
+/**
+ * fdisk_label_set_changed:
+ * @lb: label
+ * @changed: 0/1
+ *
+ * Marks in-memory data as changed, to force fdisk_write_disklabel() to write
+ * to device. This should be unnecessar by default, the library keeps track
+ * about changes.
+ */
+void fdisk_label_set_changed(struct fdisk_label *lb, int changed)
+{
+	assert(lb);
+	lb->changed = changed ? 1 : 0;
+}
+
+/**
+ * fdisk_label_is_changed:
+ * @lb: label
+ *
+ * Returns: 1 if in-memory data has been changed.
+ */
+int fdisk_label_is_changed(const struct fdisk_label *lb)
+{
+	assert(lb);
+	return lb ? lb->changed : 0;
+}
+
+/**
+ * fdisk_label_set_disabled:
+ * @lb: label
+ * @disabled: 0 or 1
+ *
+ * Mark label as disabled, then libfdisk is going to ignore the label when
+ * probe device for labels.
+ */
+void fdisk_label_set_disabled(struct fdisk_label *lb, int disabled)
+{
+	assert(lb);
+
+	DBG(LABEL, ul_debug("%s label %s",
+				lb->name,
+				disabled ? "DISABLED" : "ENABLED"));
+	lb->disabled = disabled ? 1 : 0;
+}
+
+/**
+ * fdisk_label_is_disabled:
+ * @lb: label
+ *
+ * Returns: 1 if label driver disabled.
+ */
+int fdisk_label_is_disabled(const struct fdisk_label *lb)
+{
+	assert(lb);
+	return lb ? lb->disabled : 0;
+}
diff --git a/libblkid/libfdisk/src/libfdisk.h b/libblkid/libfdisk/src/libfdisk.h
new file mode 100644
index 0000000..844e17e
--- /dev/null
+++ b/libblkid/libfdisk/src/libfdisk.h
@@ -0,0 +1,579 @@
+/*
+ * libfdisk.h - libfdisk API
+ *
+ * Copyright (C) 2012-2014 Karel Zak <kzak@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _LIBFDISK_H
+#define _LIBFDISK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdint.h>
+
+/**
+ * LIBFDISK_VERSION:
+ *
+ * Library version string
+ */
+#define LIBFDISK_VERSION   "2.25.0"
+
+/**
+ * fdisk_context:
+ *
+ * Basic library handler.
+ */
+struct fdisk_context;
+
+/**
+ * fdisk_label:
+ *
+ * Disk label specific driver and setting.
+ */
+struct fdisk_label;
+
+/**
+ * fdisk_parttype:
+ *
+ * Partition type.
+ */
+struct fdisk_parttype;
+
+/**
+ * fdisk_partition:
+ *
+ * Partition abstraction (and template).
+ */
+struct fdisk_partition;
+
+/**
+ * fdisk_ask:
+ *
+ * Ask API handler for dialogs with users.
+ */
+struct fdisk_ask;
+
+/**
+ * fdisk_iter:
+ *
+ * Unified iterator.
+ */
+struct fdisk_iter;
+
+/**
+ * fdisk_table:
+ *
+ * Container for fdisk_partition objects
+ */
+struct fdisk_table;
+
+/**
+ * fdisk_field
+ *
+ * Output field description.
+ */
+struct fdisk_field;
+
+/**
+ * fdisk_script
+ *
+ * library handler for sfdisk compatible scripts
+ */
+struct fdisk_script;
+
+/**
+ * fdisk_sector_t
+ *
+ * LBA adresses type
+ */
+typedef uint64_t fdisk_sector_t;
+
+/**
+ * fdisk_labeltype:
+ *
+ * Supported partition table types (labels)
+ */
+enum fdisk_labeltype {
+	FDISK_DISKLABEL_DOS = (1 << 1),
+	FDISK_DISKLABEL_SUN = (1 << 2),
+	FDISK_DISKLABEL_SGI = (1 << 3),
+	FDISK_DISKLABEL_BSD = (1 << 4),
+	FDISK_DISKLABEL_GPT = (1 << 5)
+};
+
+/**
+ * fdisk_asktype:
+ *
+ * Ask API dialog types
+ */
+enum fdisk_asktype {
+	FDISK_ASKTYPE_NONE = 0,
+	FDISK_ASKTYPE_NUMBER,
+	FDISK_ASKTYPE_OFFSET,
+	FDISK_ASKTYPE_WARN,
+	FDISK_ASKTYPE_WARNX,
+	FDISK_ASKTYPE_INFO,
+	FDISK_ASKTYPE_YESNO,
+	FDISK_ASKTYPE_STRING,
+	FDISK_ASKTYPE_MENU
+};
+
+/* init.c */
+extern void fdisk_init_debug(int mask);
+
+/* context.h */
+
+#define FDISK_PLURAL	0
+#define FDISK_SINGULAR	1
+
+struct fdisk_context *fdisk_new_context(void);
+struct fdisk_context *fdisk_new_nested_context(struct fdisk_context *parent, const char *name);
+void fdisk_unref_context(struct fdisk_context *cxt);
+void fdisk_ref_context(struct fdisk_context *cxt);
+
+struct fdisk_context *fdisk_get_parent(struct fdisk_context *cxt);
+size_t fdisk_get_npartitions(struct fdisk_context *cxt);
+
+struct fdisk_label *fdisk_get_label(struct fdisk_context *cxt, const char *name);
+int fdisk_next_label(struct fdisk_context *cxt, struct fdisk_label **lb);
+size_t fdisk_get_nlabels(struct fdisk_context *cxt);
+
+int fdisk_has_label(struct fdisk_context *cxt);
+int fdisk_is_labeltype(struct fdisk_context *cxt, enum fdisk_labeltype id);
+#define fdisk_is_label(c, x) fdisk_is_labeltype(c, FDISK_DISKLABEL_ ## x)
+
+
+int fdisk_assign_device(struct fdisk_context *cxt,
+			const char *fname, int readonly);
+int fdisk_deassign_device(struct fdisk_context *cxt, int nosync);
+int fdisk_is_readonly(struct fdisk_context *cxt);
+
+int fdisk_enable_details(struct fdisk_context *cxt, int enable);
+int fdisk_is_details(struct fdisk_context *cxt);
+
+int fdisk_enable_listonly(struct fdisk_context *cxt, int enable);
+int fdisk_is_listonly(struct fdisk_context *cxt);
+
+int fdisk_set_unit(struct fdisk_context *cxt, const char *str);
+const char *fdisk_get_unit(struct fdisk_context *cxt, int n);
+int fdisk_use_cylinders(struct fdisk_context *cxt);
+unsigned int fdisk_get_units_per_sector(struct fdisk_context *cxt);
+
+unsigned long fdisk_get_optimal_iosize(struct fdisk_context *cxt);
+unsigned long fdisk_get_minimal_iosize(struct fdisk_context *cxt);
+unsigned long fdisk_get_physector_size(struct fdisk_context *cxt);
+unsigned long fdisk_get_sector_size(struct fdisk_context *cxt);
+unsigned long fdisk_get_alignment_offset(struct fdisk_context *cxt);
+unsigned long fdisk_get_grain_size(struct fdisk_context *cxt);
+fdisk_sector_t fdisk_get_first_lba(struct fdisk_context *cxt);
+fdisk_sector_t fdisk_set_first_lba(struct fdisk_context *cxt, fdisk_sector_t lba);
+fdisk_sector_t fdisk_get_last_lba(struct fdisk_context *cxt);
+fdisk_sector_t fdisk_set_last_lba(struct fdisk_context *cxt, fdisk_sector_t lba);
+fdisk_sector_t fdisk_get_nsectors(struct fdisk_context *cxt);
+const char *fdisk_get_devname(struct fdisk_context *cxt);
+int fdisk_get_devfd(struct fdisk_context *cxt);
+
+unsigned int fdisk_get_geom_heads(struct fdisk_context *cxt);
+fdisk_sector_t fdisk_get_geom_sectors(struct fdisk_context *cxt);
+fdisk_sector_t fdisk_get_geom_cylinders(struct fdisk_context *cxt);
+
+
+
+/* parttype.c */
+struct fdisk_parttype *fdisk_new_parttype(void);
+void fdisk_ref_parttype(struct fdisk_parttype *t);
+void fdisk_unref_parttype(struct fdisk_parttype *t);
+int fdisk_parttype_set_name(struct fdisk_parttype *t, const char *str);
+int fdisk_parttype_set_typestr(struct fdisk_parttype *t, const char *str);
+int fdisk_parttype_set_code(struct fdisk_parttype *t, int code);
+size_t fdisk_label_get_nparttypes(const struct fdisk_label *lb);
+struct fdisk_parttype *fdisk_label_get_parttype(const struct fdisk_label *lb, size_t n);
+int fdisk_label_has_code_parttypes(const struct fdisk_label *lb);
+struct fdisk_parttype *fdisk_label_get_parttype_from_code(
+				const struct fdisk_label *lb,
+				unsigned int code);
+struct fdisk_parttype *fdisk_label_get_parttype_from_string(
+				const struct fdisk_label *lb,
+				const char *str);
+struct fdisk_parttype *fdisk_new_unknown_parttype(unsigned int code,
+						  const char *typestr);
+struct fdisk_parttype *fdisk_copy_parttype(const struct fdisk_parttype *type);
+struct fdisk_parttype *fdisk_label_parse_parttype(
+				const struct fdisk_label *lb,
+				const char *str);
+const char *fdisk_parttype_get_string(const struct fdisk_parttype *t);
+unsigned int fdisk_parttype_get_code(const struct fdisk_parttype *t);
+const char *fdisk_parttype_get_name(const struct fdisk_parttype *t);
+int fdisk_parttype_is_unknown(const struct fdisk_parttype *t);
+
+/* label.c */
+
+/**
+ * fdisk_fieldtype
+ *
+ * Types of fdisk_field
+ */
+enum fdisk_fieldtype {
+	FDISK_FIELD_NONE = 0,
+
+	/* generic */
+	FDISK_FIELD_DEVICE,
+	FDISK_FIELD_START,
+	FDISK_FIELD_END,
+	FDISK_FIELD_SECTORS,
+	FDISK_FIELD_CYLINDERS,
+	FDISK_FIELD_SIZE,
+	FDISK_FIELD_TYPE,
+	FDISK_FIELD_TYPEID,
+
+	/* label specific */
+	FDISK_FIELD_ATTR,
+	FDISK_FIELD_BOOT,
+	FDISK_FIELD_BSIZE,
+	FDISK_FIELD_CPG,
+	FDISK_FIELD_EADDR,
+	FDISK_FIELD_FSIZE,
+	FDISK_FIELD_NAME,
+	FDISK_FIELD_SADDR,
+	FDISK_FIELD_UUID,
+
+	FDISK_NFIELDS		/* must be last */
+};
+
+int fdisk_label_get_type(const struct fdisk_label *lb);
+const char *fdisk_label_get_name(const struct fdisk_label *lb);
+int fdisk_label_require_geometry(const struct fdisk_label *lb);
+
+
+extern int fdisk_write_disklabel(struct fdisk_context *cxt);
+extern int fdisk_verify_disklabel(struct fdisk_context *cxt);
+extern int fdisk_create_disklabel(struct fdisk_context *cxt, const char *name);
+extern int fdisk_list_disklabel(struct fdisk_context *cxt);
+extern int fdisk_locate_disklabel(struct fdisk_context *cxt, int n, const char **name, off_t *offset, size_t *size);
+
+extern int fdisk_get_disklabel_id(struct fdisk_context *cxt, char **id);
+extern int fdisk_set_disklabel_id(struct fdisk_context *cxt);
+
+extern int fdisk_get_partition(struct fdisk_context *cxt, size_t partno, struct fdisk_partition **pa);
+extern int fdisk_set_partition(struct fdisk_context *cxt, size_t partno, struct fdisk_partition *pa);
+extern int fdisk_add_partition(struct fdisk_context *cxt, struct fdisk_partition *pa, size_t *partno);
+extern int fdisk_delete_partition(struct fdisk_context *cxt, size_t partno);
+
+extern int fdisk_delete_all_partitions(struct fdisk_context *cxt);
+
+extern int fdisk_set_partition_type(struct fdisk_context *cxt, size_t partnum,
+			     struct fdisk_parttype *t);
+
+
+extern int fdisk_label_get_fields_ids(
+			const struct fdisk_label *lb,
+			struct fdisk_context *cxt,
+			int **ids, size_t *nids);
+
+extern const struct fdisk_field *fdisk_label_get_field(const struct fdisk_label *lb, int id);
+extern const struct fdisk_field *fdisk_label_get_field_by_name(
+			const struct fdisk_label *lb,
+			const char *name);
+
+extern int fdisk_field_get_id(const struct fdisk_field *field);
+extern const char *fdisk_field_get_name(const struct fdisk_field *field);
+extern double fdisk_field_get_width(const struct fdisk_field *field);
+extern int fdisk_field_is_number(const struct fdisk_field *field);
+
+
+extern void fdisk_label_set_changed(struct fdisk_label *lb, int changed);
+extern int fdisk_label_is_changed(const struct fdisk_label *lb);
+
+extern void fdisk_label_set_disabled(struct fdisk_label *lb, int disabled);
+extern int fdisk_label_is_disabled(const struct fdisk_label *lb);
+
+extern int fdisk_is_partition_used(struct fdisk_context *cxt, size_t n);
+
+extern int fdisk_toggle_partition_flag(struct fdisk_context *cxt, size_t partnum, unsigned long flag);
+
+extern struct fdisk_partition *fdisk_new_partition(void);
+extern void fdisk_reset_partition(struct fdisk_partition *pa);
+extern void fdisk_ref_partition(struct fdisk_partition *pa);
+extern void fdisk_unref_partition(struct fdisk_partition *pa);
+extern int fdisk_partition_is_freespace(struct fdisk_partition *pa);
+
+int fdisk_partition_set_start(struct fdisk_partition *pa, uint64_t off);
+int fdisk_partition_unset_start(struct fdisk_partition *pa);
+uint64_t fdisk_partition_get_start(struct fdisk_partition *pa);
+int fdisk_partition_has_start(struct fdisk_partition *pa);
+int fdisk_partition_cmp_start(struct fdisk_partition *a,
+			      struct fdisk_partition *b);
+int fdisk_partition_start_follow_default(struct fdisk_partition *pa, int enable);
+int fdisk_partition_start_is_default(struct fdisk_partition *pa);
+
+int fdisk_partition_set_size(struct fdisk_partition *pa, uint64_t sz);
+int fdisk_partition_unset_size(struct fdisk_partition *pa);
+uint64_t fdisk_partition_get_size(struct fdisk_partition *pa);
+int fdisk_partition_has_size(struct fdisk_partition *pa);
+int fdisk_partition_size_explicit(struct fdisk_partition *pa, int enable);
+
+int fdisk_partition_has_end(struct fdisk_partition *pa);
+fdisk_sector_t fdisk_partition_get_end(struct fdisk_partition *pa);
+
+int fdisk_partition_set_partno(struct fdisk_partition *pa, size_t num);
+int fdisk_partition_unset_partno(struct fdisk_partition *pa);
+size_t fdisk_partition_get_partno(struct fdisk_partition *pa);
+int fdisk_partition_has_partno(struct fdisk_partition *pa);
+int fdisk_partition_cmp_partno(struct fdisk_partition *a,
+	                               struct fdisk_partition *b);
+int fdisk_partition_partno_follow_default(struct fdisk_partition *pa, int enable);
+
+
+extern int fdisk_partition_set_type(struct fdisk_partition *pa, struct fdisk_parttype *type);
+extern struct fdisk_parttype *fdisk_partition_get_type(struct fdisk_partition *pa);
+extern int fdisk_partition_set_name(struct fdisk_partition *pa, const char *name);
+extern const char *fdisk_partition_get_name(struct fdisk_partition *pa);
+extern int fdisk_partition_set_uuid(struct fdisk_partition *pa, const char *uuid);
+extern int fdisk_partition_set_attrs(struct fdisk_partition *pa, const char *attrs);
+extern const char *fdisk_partition_get_uuid(struct fdisk_partition *pa);
+extern const char *fdisk_partition_get_attrs(struct fdisk_partition *pa);
+extern int fdisk_partition_is_nested(struct fdisk_partition *pa);
+extern int fdisk_partition_is_container(struct fdisk_partition *pa);
+extern int fdisk_partition_get_parent(struct fdisk_partition *pa, size_t *parent);
+extern int fdisk_partition_is_used(struct fdisk_partition *pa);
+extern int fdisk_partition_is_bootable(struct fdisk_partition *pa);
+extern int fdisk_partition_to_string(struct fdisk_partition *pa,
+				     struct fdisk_context *cxt,
+				     int id, char **data);
+
+int fdisk_partition_next_partno(struct fdisk_partition *pa,
+				       struct fdisk_context *cxt,
+				       size_t *n);
+
+extern int fdisk_partition_end_follow_default(struct fdisk_partition *pa, int enable);
+extern int fdisk_partition_end_is_default(struct fdisk_partition *pa);
+
+extern int fdisk_reorder_partitions(struct fdisk_context *cxt);
+
+/* table.c */
+extern struct fdisk_table *fdisk_new_table(void);
+extern int fdisk_reset_table(struct fdisk_table *tb);
+extern void fdisk_ref_table(struct fdisk_table *tb);
+extern void fdisk_unref_table(struct fdisk_table *tb);
+extern size_t fdisk_table_get_nents(struct fdisk_table *tb);
+extern int fdisk_table_is_empty(struct fdisk_table *tb);
+extern int fdisk_table_add_partition(struct fdisk_table *tb, struct fdisk_partition *pa);
+extern int fdisk_table_remove_partition(struct fdisk_table *tb, struct fdisk_partition *pa);
+
+extern int fdisk_get_partitions(struct fdisk_context *cxt, struct fdisk_table **tb);
+extern int fdisk_get_freespaces(struct fdisk_context *cxt, struct fdisk_table **tb);
+
+extern int fdisk_table_wrong_order(struct fdisk_table *tb);
+extern int fdisk_table_sort_partitions(struct fdisk_table *tb,
+			int (*cmp)(struct fdisk_partition *,
+				   struct fdisk_partition *));
+
+extern int fdisk_table_next_partition(
+			struct fdisk_table *tb,
+			struct fdisk_iter *itr,
+			struct fdisk_partition **pa);
+
+extern struct fdisk_partition *fdisk_table_get_partition(
+			struct fdisk_table *tb,
+			size_t n);
+extern int fdisk_apply_table(struct fdisk_context *cxt, struct fdisk_table *tb);
+
+/* alignment.c */
+#define FDISK_ALIGN_UP		1
+#define FDISK_ALIGN_DOWN	2
+#define FDISK_ALIGN_NEAREST	3
+
+fdisk_sector_t fdisk_align_lba(struct fdisk_context *cxt, fdisk_sector_t lba, int direction);
+fdisk_sector_t fdisk_align_lba_in_range(struct fdisk_context *cxt,
+				  fdisk_sector_t lba, fdisk_sector_t start, fdisk_sector_t stop);
+int fdisk_lba_is_phy_aligned(struct fdisk_context *cxt, fdisk_sector_t lba);
+
+int fdisk_override_geometry(struct fdisk_context *cxt,
+			    unsigned int cylinders,
+			    unsigned int heads,
+			    unsigned int sectors);
+int fdisk_save_user_geometry(struct fdisk_context *cxt,
+			    unsigned int cylinders,
+			    unsigned int heads,
+			    unsigned int sectors);
+int fdisk_save_user_sector_size(struct fdisk_context *cxt,
+				unsigned int phy,
+				unsigned int log);
+int fdisk_has_user_device_properties(struct fdisk_context *cxt);
+int fdisk_reset_alignment(struct fdisk_context *cxt);
+int fdisk_reset_device_properties(struct fdisk_context *cxt);
+int fdisk_reread_partition_table(struct fdisk_context *cxt);
+
+/* iter.c */
+enum {
+
+	FDISK_ITER_FORWARD = 0,
+	FDISK_ITER_BACKWARD
+};
+extern struct fdisk_iter *fdisk_new_iter(int direction);
+extern void fdisk_free_iter(struct fdisk_iter *itr);
+extern void fdisk_reset_iter(struct fdisk_iter *itr, int direction);
+extern int fdisk_iter_get_direction(struct fdisk_iter *itr);
+
+
+/* dos.c */
+#define DOS_FLAG_ACTIVE	1
+
+extern int fdisk_dos_move_begin(struct fdisk_context *cxt, size_t i);
+extern int fdisk_dos_enable_compatible(struct fdisk_label *lb, int enable);
+extern int fdisk_dos_is_compatible(struct fdisk_label *lb);
+
+/* sun.h */
+extern int fdisk_sun_set_alt_cyl(struct fdisk_context *cxt);
+extern int fdisk_sun_set_xcyl(struct fdisk_context *cxt);
+extern int fdisk_sun_set_ilfact(struct fdisk_context *cxt);
+extern int fdisk_sun_set_rspeed(struct fdisk_context *cxt);
+extern int fdisk_sun_set_pcylcount(struct fdisk_context *cxt);
+
+/* bsd.c */
+extern int fdisk_bsd_edit_disklabel(struct fdisk_context *cxt);
+extern int fdisk_bsd_write_bootstrap(struct fdisk_context *cxt);
+extern int fdisk_bsd_link_partition(struct fdisk_context *cxt);
+
+/* sgi.h */
+#define SGI_FLAG_BOOT	1
+#define SGI_FLAG_SWAP	2
+extern int fdisk_sgi_set_bootfile(struct fdisk_context *cxt);
+extern int fdisk_sgi_create_info(struct fdisk_context *cxt);
+
+/* gpt */
+
+/* GPT partition attributes */
+enum {
+	/* System partition (disk partitioning utilities must preserve the
+	 * partition as is) */
+	GPT_FLAG_REQUIRED = 1,
+
+	/* EFI firmware should ignore the content of the partition and not try
+	 * to read from it */
+	GPT_FLAG_NOBLOCK,
+
+	/* Legacy BIOS bootable  */
+	GPT_FLAG_LEGACYBOOT,
+
+	/* bites 48-63, Defined and used by the individual partition type.
+	 *
+	 * The flag GPT_FLAG_GUIDSPECIFIC forces libfdisk to ask (by ask API)
+	 * for a bit number. If you want to toggle specific bit and avoid any
+	 * dialog, then use the bit number (in range 48..63). For example:
+	 *
+	 * // start dialog to ask for bit number
+	 * fdisk_toggle_partition_flag(cxt, n, GPT_FLAG_GUIDSPECIFIC);
+	 *
+	 * // toggle bit 60
+	 * fdisk_toggle_partition_flag(cxt, n, 60);
+	 */
+	GPT_FLAG_GUIDSPECIFIC
+};
+
+extern int fdisk_gpt_is_hybrid(struct fdisk_context *cxt);
+
+
+/* script.c */
+struct fdisk_script *fdisk_new_script(struct fdisk_context *cxt);
+struct fdisk_script *fdisk_new_script_from_file(struct fdisk_context *cxt,
+						 const char *filename);
+void fdisk_ref_script(struct fdisk_script *dp);
+void fdisk_unref_script(struct fdisk_script *dp);
+
+const char *fdisk_script_get_header(struct fdisk_script *dp, const char *name);
+int fdisk_script_set_header(struct fdisk_script *dp, const char *name, const char *data);
+struct fdisk_table *fdisk_script_get_table(struct fdisk_script *dp);
+int fdisk_script_get_nlines(struct fdisk_script *dp);
+
+int fdisk_script_read_context(struct fdisk_script *dp, struct fdisk_context *cxt);
+int fdisk_script_write_file(struct fdisk_script *dp, FILE *f);
+int fdisk_script_read_file(struct fdisk_script *dp, FILE *f);
+int fdisk_script_read_line(struct fdisk_script *dp, FILE *f, char *buf, size_t bufsz);
+
+int fdisk_set_script(struct fdisk_context *cxt, struct fdisk_script *dp);
+struct fdisk_script *fdisk_get_script(struct fdisk_context *cxt);
+
+int fdisk_apply_script_headers(struct fdisk_context *cxt, struct fdisk_script *dp);
+int fdisk_apply_script(struct fdisk_context *cxt, struct fdisk_script *dp);
+
+
+/* ask.c */
+#define fdisk_is_ask(a, x) (fdisk_ask_get_type(a) == FDISK_ASKTYPE_ ## x)
+
+int fdisk_set_ask(struct fdisk_context *cxt,
+		int (*ask_cb)(struct fdisk_context *, struct fdisk_ask *, void *),
+		void *data);
+
+
+void fdisk_ref_ask(struct fdisk_ask *ask);
+void fdisk_unref_ask(struct fdisk_ask *ask);
+const char *fdisk_ask_get_query(struct fdisk_ask *ask);
+int fdisk_ask_get_type(struct fdisk_ask *ask);
+const char *fdisk_ask_number_get_range(struct fdisk_ask *ask);
+uint64_t fdisk_ask_number_get_default(struct fdisk_ask *ask);
+uint64_t fdisk_ask_number_get_low(struct fdisk_ask *ask);
+uint64_t fdisk_ask_number_get_high(struct fdisk_ask *ask);
+uint64_t fdisk_ask_number_get_result(struct fdisk_ask *ask);
+int fdisk_ask_number_set_result(struct fdisk_ask *ask, uint64_t result);
+uint64_t fdisk_ask_number_get_base(struct fdisk_ask *ask);
+uint64_t fdisk_ask_number_get_unit(struct fdisk_ask *ask);
+int fdisk_ask_number_set_relative(struct fdisk_ask *ask, int relative);
+int fdisk_ask_number_inchars(struct fdisk_ask *ask);
+int fdisk_ask_partnum(struct fdisk_context *cxt, size_t *partnum, int wantnew);
+
+int fdisk_ask_number(struct fdisk_context *cxt,
+		     uintmax_t low,
+		     uintmax_t dflt,
+		     uintmax_t high,
+		     const char *query,
+		     uintmax_t *result);
+char *fdisk_ask_string_get_result(struct fdisk_ask *ask);
+int fdisk_ask_string_set_result(struct fdisk_ask *ask, char *result);
+int fdisk_ask_string(struct fdisk_context *cxt,
+		     const char *query,
+		     char **result);
+int fdisk_ask_yesno(struct fdisk_context *cxt,
+		     const char *query,
+		     int *result);
+int fdisk_ask_yesno_get_result(struct fdisk_ask *ask);
+int fdisk_ask_yesno_set_result(struct fdisk_ask *ask, int result);
+int fdisk_ask_menu_get_default(struct fdisk_ask *ask);
+int fdisk_ask_menu_set_result(struct fdisk_ask *ask, int key);
+int fdisk_ask_menu_get_result(struct fdisk_ask *ask, int *key);
+int fdisk_ask_menu_get_item(struct fdisk_ask *ask, size_t idx, int *key,
+			    const char **name, const char **desc);
+size_t fdisk_ask_menu_get_nitems(struct fdisk_ask *ask);
+int fdisk_ask_print_get_errno(struct fdisk_ask *ask);
+const char *fdisk_ask_print_get_mesg(struct fdisk_ask *ask);
+
+int fdisk_info(struct fdisk_context *cxt, const char *fmt, ...);
+int fdisk_warn(struct fdisk_context *cxt, const char *fmt, ...);
+int fdisk_warnx(struct fdisk_context *cxt, const char *fmt, ...);
+
+/* utils.h */
+extern char *fdisk_partname(const char *dev, size_t partno);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBFDISK_H */
diff --git a/libblkid/libfdisk/src/libfdisk.h.in b/libblkid/libfdisk/src/libfdisk.h.in
new file mode 100644
index 0000000..f82d5bd
--- /dev/null
+++ b/libblkid/libfdisk/src/libfdisk.h.in
@@ -0,0 +1,579 @@
+/*
+ * libfdisk.h - libfdisk API
+ *
+ * Copyright (C) 2012-2014 Karel Zak <kzak@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _LIBFDISK_H
+#define _LIBFDISK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdint.h>
+
+/**
+ * LIBFDISK_VERSION:
+ *
+ * Library version string
+ */
+#define LIBFDISK_VERSION   "@LIBFDISK_VERSION@"
+
+/**
+ * fdisk_context:
+ *
+ * Basic library handler.
+ */
+struct fdisk_context;
+
+/**
+ * fdisk_label:
+ *
+ * Disk label specific driver and setting.
+ */
+struct fdisk_label;
+
+/**
+ * fdisk_parttype:
+ *
+ * Partition type.
+ */
+struct fdisk_parttype;
+
+/**
+ * fdisk_partition:
+ *
+ * Partition abstraction (and template).
+ */
+struct fdisk_partition;
+
+/**
+ * fdisk_ask:
+ *
+ * Ask API handler for dialogs with users.
+ */
+struct fdisk_ask;
+
+/**
+ * fdisk_iter:
+ *
+ * Unified iterator.
+ */
+struct fdisk_iter;
+
+/**
+ * fdisk_table:
+ *
+ * Container for fdisk_partition objects
+ */
+struct fdisk_table;
+
+/**
+ * fdisk_field
+ *
+ * Output field description.
+ */
+struct fdisk_field;
+
+/**
+ * fdisk_script
+ *
+ * library handler for sfdisk compatible scripts
+ */
+struct fdisk_script;
+
+/**
+ * fdisk_sector_t
+ *
+ * LBA adresses type
+ */
+typedef uint64_t fdisk_sector_t;
+
+/**
+ * fdisk_labeltype:
+ *
+ * Supported partition table types (labels)
+ */
+enum fdisk_labeltype {
+	FDISK_DISKLABEL_DOS = (1 << 1),
+	FDISK_DISKLABEL_SUN = (1 << 2),
+	FDISK_DISKLABEL_SGI = (1 << 3),
+	FDISK_DISKLABEL_BSD = (1 << 4),
+	FDISK_DISKLABEL_GPT = (1 << 5)
+};
+
+/**
+ * fdisk_asktype:
+ *
+ * Ask API dialog types
+ */
+enum fdisk_asktype {
+	FDISK_ASKTYPE_NONE = 0,
+	FDISK_ASKTYPE_NUMBER,
+	FDISK_ASKTYPE_OFFSET,
+	FDISK_ASKTYPE_WARN,
+	FDISK_ASKTYPE_WARNX,
+	FDISK_ASKTYPE_INFO,
+	FDISK_ASKTYPE_YESNO,
+	FDISK_ASKTYPE_STRING,
+	FDISK_ASKTYPE_MENU
+};
+
+/* init.c */
+extern void fdisk_init_debug(int mask);
+
+/* context.h */
+
+#define FDISK_PLURAL	0
+#define FDISK_SINGULAR	1
+
+struct fdisk_context *fdisk_new_context(void);
+struct fdisk_context *fdisk_new_nested_context(struct fdisk_context *parent, const char *name);
+void fdisk_unref_context(struct fdisk_context *cxt);
+void fdisk_ref_context(struct fdisk_context *cxt);
+
+struct fdisk_context *fdisk_get_parent(struct fdisk_context *cxt);
+size_t fdisk_get_npartitions(struct fdisk_context *cxt);
+
+struct fdisk_label *fdisk_get_label(struct fdisk_context *cxt, const char *name);
+int fdisk_next_label(struct fdisk_context *cxt, struct fdisk_label **lb);
+size_t fdisk_get_nlabels(struct fdisk_context *cxt);
+
+int fdisk_has_label(struct fdisk_context *cxt);
+int fdisk_is_labeltype(struct fdisk_context *cxt, enum fdisk_labeltype id);
+#define fdisk_is_label(c, x) fdisk_is_labeltype(c, FDISK_DISKLABEL_ ## x)
+
+
+int fdisk_assign_device(struct fdisk_context *cxt,
+			const char *fname, int readonly);
+int fdisk_deassign_device(struct fdisk_context *cxt, int nosync);
+int fdisk_is_readonly(struct fdisk_context *cxt);
+
+int fdisk_enable_details(struct fdisk_context *cxt, int enable);
+int fdisk_is_details(struct fdisk_context *cxt);
+
+int fdisk_enable_listonly(struct fdisk_context *cxt, int enable);
+int fdisk_is_listonly(struct fdisk_context *cxt);
+
+int fdisk_set_unit(struct fdisk_context *cxt, const char *str);
+const char *fdisk_get_unit(struct fdisk_context *cxt, int n);
+int fdisk_use_cylinders(struct fdisk_context *cxt);
+unsigned int fdisk_get_units_per_sector(struct fdisk_context *cxt);
+
+unsigned long fdisk_get_optimal_iosize(struct fdisk_context *cxt);
+unsigned long fdisk_get_minimal_iosize(struct fdisk_context *cxt);
+unsigned long fdisk_get_physector_size(struct fdisk_context *cxt);
+unsigned long fdisk_get_sector_size(struct fdisk_context *cxt);
+unsigned long fdisk_get_alignment_offset(struct fdisk_context *cxt);
+unsigned long fdisk_get_grain_size(struct fdisk_context *cxt);
+fdisk_sector_t fdisk_get_first_lba(struct fdisk_context *cxt);
+fdisk_sector_t fdisk_set_first_lba(struct fdisk_context *cxt, fdisk_sector_t lba);
+fdisk_sector_t fdisk_get_last_lba(struct fdisk_context *cxt);
+fdisk_sector_t fdisk_set_last_lba(struct fdisk_context *cxt, fdisk_sector_t lba);
+fdisk_sector_t fdisk_get_nsectors(struct fdisk_context *cxt);
+const char *fdisk_get_devname(struct fdisk_context *cxt);
+int fdisk_get_devfd(struct fdisk_context *cxt);
+
+unsigned int fdisk_get_geom_heads(struct fdisk_context *cxt);
+fdisk_sector_t fdisk_get_geom_sectors(struct fdisk_context *cxt);
+fdisk_sector_t fdisk_get_geom_cylinders(struct fdisk_context *cxt);
+
+
+
+/* parttype.c */
+struct fdisk_parttype *fdisk_new_parttype(void);
+void fdisk_ref_parttype(struct fdisk_parttype *t);
+void fdisk_unref_parttype(struct fdisk_parttype *t);
+int fdisk_parttype_set_name(struct fdisk_parttype *t, const char *str);
+int fdisk_parttype_set_typestr(struct fdisk_parttype *t, const char *str);
+int fdisk_parttype_set_code(struct fdisk_parttype *t, int code);
+size_t fdisk_label_get_nparttypes(const struct fdisk_label *lb);
+struct fdisk_parttype *fdisk_label_get_parttype(const struct fdisk_label *lb, size_t n);
+int fdisk_label_has_code_parttypes(const struct fdisk_label *lb);
+struct fdisk_parttype *fdisk_label_get_parttype_from_code(
+				const struct fdisk_label *lb,
+				unsigned int code);
+struct fdisk_parttype *fdisk_label_get_parttype_from_string(
+				const struct fdisk_label *lb,
+				const char *str);
+struct fdisk_parttype *fdisk_new_unknown_parttype(unsigned int code,
+						  const char *typestr);
+struct fdisk_parttype *fdisk_copy_parttype(const struct fdisk_parttype *type);
+struct fdisk_parttype *fdisk_label_parse_parttype(
+				const struct fdisk_label *lb,
+				const char *str);
+const char *fdisk_parttype_get_string(const struct fdisk_parttype *t);
+unsigned int fdisk_parttype_get_code(const struct fdisk_parttype *t);
+const char *fdisk_parttype_get_name(const struct fdisk_parttype *t);
+int fdisk_parttype_is_unknown(const struct fdisk_parttype *t);
+
+/* label.c */
+
+/**
+ * fdisk_fieldtype
+ *
+ * Types of fdisk_field
+ */
+enum fdisk_fieldtype {
+	FDISK_FIELD_NONE = 0,
+
+	/* generic */
+	FDISK_FIELD_DEVICE,
+	FDISK_FIELD_START,
+	FDISK_FIELD_END,
+	FDISK_FIELD_SECTORS,
+	FDISK_FIELD_CYLINDERS,
+	FDISK_FIELD_SIZE,
+	FDISK_FIELD_TYPE,
+	FDISK_FIELD_TYPEID,
+
+	/* label specific */
+	FDISK_FIELD_ATTR,
+	FDISK_FIELD_BOOT,
+	FDISK_FIELD_BSIZE,
+	FDISK_FIELD_CPG,
+	FDISK_FIELD_EADDR,
+	FDISK_FIELD_FSIZE,
+	FDISK_FIELD_NAME,
+	FDISK_FIELD_SADDR,
+	FDISK_FIELD_UUID,
+
+	FDISK_NFIELDS		/* must be last */
+};
+
+int fdisk_label_get_type(const struct fdisk_label *lb);
+const char *fdisk_label_get_name(const struct fdisk_label *lb);
+int fdisk_label_require_geometry(const struct fdisk_label *lb);
+
+
+extern int fdisk_write_disklabel(struct fdisk_context *cxt);
+extern int fdisk_verify_disklabel(struct fdisk_context *cxt);
+extern int fdisk_create_disklabel(struct fdisk_context *cxt, const char *name);
+extern int fdisk_list_disklabel(struct fdisk_context *cxt);
+extern int fdisk_locate_disklabel(struct fdisk_context *cxt, int n, const char **name, off_t *offset, size_t *size);
+
+extern int fdisk_get_disklabel_id(struct fdisk_context *cxt, char **id);
+extern int fdisk_set_disklabel_id(struct fdisk_context *cxt);
+
+extern int fdisk_get_partition(struct fdisk_context *cxt, size_t partno, struct fdisk_partition **pa);
+extern int fdisk_set_partition(struct fdisk_context *cxt, size_t partno, struct fdisk_partition *pa);
+extern int fdisk_add_partition(struct fdisk_context *cxt, struct fdisk_partition *pa, size_t *partno);
+extern int fdisk_delete_partition(struct fdisk_context *cxt, size_t partno);
+
+extern int fdisk_delete_all_partitions(struct fdisk_context *cxt);
+
+extern int fdisk_set_partition_type(struct fdisk_context *cxt, size_t partnum,
+			     struct fdisk_parttype *t);
+
+
+extern int fdisk_label_get_fields_ids(
+			const struct fdisk_label *lb,
+			struct fdisk_context *cxt,
+			int **ids, size_t *nids);
+
+extern const struct fdisk_field *fdisk_label_get_field(const struct fdisk_label *lb, int id);
+extern const struct fdisk_field *fdisk_label_get_field_by_name(
+			const struct fdisk_label *lb,
+			const char *name);
+
+extern int fdisk_field_get_id(const struct fdisk_field *field);
+extern const char *fdisk_field_get_name(const struct fdisk_field *field);
+extern double fdisk_field_get_width(const struct fdisk_field *field);
+extern int fdisk_field_is_number(const struct fdisk_field *field);
+
+
+extern void fdisk_label_set_changed(struct fdisk_label *lb, int changed);
+extern int fdisk_label_is_changed(const struct fdisk_label *lb);
+
+extern void fdisk_label_set_disabled(struct fdisk_label *lb, int disabled);
+extern int fdisk_label_is_disabled(const struct fdisk_label *lb);
+
+extern int fdisk_is_partition_used(struct fdisk_context *cxt, size_t n);
+
+extern int fdisk_toggle_partition_flag(struct fdisk_context *cxt, size_t partnum, unsigned long flag);
+
+extern struct fdisk_partition *fdisk_new_partition(void);
+extern void fdisk_reset_partition(struct fdisk_partition *pa);
+extern void fdisk_ref_partition(struct fdisk_partition *pa);
+extern void fdisk_unref_partition(struct fdisk_partition *pa);
+extern int fdisk_partition_is_freespace(struct fdisk_partition *pa);
+
+int fdisk_partition_set_start(struct fdisk_partition *pa, uint64_t off);
+int fdisk_partition_unset_start(struct fdisk_partition *pa);
+uint64_t fdisk_partition_get_start(struct fdisk_partition *pa);
+int fdisk_partition_has_start(struct fdisk_partition *pa);
+int fdisk_partition_cmp_start(struct fdisk_partition *a,
+			      struct fdisk_partition *b);
+int fdisk_partition_start_follow_default(struct fdisk_partition *pa, int enable);
+int fdisk_partition_start_is_default(struct fdisk_partition *pa);
+
+int fdisk_partition_set_size(struct fdisk_partition *pa, uint64_t sz);
+int fdisk_partition_unset_size(struct fdisk_partition *pa);
+uint64_t fdisk_partition_get_size(struct fdisk_partition *pa);
+int fdisk_partition_has_size(struct fdisk_partition *pa);
+int fdisk_partition_size_explicit(struct fdisk_partition *pa, int enable);
+
+int fdisk_partition_has_end(struct fdisk_partition *pa);
+fdisk_sector_t fdisk_partition_get_end(struct fdisk_partition *pa);
+
+int fdisk_partition_set_partno(struct fdisk_partition *pa, size_t num);
+int fdisk_partition_unset_partno(struct fdisk_partition *pa);
+size_t fdisk_partition_get_partno(struct fdisk_partition *pa);
+int fdisk_partition_has_partno(struct fdisk_partition *pa);
+int fdisk_partition_cmp_partno(struct fdisk_partition *a,
+	                               struct fdisk_partition *b);
+int fdisk_partition_partno_follow_default(struct fdisk_partition *pa, int enable);
+
+
+extern int fdisk_partition_set_type(struct fdisk_partition *pa, struct fdisk_parttype *type);
+extern struct fdisk_parttype *fdisk_partition_get_type(struct fdisk_partition *pa);
+extern int fdisk_partition_set_name(struct fdisk_partition *pa, const char *name);
+extern const char *fdisk_partition_get_name(struct fdisk_partition *pa);
+extern int fdisk_partition_set_uuid(struct fdisk_partition *pa, const char *uuid);
+extern int fdisk_partition_set_attrs(struct fdisk_partition *pa, const char *attrs);
+extern const char *fdisk_partition_get_uuid(struct fdisk_partition *pa);
+extern const char *fdisk_partition_get_attrs(struct fdisk_partition *pa);
+extern int fdisk_partition_is_nested(struct fdisk_partition *pa);
+extern int fdisk_partition_is_container(struct fdisk_partition *pa);
+extern int fdisk_partition_get_parent(struct fdisk_partition *pa, size_t *parent);
+extern int fdisk_partition_is_used(struct fdisk_partition *pa);
+extern int fdisk_partition_is_bootable(struct fdisk_partition *pa);
+extern int fdisk_partition_to_string(struct fdisk_partition *pa,
+				     struct fdisk_context *cxt,
+				     int id, char **data);
+
+int fdisk_partition_next_partno(struct fdisk_partition *pa,
+				       struct fdisk_context *cxt,
+				       size_t *n);
+
+extern int fdisk_partition_end_follow_default(struct fdisk_partition *pa, int enable);
+extern int fdisk_partition_end_is_default(struct fdisk_partition *pa);
+
+extern int fdisk_reorder_partitions(struct fdisk_context *cxt);
+
+/* table.c */
+extern struct fdisk_table *fdisk_new_table(void);
+extern int fdisk_reset_table(struct fdisk_table *tb);
+extern void fdisk_ref_table(struct fdisk_table *tb);
+extern void fdisk_unref_table(struct fdisk_table *tb);
+extern size_t fdisk_table_get_nents(struct fdisk_table *tb);
+extern int fdisk_table_is_empty(struct fdisk_table *tb);
+extern int fdisk_table_add_partition(struct fdisk_table *tb, struct fdisk_partition *pa);
+extern int fdisk_table_remove_partition(struct fdisk_table *tb, struct fdisk_partition *pa);
+
+extern int fdisk_get_partitions(struct fdisk_context *cxt, struct fdisk_table **tb);
+extern int fdisk_get_freespaces(struct fdisk_context *cxt, struct fdisk_table **tb);
+
+extern int fdisk_table_wrong_order(struct fdisk_table *tb);
+extern int fdisk_table_sort_partitions(struct fdisk_table *tb,
+			int (*cmp)(struct fdisk_partition *,
+				   struct fdisk_partition *));
+
+extern int fdisk_table_next_partition(
+			struct fdisk_table *tb,
+			struct fdisk_iter *itr,
+			struct fdisk_partition **pa);
+
+extern struct fdisk_partition *fdisk_table_get_partition(
+			struct fdisk_table *tb,
+			size_t n);
+extern int fdisk_apply_table(struct fdisk_context *cxt, struct fdisk_table *tb);
+
+/* alignment.c */
+#define FDISK_ALIGN_UP		1
+#define FDISK_ALIGN_DOWN	2
+#define FDISK_ALIGN_NEAREST	3
+
+fdisk_sector_t fdisk_align_lba(struct fdisk_context *cxt, fdisk_sector_t lba, int direction);
+fdisk_sector_t fdisk_align_lba_in_range(struct fdisk_context *cxt,
+				  fdisk_sector_t lba, fdisk_sector_t start, fdisk_sector_t stop);
+int fdisk_lba_is_phy_aligned(struct fdisk_context *cxt, fdisk_sector_t lba);
+
+int fdisk_override_geometry(struct fdisk_context *cxt,
+			    unsigned int cylinders,
+			    unsigned int heads,
+			    unsigned int sectors);
+int fdisk_save_user_geometry(struct fdisk_context *cxt,
+			    unsigned int cylinders,
+			    unsigned int heads,
+			    unsigned int sectors);
+int fdisk_save_user_sector_size(struct fdisk_context *cxt,
+				unsigned int phy,
+				unsigned int log);
+int fdisk_has_user_device_properties(struct fdisk_context *cxt);
+int fdisk_reset_alignment(struct fdisk_context *cxt);
+int fdisk_reset_device_properties(struct fdisk_context *cxt);
+int fdisk_reread_partition_table(struct fdisk_context *cxt);
+
+/* iter.c */
+enum {
+
+	FDISK_ITER_FORWARD = 0,
+	FDISK_ITER_BACKWARD
+};
+extern struct fdisk_iter *fdisk_new_iter(int direction);
+extern void fdisk_free_iter(struct fdisk_iter *itr);
+extern void fdisk_reset_iter(struct fdisk_iter *itr, int direction);
+extern int fdisk_iter_get_direction(struct fdisk_iter *itr);
+
+
+/* dos.c */
+#define DOS_FLAG_ACTIVE	1
+
+extern int fdisk_dos_move_begin(struct fdisk_context *cxt, size_t i);
+extern int fdisk_dos_enable_compatible(struct fdisk_label *lb, int enable);
+extern int fdisk_dos_is_compatible(struct fdisk_label *lb);
+
+/* sun.h */
+extern int fdisk_sun_set_alt_cyl(struct fdisk_context *cxt);
+extern int fdisk_sun_set_xcyl(struct fdisk_context *cxt);
+extern int fdisk_sun_set_ilfact(struct fdisk_context *cxt);
+extern int fdisk_sun_set_rspeed(struct fdisk_context *cxt);
+extern int fdisk_sun_set_pcylcount(struct fdisk_context *cxt);
+
+/* bsd.c */
+extern int fdisk_bsd_edit_disklabel(struct fdisk_context *cxt);
+extern int fdisk_bsd_write_bootstrap(struct fdisk_context *cxt);
+extern int fdisk_bsd_link_partition(struct fdisk_context *cxt);
+
+/* sgi.h */
+#define SGI_FLAG_BOOT	1
+#define SGI_FLAG_SWAP	2
+extern int fdisk_sgi_set_bootfile(struct fdisk_context *cxt);
+extern int fdisk_sgi_create_info(struct fdisk_context *cxt);
+
+/* gpt */
+
+/* GPT partition attributes */
+enum {
+	/* System partition (disk partitioning utilities must preserve the
+	 * partition as is) */
+	GPT_FLAG_REQUIRED = 1,
+
+	/* EFI firmware should ignore the content of the partition and not try
+	 * to read from it */
+	GPT_FLAG_NOBLOCK,
+
+	/* Legacy BIOS bootable  */
+	GPT_FLAG_LEGACYBOOT,
+
+	/* bites 48-63, Defined and used by the individual partition type.
+	 *
+	 * The flag GPT_FLAG_GUIDSPECIFIC forces libfdisk to ask (by ask API)
+	 * for a bit number. If you want to toggle specific bit and avoid any
+	 * dialog, then use the bit number (in range 48..63). For example:
+	 *
+	 * // start dialog to ask for bit number
+	 * fdisk_toggle_partition_flag(cxt, n, GPT_FLAG_GUIDSPECIFIC);
+	 *
+	 * // toggle bit 60
+	 * fdisk_toggle_partition_flag(cxt, n, 60);
+	 */
+	GPT_FLAG_GUIDSPECIFIC
+};
+
+extern int fdisk_gpt_is_hybrid(struct fdisk_context *cxt);
+
+
+/* script.c */
+struct fdisk_script *fdisk_new_script(struct fdisk_context *cxt);
+struct fdisk_script *fdisk_new_script_from_file(struct fdisk_context *cxt,
+						 const char *filename);
+void fdisk_ref_script(struct fdisk_script *dp);
+void fdisk_unref_script(struct fdisk_script *dp);
+
+const char *fdisk_script_get_header(struct fdisk_script *dp, const char *name);
+int fdisk_script_set_header(struct fdisk_script *dp, const char *name, const char *data);
+struct fdisk_table *fdisk_script_get_table(struct fdisk_script *dp);
+int fdisk_script_get_nlines(struct fdisk_script *dp);
+
+int fdisk_script_read_context(struct fdisk_script *dp, struct fdisk_context *cxt);
+int fdisk_script_write_file(struct fdisk_script *dp, FILE *f);
+int fdisk_script_read_file(struct fdisk_script *dp, FILE *f);
+int fdisk_script_read_line(struct fdisk_script *dp, FILE *f, char *buf, size_t bufsz);
+
+int fdisk_set_script(struct fdisk_context *cxt, struct fdisk_script *dp);
+struct fdisk_script *fdisk_get_script(struct fdisk_context *cxt);
+
+int fdisk_apply_script_headers(struct fdisk_context *cxt, struct fdisk_script *dp);
+int fdisk_apply_script(struct fdisk_context *cxt, struct fdisk_script *dp);
+
+
+/* ask.c */
+#define fdisk_is_ask(a, x) (fdisk_ask_get_type(a) == FDISK_ASKTYPE_ ## x)
+
+int fdisk_set_ask(struct fdisk_context *cxt,
+		int (*ask_cb)(struct fdisk_context *, struct fdisk_ask *, void *),
+		void *data);
+
+
+void fdisk_ref_ask(struct fdisk_ask *ask);
+void fdisk_unref_ask(struct fdisk_ask *ask);
+const char *fdisk_ask_get_query(struct fdisk_ask *ask);
+int fdisk_ask_get_type(struct fdisk_ask *ask);
+const char *fdisk_ask_number_get_range(struct fdisk_ask *ask);
+uint64_t fdisk_ask_number_get_default(struct fdisk_ask *ask);
+uint64_t fdisk_ask_number_get_low(struct fdisk_ask *ask);
+uint64_t fdisk_ask_number_get_high(struct fdisk_ask *ask);
+uint64_t fdisk_ask_number_get_result(struct fdisk_ask *ask);
+int fdisk_ask_number_set_result(struct fdisk_ask *ask, uint64_t result);
+uint64_t fdisk_ask_number_get_base(struct fdisk_ask *ask);
+uint64_t fdisk_ask_number_get_unit(struct fdisk_ask *ask);
+int fdisk_ask_number_set_relative(struct fdisk_ask *ask, int relative);
+int fdisk_ask_number_inchars(struct fdisk_ask *ask);
+int fdisk_ask_partnum(struct fdisk_context *cxt, size_t *partnum, int wantnew);
+
+int fdisk_ask_number(struct fdisk_context *cxt,
+		     uintmax_t low,
+		     uintmax_t dflt,
+		     uintmax_t high,
+		     const char *query,
+		     uintmax_t *result);
+char *fdisk_ask_string_get_result(struct fdisk_ask *ask);
+int fdisk_ask_string_set_result(struct fdisk_ask *ask, char *result);
+int fdisk_ask_string(struct fdisk_context *cxt,
+		     const char *query,
+		     char **result);
+int fdisk_ask_yesno(struct fdisk_context *cxt,
+		     const char *query,
+		     int *result);
+int fdisk_ask_yesno_get_result(struct fdisk_ask *ask);
+int fdisk_ask_yesno_set_result(struct fdisk_ask *ask, int result);
+int fdisk_ask_menu_get_default(struct fdisk_ask *ask);
+int fdisk_ask_menu_set_result(struct fdisk_ask *ask, int key);
+int fdisk_ask_menu_get_result(struct fdisk_ask *ask, int *key);
+int fdisk_ask_menu_get_item(struct fdisk_ask *ask, size_t idx, int *key,
+			    const char **name, const char **desc);
+size_t fdisk_ask_menu_get_nitems(struct fdisk_ask *ask);
+int fdisk_ask_print_get_errno(struct fdisk_ask *ask);
+const char *fdisk_ask_print_get_mesg(struct fdisk_ask *ask);
+
+int fdisk_info(struct fdisk_context *cxt, const char *fmt, ...);
+int fdisk_warn(struct fdisk_context *cxt, const char *fmt, ...);
+int fdisk_warnx(struct fdisk_context *cxt, const char *fmt, ...);
+
+/* utils.h */
+extern char *fdisk_partname(const char *dev, size_t partno);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBFDISK_H */
diff --git a/libblkid/libfdisk/src/libfdisk.sym b/libblkid/libfdisk/src/libfdisk.sym
new file mode 100644
index 0000000..bf85d4e
--- /dev/null
+++ b/libblkid/libfdisk/src/libfdisk.sym
@@ -0,0 +1,234 @@
+/*
+ * The symbol versioning ensures that a new application requiring symbol foo;
+ * can't run with old libblkid.so not providing foo;
+ * version info can't enforce this since we never change the SONAME.
+ *
+ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
+ */
+MOUNT_2.26 {
+global:
+	fdisk_add_partition;
+	fdisk_align_lba;
+	fdisk_align_lba_in_range;
+	fdisk_apply_script;
+	fdisk_apply_script_headers;
+	fdisk_apply_table;
+	fdisk_ask_get_query;
+	fdisk_ask_get_type;
+	fdisk_ask_menu_get_default;
+	fdisk_ask_menu_get_item;
+	fdisk_ask_menu_get_nitems;
+	fdisk_ask_menu_get_result;
+	fdisk_ask_menu_set_result;
+	fdisk_ask_number;
+	fdisk_ask_number_get_base;
+	fdisk_ask_number_get_default;
+	fdisk_ask_number_get_high;
+	fdisk_ask_number_get_low;
+	fdisk_ask_number_get_range;
+	fdisk_ask_number_get_result;
+	fdisk_ask_number_get_unit;
+	fdisk_ask_number_inchars;
+	fdisk_ask_number_set_relative;
+	fdisk_ask_number_set_result;
+	fdisk_ask_partnum;
+	fdisk_ask_print_get_errno;
+	fdisk_ask_print_get_mesg;
+	fdisk_ask_string;
+	fdisk_ask_string_get_result;
+	fdisk_ask_string_set_result;
+	fdisk_ask_yesno;
+	fdisk_ask_yesno_get_result;
+	fdisk_ask_yesno_set_result;
+	fdisk_assign_device;
+	fdisk_bsd_edit_disklabel;
+	fdisk_bsd_link_partition;
+	fdisk_bsd_write_bootstrap;
+	fdisk_copy_parttype;
+	fdisk_create_disklabel;
+	fdisk_deassign_device;
+	fdisk_delete_all_partitions;
+	fdisk_delete_partition;
+	fdisk_dos_enable_compatible;
+	fdisk_dos_is_compatible;
+	fdisk_dos_move_begin;
+	fdisk_enable_details;
+	fdisk_enable_listonly;
+	fdisk_field_get_id;
+	fdisk_field_get_name;
+	fdisk_field_get_width;
+	fdisk_field_is_number;
+	fdisk_free_iter;
+	fdisk_get_alignment_offset;
+	fdisk_get_devfd;
+	fdisk_get_devname;
+	fdisk_get_disklabel_id;
+	fdisk_get_first_lba;
+	fdisk_get_freespaces;
+	fdisk_get_geom_cylinders;
+	fdisk_get_geom_heads;
+	fdisk_get_geom_sectors;
+	fdisk_get_grain_size;
+	fdisk_get_label;
+	fdisk_get_last_lba;
+	fdisk_get_minimal_iosize;
+	fdisk_get_nlabels;
+	fdisk_get_npartitions;
+	fdisk_get_nsectors;
+	fdisk_get_optimal_iosize;
+	fdisk_get_parent;
+	fdisk_get_partition;
+	fdisk_get_partitions;
+	fdisk_get_physector_size;
+	fdisk_get_script;
+	fdisk_get_sector_size;
+	fdisk_get_unit;
+	fdisk_get_units_per_sector;
+	fdisk_gpt_is_hybrid;
+	fdisk_has_label;
+	fdisk_has_user_device_properties;
+	fdisk_info;
+	fdisk_init_debug;
+	fdisk_is_details;
+	fdisk_is_labeltype;
+	fdisk_is_listonly;
+	fdisk_is_partition_used;
+	fdisk_is_readonly;
+	fdisk_iter_get_direction;
+	fdisk_label_get_field;
+	fdisk_label_get_field_by_name;
+	fdisk_label_get_fields_ids;
+	fdisk_label_get_name;
+	fdisk_label_get_nparttypes;
+	fdisk_label_get_parttype;
+	fdisk_label_get_parttype_from_code;
+	fdisk_label_get_parttype_from_string;
+	fdisk_label_get_type;
+	fdisk_label_has_code_parttypes;
+	fdisk_label_is_changed;
+	fdisk_label_is_disabled;
+	fdisk_label_parse_parttype;
+	fdisk_label_require_geometry;
+	fdisk_label_set_changed;
+	fdisk_label_set_disabled;
+	fdisk_lba_is_phy_aligned;
+	fdisk_list_disklabel;
+	fdisk_locate_disklabel;
+	fdisk_new_context;
+	fdisk_new_iter;
+	fdisk_new_nested_context;
+	fdisk_new_partition;
+	fdisk_new_parttype;
+	fdisk_new_script;
+	fdisk_new_script_from_file;
+	fdisk_new_table;
+	fdisk_new_unknown_parttype;
+	fdisk_next_label;
+	fdisk_override_geometry;
+	fdisk_partition_cmp_partno;
+	fdisk_partition_cmp_start;
+	fdisk_partition_end_follow_default;
+	fdisk_partition_end_is_default;
+	fdisk_partition_get_attrs;
+	fdisk_partition_get_end;
+	fdisk_partition_get_name;
+	fdisk_partition_get_parent;
+	fdisk_partition_get_partno;
+	fdisk_partition_get_size;
+	fdisk_partition_get_start;
+	fdisk_partition_get_type;
+	fdisk_partition_get_uuid;
+	fdisk_partition_has_end;
+	fdisk_partition_has_partno;
+	fdisk_partition_has_size;
+	fdisk_partition_has_start;
+	fdisk_partition_is_bootable;
+	fdisk_partition_is_container;
+	fdisk_partition_is_freespace;
+	fdisk_partition_is_nested;
+	fdisk_partition_is_used;
+	fdisk_partition_next_partno;
+	fdisk_partition_partno_follow_default;
+	fdisk_partition_set_attrs;
+	fdisk_partition_set_name;
+	fdisk_partition_set_partno;
+	fdisk_partition_set_size;
+	fdisk_partition_set_start;
+	fdisk_partition_set_type;
+	fdisk_partition_set_uuid;
+	fdisk_partition_size_explicit;
+	fdisk_partition_start_follow_default;
+	fdisk_partition_start_is_default;
+	fdisk_toggle_partition_flag;
+	fdisk_partition_to_string;
+	fdisk_partition_unset_partno;
+	fdisk_partition_unset_size;
+	fdisk_partition_unset_start;
+	fdisk_partname;
+	fdisk_parttype_get_code;
+	fdisk_parttype_get_name;
+	fdisk_parttype_get_string;
+	fdisk_parttype_is_unknown;
+	fdisk_parttype_set_code;
+	fdisk_parttype_set_name;
+	fdisk_parttype_set_typestr;
+	fdisk_ref_ask;
+	fdisk_ref_context;
+	fdisk_ref_partition;
+	fdisk_ref_parttype;
+	fdisk_ref_script;
+	fdisk_ref_table;
+	fdisk_reorder_partitions;
+	fdisk_reread_partition_table;
+	fdisk_reset_alignment;
+	fdisk_reset_device_properties;
+	fdisk_reset_iter;
+	fdisk_reset_partition;
+	fdisk_reset_table;
+	fdisk_save_user_geometry;
+	fdisk_save_user_sector_size;
+	fdisk_script_get_header;
+	fdisk_script_get_nlines;
+	fdisk_script_get_table;
+	fdisk_script_read_context;
+	fdisk_script_read_file;
+	fdisk_script_read_line;
+	fdisk_script_set_header;
+	fdisk_script_write_file;
+	fdisk_set_ask;
+	fdisk_set_disklabel_id;
+	fdisk_set_first_lba;
+	fdisk_set_last_lba;
+	fdisk_set_partition;
+	fdisk_set_partition_type;
+	fdisk_set_script;
+	fdisk_set_unit;
+	fdisk_sgi_create_info;
+	fdisk_sgi_set_bootfile;
+	fdisk_sun_set_alt_cyl;
+	fdisk_sun_set_ilfact;
+	fdisk_sun_set_pcylcount;
+	fdisk_sun_set_rspeed;
+	fdisk_sun_set_xcyl;
+	fdisk_table_add_partition;
+	fdisk_table_get_nents;
+	fdisk_table_get_partition;
+	fdisk_table_is_empty;
+	fdisk_table_next_partition;
+	fdisk_table_remove_partition;
+	fdisk_table_sort_partitions;
+	fdisk_table_wrong_order;
+	fdisk_unref_ask;
+	fdisk_unref_context;
+	fdisk_unref_partition;
+	fdisk_unref_parttype;
+	fdisk_unref_script;
+	fdisk_unref_table;
+	fdisk_use_cylinders;
+	fdisk_verify_disklabel;
+	fdisk_warn;
+	fdisk_warnx;
+	fdisk_write_disklabel;
+local:
+	*;
+};
diff --git a/libblkid/libfdisk/src/partition.c b/libblkid/libfdisk/src/partition.c
new file mode 100644
index 0000000..8f84027
--- /dev/null
+++ b/libblkid/libfdisk/src/partition.c
@@ -0,0 +1,963 @@
+
+#include "c.h"
+#include "strutils.h"
+
+#include "fdiskP.h"
+
+/**
+ * SECTION: partition
+ * @title: Partition
+ * @short_description: generic label independent partition abstraction
+ *
+ * The fdisk_partition provides label independent abstraction. The partitions
+ * are not directly connected with partition table (label) data. Any change to
+ * fdisk_partition does not affects in-memory or on-disk label data.
+ *
+ * The fdisk_partition is possible to use as a template for
+ * fdisk_add_partition() or fdisk_set_partition() operations.
+ */
+
+static void init_partition(struct fdisk_partition *pa)
+{
+	FDISK_INIT_UNDEF(pa->size);
+	FDISK_INIT_UNDEF(pa->start);
+	FDISK_INIT_UNDEF(pa->partno);
+	FDISK_INIT_UNDEF(pa->parent_partno);
+	FDISK_INIT_UNDEF(pa->boot);
+
+	INIT_LIST_HEAD(&pa->parts);
+}
+
+/**
+ * fdisk_new_partition:
+ *
+ * Returns: new instance.
+ */
+struct fdisk_partition *fdisk_new_partition(void)
+{
+	struct fdisk_partition *pa = calloc(1, sizeof(*pa));
+
+	pa->refcount = 1;
+	init_partition(pa);
+	DBG(PART, ul_debugobj(pa, "alloc"));
+	return pa;
+}
+
+/**
+ * fdisk_reset_partition:
+ * @pa: partition
+ *
+ * Resets partition content.
+ */
+void fdisk_reset_partition(struct fdisk_partition *pa)
+{
+	int ref;
+
+	if (!pa)
+		return;
+
+	DBG(PART, ul_debugobj(pa, "reset"));
+	ref = pa->refcount;
+
+	fdisk_unref_parttype(pa->type);
+	free(pa->name);
+	free(pa->uuid);
+	free(pa->attrs);
+
+	memset(pa, 0, sizeof(*pa));
+	pa->refcount = ref;
+
+	init_partition(pa);
+}
+
+/**
+ * fdisk_ref_partition:
+ * @pa: partition pointer
+ *
+ * Incremparts reference counter.
+ */
+void fdisk_ref_partition(struct fdisk_partition *pa)
+{
+	if (pa)
+		pa->refcount++;
+}
+
+/**
+ * fdisk_unref_partition:
+ * @pa: partition pointer
+ *
+ * De-incremparts reference counter, on zero the @pa is automatically
+ * deallocated.
+ */
+void fdisk_unref_partition(struct fdisk_partition *pa)
+{
+	if (!pa)
+		return;
+
+	pa->refcount--;
+	if (pa->refcount <= 0) {
+		fdisk_reset_partition(pa);
+		list_del(&pa->parts);
+		DBG(PART, ul_debugobj(pa, "free"));
+		free(pa);
+	}
+}
+
+/**
+ * fdisk_partition_set_start:
+ * @pa: partition
+ * @off: offset in sectors, maximal is UINT64_MAX-1
+ *
+ * Note that zero is valid offset too. Use fdisk_partition_unset_start() to
+ * undefine the offset. 
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_partition_set_start(struct fdisk_partition *pa, fdisk_sector_t off)
+{
+	if (!pa)
+		return -EINVAL;
+	if (FDISK_IS_UNDEF(off))
+		return -ERANGE;
+	pa->start = off;
+	return 0;
+}
+
+/**
+ * fdisk_partition_unset_start:
+ * @pa: partition
+ *
+ * Sets the size as undefined. See fdisk_partition_has_start().
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_partition_unset_start(struct fdisk_partition *pa)
+{
+	if (!pa)
+		return -EINVAL;
+	FDISK_INIT_UNDEF(pa->start);
+	return 0;
+}
+
+/**
+ * fdisk_partition_get_start:
+ * @pa: partition
+ *
+ * The zero is also valid offset. The function may return random undefined
+ * value when start offset is undefined (for example after
+ * fdisk_partition_unset_start()). Always use fdisk_partition_has_start() to be
+ * sure that you work with valid numbers.
+ *
+ * Returns: start offset in sectors
+ */
+fdisk_sector_t fdisk_partition_get_start(struct fdisk_partition *pa)
+{
+	return pa->start;
+}
+
+/**
+ * fdisk_partition_has_start:
+ * @pa: partition
+ *
+ * Returns: 1 or 0
+ */
+int fdisk_partition_has_start(struct fdisk_partition *pa)
+{
+	return pa && !FDISK_IS_UNDEF(pa->start);
+}
+
+
+/**
+ * fdisk_partition_cmp_start:
+ * @a: partition
+ * @b: partition
+ *
+ * Compares partitons according to start offset, See fdisk_sort_table().
+ *
+ * Return: 0 if the same, <0 if @b greater, >0 if @a greater.
+ */
+int fdisk_partition_cmp_start(struct fdisk_partition *a,
+			      struct fdisk_partition *b)
+{
+	int no_a = FDISK_IS_UNDEF(a->start),
+	    no_b = FDISK_IS_UNDEF(b->start);
+
+	if (no_a && no_b)
+		return 0;
+	if (no_a)
+		return -1;
+	if (no_b)
+		return 1;
+
+	return cmp_numbers(a->start, b->start);
+}
+
+/**
+ * fdisk_partition_start_follow_default
+ * @pa: partition
+ * @enable: 0|1
+ *
+ * When @pa used as a tempalate for fdisk_add_partition() when force label driver
+ * to use the first possible space for the new partition.
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_partition_start_follow_default(struct fdisk_partition *pa, int enable)
+{
+	if (!pa)
+		return -EINVAL;
+	pa->start_follow_default = enable ? 1 : 0;
+	return 0;
+}
+
+/**
+ * fdisk_partition_start_is_default:
+ * @pa: partition
+ *
+ * See fdisk_partition_start_follow_default().
+ *
+ * Returns: 1 if the partition follows default
+ */
+int fdisk_partition_start_is_default(struct fdisk_partition *pa)
+{
+	assert(pa);
+	return pa->start_follow_default;
+}
+
+
+/**
+ * fdisk_partition_set_size:
+ * @pa: partition
+ * @sz: size in sectors, maximal is UIN64_MAX-1
+ *
+ * Note that zero is valid size too. Use fdisk_partition_unset_size() to
+ * undefine the size.
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_partition_set_size(struct fdisk_partition *pa, fdisk_sector_t sz)
+{
+	if (!pa)
+		return -EINVAL;
+	if (FDISK_IS_UNDEF(sz))
+		return -ERANGE;
+	pa->size = sz;
+	return 0;
+}
+
+/**
+ * fdisk_partition_unset_size:
+ * @pa: partition
+ *
+ * Sets the size as undefined. See fdisk_partition_has_size().
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_partition_unset_size(struct fdisk_partition *pa)
+{
+	if (!pa)
+		return -EINVAL;
+	FDISK_INIT_UNDEF(pa->size);
+	return 0;
+}
+
+/**
+ * fdisk_partition_get_size:
+ * @pa: partition
+ *
+ * The zero is also valid size. The function may return random undefined
+ * value when size is undefined (for example after fdisk_partition_unset_size()).
+ * Always use fdisk_partition_has_size() to be sure that you work with valid 
+ * numbers.
+ *
+ * Returns: size offset in sectors
+ */
+fdisk_sector_t fdisk_partition_get_size(struct fdisk_partition *pa)
+{
+	return pa->size;
+}
+
+/**
+ * fdisk_partition_has_size:
+ * @pa: partition
+ *
+ * Returns: 1 or 0
+ */
+int fdisk_partition_has_size(struct fdisk_partition *pa)
+{
+	return pa && !FDISK_IS_UNDEF(pa->size);
+}
+
+/**
+ * fdisk_partition_size_explicit:
+ * @pa: partition
+ * @enable: 0|1
+ *
+ * By default libfdisk aligns the size when add the new partition (by
+ * fdisk_add_partrition()). If you want to disable this functionality use
+ * @enable = 1.
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_partition_size_explicit(struct fdisk_partition *pa, int enable)
+{
+	if (!pa)
+		return -EINVAL;
+	pa->size_explicit = enable ? 1 : 0;
+	return 0;
+}
+
+/**
+ * fdisk_partition_set_partno:
+ * @pa: partition
+ * @num: partitin number (0 is the first partition, maximal is SIZE_MAX-1)
+ *
+ * Note that zero is valid partno too. Use fdisk_partition_unset_partno() to
+ * undefine the partno.
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_partition_set_partno(struct fdisk_partition *pa, size_t num)
+{
+	if (!pa)
+		return -EINVAL;
+	if (FDISK_IS_UNDEF(num))
+		return -ERANGE;
+	pa->partno = num;
+	return 0;
+}
+
+/**
+ * fdisk_partition_unset_partno:
+ * @pa: partition
+ *
+ * Sets the partno as undefined. See fdisk_partition_has_partno().
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_partition_unset_partno(struct fdisk_partition *pa)
+{
+	if (!pa)
+		return -EINVAL;
+	FDISK_INIT_UNDEF(pa->partno);
+	return 0;
+}
+
+/**
+ * fdisk_partition_get_partno:
+ * @pa: partition
+ *
+ * The zero is also valid parition number. The function may return random
+ * value when partno is undefined (for example after fdisk_partition_unset_partno()).
+ * Always use fdisk_partition_has_partno() to be sure that you work with valid
+ * numbers.
+ *
+ * Returns: partition number (0 is the first partition)
+ */
+size_t fdisk_partition_get_partno(struct fdisk_partition *pa)
+{
+	return pa->partno;
+}
+
+/**
+ * fdisk_partition_has_partno:
+ * @pa: partition
+ *
+ * Returns: 1 or 0
+ */
+int fdisk_partition_has_partno(struct fdisk_partition *pa)
+{
+	return pa && !FDISK_IS_UNDEF(pa->partno);
+}
+
+
+/**
+ * fdisk_partition_cmp_partno:
+ * @a: partition
+ * @b: partition
+ *
+ * Compares partitons according to partition number See fdisk_sort_table().
+ *
+ * Return: 0 if the same, <0 if @b greater, >0 if @a greater.
+ */
+int fdisk_partition_cmp_partno(struct fdisk_partition *a,
+			       struct fdisk_partition *b)
+{
+	return a->partno - b->partno;
+}
+
+/**
+ * fdisk_partition_partno_follow_default
+ * @pa: partition
+ * @enable: 0|1
+ *
+ * When @pa used as a tempalate for fdisk_add_partition() when force label driver
+ * to add a new partition to the default (next) position.
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_partition_partno_follow_default(struct fdisk_partition *pa, int enable)
+{
+	if (!pa)
+		return -EINVAL;
+	pa->partno_follow_default = enable ? 1 : 0;
+	return 0;
+}
+
+/**
+ * fdisk_partition_set_type:
+ * @pa: partition
+ * @type: partition type
+ *
+ * Sets parition type.
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_partition_set_type(struct fdisk_partition *pa,
+			     struct fdisk_parttype *type)
+{
+	if (!pa)
+		return -EINVAL;
+
+	fdisk_ref_parttype(type);
+	fdisk_unref_parttype(pa->type);
+	pa->type = type;
+
+	return 0;
+}
+
+/**
+ * fdisk_partition_get_type:
+ * @pa: partition
+ *
+ * Returns: pointer to partition type.
+ */
+struct fdisk_parttype *fdisk_partition_get_type(struct fdisk_partition *pa)
+{
+	return pa ? pa->type : NULL;
+}
+
+int fdisk_partition_set_name(struct fdisk_partition *pa, const char *name)
+{
+	char *p = NULL;
+
+	if (!pa)
+		return -EINVAL;
+	if (name) {
+	       p = strdup(name);
+	       if (!p)
+		       return -ENOMEM;
+	}
+	free(pa->name);
+	pa->name = p;
+	return 0;
+}
+
+const char *fdisk_partition_get_name(struct fdisk_partition *pa)
+{
+	return pa ? pa->name : NULL;
+}
+
+int fdisk_partition_set_uuid(struct fdisk_partition *pa, const char *uuid)
+{
+	char *p = NULL;
+
+	if (!pa)
+		return -EINVAL;
+	if (uuid) {
+	       p = strdup(uuid);
+	       if (!p)
+		       return -ENOMEM;
+	}
+	free(pa->uuid);
+	pa->uuid = p;
+	return 0;
+}
+
+/**
+ * fdisk_partition_has_end:
+ * @pa: partition
+ *
+ * Returns: 1 if the partition has defined last sector
+ */
+int fdisk_partition_has_end(struct fdisk_partition *pa)
+{
+	return pa && !FDISK_IS_UNDEF(pa->start) && !FDISK_IS_UNDEF(pa->size);
+}
+
+/**
+ * fdisk_partition_get_end:
+ * @pa: partition
+ *
+ * This function may returns absolute non-sense, always check
+ * fdisk_partition_has_end().
+ *
+ * Note that partition end is defined by fdisk_partition_set_start() and
+ * fdisk_partition_set_size().
+ *
+ * Returns: last partition sector LBA.
+ */
+fdisk_sector_t fdisk_partition_get_end(struct fdisk_partition *pa)
+{
+	return pa->start + pa->size - (pa->size == 0 ? 0 : 1);
+}
+
+/**
+ * fdisk_partition_end_follow_default
+ * @pa: partition
+ * @enable: 0|1
+ *
+ * When @pa used as a tempalate for fdisk_add_partition() when force label driver
+ * to use all the possible space for the new partition.
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_partition_end_follow_default(struct fdisk_partition *pa, int enable)
+{
+	if (!pa)
+		return -EINVAL;
+	pa->end_follow_default = enable ? 1 : 0;
+	return 0;
+}
+
+/**
+ * fdisk_partition_end_is_default:
+ * @pa: partition
+ *
+ * Returns: 1 if the partition follows default
+ */
+int fdisk_partition_end_is_default(struct fdisk_partition *pa)
+{
+	assert(pa);
+	return pa->end_follow_default;
+}
+
+const char *fdisk_partition_get_uuid(struct fdisk_partition *pa)
+{
+	return pa ? pa->uuid : NULL;
+}
+
+const char *fdisk_partition_get_attrs(struct fdisk_partition *pa)
+{
+	return pa ? pa->attrs : NULL;
+}
+
+int fdisk_partition_set_attrs(struct fdisk_partition *pa, const char *attrs)
+{
+	char *p = NULL;
+
+	if (!pa)
+		return -EINVAL;
+	if (attrs) {
+	       p = strdup(attrs);
+	       if (!p)
+		       return -ENOMEM;
+	}
+	free(pa->attrs);
+	pa->attrs = p;
+	return 0;
+}
+
+int fdisk_partition_is_nested(struct fdisk_partition *pa)
+{
+	return pa && !FDISK_IS_UNDEF(pa->parent_partno);
+}
+
+int fdisk_partition_is_container(struct fdisk_partition *pa)
+{
+	return pa && pa->container;
+}
+
+int fdisk_partition_get_parent(struct fdisk_partition *pa, size_t *parent)
+{
+	if (pa && parent)
+		*parent = pa->parent_partno;
+	else
+		return -EINVAL;
+	return 0;
+}
+
+int fdisk_partition_is_used(struct fdisk_partition *pa)
+{
+	return pa && pa->used;
+}
+
+int fdisk_partition_is_bootable(struct fdisk_partition *pa)
+{
+	return pa && pa->boot == 1;
+}
+
+int fdisk_partition_is_freespace(struct fdisk_partition *pa)
+{
+	return pa && pa->freespace;
+}
+
+int fdisk_partition_next_partno(
+		struct fdisk_partition *pa,
+		struct fdisk_context *cxt,
+		size_t *n)
+{
+	assert(cxt);
+	assert(n);
+
+	if (pa && pa->partno_follow_default) {
+		size_t i;
+
+		DBG(PART, ul_debugobj(pa, "next partno (follow default)"));
+
+		for (i = 0; i < cxt->label->nparts_max; i++) {
+			if (!fdisk_is_partition_used(cxt, i)) {
+				*n = i;
+				return 0;
+			}
+		}
+		return -ERANGE;
+
+	} else if (pa && fdisk_partition_has_partno(pa)) {
+
+		DBG(PART, ul_debugobj(pa, "next partno (specified=%zu)", pa->partno));
+
+		if (pa->partno >= cxt->label->nparts_max)
+			return -ERANGE;
+		*n = pa->partno;
+	} else
+		return fdisk_ask_partnum(cxt, n, 1);
+
+	return 0;
+}
+
+/**
+ * fdisk_partition_to_string:
+ * @pa: partition
+ * @cxt: context
+ * @id: field (FDISK_FIELD_*)
+ * @data: returns string with allocated data
+ *
+ * Returns info about partition converted to printable string.
+ *
+ * For example
+ * <informalexample>
+ *   <programlisting>
+ *      struct fdisk_parition *pa;
+ *
+ *      fdisk_get_partition(cxt, 0, &pa);
+ *	fdisk_partition_to_string(pa, FDISK_FIELD_UUID, &data);
+ *	printf("first partition uuid: %s\n", data);
+ *	free(data);
+ *	fdisk_unref_partition(pa);
+ *   </programlisting>
+ * </informalexample>
+ *
+ * returns UUID for the first partition.
+ *
+ * Returns: 0 on success, otherwise, a corresponding error.
+ */
+int fdisk_partition_to_string(struct fdisk_partition *pa,
+			      struct fdisk_context *cxt,
+			      int id,
+			      char **data)
+{
+	char *p = NULL;
+	int rc = 0;
+	uint64_t x;
+
+	if (!pa || !cxt)
+		return -EINVAL;
+
+	switch (id) {
+	case FDISK_FIELD_DEVICE:
+		if (pa->freespace)
+			p = strdup(_("Free space"));
+		else if (fdisk_partition_has_partno(pa) && cxt->dev_path) {
+			if (cxt->label->flags & FDISK_LABEL_FL_INCHARS_PARTNO)
+				rc = asprintf(&p, "%c", (int) pa->partno + 'a');
+			else
+				p = fdisk_partname(cxt->dev_path, pa->partno + 1);
+		}
+		break;
+	case FDISK_FIELD_BOOT:
+		if (fdisk_partition_is_bootable(pa))
+			rc = asprintf(&p, "%c", pa->boot ? '*' : ' ');
+		break;
+	case FDISK_FIELD_START:
+		if (fdisk_partition_has_start(pa)) {
+			x = fdisk_cround(cxt, pa->start);
+			rc = pa->start_post ?
+				asprintf(&p, "%ju%c", x, pa->start_post) :
+				asprintf(&p, "%ju", x);
+		}
+		break;
+	case FDISK_FIELD_END:
+		if (fdisk_partition_has_end(pa)) {
+			x = fdisk_cround(cxt, fdisk_partition_get_end(pa));
+			rc = pa->end_post ?
+					asprintf(&p, "%ju%c", x, pa->end_post) :
+					asprintf(&p, "%ju", x);
+		}
+		break;
+	case FDISK_FIELD_SIZE:
+		if (fdisk_partition_has_size(pa)) {
+			uint64_t sz = pa->size * cxt->sector_size;
+
+			if (fdisk_is_details(cxt)) {
+				rc = pa->size_post ?
+						asprintf(&p, "%ju%c", sz, pa->size_post) :
+						asprintf(&p, "%ju", sz);
+			} else {
+				p = size_to_human_string(SIZE_SUFFIX_1LETTER, sz);
+				if (!p)
+					rc = -ENOMEM;
+			}
+		}
+		break;
+	case FDISK_FIELD_CYLINDERS:
+		rc = asprintf(&p, "%ju", (uintmax_t)
+			fdisk_cround(cxt, fdisk_partition_has_size(pa) ? pa->size : 0));
+		break;
+	case FDISK_FIELD_SECTORS:
+		rc = asprintf(&p, "%ju",
+			fdisk_partition_has_size(pa) ? (uintmax_t) pa->size : 0);
+		break;
+	case FDISK_FIELD_BSIZE:
+		rc = asprintf(&p, "%ju", pa->bsize);
+		break;
+	case FDISK_FIELD_FSIZE:
+		rc = asprintf(&p, "%ju", pa->fsize);
+		break;
+	case FDISK_FIELD_CPG:
+		rc = asprintf(&p, "%ju", pa->cpg);
+		break;
+	case FDISK_FIELD_TYPE:
+		p = pa->type && pa->type->name ? strdup(pa->type->name) : NULL;
+		break;
+	case FDISK_FIELD_TYPEID:
+		if (pa->type && fdisk_parttype_get_string(pa->type))
+			rc = asprintf(&p, "%s", fdisk_parttype_get_string(pa->type));
+		else if (pa->type)
+			rc = asprintf(&p, "%x", fdisk_parttype_get_code(pa->type));
+		break;
+	case FDISK_FIELD_UUID:
+		p = pa->uuid ? strdup(pa->uuid) : NULL;
+		break;
+	case FDISK_FIELD_NAME:
+		p = pa->name ? strdup(pa->name) : NULL;
+		break;
+	case FDISK_FIELD_ATTR:
+		p = pa->attrs ? strdup(pa->attrs) : NULL;
+		break;
+	case FDISK_FIELD_SADDR:
+		p = pa->start_chs ? strdup(pa->start_chs) : NULL;
+		break;
+	case FDISK_FIELD_EADDR:
+		p = pa->end_chs ? strdup(pa->end_chs) : NULL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (rc < 0)
+		rc = -ENOMEM;
+	else if (rc > 0)
+		rc = 0;
+
+	if (data)
+		*data = p;
+	return rc;
+}
+
+/**
+ * fdisk_get_partition:
+ * @cxt: context
+ * @partno: partition number (0 is the first partition)
+ * @pa: returns data about partition
+ *
+ * Reads disklabel and fills in @pa with data about partition @n.
+ *
+ * Note that partno may address unused partition and then this function does
+ * not fill anything to @pa.  See fdisk_is_partition_used(). If @pa points to
+ * NULL then the function allocates a newly allocated fdisk_partition struct,
+ * use fdisk_unref_partition() to deallocate.
+ *
+ * Returns: 0 on success, otherwise, a corresponding error.
+ */
+int fdisk_get_partition(struct fdisk_context *cxt, size_t partno,
+			struct fdisk_partition **pa)
+{
+	int rc;
+	struct fdisk_partition *np = NULL;
+
+	if (!cxt || !cxt->label || !pa)
+		return -EINVAL;
+	if (!cxt->label->op->get_part)
+		return -ENOSYS;
+	if (!fdisk_is_partition_used(cxt, partno))
+		return -EINVAL;
+
+	if (!*pa) {
+		np = *pa = fdisk_new_partition();
+		if (!*pa)
+			return -ENOMEM;
+	} else
+		fdisk_reset_partition(*pa);
+
+	(*pa)->partno = partno;
+	rc = cxt->label->op->get_part(cxt, partno, *pa);
+
+	if (rc) {
+		if (np) {
+			fdisk_unref_partition(np);
+			*pa = NULL;
+		} else
+			fdisk_reset_partition(*pa);
+	} else
+		(*pa)->size_explicit = 1;
+	return rc;
+}
+
+/**
+ * fdisk_set_partition:
+ * @cxt: context
+ * @partno: partition number (0 is the first partition)
+ * @pa: new partition setting
+ *
+ * Modifies disklabel according to setting with in @pa.
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_set_partition(struct fdisk_context *cxt, size_t partno,
+			struct fdisk_partition *pa)
+{
+	if (!cxt || !cxt->label || !pa)
+		return -EINVAL;
+	if (!cxt->label->op->set_part)
+		return -ENOSYS;
+
+	DBG(CXT, ul_debugobj(cxt, "setting partition %zu %p (start=%ju, end=%ju, size=%ju, "
+		    "defaults(start=%s, end=%s, partno=%s)",
+		    partno, pa,
+		    (uintmax_t) fdisk_partition_get_start(pa),
+		    (uintmax_t) fdisk_partition_get_end(pa),
+		    (uintmax_t) fdisk_partition_get_size(pa),
+		    pa->start_follow_default ? "yes" : "no",
+		    pa->end_follow_default ? "yes" : "no",
+		    pa->partno_follow_default ? "yes" : "no"));
+
+	return cxt->label->op->set_part(cxt, partno, pa);
+}
+
+/**
+ * fdisk_add_partition:
+ * @cxt: fdisk context
+ * @pa: template for the partition (or NULL)
+ * @partno: NULL or returns new partition number
+ *
+ * If @pa is not specified or any @pa item is missiong the libfdisk will ask by
+ * fdisk_ask_ API.
+ *
+ * Adds a new partition to disklabel.
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_add_partition(struct fdisk_context *cxt,
+			struct fdisk_partition *pa,
+			size_t *partno)
+{
+	int rc;
+
+	assert(cxt);
+	assert(cxt->label);
+
+	if (!cxt || !cxt->label)
+		return -EINVAL;
+	if (!cxt->label->op->add_part)
+		return -ENOSYS;
+	if (fdisk_missing_geometry(cxt))
+		return -EINVAL;
+
+	if (pa)
+		DBG(CXT, ul_debugobj(cxt, "adding new partition %p (start=%ju, end=%ju, size=%ju, "
+			    "defaults(start=%s, end=%s, partno=%s)",
+			    pa,
+			    (uintmax_t) fdisk_partition_get_start(pa),
+			    (uintmax_t) fdisk_partition_get_end(pa),
+			    (uintmax_t) fdisk_partition_get_size(pa),
+			    pa->start_follow_default ? "yes" : "no",
+			    pa->end_follow_default ? "yes" : "no",
+			    pa->partno_follow_default ? "yes" : "no"));
+	else
+		DBG(CXT, ul_debugobj(cxt, "adding partition"));
+
+	rc = cxt->label->op->add_part(cxt, pa, partno);
+
+	DBG(CXT, ul_debugobj(cxt, "add partition done (rc=%d)", rc));
+	return rc;
+}
+
+/**
+ * fdisk_delete_partition:
+ * @cxt: fdisk context
+ * @partno: partition number to delete (0 is the first partition)
+ *
+ * Deletes a @partno partition from disklabel.
+ *
+ * Returns: 0 on success, <0 on error
+ */
+int fdisk_delete_partition(struct fdisk_context *cxt, size_t partno)
+{
+	if (!cxt || !cxt->label)
+		return -EINVAL;
+	if (!cxt->label->op->del_part)
+		return -ENOSYS;
+
+	DBG(CXT, ul_debugobj(cxt, "deleting %s partition number %zd",
+				cxt->label->name, partno));
+	return cxt->label->op->del_part(cxt, partno);
+}
+
+/**
+ * fdisk_delete_all_partitions:
+ * @cxt: fdisk context
+ *
+ * Delete all used partitions from disklabel.
+ *
+ * Returns: 0 on success, otherwise, a corresponding error.
+ */
+int fdisk_delete_all_partitions(struct fdisk_context *cxt)
+{
+	size_t i;
+	int rc;
+
+	if (!cxt || !cxt->label)
+		return -EINVAL;
+
+	for (i = 0; i < cxt->label->nparts_max; i++) {
+
+		if (!fdisk_is_partition_used(cxt, i))
+			continue;
+		rc = fdisk_delete_partition(cxt, i);
+		if (rc)
+			break;
+	}
+
+	return rc;
+}
+
+/**
+ * fdisk_is_partition_used:
+ * @cxt: context
+ * @n: partition number (0 is the first partition)
+ *
+ * This is faster than fdisk_get_partition() + fdisk_partition_is_used().
+ *
+ * Returns: 0 or 1
+ */
+int fdisk_is_partition_used(struct fdisk_context *cxt, size_t n)
+{
+	if (!cxt || !cxt->label)
+		return -EINVAL;
+	if (!cxt->label->op->part_is_used)
+		return -ENOSYS;
+
+	return cxt->label->op->part_is_used(cxt, n);
+}
+
diff --git a/libblkid/libfdisk/src/parttype.c b/libblkid/libfdisk/src/parttype.c
new file mode 100644
index 0000000..aedf4e8
--- /dev/null
+++ b/libblkid/libfdisk/src/parttype.c
@@ -0,0 +1,401 @@
+
+#include <ctype.h>
+
+#include "nls.h"
+#include "fdiskP.h"
+
+/**
+ * SECTION: parttype
+ * @title: Partition types
+ * @short_description: abstraction to partition types
+ *
+ * There are two basic types of parttypes, string based (e.g. GPT)
+ * and code/hex based (e.g. MBR).
+ */
+
+/**
+ * fdisk_new_parttype:
+ *
+ * It's recommended to use fdisk_label_get_parttype_from_code() or
+ * fdisk_label_get_parttype_from_string() for well known types rather
+ * than allocate a new instance.
+ *
+ * Returns: new instance.
+ */
+struct fdisk_parttype *fdisk_new_parttype(void)
+{
+	struct fdisk_parttype *t = calloc(1, sizeof(*t));
+
+	t->refcount = 1;
+	t->flags = FDISK_PARTTYPE_ALLOCATED;
+	DBG(PARTTYPE, ul_debugobj(t, "alloc"));
+	return t;
+}
+
+/**
+ * fdisk_ref_parttype:
+ * @t: partition type
+ *
+ * Incremparts reference counter for allocated types
+ */
+void fdisk_ref_parttype(struct fdisk_parttype *t)
+{
+	if (fdisk_parttype_is_allocated(t))
+		t->refcount++;
+}
+
+/**
+ * fdisk_unref_parttype
+ * @t: partition pointer
+ *
+ * De-incremparts reference counter, on zero the @t is automatically
+ * deallocated.
+ */
+void fdisk_unref_parttype(struct fdisk_parttype *t)
+{
+	if (!fdisk_parttype_is_allocated(t))
+		return;
+
+	t->refcount--;
+	if (t->refcount <= 0) {
+		DBG(PARTTYPE, ul_debugobj(t, "free"));
+		free(t->typestr);
+		free(t->name);
+		free(t);
+	}
+}
+
+/**
+ * fdisk_parttype_set_name:
+ * @t: partition type
+ * @str: type name
+ *
+ * Sets type name to allocated partition type, for static types
+ * it returns -EINVAL.
+ *
+ * Return: 0 on success, <0 on error
+ */
+int fdisk_parttype_set_name(struct fdisk_parttype *t, const char *str)
+{
+	char *p = NULL;
+
+	if (!t || !fdisk_parttype_is_allocated(t))
+		return -EINVAL;
+	if (str) {
+		p = strdup(str);
+		if (!p)
+			return -ENOMEM;
+	}
+
+	free(t->name);
+	t->name = p;
+	return 0;
+}
+
+/**
+ * fdisk_parttype_set_typestr:
+ * @t: partition type
+ * @str: type identificator (e.g. GUID for GPT)
+ *
+ * Sets type string to allocated partition type, for static types
+ * it returns -EINVAL. Don't use this function for MBR, see
+ * fdisk_parttype_set_code().
+ *
+ * Return: 0 on success, <0 on error
+ */
+int fdisk_parttype_set_typestr(struct fdisk_parttype *t, const char *str)
+{
+	char *p = NULL;
+
+	if (!t || !fdisk_parttype_is_allocated(t))
+		return -EINVAL;
+	if (str) {
+		p = strdup(str);
+		if (!p)
+			return -ENOMEM;
+	}
+
+	free(t->typestr);
+	t->typestr = p;
+	return 0;
+}
+
+/**
+ * fdisk_parttype_set_code:
+ * @t: partition type
+ * @code: type identificator (e.g. MBR type codes)
+ *
+ * Sets type code to allocated partition type, for static types it returns
+ * -EINVAL. Don't use this function for GPT, see fdisk_parttype_set_typestr().
+ *
+ * Return: 0 on success, <0 on error
+ */
+int fdisk_parttype_set_code(struct fdisk_parttype *t, int code)
+{
+	if (!t || !fdisk_parttype_is_allocated(t))
+		return -EINVAL;
+	t->code = code;
+	return 0;
+}
+
+/**
+ * fdisk_label_get_nparttypes:
+ * @lb: label
+ *
+ * Returns: number of types supported by label.
+ */
+size_t fdisk_label_get_nparttypes(const struct fdisk_label *lb)
+{
+	if (!lb)
+		return 0;
+	return lb->nparttypes;
+}
+
+/**
+ * fdisk_label_get_parttype:
+ * @lb: label
+ * @n: number
+ *
+ * Returns: return parttype
+ */
+struct fdisk_parttype *fdisk_label_get_parttype(const struct fdisk_label *lb, size_t n)
+{
+	if (!lb || n >= lb->nparttypes)
+		return NULL;
+	return &lb->parttypes[n];
+}
+
+/**
+ * fdisk_label_has_code_parttypes:
+ * @lb: label
+ *
+ * Returns: 1 if the label uses code as partition type
+ *          identifiers (e.g. MBR) or 0.
+ */
+int fdisk_label_has_code_parttypes(const struct fdisk_label *lb)
+{
+	assert(lb);
+
+	if (lb->parttypes && lb->parttypes[0].typestr)
+		return 0;
+	return 1;
+}
+
+
+/**
+ * fdisk_label_get_parttype_from_code:
+ * @lb: label
+ * @code: code to search for
+ *
+ * Search for partition type in label-specific table. The result
+ * is pointer to static array of label types.
+ *
+ * Returns: partition type or NULL upon failure or invalid @code.
+ */
+struct fdisk_parttype *fdisk_label_get_parttype_from_code(
+				const struct fdisk_label *lb,
+				unsigned int code)
+{
+	size_t i;
+
+	assert(lb);
+
+	if (!lb->nparttypes)
+		return NULL;
+
+	for (i = 0; i < lb->nparttypes; i++)
+		if (lb->parttypes[i].code == code)
+			return &lb->parttypes[i];
+	return NULL;
+}
+
+/**
+ * fdisk_label_get_parttype_from_string:
+ * @lb: label
+ * @str: string to search for
+ *
+ * Search for partition type in label-specific table. The result
+ * is pointer to static array of label types.
+ *
+ * Returns: partition type or NULL upon failure or invalid @str.
+ */
+struct fdisk_parttype *fdisk_label_get_parttype_from_string(
+				const struct fdisk_label *lb,
+				const char *str)
+{
+	size_t i;
+
+	assert(lb);
+
+	if (!lb->nparttypes)
+		return NULL;
+
+	for (i = 0; i < lb->nparttypes; i++)
+		if (lb->parttypes[i].typestr
+		    && strcasecmp(lb->parttypes[i].typestr, str) == 0)
+			return &lb->parttypes[i];
+
+	return NULL;
+}
+
+/**
+ * fdisk_new_unknown_parttype:
+ * @code: type as number
+ * @typestr: type as string
+
+ * Allocates new 'unknown' partition type. Use fdisk_unref_parttype() to
+ * deallocate.
+ *
+ * Returns: newly allocated partition type, or NULL upon failure.
+ */
+struct fdisk_parttype *fdisk_new_unknown_parttype(unsigned int code,
+						  const char *typestr)
+{
+	struct fdisk_parttype *t = fdisk_new_parttype();
+
+	if (!t)
+		return NULL;
+
+	fdisk_parttype_set_name(t, _("unknown"));
+	fdisk_parttype_set_code(t, code);
+	fdisk_parttype_set_typestr(t, typestr);
+	t->flags |= FDISK_PARTTYPE_UNKNOWN;
+
+	return t;
+}
+
+/**
+ * fdisk_copy_parttype:
+ * @type: type to copy
+ *
+ * Use fdisk_unref_parttype() to deallocate.
+ *
+ * Returns: newly allocated partition type, or NULL upon failure.
+ */
+struct fdisk_parttype *fdisk_copy_parttype(const struct fdisk_parttype *type)
+{
+	struct fdisk_parttype *t = fdisk_new_parttype();
+
+	if (!t)
+		return NULL;
+
+	fdisk_parttype_set_name(t, type->name);
+	fdisk_parttype_set_code(t, type->code);
+	fdisk_parttype_set_typestr(t, type->typestr);
+
+	return t;
+}
+
+/**
+ * fdisk_label_parse_parttype:
+ * @lb: label
+ * @str: string to parse from
+ *
+ * Parses partition type from @str according to the label. Thefunction returns
+ * a pointer to static table of the partition types, or newly allocated
+ * partition type for unknown types (see fdisk_parttype_is_unknown(). It's
+ * safe to call fdisk_unref_parttype() for all results.
+ *
+ * Returns: pointer to type or NULL on error.
+ */
+struct fdisk_parttype *fdisk_label_parse_parttype(
+				const struct fdisk_label *lb,
+				const char *str)
+{
+	struct fdisk_parttype *types, *ret;
+	unsigned int code = 0;
+	char *typestr = NULL, *end = NULL;
+
+	assert(lb);
+
+	if (!lb->nparttypes)
+		return NULL;
+
+	DBG(LABEL, ul_debugobj((void *) lb, "parsing '%s' (%s) partition type",
+				str, lb->name));
+	types = lb->parttypes;
+
+	if (types[0].typestr == NULL && isxdigit(*str)) {
+
+		errno = 0;
+		code = strtol(str, &end, 16);
+
+		if (errno || *end != '\0') {
+			DBG(LABEL, ul_debugobj((void *) lb, "parsing failed: %m"));
+			return NULL;
+		}
+		ret = fdisk_label_get_parttype_from_code(lb, code);
+		if (ret)
+			goto done;
+	} else {
+		int i;
+
+		/* maybe specified by type string (e.g. UUID) */
+		ret = fdisk_label_get_parttype_from_string(lb, str);
+		if (ret)
+			goto done;
+
+		/* maybe specified by order number */
+		errno = 0;
+		i = strtol(str, &end, 0);
+		if (errno == 0 && *end == '\0' && i > 0
+		    && i - 1 < (int) lb->nparttypes) {
+			ret = &types[i - 1];
+			goto done;
+		}
+	}
+
+	ret = fdisk_new_unknown_parttype(code, typestr);
+done:
+	DBG(PARTTYPE, ul_debugobj(ret, "returns parsed '%s' partition type", ret->name));
+	return ret;
+}
+
+/**
+ * fdisk_parttype_get_string:
+ * @t: type
+ *
+ * Returns: partition type string (e.g. GUID for GPT)
+ */
+const char *fdisk_parttype_get_string(const struct fdisk_parttype *t)
+{
+	assert(t);
+	return t->typestr && *t->typestr ? t->typestr : NULL;
+}
+
+/**
+ * fdisk_parttype_get_code:
+ * @t: type
+ *
+ * Returns: partition type code (e.g. for MBR)
+ */
+unsigned int fdisk_parttype_get_code(const struct fdisk_parttype *t)
+{
+	assert(t);
+	return t->code;
+}
+
+/**
+ * fdisk_parttype_get_name:
+ * @t: type
+ *
+ * Returns: partition type human readable name
+ */
+const char *fdisk_parttype_get_name(const struct fdisk_parttype *t)
+{
+	assert(t);
+	return t->name;
+}
+
+/**
+ * fdisk_parttype_is_unknown:
+ * @t: type
+ *
+ * Checks for example result from fdisk_label_parse_parttype().
+ *
+ * Returns: 1 is type is "unknonw" or 0.
+ */
+int fdisk_parttype_is_unknown(const struct fdisk_parttype *t)
+{
+	return t && (t->flags & FDISK_PARTTYPE_UNKNOWN) ? 1 : 0;
+}
diff --git a/libblkid/libfdisk/src/script.c b/libblkid/libfdisk/src/script.c
new file mode 100644
index 0000000..83bda99
--- /dev/null
+++ b/libblkid/libfdisk/src/script.c
@@ -0,0 +1,1235 @@
+
+#include "fdiskP.h"
+#include "strutils.h"
+
+/**
+ * SECTION: script
+ * @title: Script
+ * @short_description: text based sfdisk compatible description of partition table
+ *
+ * The libfdisk scripts are based on original sfdisk script (dumps).  Each
+ * script has two parts: script headers and partition table entries
+ * (partitions).
+ *
+ * For more details about script format see sfdisk man page.
+ */
+
+/* script header (e.g. unit: sectors) */
+struct fdisk_scriptheader {
+	struct list_head	headers;
+	char			*name;
+	char			*data;
+};
+
+/* script control struct */
+struct fdisk_script {
+	struct fdisk_table	*table;
+	struct list_head	headers;
+	struct fdisk_context	*cxt;
+
+	int			refcount;
+
+	/* parser's state */
+	size_t			nlines;
+	int			fmt;		/* input format */
+	struct fdisk_label	*label;
+};
+
+
+static void fdisk_script_free_header(struct fdisk_script *dp, struct fdisk_scriptheader *fi)
+{
+	if (!fi)
+		return;
+
+	DBG(SCRIPT, ul_debugobj(fi, "free header %s", fi->name));
+	free(fi->name);
+	free(fi->data);
+	list_del(&fi->headers);
+	free(fi);
+}
+
+/**
+ * fdisk_new_script:
+ * @cxt: context
+ *
+ * The script hold fdisk_table and additional information to read/write
+ * script to the file.
+ *
+ * Returns: newly allocated script struct.
+ */
+struct fdisk_script *fdisk_new_script(struct fdisk_context *cxt)
+{
+	struct fdisk_script *dp = NULL;
+
+	dp = calloc(1, sizeof(*dp));
+	if (!dp)
+		return NULL;
+
+	DBG(SCRIPT, ul_debugobj(dp, "alloc"));
+	dp->refcount = 1;
+	dp->cxt = cxt;
+	fdisk_ref_context(cxt);
+
+	dp->table = fdisk_new_table();
+	if (!dp->table) {
+		fdisk_unref_script(dp);
+		return NULL;
+	}
+
+	INIT_LIST_HEAD(&dp->headers);
+	return dp;
+}
+
+/**
+ * fdisk_new_script_from_file:
+ * @cxt: context
+ * @filename: path to the script file
+ *
+ * Allocates a new script and reads script from @filename.
+ *
+ * Returns: new script instance or NULL in case of error (check errno for more details).
+ */
+struct fdisk_script *fdisk_new_script_from_file(struct fdisk_context *cxt,
+						 const char *filename)
+{
+	int rc;
+	FILE *f;
+	struct fdisk_script *dp, *res = NULL;
+
+	assert(cxt);
+	assert(filename);
+
+	DBG(SCRIPT, ul_debug("opening %s", filename));
+	f = fopen(filename, "r");
+	if (!f)
+		return NULL;
+
+	dp = fdisk_new_script(cxt);
+	if (!dp)
+		goto done;
+
+	rc = fdisk_script_read_file(dp, f);
+	if (rc) {
+		errno = -rc;
+		goto done;
+	}
+
+	res = dp;
+done:
+	fclose(f);
+	if (!res)
+		fdisk_unref_script(dp);
+	else
+		errno = 0;
+
+	return res;
+}
+
+/**
+ * fdisk_ref_script:
+ * @dp: script pointer
+ *
+ * Incremparts reference counter.
+ */
+void fdisk_ref_script(struct fdisk_script *dp)
+{
+	if (dp)
+		dp->refcount++;
+}
+
+static void fdisk_reset_script(struct fdisk_script *dp)
+{
+	assert(dp);
+
+	DBG(SCRIPT, ul_debugobj(dp, "reset"));
+	fdisk_unref_table(dp->table);
+	dp->table = NULL;
+
+	while (!list_empty(&dp->headers)) {
+		struct fdisk_scriptheader *fi = list_entry(dp->headers.next,
+						  struct fdisk_scriptheader, headers);
+		fdisk_script_free_header(dp, fi);
+	}
+	INIT_LIST_HEAD(&dp->headers);
+}
+
+/**
+ * fdisk_unref_script:
+ * @dp: script pointer
+ *
+ * De-incremparts reference counter, on zero the @dp is automatically
+ * deallocated.
+ */
+void fdisk_unref_script(struct fdisk_script *dp)
+{
+	if (!dp)
+		return;
+
+	dp->refcount--;
+	if (dp->refcount <= 0) {
+		fdisk_reset_script(dp);
+		fdisk_unref_context(dp->cxt);
+		DBG(SCRIPT, ul_debugobj(dp, "free script"));
+		free(dp);
+	}
+}
+
+static struct fdisk_scriptheader *script_get_header(struct fdisk_script *dp,
+						     const char *name)
+{
+	struct list_head *p;
+
+	list_for_each(p, &dp->headers) {
+		struct fdisk_scriptheader *fi = list_entry(p, struct fdisk_scriptheader, headers);
+
+		if (strcasecmp(fi->name, name) == 0)
+			return fi;
+	}
+
+	return NULL;
+}
+
+/**
+ * fdisk_script_get_header:
+ * @dp: script instance
+ * @name: header name
+ *
+ * Returns: pointer to header data or NULL.
+ */
+const char *fdisk_script_get_header(struct fdisk_script *dp, const char *name)
+{
+	struct fdisk_scriptheader *fi;
+
+	assert(dp);
+	assert(name);
+
+	fi = script_get_header(dp, name);
+	return fi ? fi->data : NULL;
+}
+
+
+/**
+ * fdisk_script_set_header:
+ * @dp: script instance
+ * @name: header name
+ * @data: header data (or NULL)
+ *
+ * The headers are used as global options (in script) for whole partition
+ * table, always one header per line.
+ *
+ * If no @data specified then the header is removed. If header does not exist
+ * and @data specified then a new header added.
+ *
+ * Note that libfdisk allows to specify arbitrary custom header, the default
+ * build-in headers are "unit" and "label", and some label specific headers
+ * (for example "uuid" and "name" for GPT).
+ *
+ * Returns: 0 on success, <0 on error
+ */
+int fdisk_script_set_header(struct fdisk_script *dp,
+			    const char *name,
+			    const char *data)
+{
+	struct fdisk_scriptheader *fi;
+
+	assert(dp);
+	assert(name);
+
+	if (!dp || !name)
+		return -EINVAL;
+
+	fi = script_get_header(dp, name);
+	if (!fi && !data)
+		return 0;	/* want to remove header that does not exist, success */
+
+	if (!data) {
+		/* no data, remove the header */
+		fdisk_script_free_header(dp, fi);
+		return 0;
+	}
+
+	if (!fi) {
+		/* new header */
+		fi = calloc(1, sizeof(*fi));
+		if (!fi)
+			return -ENOMEM;
+		INIT_LIST_HEAD(&fi->headers);
+		fi->name = strdup(name);
+		fi->data = strdup(data);
+		if (!fi->data || !fi->name) {
+			fdisk_script_free_header(dp, fi);
+			return -ENOMEM;
+		}
+		list_add_tail(&fi->headers, &dp->headers);
+	} else {
+		/* update existing */
+		char *x = strdup(data);
+
+		if (!x)
+			return -ENOMEM;
+		free(fi->data);
+		fi->data = x;
+	}
+
+	if (strcmp(name, "label") == 0)
+		dp->label = NULL;
+
+	return 0;
+}
+
+/**
+ * fdisk_script_get_table:
+ * @dp: script
+ *
+ * The table (container with partitions) is possible to create by
+ * fdisk_script_read_context() or fdisk_script_read_file(), otherwise
+ * this function returns NULL.
+ *
+ * Returns: NULL or script.
+ */
+struct fdisk_table *fdisk_script_get_table(struct fdisk_script *dp)
+{
+	assert(dp);
+	return dp ? dp->table : NULL;
+}
+
+static struct fdisk_label *script_get_label(struct fdisk_script *dp)
+{
+	assert(dp);
+	assert(dp->cxt);
+
+	if (!dp->label) {
+		dp->label = fdisk_get_label(dp->cxt,
+					fdisk_script_get_header(dp, "label"));
+		DBG(SCRIPT, ul_debugobj(dp, "label '%s'", dp->label ? dp->label->name : ""));
+	}
+	return dp->label;
+}
+
+/**
+ * fdisk_script_get_nlines:
+ * @dp: script
+ *
+ * Returns: number of parsed lines or <0 on error.
+ */
+int fdisk_script_get_nlines(struct fdisk_script *dp)
+{
+	assert(dp);
+	return dp->nlines;
+}
+
+/**
+ * fdisk_script_read_context:
+ * @dp: script
+ * @cxt: context
+ *
+ * Reads data from the @cxt context (on disk partition table) into the script.
+ * If the context is no specified than defaults to context used for fdisk_new_script().
+ *
+ * Return: 0 on success, <0 on error.
+ */
+int fdisk_script_read_context(struct fdisk_script *dp, struct fdisk_context *cxt)
+{
+	struct fdisk_label *lb;
+	int rc;
+	char *p = NULL;
+
+	assert(dp);
+
+	if (!cxt)
+		cxt = dp->cxt;
+
+	if (!dp || !cxt)
+		return -EINVAL;
+
+	DBG(SCRIPT, ul_debugobj(dp, "reading context into script"));
+	fdisk_reset_script(dp);
+
+	lb = fdisk_get_label(cxt, NULL);
+	if (!lb)
+		return -EINVAL;
+
+	/* allocate and fill new table */
+	rc = fdisk_get_partitions(cxt, &dp->table);
+	if (rc)
+		return rc;
+
+	/* generate headers */
+	rc = fdisk_script_set_header(dp, "label", fdisk_label_get_name(lb));
+
+	if (!rc && fdisk_get_disklabel_id(cxt, &p) == 0 && p) {
+		rc = fdisk_script_set_header(dp, "label-id", p);
+		free(p);
+	}
+	if (!rc && cxt->dev_path)
+		rc = fdisk_script_set_header(dp, "device", cxt->dev_path);
+	if (!rc)
+		rc = fdisk_script_set_header(dp, "unit", "sectors");
+
+	/* TODO: label specific headers (e.g. uuid for GPT) */
+
+	DBG(SCRIPT, ul_debugobj(dp, "read context done [rc=%d]", rc));
+	return rc;
+}
+
+/**
+ * fdisk_script_write_file:
+ * @dp: script
+ * @f: output file
+ *
+ * Writes script @dp to the ile @f.
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_script_write_file(struct fdisk_script *dp, FILE *f)
+{
+	struct list_head *h;
+	struct fdisk_partition *pa;
+	struct fdisk_iter itr;
+	const char *devname = NULL;
+
+	assert(dp);
+	assert(f);
+
+	DBG(SCRIPT, ul_debugobj(dp, "writing script to file"));
+
+	/* script headers */
+	list_for_each(h, &dp->headers) {
+		struct fdisk_scriptheader *fi = list_entry(h, struct fdisk_scriptheader, headers);
+		fprintf(f, "%s: %s\n", fi->name, fi->data);
+		if (strcmp(fi->name, "device") == 0)
+			devname = fi->data;
+	}
+
+	if (!dp->table) {
+		DBG(SCRIPT, ul_debugobj(dp, "script table empty"));
+		return 0;
+	}
+
+	DBG(SCRIPT, ul_debugobj(dp, "%zu entries", fdisk_table_get_nents(dp->table)));
+
+	fputc('\n', f);
+
+	fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
+	while (fdisk_table_next_partition(dp->table, &itr, &pa) == 0) {
+		char *p = NULL;
+
+		if (devname)
+			p = fdisk_partname(devname, pa->partno + 1);
+		if (p) {
+			DBG(SCRIPT, ul_debugobj(dp, "write %s entry", p));
+			fprintf(f, "%s :", p);
+		} else
+			fprintf(f, "%zu :", pa->partno + 1);
+
+		if (fdisk_partition_has_start(pa))
+			fprintf(f, " start=%12ju", pa->start);
+		if (fdisk_partition_has_size(pa))
+			fprintf(f, ", size=%12ju", pa->size);
+
+		if (pa->type && fdisk_parttype_get_string(pa->type))
+			fprintf(f, ", type=%s", fdisk_parttype_get_string(pa->type));
+		else if (pa->type)
+			fprintf(f, ", type=%x", fdisk_parttype_get_code(pa->type));
+
+		if (pa->uuid)
+			fprintf(f, ", uuid=%s", pa->uuid);
+		if (pa->name && *pa->name)
+			fprintf(f, ", name=\"%s\"", pa->name);
+
+		/* for MBR attr=80 means bootable */
+		if (pa->attrs) {
+			struct fdisk_label *lb = script_get_label(dp);
+
+			if (!lb || fdisk_label_get_type(lb) != FDISK_DISKLABEL_DOS)
+				fprintf(f, ", attrs=\"%s\"", pa->attrs);
+		}
+		if (fdisk_partition_is_bootable(pa))
+			fprintf(f, ", bootable");
+		fputc('\n', f);
+	}
+
+	DBG(SCRIPT, ul_debugobj(dp, "write script done"));
+	return 0;
+}
+
+static inline int is_header_line(const char *s)
+{
+	const char *p = strchr(s, ':');
+
+	if (!p || p == s || !*(p + 1) || strchr(s, '='))
+		return 0;
+
+	return 1;
+}
+
+/* parses "<name>: value", note modifies @s*/
+static int parse_header_line(struct fdisk_script *dp, char *s)
+{
+	int rc = -EINVAL;
+	char *name, *value;
+
+	DBG(SCRIPT, ul_debugobj(dp, "   parse header '%s'", s));
+
+	if (!s || !*s)
+		return -EINVAL;
+
+	name = s;
+	value = strchr(s, ':');
+	if (!value)
+		goto done;
+	*value = '\0';
+	value++;
+
+	ltrim_whitespace((unsigned char *) name);
+	rtrim_whitespace((unsigned char *) name);
+	ltrim_whitespace((unsigned char *) value);
+	rtrim_whitespace((unsigned char *) value);
+
+	if (strcmp(name, "label") == 0) {
+		if (dp->cxt && !fdisk_get_label(dp->cxt, value))
+			goto done;			/* unknown label name */
+	} else if (strcmp(name, "unit") == 0) {
+		if (strcmp(value, "sectors") != 0)
+			goto done;			/* only "sectors" supported */
+	} else if (strcmp(name, "label-id") == 0
+		   || strcmp(name, "device") == 0) {
+		;					/* whatever is posssible */
+	} else
+		goto done;				/* unknown header */
+
+	if (*name && *value)
+		rc = fdisk_script_set_header(dp, name, value);
+done:
+	if (rc)
+		DBG(SCRIPT, ul_debugobj(dp, "header parse error: "
+				"[rc=%d, name='%s', value='%s']",
+				rc, name, value));
+	return rc;
+
+}
+
+/* returns zero terminated string with next token and @str is updated */
+static char *next_token(char **str)
+{
+	char *tk_begin = NULL,
+	     *tk_end = NULL,
+	     *end = NULL,
+	     *p;
+	int open_quote = 0;
+
+	for (p = *str; p && *p; p++) {
+		if (!tk_begin) {
+			if (isblank(*p))
+				continue;
+			tk_begin = *p == '"' ? p + 1 : p;
+		}
+		if (*p == '"')
+			open_quote ^= 1;
+		if (open_quote)
+			continue;
+		if (isblank(*p) || *p == ',' || *p == ';' || *p == '"' )
+			tk_end = p;
+		else if (*(p + 1) == '\0')
+			tk_end = p + 1;
+		if (tk_begin && tk_end)
+			break;
+	}
+
+	if (!tk_end)
+		return NULL;
+	end = isblank(*tk_end) ? (char *) skip_blank(tk_end) : tk_end;
+	if (*end == ',' || *end == ';')
+		end++;
+
+	*tk_end = '\0';
+	*str = end;
+	return tk_begin;
+}
+
+static int next_number(char **s, uint64_t *num, int *power)
+{
+	char *tk;
+	int rc = -EINVAL;
+
+	assert(num);
+	assert(s);
+
+	tk = next_token(s);
+	if (tk)
+		rc = parse_size(tk, (uintmax_t *) num, power);
+	return rc;
+}
+
+static int next_string(char **s, char **str)
+{
+	char *tk;
+	int rc = -EINVAL;
+
+	assert(s);
+	assert(str);
+
+	tk = next_token(s);
+	if (tk) {
+		*str = strdup(tk);
+		rc = !*str ? -ENOMEM : 0;
+	}
+	return rc;
+}
+
+static int partno_from_devname(char *s)
+{
+	int pno;
+	size_t sz;
+	char *end, *p;
+
+	sz = rtrim_whitespace((unsigned char *)s);
+	p = s + sz - 1;
+
+	while (p > s && isdigit(*(p - 1)))
+		p--;
+
+	errno = 0;
+	pno = strtol(p, &end, 10);
+	if (errno || !end || p == end)
+		return -1;
+	return pno - 1;
+}
+
+/* dump format
+ * <device>: start=<num>, size=<num>, type=<string>, ...
+ */
+static int parse_script_line(struct fdisk_script *dp, char *s)
+{
+	char *p, *x;
+	struct fdisk_partition *pa;
+	int rc = 0;
+	uint64_t num;
+	int pno;
+
+	assert(dp);
+	assert(s);
+
+	DBG(SCRIPT, ul_debugobj(dp, "   parse script line: '%s'", s));
+
+	pa = fdisk_new_partition();
+	if (!pa)
+		return -ENOMEM;
+
+	fdisk_partition_start_follow_default(pa, 1);
+	fdisk_partition_end_follow_default(pa, 1);
+	fdisk_partition_partno_follow_default(pa, 1);
+
+	/* set partno */
+	p = strchr(s, ':');
+	x = strchr(s, '=');
+	if (p && (!x || p < x)) {
+		*p = '\0';
+		p++;
+
+		pno = partno_from_devname(s);
+		if (pno >= 0) {
+			fdisk_partition_partno_follow_default(pa, 0);
+			fdisk_partition_set_partno(pa, pno);
+		}
+	} else
+		p = s;
+
+	while (rc == 0 && p && *p) {
+
+		DBG(SCRIPT, ul_debugobj(dp, " parsing '%s'", p));
+		p = (char *) skip_blank(p);
+
+		if (!strncasecmp(p, "start=", 6)) {
+			p += 6;
+			rc = next_number(&p, &num, NULL);
+			if (!rc) {
+				fdisk_partition_set_start(pa, num);
+				fdisk_partition_start_follow_default(pa, 0);
+			}
+		} else if (!strncasecmp(p, "size=", 5)) {
+			int pow = 0;
+
+			p += 5;
+			rc = next_number(&p, &num, &pow);
+			if (!rc) {
+				if (pow)	/* specified as <num><suffix> */
+					num /= dp->cxt->sector_size;
+				else		/* specified as number of sectors */
+					fdisk_partition_size_explicit(pa, 1);
+				fdisk_partition_set_size(pa, num);
+				fdisk_partition_end_follow_default(pa, 0);
+			}
+
+		} else if (!strncasecmp(p, "bootable", 8)) {
+			char *tk = next_token(&p);
+			if (strcmp(tk, "bootable") == 0)
+				pa->boot = 1;
+			else
+				rc = -EINVAL;
+
+		} else if (!strncasecmp(p, "attrs=", 6)) {
+			p += 6;
+			rc = next_string(&p, &pa->attrs);
+
+		} else if (!strncasecmp(p, "uuid=", 5)) {
+			p += 5;
+			rc = next_string(&p, &pa->uuid);
+
+		} else if (!strncasecmp(p, "name=", 5)) {
+			p += 5;
+			rc = next_string(&p, &pa->name);
+
+		} else if (!strncasecmp(p, "type=", 5) ||
+
+			   !strncasecmp(p, "Id=", 3)) {		/* backward compatiility */
+			char *type;
+
+			p += (*p == 'I' ? 3 : 5);		/* "Id=" or "type=" */
+
+			rc = next_string(&p, &type);
+			if (rc)
+				break;
+			pa->type = fdisk_label_parse_parttype(
+					script_get_label(dp), type);
+			free(type);
+
+			if (!pa->type || fdisk_parttype_is_unknown(pa->type)) {
+				rc = -EINVAL;
+				fdisk_unref_parttype(pa->type);
+				pa->type = NULL;
+				break;
+			}
+
+		} else {
+			DBG(SCRIPT, ul_debugobj(dp, "script parse error: unknown field '%s'", p));
+			rc = -EINVAL;
+			break;
+		}
+	}
+
+	if (!rc)
+		rc = fdisk_table_add_partition(dp->table, pa);
+	if (rc)
+		DBG(SCRIPT, ul_debugobj(dp, "script parse error: [rc=%d]", rc));
+
+	fdisk_unref_partition(pa);
+	return rc;
+}
+
+/* original sfdisk supports partition types shortcuts like 'L' = Linux native
+ */
+static struct fdisk_parttype *translate_type_shortcuts(struct fdisk_script *dp, char *str)
+{
+	struct fdisk_label *lb;
+	const char *type = NULL;
+
+	if (strlen(str) != 1)
+		return NULL;
+
+	lb = script_get_label(dp);
+	if (!lb)
+		return NULL;
+
+	if (lb->id == FDISK_DISKLABEL_DOS) {
+		switch (*str) {
+		case 'L':	/* Linux */
+			type = "83";
+			break;
+		case 'S':	/* Swap */
+			type = "82";
+			break;
+		case 'E':	/* Dos extended */
+			type = "05";
+			break;
+		case 'X':	/* Linux extended */
+			type = "85";
+			break;
+		}
+	} else if (lb->id == FDISK_DISKLABEL_GPT) {
+		switch (*str) {
+		case 'L':	/* Linux */
+			type = "0FC63DAF-8483-4772-8E79-3D69D8477DE4";
+			break;
+		case 'S':	/* Swap */
+			type = "0657FD6D-A4AB-43C4-84E5-0933C84B4F4F";
+			break;
+		case 'H':	/* Home */
+			type = "933AC7E1-2EB4-4F13-B844-0E14E2AEF915";
+			break;
+		}
+	}
+
+	return type ? fdisk_label_parse_parttype(lb, type) : NULL;
+}
+
+/* simple format:
+ * <start>, <size>, <type>, <bootable>, ...
+ */
+static int parse_commas_line(struct fdisk_script *dp, char *s)
+{
+	int rc = 0;
+	char *p = s, *str;
+	struct fdisk_partition *pa;
+	enum { ITEM_START, ITEM_SIZE, ITEM_TYPE, ITEM_BOOTABLE };
+	int item = -1;
+
+	assert(dp);
+	assert(s);
+
+	pa = fdisk_new_partition();
+	if (!pa)
+		return -ENOMEM;
+
+	fdisk_partition_start_follow_default(pa, 1);
+	fdisk_partition_end_follow_default(pa, 1);
+	fdisk_partition_partno_follow_default(pa, 1);
+
+	while (rc == 0 && p && *p) {
+		uint64_t num;
+		char *begin;
+
+		p = (char *) skip_blank(p);
+		item++;
+
+		DBG(SCRIPT, ul_debugobj(dp, " parsing item %d ('%s')", item, p));
+		begin = p;
+
+		switch (item) {
+		case ITEM_START:
+			if (*p == ',' || *p == ';')
+				fdisk_partition_start_follow_default(pa, 1);
+			else {
+				rc = next_number(&p, &num, NULL);
+				if (!rc)
+					fdisk_partition_set_start(pa, num);
+				fdisk_partition_start_follow_default(pa, 0);
+			}
+			break;
+		case ITEM_SIZE:
+			if (*p == ',' || *p == ';' || *p == '+')
+				fdisk_partition_end_follow_default(pa, 1);
+			else {
+				int pow = 0;
+				rc = next_number(&p, &num, &pow);
+				if (!rc) {
+					if (pow) /* specified as <size><suffix> */
+						num /= dp->cxt->sector_size;
+					else	 /* specified as number of sectors */
+						fdisk_partition_size_explicit(pa, 1);
+					fdisk_partition_set_size(pa, num);
+				}
+				fdisk_partition_end_follow_default(pa, 0);
+			}
+			break;
+		case ITEM_TYPE:
+			if (*p == ',' || *p == ';')
+				break;	/* use default type */
+
+			rc = next_string(&p, &str);
+			if (rc)
+				break;
+
+			pa->type = translate_type_shortcuts(dp, str);
+			if (!pa->type)
+				pa->type = fdisk_label_parse_parttype(
+						script_get_label(dp), str);
+			free(str);
+
+			if (!pa->type || fdisk_parttype_is_unknown(pa->type)) {
+				rc = -EINVAL;
+				fdisk_unref_parttype(pa->type);
+				pa->type = NULL;
+				break;
+			}
+			break;
+		case ITEM_BOOTABLE:
+			if (*p == ',' || *p == ';')
+				break;
+			else {
+				char *tk = next_token(&p);
+				if (tk && *tk == '*' && *(tk + 1) == '\0')
+					pa->boot = 1;
+				else if (tk && *tk == '-' && *(tk + 1) == '\0')
+					pa->boot = 0;
+				else
+					rc = -EINVAL;
+			}
+			break;
+		default:
+			break;
+		}
+
+		if (begin == p)
+			p++;
+	}
+
+	if (!rc)
+		rc = fdisk_table_add_partition(dp->table, pa);
+	if (rc)
+		DBG(SCRIPT, ul_debugobj(dp, "script parse error: [rc=%d]", rc));
+
+	fdisk_unref_partition(pa);
+	return rc;
+}
+
+/* modifies @s ! */
+int fdisk_script_read_buffer(struct fdisk_script *dp, char *s)
+{
+	int rc = 0;
+
+	assert(dp);
+	assert(s);
+
+	DBG(SCRIPT, ul_debugobj(dp, "  parsing buffer"));
+
+	s = (char *) skip_blank(s);
+	if (!s || !*s)
+		return 0;	/* nothing baby, ignore */
+
+	if (!dp->table) {
+		dp->table = fdisk_new_table();
+		if (!dp->table)
+			return -ENOMEM;
+	}
+
+	/* parse header lines only if no partition specified yet */
+	if (fdisk_table_is_empty(dp->table) && is_header_line(s))
+		rc = parse_header_line(dp, s);
+
+	/* parse script format */
+	else if (strchr(s, '='))
+		rc = parse_script_line(dp, s);
+
+	/* parse simple <value>, ... format */
+	else
+		rc = parse_commas_line(dp, s);
+
+	if (rc)
+		DBG(SCRIPT, ul_debugobj(dp, "%zu: parse error [rc=%d]",
+				dp->nlines, rc));
+	return rc;
+}
+
+/**
+ * fdisk_script_read_line:
+ * @dp: script
+ * @f: file
+ * @buf: buffer to store one line of the file
+ * @bufsz: buffer size
+ *
+ * Reads next line into dump.
+ *
+ * Returns: 0 on success, <0 on error, 1 when nothing to read.
+ */
+int fdisk_script_read_line(struct fdisk_script *dp, FILE *f, char *buf, size_t bufsz)
+{
+	char *s;
+
+	assert(dp);
+	assert(f);
+
+	DBG(SCRIPT, ul_debugobj(dp, " parsing line %zu", dp->nlines));
+
+	/* read the next non-blank non-comment line */
+	do {
+		if (fgets(buf, bufsz, f) == NULL)
+			return 1;
+		dp->nlines++;
+		s = strchr(buf, '\n');
+		if (!s) {
+			/* Missing final newline?  Otherwise an extremely */
+			/* long line - assume file was corrupted */
+			if (feof(f)) {
+				DBG(SCRIPT, ul_debugobj(dp, "no final newline"));
+				s = strchr(buf, '\0');
+			} else {
+				DBG(SCRIPT, ul_debugobj(dp,
+					"%zu: missing newline at line", dp->nlines));
+				return -EINVAL;
+			}
+		}
+
+		*s = '\0';
+		if (--s >= buf && *s == '\r')
+			*s = '\0';
+		s = (char *) skip_blank(buf);
+	} while (*s == '\0' || *s == '#');
+
+	return fdisk_script_read_buffer(dp, s);
+}
+
+
+/**
+ * fdisk_script_read_file:
+ * @dp: script
+ * @f: input file
+ *
+ * Reads file @f into script @dp.
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_script_read_file(struct fdisk_script *dp, FILE *f)
+{
+	char buf[BUFSIZ];
+	int rc;
+
+	assert(dp);
+	assert(f);
+
+	DBG(SCRIPT, ul_debugobj(dp, "parsing file"));
+
+	while (!feof(f)) {
+		rc = fdisk_script_read_line(dp, f, buf, sizeof(buf));
+		if (rc)
+			break;
+	}
+
+	if (rc == 1)
+		rc = 0;		/* end of file */
+
+	DBG(SCRIPT, ul_debugobj(dp, "parsing file done [rc=%d]", rc));
+	return rc;
+}
+
+/**
+ * fdisk_set_script:
+ * @cxt: context
+ * @dp: script (or NULL to remove previous reference)
+ *
+ * Sets reference to the @dp script. The script headers might be used by label
+ * drivers to overwrite built-in defaults (for example disk label Id) and label
+ * driver might optimize the default semantic to be more usable for scripts
+ * (for example to not ask for primary/logical/extended partition type).
+ *
+ * Note that script also contains reference to the fdisk context (see
+ * fdisk_new_script()). This context may be completely independent on
+ * context used for fdisk_set_script().
+ *
+ * Returns: <0 on error, 0 on success.
+ */
+int fdisk_set_script(struct fdisk_context *cxt, struct fdisk_script *dp)
+{
+	assert(cxt);
+
+	/* unref old */
+	if (cxt->script)
+		fdisk_unref_script(cxt->script);
+
+	/* ref new */
+	cxt->script = dp;
+	if (cxt->script) {
+		DBG(CXT, ul_debugobj(cxt, "setting reference to script %p", cxt->script));
+		fdisk_ref_script(cxt->script);
+	}
+
+	return 0;
+}
+
+/**
+ * fdisk_get_script:
+ * @cxt: context
+ *
+ * Returns: the current script or NULL.
+ */
+struct fdisk_script *fdisk_get_script(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	return cxt->script;
+}
+
+/**
+ * fdisk_apply_script_headers:
+ * @cxt: context
+ * @dp: script
+ *
+ * Associte context @cxt with script @dp and creates a new empty disklabel.
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_apply_script_headers(struct fdisk_context *cxt, struct fdisk_script *dp)
+{
+	const char *name;
+
+	assert(cxt);
+	assert(dp);
+
+	DBG(SCRIPT, ul_debugobj(dp, "applying script headers"));
+	fdisk_set_script(cxt, dp);
+
+	/* create empty label */
+	name = fdisk_script_get_header(dp, "label");
+	if (!name)
+		return -EINVAL;
+
+	return fdisk_create_disklabel(cxt, name);
+}
+
+/**
+ * fdisk_apply_script:
+ * @cxt: context
+ * @dp: script
+ *
+ * This function creates a new disklabel and partition within context @cxt. You
+ * have to call fdisk_write_disklabel() to apply changes to the device.
+ *
+ * Returns: 0 on error, <0 on error.
+ */
+int fdisk_apply_script(struct fdisk_context *cxt, struct fdisk_script *dp)
+{
+	int rc;
+	struct fdisk_script *old;
+
+	assert(dp);
+	assert(cxt);
+
+	DBG(CXT, ul_debugobj(cxt, "applying script %p", dp));
+
+	old = fdisk_get_script(cxt);
+
+	/* create empty disk label */
+	rc = fdisk_apply_script_headers(cxt, dp);
+
+	/* create partitions */
+	if (!rc && dp->table)
+		rc = fdisk_apply_table(cxt, dp->table);
+
+	fdisk_set_script(cxt, old);
+	DBG(CXT, ul_debugobj(cxt, "script done [rc=%d]", rc));
+	return rc;
+}
+
+#ifdef TEST_PROGRAM
+int test_dump(struct fdisk_test *ts, int argc, char *argv[])
+{
+	char *devname = argv[1];
+	struct fdisk_context *cxt;
+	struct fdisk_script *dp;
+
+	cxt = fdisk_new_context();
+	fdisk_assign_device(cxt, devname, 1);
+
+	dp = fdisk_new_script(cxt);
+	fdisk_script_read_context(dp, NULL);
+
+	fdisk_script_write_file(dp, stdout);
+	fdisk_unref_script(dp);
+	fdisk_unref_context(cxt);
+
+	return 0;
+}
+
+int test_read(struct fdisk_test *ts, int argc, char *argv[])
+{
+	char *filename = argv[1];
+	struct fdisk_script *dp;
+	struct fdisk_context *cxt;
+	FILE *f;
+
+	if (!(f = fopen(filename, "r")))
+		err(EXIT_FAILURE, "%s: cannot open", filename);
+
+	cxt = fdisk_new_context();
+	dp = fdisk_new_script(cxt);
+
+	fdisk_script_read_file(dp, f);
+	fclose(f);
+
+	fdisk_script_write_file(dp, stdout);
+	fdisk_unref_script(dp);
+	fdisk_unref_context(cxt);
+
+	return 0;
+}
+
+int test_stdin(struct fdisk_test *ts, int argc, char *argv[])
+{
+	char buf[BUFSIZ];
+	struct fdisk_script *dp;
+	struct fdisk_context *cxt;
+	int rc = 0;
+
+	cxt = fdisk_new_context();
+	dp = fdisk_new_script(cxt);
+	fdisk_script_set_header(dp, "label", "dos");
+
+	printf("<start>, <size>, <type>, <bootable: *|->\n");
+	do {
+		struct fdisk_partition *pa;
+		size_t n = fdisk_table_get_nents(dp->table);
+
+		printf(" #%zu :\n", n + 1);
+		rc = fdisk_script_read_line(dp, stdin, buf, sizeof(buf));
+
+		if (rc == 0) {
+			pa = fdisk_table_get_partition(dp->table, n);
+			printf(" #%zu  %12ju %12ju\n",	n + 1,
+						fdisk_partition_get_start(pa),
+						fdisk_partition_get_size(pa));
+		}
+	} while (rc == 0);
+
+	if (!rc)
+		fdisk_script_write_file(dp, stdout);
+	fdisk_unref_script(dp);
+	fdisk_unref_context(cxt);
+
+	return rc;
+}
+
+int test_apply(struct fdisk_test *ts, int argc, char *argv[])
+{
+	char *devname = argv[1], *scriptname = argv[2];
+	struct fdisk_context *cxt;
+	struct fdisk_script *dp = NULL;
+	struct fdisk_table *tb = NULL;
+	struct fdisk_iter *itr = NULL;
+	struct fdisk_partition *pa = NULL;
+	int rc;
+
+	cxt = fdisk_new_context();
+	fdisk_assign_device(cxt, devname, 0);
+
+	dp = fdisk_new_script_from_file(cxt, scriptname);
+	if (!dp)
+		return -errno;
+
+	rc = fdisk_apply_script(cxt, dp);
+	if (rc)
+		goto done;
+	fdisk_unref_script(dp);
+
+	/* list result */
+	fdisk_list_disklabel(cxt);
+	fdisk_get_partitions(cxt, &tb);
+
+	itr = fdisk_new_iter(FDISK_ITER_FORWARD);
+	while (fdisk_table_next_partition(tb, itr, &pa) == 0) {
+		printf(" #%zu  %12ju %12ju\n",	fdisk_partition_get_partno(pa),
+						fdisk_partition_get_start(pa),
+						fdisk_partition_get_size(pa));
+	}
+
+done:
+	fdisk_free_iter(itr);
+	fdisk_unref_table(tb);
+
+	/*fdisk_write_disklabel(cxt);*/
+	fdisk_unref_context(cxt);
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	struct fdisk_test tss[] = {
+	{ "--dump",    test_dump,    "<device>            dump PT as script" },
+	{ "--read",    test_read,    "<file>              read PT script from file" },
+	{ "--apply",   test_apply,   "<device> <file>     try apply script from file to device" },
+	{ "--stdin",   test_stdin,   "                    read input like sfdisk" },
+	{ NULL }
+	};
+
+	return fdisk_run_test(tss, argc, argv);
+}
+
+#endif
diff --git a/libblkid/libfdisk/src/sgi.c b/libblkid/libfdisk/src/sgi.c
new file mode 100644
index 0000000..cd4cedf
--- /dev/null
+++ b/libblkid/libfdisk/src/sgi.c
@@ -0,0 +1,1185 @@
+/*
+ *
+ * Copyright (C) 2012 Davidlohr Bueso <dave@gnu.org>
+ *               2013 Karel Zak <kzak@redhat.com>
+ *
+ * This is a re-written version for libfdisk, the original was fdisksgilabel.c
+ * from util-linux fdisk, by:
+ *
+ *               Andreas Neuper, Sep 1998,
+ *               Arnaldo Carvalho de Melo <acme@conectiva.com.br>, Mar 1999,
+ *               Phillip Kesling <pkesling@sgi.com>, Mar 2003.
+ */
+
+#include "c.h"
+#include "nls.h"
+#include "all-io.h"
+
+#include "blkdev.h"
+
+#include "bitops.h"
+#include "pt-sgi.h"
+#include "pt-mbr.h"
+#include "fdiskP.h"
+
+/**
+ * SECTION: sgi
+ * @title: SGI
+ * @short_description: disk label specific functions
+ *
+ */
+
+/*
+ * in-memory fdisk SGI stuff
+ */
+struct fdisk_sgi_label {
+	struct fdisk_label	head;		/* generic fdisk part */
+	struct sgi_disklabel	*header;	/* on-disk data (pointer to cxt->firstsector) */
+
+	struct sgi_freeblocks {
+		unsigned int first;
+		unsigned int last;
+	} freelist[SGI_MAXPARTITIONS + 1];
+};
+
+static struct fdisk_parttype sgi_parttypes[] =
+{
+	{SGI_TYPE_VOLHDR,	N_("SGI volhdr")},
+	{SGI_TYPE_TRKREPL,	N_("SGI trkrepl")},
+	{SGI_TYPE_SECREPL,	N_("SGI secrepl")},
+	{SGI_TYPE_SWAP,		N_("SGI raw")},
+	{SGI_TYPE_BSD,		N_("SGI bsd")},
+	{SGI_TYPE_SYSV,		N_("SGI sysv")},
+	{SGI_TYPE_ENTIRE_DISK,	N_("SGI volume")},
+	{SGI_TYPE_EFS,		N_("SGI efs")},
+	{SGI_TYPE_LVOL,		N_("SGI lvol")},
+	{SGI_TYPE_RLVOL,	N_("SGI rlvol")},
+	{SGI_TYPE_XFS,		N_("SGI xfs")},
+	{SGI_TYPE_XFSLOG,	N_("SGI xfslog")},
+	{SGI_TYPE_XLV,		N_("SGI xlv")},
+	{SGI_TYPE_XVM,		N_("SGI xvm")},
+	{MBR_LINUX_SWAP_PARTITION, N_("Linux swap")},
+	{MBR_LINUX_DATA_PARTITION, N_("Linux native")},
+	{MBR_LINUX_LVM_PARTITION, N_("Linux LVM")},
+	{MBR_LINUX_RAID_PARTITION, N_("Linux RAID")},
+	{0, NULL }
+};
+
+static unsigned int sgi_get_start_sector(struct fdisk_context *cxt, int i );
+static unsigned int sgi_get_num_sectors(struct fdisk_context *cxt, int i );
+static int sgi_get_bootpartition(struct fdisk_context *cxt);
+static int sgi_get_swappartition(struct fdisk_context *cxt);
+
+/* Returns a pointer buffer with on-disk data. */
+static inline struct sgi_disklabel *self_disklabel(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, SGI));
+
+	return ((struct fdisk_sgi_label *) cxt->label)->header;
+}
+
+/* Returns in-memory fdisk data. */
+static inline struct fdisk_sgi_label *self_label(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, SGI));
+
+	return (struct fdisk_sgi_label *) cxt->label;
+}
+
+/*
+ * Information within second on-disk block
+ */
+#define	SGI_INFO_MAGIC		0x00072959
+
+struct sgi_info {
+	unsigned int   magic;		/* looks like a magic number */
+	unsigned int   a2;
+	unsigned int   a3;
+	unsigned int   a4;
+	unsigned int   b1;
+	unsigned short b2;
+	unsigned short b3;
+	unsigned int   c[16];
+	unsigned short d[3];
+	unsigned char  scsi_string[50];
+	unsigned char  serial[137];
+	unsigned short check1816;
+	unsigned char  installer[225];
+};
+
+static struct sgi_info *sgi_new_info(void)
+{
+	struct sgi_info *info = calloc(1, sizeof(struct sgi_info));
+
+	if (!info)
+		return NULL;
+
+	info->magic = cpu_to_be32(SGI_INFO_MAGIC);
+	info->b1 = cpu_to_be32(-1);
+	info->b2 = cpu_to_be16(-1);
+	info->b3 = cpu_to_be16(1);
+
+	/* You may want to replace this string !!!!!!! */
+	strcpy((char *) info->scsi_string, "IBM OEM 0662S12         3 30");
+	strcpy((char *) info->serial, "0000");
+	info->check1816 = cpu_to_be16(18 * 256 + 16);
+	strcpy((char *) info->installer, "Sfx version 5.3, Oct 18, 1994");
+
+	return info;
+}
+
+static void sgi_free_info(struct sgi_info *info)
+{
+	free(info);
+}
+
+/**
+ * fdisk_sgi_create_info:
+ * @cxt: context
+ *
+ * This function add hint about SGI label (e.g. set "sgilabel" as volume name)
+ * to the first SGI volume. This is probably old SGI convention without any
+ * effect to the device partitioning.
+ *
+ * Returns: 0 on success, <0 on error
+ */
+int fdisk_sgi_create_info(struct fdisk_context *cxt)
+{
+	struct sgi_disklabel *sgilabel = self_disklabel(cxt);
+
+	/* I keep SGI's habit to write the sgilabel to the second block */
+	sgilabel->volume[0].block_num = cpu_to_be32(2);
+	sgilabel->volume[0].num_bytes = cpu_to_be32(sizeof(struct sgi_info));
+	strncpy((char *) sgilabel->volume[0].name, "sgilabel", 8);
+
+	fdisk_info(cxt, _("SGI info created on second sector."));
+	return 0;
+}
+
+
+/*
+ * only dealing with free blocks here
+ */
+static void set_freelist(struct fdisk_context *cxt,
+		size_t i, unsigned int f, unsigned int l)
+{
+	struct fdisk_sgi_label *sgi = self_label(cxt);
+
+	if (i < ARRAY_SIZE(sgi->freelist)) {
+		sgi->freelist[i].first = f;
+		sgi->freelist[i].last = l;
+	}
+}
+
+static void add_to_freelist(struct fdisk_context *cxt,
+		unsigned int f, unsigned int l)
+{
+	struct fdisk_sgi_label *sgi = self_label(cxt);
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(sgi->freelist); i++) {
+		if (sgi->freelist[i].last == 0)
+			break;
+	}
+	set_freelist(cxt, i, f, l);
+}
+
+static void clear_freelist(struct fdisk_context *cxt)
+{
+	struct fdisk_sgi_label *sgi = self_label(cxt);
+
+	memset(sgi->freelist, 0, sizeof(sgi->freelist));
+}
+
+static unsigned int is_in_freelist(struct fdisk_context *cxt, unsigned int b)
+{
+	struct fdisk_sgi_label *sgi = self_label(cxt);
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(sgi->freelist); i++) {
+		if (sgi->freelist[i].first <= b
+		    && sgi->freelist[i].last >= b)
+			return sgi->freelist[i].last;
+	}
+
+	return 0;
+}
+
+
+static int sgi_get_nsect(struct fdisk_context *cxt)
+{
+	struct sgi_disklabel *sgilabel = self_disklabel(cxt);
+	return be16_to_cpu(sgilabel->devparam.nsect);
+}
+
+static int sgi_get_ntrks(struct fdisk_context *cxt)
+{
+	struct sgi_disklabel *sgilabel = self_disklabel(cxt);
+	return be16_to_cpu(sgilabel->devparam.ntrks);
+}
+
+static size_t count_used_partitions(struct fdisk_context *cxt)
+{
+	size_t i, ct = 0;
+
+	for (i = 0; i < cxt->label->nparts_max; i++)
+		ct += sgi_get_num_sectors(cxt, i) > 0;
+
+	return ct;
+}
+
+static int sgi_probe_label(struct fdisk_context *cxt)
+{
+	struct fdisk_sgi_label *sgi;
+	struct sgi_disklabel *sgilabel;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, SGI));
+	assert(sizeof(struct sgi_disklabel) <= 512);
+
+	/* map first sector to header */
+	sgi = (struct fdisk_sgi_label *) cxt->label;
+	sgi->header = (struct sgi_disklabel *) cxt->firstsector;
+	sgilabel = sgi->header;
+
+	if (be32_to_cpu(sgilabel->magic) != SGI_LABEL_MAGIC) {
+		sgi->header = NULL;
+		return 0;
+	}
+
+	/*
+	 * test for correct checksum
+	 */
+	if (sgi_pt_checksum(sgilabel) != 0)
+		fdisk_warnx(cxt, _("Detected an SGI disklabel with wrong checksum."));
+
+	clear_freelist(cxt);
+	cxt->label->nparts_max = SGI_MAXPARTITIONS;
+	cxt->label->nparts_cur = count_used_partitions(cxt);
+	return 1;
+}
+
+static int sgi_list_table(struct fdisk_context *cxt)
+{
+	struct sgi_disklabel *sgilabel = self_disklabel(cxt);
+	struct sgi_device_parameter *sgiparam = &sgilabel->devparam;
+	int rc = 0;
+
+	if (fdisk_is_details(cxt))
+		fdisk_info(cxt, _(
+			"Label geometry: %d heads, %llu sectors\n"
+			"                %llu cylinders, %d physical cylinders\n"
+			"                %d extra sects/cyl, interleave %d:1\n"),
+			cxt->geom.heads, cxt->geom.sectors,
+			cxt->geom.cylinders, be16_to_cpu(sgiparam->pcylcount),
+			(int) sgiparam->sparecyl, be16_to_cpu(sgiparam->ilfact));
+
+	fdisk_info(cxt, _("Bootfile: %s"), sgilabel->boot_file);
+	return rc;
+}
+
+static unsigned int sgi_get_start_sector(struct fdisk_context *cxt, int i)
+{
+	struct sgi_disklabel *sgilabel = self_disklabel(cxt);
+	return be32_to_cpu(sgilabel->partitions[i].first_block);
+}
+
+static unsigned int sgi_get_num_sectors(struct fdisk_context *cxt, int i)
+{
+	struct sgi_disklabel *sgilabel = self_disklabel(cxt);
+	return be32_to_cpu(sgilabel->partitions[i].num_blocks);
+}
+
+static int sgi_get_sysid(struct fdisk_context *cxt, int i)
+{
+	struct sgi_disklabel *sgilabel = self_disklabel(cxt);
+	return be32_to_cpu(sgilabel->partitions[i].type);
+}
+
+static int sgi_get_bootpartition(struct fdisk_context *cxt)
+{
+	struct sgi_disklabel *sgilabel = self_disklabel(cxt);
+	return be16_to_cpu(sgilabel->root_part_num);
+}
+
+static int sgi_get_swappartition(struct fdisk_context *cxt)
+{
+	struct sgi_disklabel *sgilabel = self_disklabel(cxt);
+	return be16_to_cpu(sgilabel->swap_part_num);
+}
+
+static unsigned int sgi_get_lastblock(struct fdisk_context *cxt)
+{
+	return cxt->geom.heads * cxt->geom.sectors * cxt->geom.cylinders;
+}
+
+static struct fdisk_parttype *sgi_get_parttype(struct fdisk_context *cxt, size_t n)
+{
+	struct fdisk_parttype *t;
+
+	if (n >= cxt->label->nparts_max)
+		return NULL;
+
+	t = fdisk_label_get_parttype_from_code(cxt->label, sgi_get_sysid(cxt, n));
+	return t ? : fdisk_new_unknown_parttype(sgi_get_sysid(cxt, n), NULL);
+}
+
+/* fdisk_get_partition() backend */
+static int sgi_get_partition(struct fdisk_context *cxt, size_t n, struct fdisk_partition *pa)
+{
+	fdisk_sector_t start, len;
+
+	pa->used = sgi_get_num_sectors(cxt, n) > 0;
+	if (!pa->used)
+		return 0;
+
+	start = sgi_get_start_sector(cxt, n);
+	len = sgi_get_num_sectors(cxt, n);
+
+	pa->type = sgi_get_parttype(cxt, n);
+	pa->size = len;
+	pa->start = start;
+
+	if (pa->type && pa->type->code == SGI_TYPE_ENTIRE_DISK)
+		pa->wholedisk = 1;
+
+	pa->attrs = sgi_get_swappartition(cxt) == (int) n ? "swap" :
+		    sgi_get_bootpartition(cxt) == (int) n ? "boot" : NULL;
+	if (pa->attrs)
+		pa->attrs = strdup(pa->attrs);
+
+	return 0;
+}
+
+
+static int sgi_check_bootfile(struct fdisk_context *cxt, const char *name)
+{
+	size_t sz;
+	struct sgi_disklabel *sgilabel = self_disklabel(cxt);
+
+	sz = strlen(name);
+
+	if (sz < 3) {
+		/* "/a\n" is minimum */
+		fdisk_warnx(cxt, _("Invalid bootfile!  The bootfile must "
+				   "be an absolute non-zero pathname, "
+				   "e.g. \"/unix\" or \"/unix.save\"."));
+		return -EINVAL;
+
+	} else if (sz > sizeof(sgilabel->boot_file)) {
+		fdisk_warnx(cxt, P_("Name of bootfile is too long: %zu byte maximum.",
+				    "Name of bootfile is too long: %zu bytes maximum.",
+				    sizeof(sgilabel->boot_file)),
+			    sizeof(sgilabel->boot_file));
+		return -EINVAL;
+
+	} else if (*name != '/') {
+		fdisk_warnx(cxt, _("Bootfile must have a fully qualified pathname."));
+		return -EINVAL;
+	}
+
+	if (strncmp(name, (char *) sgilabel->boot_file,
+				sizeof(sgilabel->boot_file))) {
+		fdisk_warnx(cxt, _("Be aware that the bootfile is not checked "
+				   "for existence.  SGI's default is \"/unix\", "
+				   "and for backup \"/unix.save\"."));
+		return 0;	/* filename is correct and did change */
+	}
+
+	return 1;	/* filename did not change */
+}
+
+/**
+ * fdisk_sgi_set_bootfile:
+ * @cxt: context
+ *
+ * Allows to set SGI boot file. The function uses Ask API for dialog with
+ * user.
+ *
+ * Returns: 0 on success, <0 on error
+ */
+int fdisk_sgi_set_bootfile(struct fdisk_context *cxt)
+{
+	int rc = 0;
+	size_t sz;
+	char *name = NULL;
+	struct sgi_disklabel *sgilabel = self_disklabel(cxt);
+
+	fdisk_info(cxt, _("The current boot file is: %s"), sgilabel->boot_file);
+
+	rc = fdisk_ask_string(cxt, _("Enter of the new boot file"), &name);
+	if (rc == 0)
+		rc = sgi_check_bootfile(cxt, name);
+	if (rc) {
+		if (rc == 1)
+			fdisk_info(cxt, _("Boot file is unchanged."));
+		goto done;
+	}
+
+	memset(sgilabel->boot_file, 0, sizeof(sgilabel->boot_file));
+	sz = strlen(name);
+
+	assert(sz <= sizeof(sgilabel->boot_file));	/* see sgi_check_bootfile() */
+
+	memcpy(sgilabel->boot_file, name, sz);
+
+	fdisk_info(cxt, _("Bootfile has been changed to \"%s\"."), name);
+done:
+	free(name);
+	return rc;
+}
+
+static int sgi_write_disklabel(struct fdisk_context *cxt)
+{
+	struct sgi_disklabel *sgilabel;
+	struct sgi_info *info = NULL;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, SGI));
+
+	sgilabel = self_disklabel(cxt);
+	sgilabel->csum = 0;
+	sgilabel->csum = cpu_to_be32(sgi_pt_checksum(sgilabel));
+
+	assert(sgi_pt_checksum(sgilabel) == 0);
+
+	if (lseek(cxt->dev_fd, 0, SEEK_SET) < 0)
+		goto err;
+	if (write_all(cxt->dev_fd, sgilabel, DEFAULT_SECTOR_SIZE))
+		goto err;
+	if (!strncmp((char *) sgilabel->volume[0].name, "sgilabel", 8)) {
+		/*
+		 * Keep this habit of first writing the "sgilabel".
+		 * I never tested whether it works without. (AN 1998-10-02)
+		 */
+		int infostartblock
+			= be32_to_cpu(sgilabel->volume[0].block_num);
+
+		if (lseek(cxt->dev_fd, (off_t) infostartblock *
+					DEFAULT_SECTOR_SIZE, SEEK_SET) < 0)
+			goto err;
+		info = sgi_new_info();
+		if (!info)
+			goto err;
+		if (write_all(cxt->dev_fd, info, sizeof(*info)))
+			goto err;
+	}
+
+	sgi_free_info(info);
+	return 0;
+err:
+	sgi_free_info(info);
+	return -errno;
+}
+
+static int compare_start(struct fdisk_context *cxt,
+			 const void *x, const void *y)
+{
+	/*
+	 * Sort according to start sectors and prefer the largest partition:
+	 * entry zero is the entire-disk entry.
+	 */
+	unsigned int i = *(int *) x;
+	unsigned int j = *(int *) y;
+	unsigned int a = sgi_get_start_sector(cxt, i);
+	unsigned int b = sgi_get_start_sector(cxt, j);
+	unsigned int c = sgi_get_num_sectors(cxt, i);
+	unsigned int d = sgi_get_num_sectors(cxt, j);
+
+	if (a == b)
+		return (d > c) ? 1 : (d == c) ? 0 : -1;
+	return (a > b) ? 1 : -1;
+}
+
+static void generic_swap(void *a0, void *b0, int size)
+{
+	char *a = a0, *b = b0;
+
+	for (; size > 0; --size, a++, b++) {
+		char t = *a;
+		*a = *b;
+		*b = t;
+	}
+}
+
+
+/* heap sort, based on Matt Mackall's linux kernel version */
+static void sort(void *base0, size_t num, size_t size, struct fdisk_context *cxt,
+		 int (*cmp_func)(struct fdisk_context *, const void *, const void *))
+{
+	/* pre-scale counters for performance */
+	int i = (num/2 - 1) * size;
+	size_t n = num * size, c, r;
+	char *base = base0;
+
+	/* heapify */
+	for ( ; i >= 0; i -= size) {
+		for (r = i; r * 2 + size < n; r  = c) {
+			c = r * 2 + size;
+			if (c < n - size &&
+			    cmp_func(cxt, base + c, base + c + size) < 0)
+				c += size;
+			if (cmp_func(cxt, base + r, base + c) >= 0)
+				break;
+			generic_swap(base + r, base + c, size);
+		}
+	}
+
+	/* sort */
+	for (i = n - size; i > 0; i -= size) {
+		generic_swap(base, base + i, size);
+		for (r = 0; r * 2 + size < (size_t) i; r = c) {
+			c = r * 2 + size;
+			if (c < i - size &&
+			    cmp_func(cxt, base + c, base + c + size) < 0)
+				c += size;
+			if (cmp_func(cxt, base + r, base + c) >= 0)
+				break;
+			generic_swap(base + r, base + c, size);
+		}
+	}
+}
+
+static int verify_disklabel(struct fdisk_context *cxt, int verbose)
+{
+	int Index[SGI_MAXPARTITIONS];	/* list of valid partitions */
+	int sortcount = 0;		/* number of used partitions, i.e. non-zero lengths */
+	int entire = 0, i = 0;
+	unsigned int start = 0;
+	long long gap = 0;	/* count unused blocks */
+	unsigned int lastblock = sgi_get_lastblock(cxt);
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, SGI));
+
+	clear_freelist(cxt);
+	memset(Index, 0, sizeof(Index));
+
+	for (i=0; i < SGI_MAXPARTITIONS; i++) {
+		if (sgi_get_num_sectors(cxt, i) != 0) {
+			Index[sortcount++] = i;
+			if (sgi_get_sysid(cxt, i) == SGI_TYPE_ENTIRE_DISK
+			    && entire++ == 1) {
+				if (verbose)
+					fdisk_info(cxt, _("More than one entire "
+						"disk entry present."));
+			}
+		}
+	}
+	if (sortcount == 0) {
+		if (verbose)
+			fdisk_info(cxt, _("No partitions defined."));
+		if (lastblock)
+			add_to_freelist(cxt, 0, lastblock);
+		return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
+	}
+
+	sort(Index, sortcount, sizeof(Index[0]), cxt, compare_start);
+
+	if (sgi_get_sysid(cxt, Index[0]) == SGI_TYPE_ENTIRE_DISK) {
+		if (verbose && Index[0] != 10)
+			fdisk_info(cxt, _("IRIX likes it when partition 11 "
+					  "covers the entire disk."));
+
+		if (verbose && sgi_get_start_sector(cxt, Index[0]) != 0)
+			fdisk_info(cxt, _("The entire disk partition should "
+					  "start at block 0, not at block %d."),
+				   sgi_get_start_sector(cxt, Index[0]));
+
+		if (verbose && sgi_get_num_sectors(cxt, Index[0]) != lastblock)
+			DBG(LABEL, ul_debug(
+				"entire disk partition=%ds, but disk=%ds",
+				sgi_get_num_sectors(cxt, Index[0]),
+				lastblock));
+		lastblock = sgi_get_num_sectors(cxt, Index[0]);
+	} else if (verbose) {
+		fdisk_info(cxt, _("Partition 11 should cover the entire disk."));
+		DBG(LABEL, ul_debug("sysid=%d\tpartition=%d",
+			       sgi_get_sysid(cxt, Index[0]), Index[0]+1));
+	}
+	for (i=1, start=0; i<sortcount; i++) {
+		int cylsize = sgi_get_nsect(cxt) * sgi_get_ntrks(cxt);
+
+		if (verbose && cylsize
+		    && (sgi_get_start_sector(cxt, Index[i]) % cylsize) != 0)
+			DBG(LABEL, ul_debug("partition %d does not start on "
+					"cylinder boundary.", Index[i]+1));
+
+		if (verbose && cylsize
+		    && sgi_get_num_sectors(cxt, Index[i]) % cylsize != 0)
+			DBG(LABEL, ul_debug("partition %d does not end on "
+					"cylinder boundary.", Index[i]+1));
+
+		/* We cannot handle several "entire disk" entries. */
+		if (sgi_get_sysid(cxt, Index[i]) == SGI_TYPE_ENTIRE_DISK)
+			continue;
+
+		if (start > sgi_get_start_sector(cxt, Index[i])) {
+			if (verbose)
+				fdisk_info(cxt,
+					   P_("Partitions %d and %d overlap by %d sector.",
+					      "Partitions %d and %d overlap by %d sectors.",
+					      start - sgi_get_start_sector(cxt, Index[i])),
+					   Index[i-1]+1, Index[i]+1,
+					   start - sgi_get_start_sector(cxt, Index[i]));
+			if (gap >  0) gap = -gap;
+			if (gap == 0) gap = -1;
+		}
+		if (start < sgi_get_start_sector(cxt, Index[i])) {
+			if (verbose)
+				fdisk_info(cxt,
+					   P_("Unused gap of %8u sector: sector %8u",
+					      "Unused gap of %8u sectors: sectors %8u-%u",
+					      sgi_get_start_sector(cxt, Index[i]) - start),
+					   sgi_get_start_sector(cxt, Index[i]) - start,
+					   start, sgi_get_start_sector(cxt, Index[i])-1);
+			gap += sgi_get_start_sector(cxt, Index[i]) - start;
+			add_to_freelist(cxt, start,
+					sgi_get_start_sector(cxt, Index[i]));
+		}
+		start = sgi_get_start_sector(cxt, Index[i])
+			+ sgi_get_num_sectors(cxt, Index[i]);
+		/* Align free space on cylinder boundary. */
+		if (cylsize && start % cylsize)
+			start += cylsize - (start % cylsize);
+
+		DBG(LABEL, ul_debug("%2d:%12d\t%12d\t%12d", Index[i],
+				       sgi_get_start_sector(cxt, Index[i]),
+				       sgi_get_num_sectors(cxt, Index[i]),
+				       sgi_get_sysid(cxt, Index[i])));
+	}
+	if (start < lastblock) {
+		if (verbose)
+			fdisk_info(cxt, P_("Unused gap of %8u sector: sector %8u",
+					   "Unused gap of %8u sectors: sectors %8u-%u",
+					   lastblock - start),
+				   lastblock - start, start, lastblock-1);
+		gap += lastblock - start;
+		add_to_freelist(cxt, start, lastblock);
+	}
+	/*
+	 * Done with arithmetics. Go for details now.
+	 */
+	if (verbose) {
+		if (sgi_get_bootpartition(cxt) < 0
+		    || !sgi_get_num_sectors(cxt, sgi_get_bootpartition(cxt)))
+			fdisk_info(cxt, _("The boot partition does not exist."));
+
+		if (sgi_get_swappartition(cxt) < 0
+		    || !sgi_get_num_sectors(cxt, sgi_get_swappartition(cxt)))
+			fdisk_info(cxt, _("The swap partition does not exist."));
+
+		else if (sgi_get_sysid(cxt, sgi_get_swappartition(cxt)) != SGI_TYPE_SWAP
+		    && sgi_get_sysid(cxt, sgi_get_swappartition(cxt)) != MBR_LINUX_SWAP_PARTITION)
+			fdisk_info(cxt, _("The swap partition has no swap type."));
+
+		if (sgi_check_bootfile(cxt, "/unix"))
+			fdisk_info(cxt, _("You have chosen an unusual bootfile name."));
+	}
+
+	return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
+}
+
+static int sgi_verify_disklabel(struct fdisk_context *cxt)
+{
+	return verify_disklabel(cxt, 1);
+}
+
+static int sgi_gaps(struct fdisk_context *cxt)
+{
+	/*
+	 * returned value is:
+	 *  = 0 : disk is properly filled to the rim
+	 *  < 0 : there is an overlap
+	 *  > 0 : there is still some vacant space
+	 */
+	return verify_disklabel(cxt, 0);
+}
+
+/* Returns partition index of first entry marked as entire disk. */
+static int sgi_entire(struct fdisk_context *cxt)
+{
+	size_t i;
+
+	for (i = 0; i < SGI_MAXPARTITIONS; i++)
+		if (sgi_get_sysid(cxt, i) == SGI_TYPE_ENTIRE_DISK)
+			return i;
+	return -1;
+}
+
+static int set_partition(struct fdisk_context *cxt, size_t i,
+			     unsigned int start, unsigned int length, int sys)
+{
+	struct sgi_disklabel *sgilabel;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, SGI));
+
+	sgilabel = self_disklabel(cxt);
+	sgilabel->partitions[i].type = cpu_to_be32(sys);
+	sgilabel->partitions[i].num_blocks = cpu_to_be32(length);
+	sgilabel->partitions[i].first_block = cpu_to_be32(start);
+
+	fdisk_label_set_changed(cxt->label, 1);
+
+	if (sgi_gaps(cxt) < 0)	/* rebuild freelist */
+		fdisk_warnx(cxt, _("Partition overlap on the disk."));
+	if (length) {
+		struct fdisk_parttype *t =
+				fdisk_label_get_parttype_from_code(cxt->label, sys);
+		fdisk_info_new_partition(cxt, i + 1, start, start + length, t);
+	}
+
+	return 0;
+}
+
+static void sgi_set_entire(struct fdisk_context *cxt)
+{
+	size_t n;
+
+	for (n = 10; n < cxt->label->nparts_max; n++) {
+		if (!sgi_get_num_sectors(cxt, n)) {
+			set_partition(cxt, n, 0, sgi_get_lastblock(cxt), SGI_TYPE_ENTIRE_DISK);
+			break;
+		}
+	}
+}
+
+static void sgi_set_volhdr(struct fdisk_context *cxt)
+{
+	size_t n;
+
+	for (n = 8; n < cxt->label->nparts_max; n++) {
+		if (!sgi_get_num_sectors(cxt, n)) {
+			/* Choose same default volume header size as IRIX fx uses. */
+			if (4096 < sgi_get_lastblock(cxt))
+				set_partition(cxt, n, 0, 4096, SGI_TYPE_VOLHDR);
+			break;
+		}
+	}
+}
+
+static int sgi_delete_partition(struct fdisk_context *cxt, size_t partnum)
+{
+	int rc;
+
+	assert(cxt);
+	assert(cxt->label);
+
+	if (partnum > cxt->label->nparts_max)
+		return -EINVAL;
+
+	rc = set_partition(cxt, partnum, 0, 0, 0);
+
+	cxt->label->nparts_cur = count_used_partitions(cxt);
+
+	return rc;
+}
+
+static int sgi_add_partition(struct fdisk_context *cxt,
+			     struct fdisk_partition *pa,
+			     size_t *partno)
+{
+	struct fdisk_sgi_label *sgi;
+	char mesg[256];
+	unsigned int first = 0, last = 0;
+	struct fdisk_ask *ask;
+	int sys = pa && pa->type ? pa->type->code : SGI_TYPE_XFS;
+	int rc;
+	size_t n;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, SGI));
+
+	rc = fdisk_partition_next_partno(pa, cxt, &n);
+	if (rc)
+		return rc;
+	if (n == 10)
+		sys = SGI_TYPE_ENTIRE_DISK;
+	else if (n == 8)
+		sys = 0;
+
+	sgi = self_label(cxt);
+
+	if (sgi_get_num_sectors(cxt, n)) {
+		fdisk_warnx(cxt, _("Partition %zu is already defined.  "
+				   "Delete it before re-adding it."), n + 1);
+		return -EINVAL;
+	}
+	if (!cxt->script && sgi_entire(cxt) == -1 &&  sys != SGI_TYPE_ENTIRE_DISK) {
+		fdisk_info(cxt, _("Attempting to generate entire disk entry automatically."));
+		sgi_set_entire(cxt);
+		sgi_set_volhdr(cxt);
+	}
+	if (sgi_gaps(cxt) == 0 && sys != SGI_TYPE_ENTIRE_DISK) {
+		fdisk_warnx(cxt, _("The entire disk is already covered with partitions."));
+		return -EINVAL;
+	}
+	if (sgi_gaps(cxt) < 0) {
+		fdisk_warnx(cxt, _("You got a partition overlap on the disk. Fix it first!"));
+		return -EINVAL;
+	}
+
+	if (sys == SGI_TYPE_ENTIRE_DISK) {
+		first = 0;
+		last = sgi_get_lastblock(cxt);
+	} else {
+		first = sgi->freelist[0].first;
+		last  = sgi->freelist[0].last;
+	}
+
+	/* first sector */
+	if (pa && pa->start_follow_default)
+		;
+	else if (pa && fdisk_partition_has_start(pa)) {
+		first = pa->start;
+		last = is_in_freelist(cxt, first);
+
+		if (sys != SGI_TYPE_ENTIRE_DISK && !last)
+			return -ERANGE;
+	} else {
+		snprintf(mesg, sizeof(mesg), _("First %s"),
+				fdisk_get_unit(cxt, FDISK_SINGULAR));
+		ask = fdisk_new_ask();
+		if (!ask)
+			return -ENOMEM;
+
+		fdisk_ask_set_query(ask, mesg);
+		fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER);
+
+		fdisk_ask_number_set_low(ask,     fdisk_scround(cxt, first));	/* minimal */
+		fdisk_ask_number_set_default(ask, fdisk_scround(cxt, first));	/* default */
+		fdisk_ask_number_set_high(ask,    fdisk_scround(cxt, last) - 1); /* maximal */
+
+		rc = fdisk_do_ask(cxt, ask);
+		first = fdisk_ask_number_get_result(ask);
+		fdisk_unref_ask(ask);
+
+		if (rc)
+			return rc;
+		if (fdisk_use_cylinders(cxt))
+			first *= fdisk_get_units_per_sector(cxt);
+	}
+
+	if (first && sys == SGI_TYPE_ENTIRE_DISK)
+		fdisk_info(cxt, _("It is highly recommended that the "
+				  "eleventh partition covers the entire "
+				  "disk and is of type 'SGI volume'."));
+	if (!last)
+		last = is_in_freelist(cxt, first);
+
+	/* last sector */
+	if (pa && pa->end_follow_default)
+		last -= 1ULL;
+	else if (pa && fdisk_partition_has_size(pa)) {
+		if (first + pa->size - 1ULL > last)
+			return -ERANGE;
+		last = first + pa->size - 1ULL;
+	} else {
+		snprintf(mesg, sizeof(mesg),
+			 _("Last %s or +%s or +size{K,M,G,T,P}"),
+			 fdisk_get_unit(cxt, FDISK_SINGULAR),
+			 fdisk_get_unit(cxt, FDISK_PLURAL));
+
+		ask = fdisk_new_ask();
+		if (!ask)
+			return -ENOMEM;
+
+		fdisk_ask_set_query(ask, mesg);
+		fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET);
+
+		fdisk_ask_number_set_low(ask,     fdisk_scround(cxt, first));	/* minimal */
+		fdisk_ask_number_set_default(ask, fdisk_scround(cxt, last) - 1);/* default */
+		fdisk_ask_number_set_high(ask,    fdisk_scround(cxt, last) - 1);/* maximal */
+		fdisk_ask_number_set_base(ask,    fdisk_scround(cxt, first));
+
+		if (fdisk_use_cylinders(cxt))
+			fdisk_ask_number_set_unit(ask,
+				     cxt->sector_size *
+				     fdisk_get_units_per_sector(cxt));
+		else
+			fdisk_ask_number_set_unit(ask,cxt->sector_size);
+
+		rc = fdisk_do_ask(cxt, ask);
+		last = fdisk_ask_number_get_result(ask) + 1;
+
+		fdisk_unref_ask(ask);
+		if (rc)
+			return rc;
+		if (fdisk_use_cylinders(cxt))
+			last *= fdisk_get_units_per_sector(cxt);
+	}
+
+	if (sys == SGI_TYPE_ENTIRE_DISK
+	    && (first != 0 || last != sgi_get_lastblock(cxt)))
+		fdisk_info(cxt, _("It is highly recommended that the "
+				  "eleventh partition covers the entire "
+				  "disk and is of type 'SGI volume'."));
+
+	set_partition(cxt, n, first, last - first, sys);
+	cxt->label->nparts_cur = count_used_partitions(cxt);
+	if (partno)
+		*partno = n;
+	return 0;
+}
+
+static int sgi_create_disklabel(struct fdisk_context *cxt)
+{
+	struct fdisk_sgi_label *sgi;
+	struct sgi_disklabel *sgilabel;
+	int rc;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, SGI));
+
+#ifdef HDIO_GETGEO
+	if (cxt->geom.heads && cxt->geom.sectors) {
+		fdisk_sector_t llsectors;
+
+		if (blkdev_get_sectors(cxt->dev_fd, (unsigned long long *) &llsectors) == 0) {
+			/* the get device size ioctl was successful */
+			fdisk_sector_t llcyls;
+			int sec_fac = cxt->sector_size / 512;
+
+			llcyls = llsectors / (cxt->geom.heads * cxt->geom.sectors * sec_fac);
+			cxt->geom.cylinders = llcyls;
+			if (cxt->geom.cylinders != llcyls)	/* truncated? */
+				cxt->geom.cylinders = ~0;
+		} else {
+			/* otherwise print error and use truncated version */
+			fdisk_warnx(cxt,
+				_("BLKGETSIZE ioctl failed on %s. "
+				  "Using geometry cylinder value of %llu. "
+				  "This value may be truncated for devices "
+				  "> 33.8 GB."), cxt->dev_path, cxt->geom.cylinders);
+		}
+	}
+#endif
+	rc = fdisk_init_firstsector_buffer(cxt);
+	if (rc)
+		return rc;
+
+	sgi = (struct fdisk_sgi_label *) cxt->label;
+	sgi->header = (struct sgi_disklabel *) cxt->firstsector;
+
+	sgilabel = sgi->header;
+
+	sgilabel->magic = cpu_to_be32(SGI_LABEL_MAGIC);
+	sgilabel->root_part_num = cpu_to_be16(0);
+	sgilabel->swap_part_num = cpu_to_be16(1);
+
+	/* sizeof(sgilabel->boot_file) = 16 > 6 */
+	memset(sgilabel->boot_file, 0, 16);
+	strcpy((char *) sgilabel->boot_file, "/unix");
+
+	sgilabel->devparam.skew			= (0);
+	sgilabel->devparam.gap1			= (0);
+	sgilabel->devparam.gap2			= (0);
+	sgilabel->devparam.sparecyl			= (0);
+	sgilabel->devparam.pcylcount	= cpu_to_be16(cxt->geom.cylinders);
+	sgilabel->devparam.head_vol0	= cpu_to_be16(0);
+	sgilabel->devparam.ntrks	= cpu_to_be16(cxt->geom.heads);
+	/* tracks/cylinder (heads) */
+	sgilabel->devparam.cmd_tag_queue_depth	= (0);
+	sgilabel->devparam.unused0			= (0);
+	sgilabel->devparam.unused1	= cpu_to_be16(0);
+	sgilabel->devparam.nsect	= cpu_to_be16(cxt->geom.sectors);
+	/* sectors/track */
+	sgilabel->devparam.bytes	= cpu_to_be16(cxt->sector_size);
+	sgilabel->devparam.ilfact	= cpu_to_be16(1);
+	sgilabel->devparam.flags	= cpu_to_be32(
+			SGI_DEVPARAM_TRACK_FWD
+			| SGI_DEVPARAM_IGNORE_ERRORS
+			| SGI_DEVPARAM_RESEEK);
+	sgilabel->devparam.datarate	= cpu_to_be32(0);
+	sgilabel->devparam.retries_on_error	= cpu_to_be32(1);
+	sgilabel->devparam.ms_per_word		= cpu_to_be32(0);
+	sgilabel->devparam.xylogics_gap1	= cpu_to_be16(0);
+	sgilabel->devparam.xylogics_syncdelay	= cpu_to_be16(0);
+	sgilabel->devparam.xylogics_readdelay	= cpu_to_be16(0);
+	sgilabel->devparam.xylogics_gap2	= cpu_to_be16(0);
+	sgilabel->devparam.xylogics_readgate	= cpu_to_be16(0);
+	sgilabel->devparam.xylogics_writecont	= cpu_to_be16(0);
+
+	memset(&(sgilabel->volume), 0,
+			sizeof(struct sgi_volume) * SGI_MAXVOLUMES);
+	memset(&(sgilabel->partitions), 0,
+			sizeof(struct sgi_partition) * SGI_MAXPARTITIONS);
+	cxt->label->nparts_max = SGI_MAXPARTITIONS;
+
+	/* don't create default layout when a script defined */
+	if (!cxt->script) {
+		sgi_set_entire(cxt);
+		sgi_set_volhdr(cxt);
+	}
+	cxt->label->nparts_cur = count_used_partitions(cxt);
+
+	fdisk_info(cxt, _("Created a new SGI disklabel."));
+	return 0;
+}
+
+static int sgi_set_partition(struct fdisk_context *cxt,
+		size_t i,
+		struct fdisk_partition *pa)
+{
+	struct sgi_disklabel *sgilabel;
+
+	if (i >= cxt->label->nparts_max)
+		return -EINVAL;
+
+	sgilabel = self_disklabel(cxt);
+
+	if (pa->type) {
+		struct fdisk_parttype *t = pa->type;
+
+		if (t->code > UINT32_MAX)
+			return -EINVAL;
+
+		if (sgi_get_num_sectors(cxt, i) == 0)	/* caught already before, ... */ {
+			fdisk_warnx(cxt, _("Sorry, only for non-empty partitions you can change the tag."));
+			return -EINVAL;
+		}
+
+		if ((i == 10 && t->code != SGI_TYPE_ENTIRE_DISK)
+		    || (i == 8 && t->code != 0))
+			fdisk_info(cxt, _("Consider leaving partition 9 as volume header (0), "
+					  "and partition 11 as entire volume (6), "
+					  "as IRIX expects it."));
+
+		if (cxt->script == NULL
+		    && ((t->code != SGI_TYPE_ENTIRE_DISK) && (t->code != SGI_TYPE_VOLHDR))
+		    && (sgi_get_start_sector(cxt, i) < 1)) {
+			int yes = 0;
+			fdisk_ask_yesno(cxt,
+				_("It is highly recommended that the partition at offset 0 "
+				  "is of type \"SGI volhdr\", the IRIX system will rely on it to "
+				  "retrieve from its directory standalone tools like sash and fx. "
+				  "Only the \"SGI volume\" entire disk section may violate this. "
+				  "Are you sure about tagging this partition differently?"), &yes);
+			if (!yes)
+				return 1;
+		}
+
+		sgilabel->partitions[i].type = cpu_to_be32(t->code);
+	}
+
+	if (fdisk_partition_has_start(pa))
+		sgilabel->partitions[i].first_block = cpu_to_be32(pa->start);
+	if (fdisk_partition_has_size(pa))
+		sgilabel->partitions[i].num_blocks = cpu_to_be32(pa->size);
+
+	fdisk_label_set_changed(cxt->label, 1);
+	return 0;
+}
+
+
+static int sgi_partition_is_used(
+		struct fdisk_context *cxt,
+		size_t i)
+{
+	assert(cxt);
+	assert(fdisk_is_label(cxt, SGI));
+
+	if (i >= cxt->label->nparts_max)
+		return 0;
+	return sgi_get_num_sectors(cxt, i) ? 1 : 0;
+}
+
+static int sgi_toggle_partition_flag(struct fdisk_context *cxt, size_t i, unsigned long flag)
+{
+	struct sgi_disklabel *sgilabel;
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, SGI));
+
+	if (i >= cxt->label->nparts_max)
+		return -EINVAL;
+
+	sgilabel = self_disklabel(cxt);
+
+	switch (flag) {
+	case SGI_FLAG_BOOT:
+		sgilabel->root_part_num =
+			be16_to_cpu(sgilabel->root_part_num) == i ?
+			0 : cpu_to_be16(i);
+		fdisk_label_set_changed(cxt->label, 1);
+		break;
+	case SGI_FLAG_SWAP:
+		sgilabel->swap_part_num =
+			be16_to_cpu(sgilabel->swap_part_num) == i ?
+			0 : cpu_to_be16(i);
+		fdisk_label_set_changed(cxt->label, 1);
+		break;
+	default:
+		return 1;
+	}
+
+	return 0;
+}
+
+static const struct fdisk_field sgi_fields[] =
+{
+	{ FDISK_FIELD_DEVICE,	N_("Device"),	 10,	0 },
+	{ FDISK_FIELD_START,	N_("Start"),	  5,	FDISK_FIELDFL_NUMBER },
+	{ FDISK_FIELD_END,	N_("End"),	  5,	FDISK_FIELDFL_NUMBER },
+	{ FDISK_FIELD_SECTORS,	N_("Sectors"),	  5,	FDISK_FIELDFL_NUMBER },
+	{ FDISK_FIELD_CYLINDERS,N_("Cylinders"),  5,	FDISK_FIELDFL_NUMBER },
+	{ FDISK_FIELD_SIZE,	N_("Size"),	  5,	FDISK_FIELDFL_NUMBER | FDISK_FIELDFL_EYECANDY },
+	{ FDISK_FIELD_TYPEID,	N_("Id"),	  2,	FDISK_FIELDFL_NUMBER },
+	{ FDISK_FIELD_TYPE,	N_("Type"),	0.1,	FDISK_FIELDFL_EYECANDY },
+	{ FDISK_FIELD_ATTR,	N_("Attrs"),	  0,	FDISK_FIELDFL_NUMBER }
+};
+
+static const struct fdisk_label_operations sgi_operations =
+{
+	.probe		= sgi_probe_label,
+	.write		= sgi_write_disklabel,
+	.verify		= sgi_verify_disklabel,
+	.create		= sgi_create_disklabel,
+	.list		= sgi_list_table,
+
+	.get_part	= sgi_get_partition,
+	.set_part	= sgi_set_partition,
+	.add_part	= sgi_add_partition,
+	.del_part	= sgi_delete_partition,
+
+	.part_is_used	= sgi_partition_is_used,
+	.part_toggle_flag = sgi_toggle_partition_flag
+};
+
+/* Allocates an SGI label driver. */
+struct fdisk_label *fdisk_new_sgi_label(struct fdisk_context *cxt)
+{
+	struct fdisk_label *lb;
+	struct fdisk_sgi_label *sgi;
+
+	assert(cxt);
+
+	sgi = calloc(1, sizeof(*sgi));
+	if (!sgi)
+		return NULL;
+
+	/* initialize generic part of the driver */
+	lb = (struct fdisk_label *) sgi;
+	lb->name = "sgi";
+	lb->id = FDISK_DISKLABEL_SGI;
+	lb->op = &sgi_operations;
+	lb->parttypes = sgi_parttypes;
+	lb->nparttypes = ARRAY_SIZE(sgi_parttypes) - 1;
+	lb->fields = sgi_fields;
+	lb->nfields = ARRAY_SIZE(sgi_fields);
+
+	lb->flags |= FDISK_LABEL_FL_REQUIRE_GEOMETRY;
+
+	return lb;
+}
diff --git a/libblkid/libfdisk/src/sun.c b/libblkid/libfdisk/src/sun.c
new file mode 100644
index 0000000..babff62
--- /dev/null
+++ b/libblkid/libfdisk/src/sun.c
@@ -0,0 +1,1130 @@
+/*
+ * Copyright (C) 2013 Karel Zak <kzak@redhat.com>
+ *
+ * Based on original code from fdisk:
+ *   Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
+ *   Merged with fdisk for other architectures, aeb, June 1998.
+ *   Arnaldo Carvalho de Melo <acme@conectiva.com.br> Mar 1999, Internationalization
+ */
+#include <stdio.h>		/* stderr */
+#include <stdlib.h>		/* qsort */
+#include <string.h>		/* strstr */
+#include <unistd.h>		/* write */
+#include <sys/ioctl.h>		/* ioctl */
+
+#include "nls.h"
+#include "blkdev.h"
+#include "bitops.h"
+
+#include "fdiskP.h"
+#include "pt-sun.h"
+#include "all-io.h"
+
+
+/**
+ * SECTION: sun
+ * @title: SUN
+ * @short_description: disk label specific functions
+ *
+ */
+
+/*
+ * in-memory fdisk SUN stuff
+ */
+struct fdisk_sun_label {
+	struct fdisk_label	head;		/* generic part */
+	struct sun_disklabel   *header;		/* on-disk data (pointer to cxt->firstsector) */
+};
+
+static struct fdisk_parttype sun_parttypes[] = {
+	{SUN_TAG_UNASSIGNED, N_("Unassigned")},
+	{SUN_TAG_BOOT, N_("Boot")},
+	{SUN_TAG_ROOT, N_("SunOS root")},
+	{SUN_TAG_SWAP, N_("SunOS swap")},
+	{SUN_TAG_USR, N_("SunOS usr")},
+	{SUN_TAG_WHOLEDISK, N_("Whole disk")},
+	{SUN_TAG_STAND, N_("SunOS stand")},
+	{SUN_TAG_VAR, N_("SunOS var")},
+	{SUN_TAG_HOME, N_("SunOS home")},
+	{SUN_TAG_ALTSCTR, N_("SunOS alt sectors")},
+	{SUN_TAG_CACHE, N_("SunOS cachefs")},
+	{SUN_TAG_RESERVED, N_("SunOS reserved")},
+	{SUN_TAG_LINUX_SWAP, N_("Linux swap")},
+	{SUN_TAG_LINUX_NATIVE, N_("Linux native")},
+	{SUN_TAG_LINUX_LVM, N_("Linux LVM")},
+	{SUN_TAG_LINUX_RAID, N_("Linux raid autodetect")},
+	{ 0, NULL }
+};
+
+/* return poiter buffer with on-disk data */
+static inline struct sun_disklabel *self_disklabel(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, SUN));
+
+	return ((struct fdisk_sun_label *) cxt->label)->header;
+}
+
+/* return in-memory sun fdisk data */
+static inline struct fdisk_sun_label *self_label(struct fdisk_context *cxt)
+{
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, SUN));
+
+	return (struct fdisk_sun_label *) cxt->label;
+}
+
+static void set_partition(struct fdisk_context *cxt, size_t i,
+		uint32_t start,uint32_t stop, uint16_t sysid)
+{
+	struct sun_disklabel *sunlabel = self_disklabel(cxt);
+	struct fdisk_parttype *t =
+			fdisk_label_get_parttype_from_code(cxt->label, sysid);
+
+	sunlabel->vtoc.infos[i].id = cpu_to_be16(sysid);
+	sunlabel->vtoc.infos[i].flags = cpu_to_be16(0);
+	sunlabel->partitions[i].start_cylinder =
+		cpu_to_be32(start / (cxt->geom.heads * cxt->geom.sectors));
+	sunlabel->partitions[i].num_sectors = cpu_to_be32(stop - start);
+	fdisk_label_set_changed(cxt->label, 1);
+
+	fdisk_info_new_partition(cxt, i + 1, start, stop, t);
+}
+
+static size_t count_used_partitions(struct fdisk_context *cxt)
+{
+	struct sun_disklabel *sunlabel = self_disklabel(cxt);
+	size_t ct = 0, i;
+
+	assert(sunlabel);
+
+	for (i = 0; i < cxt->label->nparts_max; i++) {
+		if (sunlabel->partitions[i].num_sectors)
+			ct++;
+	}
+	return ct;
+}
+
+static int sun_probe_label(struct fdisk_context *cxt)
+{
+	struct fdisk_sun_label *sun;
+	struct sun_disklabel *sunlabel;
+	unsigned short *ush;
+	int csum;
+	int need_fixing = 0;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, SUN));
+
+	/* map first sector to header */
+	sun = (struct fdisk_sun_label *) cxt->label;
+	sun->header = (struct sun_disklabel *) cxt->firstsector;
+	sunlabel = sun->header;
+
+	if (be16_to_cpu(sunlabel->magic) != SUN_LABEL_MAGIC) {
+		sun->header = NULL;
+		return 0;		/* failed */
+	}
+
+	ush = ((unsigned short *) (sunlabel + 1)) - 1;
+	for (csum = 0; ush >= (unsigned short *)sunlabel;)
+		csum ^= *ush--;
+
+	if (csum) {
+		fdisk_warnx(cxt, _("Detected sun disklabel with wrong checksum. "
+			      "Probably you'll have to set all the values, "
+			      "e.g. heads, sectors, cylinders and partitions "
+			      "or force a fresh label (s command in main menu)"));
+		return 1;
+	}
+
+	cxt->label->nparts_max = SUN_MAXPARTITIONS;
+	cxt->geom.heads = be16_to_cpu(sunlabel->nhead);
+	cxt->geom.cylinders = be16_to_cpu(sunlabel->ncyl);
+	cxt->geom.sectors = be16_to_cpu(sunlabel->nsect);
+
+	if (be32_to_cpu(sunlabel->vtoc.version) != SUN_VTOC_VERSION) {
+		fdisk_warnx(cxt, _("Detected sun disklabel with wrong version [%d]."),
+			be32_to_cpu(sunlabel->vtoc.version));
+		need_fixing = 1;
+	}
+	if (be32_to_cpu(sunlabel->vtoc.sanity) != SUN_VTOC_SANITY) {
+		fdisk_warnx(cxt, _("Detected sun disklabel with wrong vtoc.sanity [0x%08x]."),
+			be32_to_cpu(sunlabel->vtoc.sanity));
+		need_fixing = 1;
+	}
+	if (be16_to_cpu(sunlabel->vtoc.nparts) != SUN_MAXPARTITIONS) {
+		fdisk_warnx(cxt, _("Detected sun disklabel with wrong vtoc.nparts [%u]."),
+			be16_to_cpu(sunlabel->vtoc.nparts));
+		need_fixing = 1;
+	}
+	if (need_fixing) {
+		fdisk_warnx(cxt, _("Warning: Wrong values need to be fixed up and "
+			           "will be corrected by w(rite)"));
+
+		sunlabel->vtoc.version = cpu_to_be32(SUN_VTOC_VERSION);
+		sunlabel->vtoc.sanity = cpu_to_be32(SUN_VTOC_SANITY);
+		sunlabel->vtoc.nparts = cpu_to_be16(SUN_MAXPARTITIONS);
+
+		ush = (unsigned short *)sunlabel;
+		csum = 0;
+		while(ush < (unsigned short *)(&sunlabel->csum))
+			csum ^= *ush++;
+		sunlabel->csum = csum;
+
+		fdisk_label_set_changed(cxt->label, 1);
+	}
+
+	cxt->label->nparts_cur = count_used_partitions(cxt);
+
+	return 1;
+}
+
+static void ask_geom(struct fdisk_context *cxt)
+{
+	uintmax_t res;
+
+	assert(cxt);
+
+	if (fdisk_ask_number(cxt, 1, 1, 1024, _("Heads"), &res) == 0)
+		cxt->geom.heads = res;
+	if (fdisk_ask_number(cxt, 1, 1, 1024, _("Sectors/track"), &res) == 0)
+		cxt->geom.sectors = res;
+	if (fdisk_ask_number(cxt, 1, 1, USHRT_MAX, _("Cylinders"), &res) == 0)
+		cxt->geom.cylinders = res;
+}
+
+static int sun_create_disklabel(struct fdisk_context *cxt)
+{
+	unsigned int ndiv;
+	struct fdisk_sun_label *sun;		/* libfdisk sun handler */
+	struct sun_disklabel *sunlabel;	/* on disk data */
+	int rc = 0;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, SUN));
+
+	/* map first sector to header */
+	rc = fdisk_init_firstsector_buffer(cxt);
+	if (rc)
+		return rc;
+
+	sun = (struct fdisk_sun_label *) cxt->label;
+	sun->header = (struct sun_disklabel *) cxt->firstsector;
+
+	sunlabel = sun->header;
+
+	cxt->label->nparts_max = SUN_MAXPARTITIONS;
+
+	sunlabel->magic = cpu_to_be16(SUN_LABEL_MAGIC);
+	sunlabel->vtoc.version = cpu_to_be32(SUN_VTOC_VERSION);
+	sunlabel->vtoc.sanity = cpu_to_be32(SUN_VTOC_SANITY);
+	sunlabel->vtoc.nparts = cpu_to_be16(SUN_MAXPARTITIONS);
+
+#ifdef HDIO_GETGEO
+	if (cxt->geom.heads && cxt->geom.sectors) {
+		fdisk_sector_t llsectors;
+
+		if (blkdev_get_sectors(cxt->dev_fd, (unsigned long long *) &llsectors) == 0) {
+			int sec_fac = cxt->sector_size / 512;
+			fdisk_sector_t llcyls;
+
+			llcyls = llsectors / (cxt->geom.heads * cxt->geom.sectors * sec_fac);
+			cxt->geom.cylinders = llcyls;
+			if (cxt->geom.cylinders != llcyls)
+				cxt->geom.cylinders = ~0;
+		} else {
+			fdisk_warnx(cxt,
+				_("BLKGETSIZE ioctl failed on %s. "
+				  "Using geometry cylinder value of %llu. "
+				  "This value may be truncated for devices "
+				  "> 33.8 GB."),
+				cxt->dev_path, cxt->geom.cylinders);
+		}
+	} else
+#endif
+		ask_geom(cxt);
+
+	sunlabel->acyl   = cpu_to_be16(0);
+	sunlabel->pcyl   = cpu_to_be16(cxt->geom.cylinders);
+	sunlabel->rpm    = cpu_to_be16(5400);
+	sunlabel->intrlv = cpu_to_be16(1);
+	sunlabel->apc    = cpu_to_be16(0);
+
+	sunlabel->nhead  = cpu_to_be16(cxt->geom.heads);
+	sunlabel->nsect  = cpu_to_be16(cxt->geom.sectors);
+	sunlabel->ncyl   = cpu_to_be16(cxt->geom.cylinders);
+
+	snprintf((char *) sunlabel->label_id, sizeof(sunlabel->label_id),
+		 "Linux cyl %ju alt %u hd %u sec %ju",
+		 (uintmax_t) cxt->geom.cylinders,
+		 be16_to_cpu(sunlabel->acyl),
+		 cxt->geom.heads,
+		 (uintmax_t) cxt->geom.sectors);
+
+	if (cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors >= 150 * 2048) {
+	        ndiv = cxt->geom.cylinders - (50 * 2048 / (cxt->geom.heads * cxt->geom.sectors)); /* 50M swap */
+	} else
+	        ndiv = cxt->geom.cylinders * 2 / 3;
+
+	/* create the default layout only if no-script defined */
+	if (!cxt->script) {
+		set_partition(cxt, 0, 0, ndiv * cxt->geom.heads * cxt->geom.sectors,
+			  SUN_TAG_LINUX_NATIVE);
+		set_partition(cxt, 1, ndiv * cxt->geom.heads * cxt->geom.sectors,
+			  cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors,
+			  SUN_TAG_LINUX_SWAP);
+		sunlabel->vtoc.infos[1].flags |= cpu_to_be16(SUN_FLAG_UNMNT);
+
+		set_partition(cxt, 2, 0,
+			  cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors,
+			  SUN_TAG_WHOLEDISK);
+	}
+
+	{
+		unsigned short *ush = (unsigned short *)sunlabel;
+		unsigned short csum = 0;
+		while(ush < (unsigned short *)(&sunlabel->csum))
+			csum ^= *ush++;
+		sunlabel->csum = csum;
+	}
+
+	fdisk_label_set_changed(cxt->label, 1);
+	cxt->label->nparts_cur = count_used_partitions(cxt);
+
+	fdisk_info(cxt, _("Created a new Sun disklabel."));
+	return 0;
+}
+
+static int sun_toggle_partition_flag(struct fdisk_context *cxt, size_t i, unsigned long flag)
+{
+	struct sun_disklabel *sunlabel;
+	struct sun_info *p;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, SUN));
+
+	if (i >= cxt->label->nparts_max)
+		return -EINVAL;
+
+	sunlabel = self_disklabel(cxt);
+	p = &sunlabel->vtoc.infos[i];
+
+	switch (flag) {
+	case SUN_FLAG_UNMNT:
+		p->flags ^= cpu_to_be16(SUN_FLAG_UNMNT);
+		fdisk_label_set_changed(cxt->label, 1);
+		break;
+	case SUN_FLAG_RONLY:
+		p->flags ^= cpu_to_be16(SUN_FLAG_RONLY);
+		fdisk_label_set_changed(cxt->label, 1);
+		break;
+	default:
+		return 1;
+	}
+
+	return 0;
+}
+
+static void fetch_sun(struct fdisk_context *cxt,
+		      uint32_t *starts,
+		      uint32_t *lens,
+		      uint32_t *start,
+		      uint32_t *stop)
+{
+	struct sun_disklabel *sunlabel;
+	int continuous = 1;
+	size_t i;
+
+	assert(cxt);
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, SUN));
+
+	sunlabel = self_disklabel(cxt);
+
+	*start = 0;
+	*stop = cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors;
+
+	for (i = 0; i < cxt->label->nparts_max; i++) {
+		struct sun_partition *part = &sunlabel->partitions[i];
+		struct sun_info *info = &sunlabel->vtoc.infos[i];
+
+		if (part->num_sectors &&
+		    be16_to_cpu(info->id) != SUN_TAG_UNASSIGNED &&
+		    be16_to_cpu(info->id) != SUN_TAG_WHOLEDISK) {
+			starts[i] = be32_to_cpu(part->start_cylinder) *
+				     cxt->geom.heads * cxt->geom.sectors;
+			lens[i] = be32_to_cpu(part->num_sectors);
+			if (continuous) {
+				if (starts[i] == *start)
+					*start += lens[i];
+				else if (starts[i] + lens[i] >= *stop)
+					*stop = starts[i];
+				else
+					continuous = 0;
+				        /* There will be probably more gaps
+					  than one, so lets check afterwards */
+			}
+		} else {
+			starts[i] = 0;
+			lens[i] = 0;
+		}
+	}
+}
+
+#ifdef HAVE_QSORT_R
+static int verify_sun_cmp(int *a, int *b, void *data)
+{
+    unsigned int *verify_sun_starts = (unsigned int *) data;
+
+    if (*a == -1)
+	    return 1;
+    if (*b == -1)
+	    return -1;
+    if (verify_sun_starts[*a] > verify_sun_starts[*b])
+	    return 1;
+    return -1;
+}
+#endif
+
+static int sun_verify_disklabel(struct fdisk_context *cxt)
+{
+    uint32_t starts[SUN_MAXPARTITIONS], lens[SUN_MAXPARTITIONS], start, stop;
+    uint32_t i,j,k,starto,endo;
+#ifdef HAVE_QSORT_R
+    int array[SUN_MAXPARTITIONS];
+    unsigned int *verify_sun_starts;
+#endif
+    assert(cxt);
+    assert(cxt->label);
+    assert(fdisk_is_label(cxt, SUN));
+
+    fetch_sun(cxt, starts, lens, &start, &stop);
+
+    for (k = 0; k < 7; k++) {
+	for (i = 0; i < SUN_MAXPARTITIONS; i++) {
+	    if (k && (lens[i] % (cxt->geom.heads * cxt->geom.sectors)))
+	        fdisk_warnx(cxt, _("Partition %u doesn't end on cylinder boundary."), i+1);
+	    if (lens[i]) {
+	        for (j = 0; j < i; j++)
+	            if (lens[j]) {
+	                if (starts[j] == starts[i]+lens[i]) {
+	                    starts[j] = starts[i]; lens[j] += lens[i];
+	                    lens[i] = 0;
+	                } else if (starts[i] == starts[j]+lens[j]){
+	                    lens[j] += lens[i];
+	                    lens[i] = 0;
+	                } else if (!k) {
+	                    if (starts[i] < starts[j]+lens[j] &&
+				starts[j] < starts[i]+lens[i]) {
+	                        starto = starts[i];
+	                        if (starts[j] > starto)
+					starto = starts[j];
+	                        endo = starts[i]+lens[i];
+	                        if (starts[j]+lens[j] < endo)
+					endo = starts[j]+lens[j];
+	                        fdisk_warnx(cxt, _("Partition %u overlaps with others in "
+				       "sectors %u-%u."), i+1, starto, endo);
+	                    }
+	                }
+	            }
+	    }
+	}
+    }
+
+#ifdef HAVE_QSORT_R
+    for (i = 0; i < SUN_MAXPARTITIONS; i++) {
+        if (lens[i])
+            array[i] = i;
+        else
+            array[i] = -1;
+    }
+    verify_sun_starts = starts;
+
+    qsort_r(array,ARRAY_SIZE(array),sizeof(array[0]),
+	  (int (*)(const void *,const void *,void *)) verify_sun_cmp,
+	  verify_sun_starts);
+
+    if (array[0] == -1) {
+	fdisk_info(cxt, _("No partitions defined."));
+	return 0;
+    }
+    stop = cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors;
+    if (starts[array[0]])
+        fdisk_warnx(cxt, _("Unused gap - sectors 0-%u."), starts[array[0]]);
+    for (i = 0; i < 7 && array[i+1] != -1; i++) {
+        fdisk_warnx(cxt, _("Unused gap - sectors %u-%u."),
+	       (starts[array[i]] + lens[array[i]]),
+	       starts[array[i+1]]);
+    }
+    start = (starts[array[i]] + lens[array[i]]);
+    if (start < stop)
+        fdisk_warnx(cxt, _("Unused gap - sectors %u-%u."), start, stop);
+#endif
+    return 0;
+}
+
+
+static int is_free_sector(struct fdisk_context *cxt,
+		fdisk_sector_t s, uint32_t starts[], uint32_t lens[])
+{
+	size_t i;
+
+	for (i = 0; i < cxt->label->nparts_max; i++) {
+		if (lens[i] && starts[i] <= s
+		    && starts[i] + lens[i] > s)
+			return 0;
+	}
+	return 1;
+}
+
+static int sun_add_partition(
+		struct fdisk_context *cxt,
+		struct fdisk_partition *pa,
+		size_t *partno)
+{
+	struct sun_disklabel *sunlabel = self_disklabel(cxt);
+	uint32_t starts[SUN_MAXPARTITIONS], lens[SUN_MAXPARTITIONS];
+	struct sun_partition *part;
+	struct sun_info *info;
+	uint32_t start, stop, stop2;
+	int whole_disk = 0;
+	int sys = pa && pa->type ? pa->type->code : SUN_TAG_LINUX_NATIVE;
+	int rc;
+	size_t n;
+
+	char mesg[256];
+	size_t i;
+	unsigned int first, last;
+
+	rc = fdisk_partition_next_partno(pa, cxt, &n);
+	if (rc)
+		return rc;
+
+	part = &sunlabel->partitions[n];
+	info = &sunlabel->vtoc.infos[n];
+
+	if (part->num_sectors && be16_to_cpu(info->id) != SUN_TAG_UNASSIGNED) {
+		fdisk_info(cxt, _("Partition %zu is already defined.  Delete "
+			"it before re-adding it."), n + 1);
+		return -EINVAL;
+	}
+
+	fetch_sun(cxt, starts, lens, &start, &stop);
+
+	if (stop <= start) {
+		if (n == 2)
+			whole_disk = 1;
+		else {
+			fdisk_info(cxt, _("Other partitions already cover the "
+				"whole disk. Delete some/shrink them before retry."));
+			return -EINVAL;
+		}
+	}
+
+	if (pa && pa->start_follow_default)
+		first = start;
+	else if (pa && fdisk_partition_has_start(pa)) {
+		first = pa->start;
+
+		if (!whole_disk && !is_free_sector(cxt, first, starts, lens))
+			return -ERANGE;
+	} else {
+		struct fdisk_ask *ask;
+
+		snprintf(mesg, sizeof(mesg), _("First %s"),
+				fdisk_get_unit(cxt, FDISK_SINGULAR));
+		for (;;) {
+			ask = fdisk_new_ask();
+			if (!ask)
+				return -ENOMEM;
+
+			fdisk_ask_set_query(ask, mesg);
+			fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER);
+
+			if (whole_disk) {
+				fdisk_ask_number_set_low(ask,     0);	/* minimal */
+				fdisk_ask_number_set_default(ask, 0);	/* default */
+				fdisk_ask_number_set_high(ask,    0);	/* maximal */
+			} else {
+				fdisk_ask_number_set_low(ask,     fdisk_scround(cxt, start));	/* minimal */
+				fdisk_ask_number_set_default(ask, fdisk_scround(cxt, start));	/* default */
+				fdisk_ask_number_set_high(ask,    fdisk_scround(cxt, stop));	/* maximal */
+			}
+			rc = fdisk_do_ask(cxt, ask);
+			first = fdisk_ask_number_get_result(ask);
+			fdisk_unref_ask(ask);
+			if (rc)
+				return rc;
+
+			if (fdisk_use_cylinders(cxt))
+				first *= fdisk_get_units_per_sector(cxt);
+
+			/* ewt asks to add: "don't start a partition at cyl 0"
+			   However, edmundo@rano.demon.co.uk writes:
+			   "In addition to having a Sun partition table, to be able to
+			   boot from the disc, the first partition, /dev/sdX1, must
+			   start at cylinder 0. This means that /dev/sdX1 contains
+			   the partition table and the boot block, as these are the
+			   first two sectors of the disc. Therefore you must be
+			   careful what you use /dev/sdX1 for. In particular, you must
+			   not use a partition starting at cylinder 0 for Linux swap,
+			   as that would overwrite the partition table and the boot
+			   block. You may, however, use such a partition for a UFS
+			   or EXT2 file system, as these file systems leave the first
+			   1024 bytes undisturbed. */
+			/* On the other hand, one should not use partitions
+			   starting at block 0 in an md, or the label will
+			   be trashed. */
+			if (!is_free_sector(cxt, first, starts,  lens) && !whole_disk) {
+				if (n == 2 && !first) {
+				    whole_disk = 1;
+				    break;
+				}
+				fdisk_warnx(cxt, _("Sector %d is already allocated"), first);
+			} else
+				break;
+		}
+	}
+
+	if (n == 2 && first != 0)
+		fdisk_warnx(cxt, _("It is highly recommended that the "
+				   "third partition covers the whole disk "
+				   "and is of type `Whole disk'"));
+
+	if (!fdisk_use_cylinders(cxt)) {
+		/* Starting sector has to be properly aligned */
+		int cs = cxt->geom.heads * cxt->geom.sectors;
+		int x = first % cs;
+
+		if (x) {
+			fdisk_info(cxt, _("Aligning the first sector from %u to %u "
+					  "to be on cylinder boundary."),
+					first, first + cs - x);
+			first += cs - x;
+		}
+	}
+
+	stop = cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors;	/* ancient */
+	stop2 = stop;
+	for (i = 0; i < cxt->label->nparts_max; i++) {
+		if (starts[i] > first && starts[i] < stop)
+			stop = starts[i];
+	}
+
+	/* last */
+	if (pa && pa->end_follow_default)
+		last = whole_disk || (n == 2 && !first) ? stop2 : stop;
+	else if (pa && fdisk_partition_has_size(pa)) {
+		last = first + pa->size - 1ULL;
+
+		if (!whole_disk && last > stop)
+			return -ERANGE;
+	} else {
+		struct fdisk_ask *ask = fdisk_new_ask();
+
+		if (!ask)
+			return -ENOMEM;
+
+		snprintf(mesg, sizeof(mesg),
+			 _("Last %s or +%s or +size{K,M,G,T,P}"),
+			 fdisk_get_unit(cxt, FDISK_SINGULAR),
+			 fdisk_get_unit(cxt, FDISK_PLURAL));
+		fdisk_ask_set_query(ask, mesg);
+		fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET);
+
+		if (whole_disk) {
+			fdisk_ask_number_set_low(ask,     fdisk_scround(cxt, stop2));	/* minimal */
+			fdisk_ask_number_set_default(ask, fdisk_scround(cxt, stop2));	/* default */
+			fdisk_ask_number_set_high(ask,    fdisk_scround(cxt, stop2));	/* maximal */
+			fdisk_ask_number_set_base(ask,    0);
+		} else if (n == 2 && !first) {
+			fdisk_ask_number_set_low(ask,     fdisk_scround(cxt, first));	/* minimal */
+			fdisk_ask_number_set_default(ask, fdisk_scround(cxt, stop2));	/* default */
+			fdisk_ask_number_set_high(ask,    fdisk_scround(cxt, stop2));	/* maximal */
+			fdisk_ask_number_set_base(ask,	  fdisk_scround(cxt, first));
+		} else {
+			fdisk_ask_number_set_low(ask,     fdisk_scround(cxt, first));	/* minimal */
+			fdisk_ask_number_set_default(ask, fdisk_scround(cxt, stop));	/* default */
+			fdisk_ask_number_set_high(ask,    fdisk_scround(cxt, stop));	/* maximal */
+			fdisk_ask_number_set_base(ask,    fdisk_scround(cxt, first));
+		}
+
+		if (fdisk_use_cylinders(cxt))
+			fdisk_ask_number_set_unit(ask,
+				     cxt->sector_size *
+				     fdisk_get_units_per_sector(cxt));
+		else
+			fdisk_ask_number_set_unit(ask,	cxt->sector_size);
+
+		rc = fdisk_do_ask(cxt, ask);
+		last = fdisk_ask_number_get_result(ask);
+
+		fdisk_unref_ask(ask);
+		if (rc)
+			return rc;
+		if (fdisk_use_cylinders(cxt))
+			last *= fdisk_get_units_per_sector(cxt);
+	}
+
+	if (n == 2 && !first) {
+		if (last >= stop2) {
+		    whole_disk = 1;
+		    last = stop2;
+		} else if (last > stop) {
+		    fdisk_warnx(cxt,
+   _("You haven't covered the whole disk with the 3rd partition, but your value\n"
+     "%lu %s covers some other partition. Your entry has been changed\n"
+     "to %lu %s"),
+			(unsigned long) fdisk_scround(cxt, last), fdisk_get_unit(cxt, FDISK_SINGULAR),
+			(unsigned long) fdisk_scround(cxt, stop), fdisk_get_unit(cxt, FDISK_SINGULAR));
+		    last = stop;
+		}
+	} else if (!whole_disk && last > stop)
+		last = stop;
+
+	if (whole_disk)
+		sys = SUN_TAG_WHOLEDISK;
+
+	set_partition(cxt, n, first, last, sys);
+	cxt->label->nparts_cur = count_used_partitions(cxt);
+	if (partno)
+		*partno = n;
+	return 0;
+}
+
+static int sun_delete_partition(struct fdisk_context *cxt,
+		size_t partnum)
+{
+	struct sun_disklabel *sunlabel;
+	struct sun_partition *part;
+	struct sun_info *info;
+	unsigned int nsec;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, SUN));
+
+	sunlabel = self_disklabel(cxt);
+	part = &sunlabel->partitions[partnum];
+	info = &sunlabel->vtoc.infos[partnum];
+
+	if (partnum == 2 &&
+	    be16_to_cpu(info->id) == SUN_TAG_WHOLEDISK &&
+	    !part->start_cylinder &&
+	    (nsec = be32_to_cpu(part->num_sectors))
+	    == cxt->geom.heads * cxt->geom.sectors * cxt->geom.cylinders)
+		fdisk_info(cxt, _("If you want to maintain SunOS/Solaris compatibility, "
+			 "consider leaving this "
+			 "partition as Whole disk (5), starting at 0, with %u "
+			 "sectors"), nsec);
+	info->id = cpu_to_be16(SUN_TAG_UNASSIGNED);
+	part->num_sectors = 0;
+	cxt->label->nparts_cur = count_used_partitions(cxt);
+	fdisk_label_set_changed(cxt->label, 1);
+	return 0;
+}
+
+
+static int sun_list_disklabel(struct fdisk_context *cxt)
+{
+	struct sun_disklabel *sunlabel;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, SUN));
+
+	sunlabel = self_disklabel(cxt);
+
+	if (fdisk_is_details(cxt)) {
+		fdisk_info(cxt,
+		_("Label geometry: %d rpm, %d alternate and %d physical cylinders,\n"
+		  "                %d extra sects/cyl, interleave %d:1"),
+		       be16_to_cpu(sunlabel->rpm),
+		       be16_to_cpu(sunlabel->acyl),
+		       be16_to_cpu(sunlabel->pcyl),
+		       be16_to_cpu(sunlabel->apc),
+		       be16_to_cpu(sunlabel->intrlv));
+		fdisk_info(cxt, _("Label ID: %s"), sunlabel->label_id);
+		fdisk_info(cxt, _("Volume ID: %s"),
+		       *sunlabel->vtoc.volume_id ? sunlabel->vtoc.volume_id : _("<none>"));
+	}
+
+	return 0;
+}
+
+static struct fdisk_parttype *sun_get_parttype(
+		struct fdisk_context *cxt,
+		size_t n)
+{
+	struct sun_disklabel *sunlabel = self_disklabel(cxt);
+	struct fdisk_parttype *t;
+
+	if (n >= cxt->label->nparts_max)
+		return NULL;
+
+	t = fdisk_label_get_parttype_from_code(cxt->label,
+			be16_to_cpu(sunlabel->vtoc.infos[n].id));
+	return t ? : fdisk_new_unknown_parttype(be16_to_cpu(sunlabel->vtoc.infos[n].id), NULL);
+}
+
+
+static int sun_get_partition(struct fdisk_context *cxt, size_t n,
+			      struct fdisk_partition *pa)
+{
+	struct sun_disklabel *sunlabel;
+	struct sun_partition *part;
+	uint16_t flags;
+	uint32_t start, len;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, SUN));
+
+	if (n >= cxt->label->nparts_max)
+		return -EINVAL;
+
+	sunlabel = self_disklabel(cxt);
+	part = &sunlabel->partitions[n];
+
+	pa->used = part->num_sectors ? 1 : 0;
+	if (!pa->used)
+		return 0;
+
+	flags = be16_to_cpu(sunlabel->vtoc.infos[n].flags);
+	start = be32_to_cpu(part->start_cylinder)
+			* cxt->geom.heads * cxt->geom.sectors;
+	len = be32_to_cpu(part->num_sectors);
+
+	pa->type = sun_get_parttype(cxt, n);
+	if (pa->type && pa->type->code == SUN_TAG_WHOLEDISK)
+		pa->wholedisk = 1;
+
+	if (flags & SUN_FLAG_UNMNT || flags & SUN_FLAG_RONLY) {
+		if (asprintf(&pa->attrs, "%c%c",
+				flags & SUN_FLAG_UNMNT ? 'u' : ' ',
+				flags & SUN_FLAG_RONLY ? 'r' : ' ') < 0)
+			return -ENOMEM;
+	}
+
+	pa->start = start;
+	pa->size = len;
+
+	return 0;
+}
+
+/**
+ * fdisk_sun_set_alt_cyl:
+ * @cxt: context
+ *
+ * Sets number of alternative cylinders. This function uses libfdisk Ask API
+ * for dialog with user.
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_sun_set_alt_cyl(struct fdisk_context *cxt)
+{
+	struct sun_disklabel *sunlabel = self_disklabel(cxt);
+	uintmax_t res;
+	int rc = fdisk_ask_number(cxt, 0,			/* low */
+			be16_to_cpu(sunlabel->acyl),		/* default */
+			65535,					/* high */
+			_("Number of alternate cylinders"),	/* query */
+			&res);					/* result */
+	if (rc)
+		return rc;
+
+	sunlabel->acyl = cpu_to_be16(res);
+	return 0;
+}
+
+/**
+ * fdisk_sun_set_xcyl:
+ * @cxt: context
+ *
+ * Sets number of extra sectors per cylinder. This function uses libfdisk Ask API
+ * for dialog with user.
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_sun_set_xcyl(struct fdisk_context *cxt)
+{
+	struct sun_disklabel *sunlabel = self_disklabel(cxt);
+	uintmax_t res;
+	int rc = fdisk_ask_number(cxt, 0,			/* low */
+			be16_to_cpu(sunlabel->apc),		/* default */
+			cxt->geom.sectors,			/* high */
+			_("Extra sectors per cylinder"),	/* query */
+			&res);					/* result */
+	if (rc)
+		return rc;
+	sunlabel->apc = cpu_to_be16(res);
+	return 0;
+}
+
+/**
+ * fdisk_sun_set_ilfact:
+ * @cxt: context
+ *
+ * Sets interleave factor. This function uses libfdisk Ask API for dialog with
+ * user.
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_sun_set_ilfact(struct fdisk_context *cxt)
+{
+	struct sun_disklabel *sunlabel = self_disklabel(cxt);
+	uintmax_t res;
+	int rc = fdisk_ask_number(cxt, 1,			/* low */
+			be16_to_cpu(sunlabel->intrlv),		/* default */
+			32,					/* high */
+			_("Interleave factor"),	/* query */
+			&res);					/* result */
+	if (rc)
+		return rc;
+	sunlabel->intrlv = cpu_to_be16(res);
+	return 0;
+}
+
+/**
+ * fdisk_sun_set_rspeed
+ * @cxt: context
+ *
+ * Sets rotation speed. This function uses libfdisk Ask API for dialog with
+ * user.
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_sun_set_rspeed(struct fdisk_context *cxt)
+{
+	struct sun_disklabel *sunlabel = self_disklabel(cxt);
+	uintmax_t res;
+	int rc = fdisk_ask_number(cxt, 1,			/* low */
+			be16_to_cpu(sunlabel->rpm),		/* default */
+			USHRT_MAX,				/* high */
+			_("Rotation speed (rpm)"),		/* query */
+			&res);					/* result */
+	if (rc)
+		return rc;
+	sunlabel->rpm = cpu_to_be16(res);
+	return 0;
+}
+
+/**
+ * fdisk_sun_set_pcylcount
+ * @cxt: context
+ *
+ * Sets number of physical cylinders. This function uses libfdisk Ask API for
+ * dialog with user.
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_sun_set_pcylcount(struct fdisk_context *cxt)
+{
+	struct sun_disklabel *sunlabel = self_disklabel(cxt);
+	uintmax_t res;
+	int rc = fdisk_ask_number(cxt, 0,			/* low */
+			be16_to_cpu(sunlabel->pcyl),		/* default */
+			USHRT_MAX,				/* high */
+			_("Number of physical cylinders"),	/* query */
+			&res);					/* result */
+	if (!rc)
+		return rc;
+	sunlabel->pcyl = cpu_to_be16(res);
+	return 0;
+}
+
+static int sun_write_disklabel(struct fdisk_context *cxt)
+{
+	struct sun_disklabel *sunlabel;
+	unsigned short *ush;
+	unsigned short csum = 0;
+	const size_t sz = sizeof(struct sun_disklabel);
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, SUN));
+
+	sunlabel = self_disklabel(cxt);
+
+	/* Maybe geometry has been modified */
+	sunlabel->nhead = cpu_to_be16(cxt->geom.heads);
+	sunlabel->nsect = cpu_to_be16(cxt->geom.sectors);
+
+	if (cxt->geom.cylinders != be16_to_cpu(sunlabel->ncyl))
+		sunlabel->ncyl = cpu_to_be16( cxt->geom.cylinders
+				      - be16_to_cpu(sunlabel->acyl) );
+
+	ush = (unsigned short *) sunlabel;
+
+	while(ush < (unsigned short *)(&sunlabel->csum))
+		csum ^= *ush++;
+	sunlabel->csum = csum;
+	if (lseek(cxt->dev_fd, 0, SEEK_SET) < 0)
+		return -errno;
+	if (write_all(cxt->dev_fd, sunlabel, sz) != 0)
+		return -errno;
+
+	return 0;
+}
+
+static int sun_set_partition(
+		struct fdisk_context *cxt,
+		size_t i,
+		struct fdisk_partition *pa)
+{
+	struct sun_disklabel *sunlabel;
+	struct sun_partition *part;
+	struct sun_info *info;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, SUN));
+
+	sunlabel = self_disklabel(cxt);
+
+	if (i >= cxt->label->nparts_max)
+		return -EINVAL;
+
+	if (pa->type) {
+		struct fdisk_parttype *t = pa->type;
+
+		if (t->code > UINT16_MAX)
+			return -EINVAL;
+
+		if (i == 2 && t->code != SUN_TAG_WHOLEDISK)
+			fdisk_info(cxt, _("Consider leaving partition 3 as Whole disk (5),\n"
+			         "as SunOS/Solaris expects it and even Linux likes it.\n"));
+
+		part = &sunlabel->partitions[i];
+		info = &sunlabel->vtoc.infos[i];
+
+		if (cxt->script == NULL &&
+		    t->code == SUN_TAG_LINUX_SWAP && !part->start_cylinder) {
+			int yes, rc;
+
+			rc = fdisk_ask_yesno(cxt,
+			      _("It is highly recommended that the partition at offset 0\n"
+			      "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
+			      "there may destroy your partition table and bootblock.\n"
+			      "Are you sure you want to tag the partition as Linux swap?"), &yes);
+			if (rc)
+				return rc;
+			if (!yes)
+				return 1;
+		}
+
+		switch (t->code) {
+		case SUN_TAG_SWAP:
+		case SUN_TAG_LINUX_SWAP:
+			/* swaps are not mountable by default */
+			info->flags |= cpu_to_be16(SUN_FLAG_UNMNT);
+			break;
+		default:
+			/* assume other types are mountable;
+			   user can change it anyway */
+			info->flags &= ~cpu_to_be16(SUN_FLAG_UNMNT);
+			break;
+		}
+		info->id = cpu_to_be16(t->code);
+	}
+
+	if (fdisk_partition_has_start(pa))
+		sunlabel->partitions[i].start_cylinder =
+			cpu_to_be32(pa->start / (cxt->geom.heads * cxt->geom.sectors));
+	if (fdisk_partition_has_size(pa))
+		sunlabel->partitions[i].num_sectors = cpu_to_be32(pa->size);
+
+	fdisk_label_set_changed(cxt->label, 1);
+	return 0;
+}
+
+
+static int sun_reset_alignment(struct fdisk_context *cxt __attribute__((__unused__)))
+{
+	return 0;
+}
+
+
+static int sun_partition_is_used(
+		struct fdisk_context *cxt,
+		size_t i)
+{
+	struct sun_disklabel *sunlabel;
+
+	assert(cxt);
+	assert(cxt->label);
+	assert(fdisk_is_label(cxt, SUN));
+
+	if (i >= cxt->label->nparts_max)
+		return 0;
+
+	sunlabel = self_disklabel(cxt);
+	return sunlabel->partitions[i].num_sectors ? 1 : 0;
+}
+
+static const struct fdisk_field sun_fields[] =
+{
+	{ FDISK_FIELD_DEVICE,	N_("Device"),	 10,	0 },
+	{ FDISK_FIELD_START,	N_("Start"),	  5,	FDISK_FIELDFL_NUMBER },
+	{ FDISK_FIELD_END,	N_("End"),	  5,	FDISK_FIELDFL_NUMBER },
+	{ FDISK_FIELD_SECTORS,	N_("Sectors"),	  5,	FDISK_FIELDFL_NUMBER },
+	{ FDISK_FIELD_CYLINDERS,N_("Cylinders"),  5,	FDISK_FIELDFL_NUMBER },
+	{ FDISK_FIELD_SIZE,	N_("Size"),	  5,	FDISK_FIELDFL_NUMBER },
+	{ FDISK_FIELD_TYPEID,	N_("Id"),	  2,	FDISK_FIELDFL_NUMBER },
+	{ FDISK_FIELD_TYPE,	N_("Type"),	0.1,	0 },
+	{ FDISK_FIELD_ATTR,	N_("Flags"),	  0,	FDISK_FIELDFL_NUMBER }
+};
+
+const struct fdisk_label_operations sun_operations =
+{
+	.probe		= sun_probe_label,
+	.write		= sun_write_disklabel,
+	.verify		= sun_verify_disklabel,
+	.create		= sun_create_disklabel,
+	.list		= sun_list_disklabel,
+
+	.get_part	= sun_get_partition,
+	.set_part	= sun_set_partition,
+	.add_part	= sun_add_partition,
+	.del_part	= sun_delete_partition,
+
+	.part_is_used	= sun_partition_is_used,
+	.part_toggle_flag = sun_toggle_partition_flag,
+
+	.reset_alignment = sun_reset_alignment,
+};
+
+/*
+ * allocates SUN label driver
+ */
+struct fdisk_label *fdisk_new_sun_label(struct fdisk_context *cxt)
+{
+	struct fdisk_label *lb;
+	struct fdisk_sun_label *sun;
+
+	assert(cxt);
+
+	sun = calloc(1, sizeof(*sun));
+	if (!sun)
+		return NULL;
+
+	/* initialize generic part of the driver */
+	lb = (struct fdisk_label *) sun;
+	lb->name = "sun";
+	lb->id = FDISK_DISKLABEL_SUN;
+	lb->op = &sun_operations;
+	lb->parttypes = sun_parttypes;
+	lb->nparttypes = ARRAY_SIZE(sun_parttypes) - 1;
+	lb->fields = sun_fields;
+	lb->nfields = ARRAY_SIZE(sun_fields);
+	lb->flags |= FDISK_LABEL_FL_REQUIRE_GEOMETRY;
+
+	return lb;
+}
diff --git a/libblkid/libfdisk/src/table.c b/libblkid/libfdisk/src/table.c
new file mode 100644
index 0000000..1add09f
--- /dev/null
+++ b/libblkid/libfdisk/src/table.c
@@ -0,0 +1,664 @@
+
+#include "fdiskP.h"
+
+/**
+ * SECTION: table
+ * @title: Table
+ * @short_description: container for fdisk partitions
+ *
+ * The fdisk_table is simple container for fdisk_partitions. The table is no
+ * directly connected to label data (partition table), and table changes don't
+ * affect in-memory or on-disk data.
+ */
+
+/**
+ * fdisk_new_table:
+ *
+ * The table is a container for struct fdisk_partition entries. The container
+ * does not have any real connection with label (partition table) and with
+ * real on-disk data.
+ *
+ * Returns: newly allocated table struct.
+ */
+struct fdisk_table *fdisk_new_table(void)
+{
+	struct fdisk_table *tb = NULL;
+
+	tb = calloc(1, sizeof(*tb));
+	if (!tb)
+		return NULL;
+
+	DBG(TAB, ul_debugobj(tb, "alloc"));
+	tb->refcount = 1;
+	INIT_LIST_HEAD(&tb->parts);
+	return tb;
+}
+
+/**
+ * fdisk_reset_table:
+ * @tb: tab pointer
+ *
+ * Removes all entries (partitions) from the table. The parititons with zero
+ * reference count will be deallocated. This function does not modify partition
+ * table.
+ *
+ * Returns: 0 on success or negative number in case of error.
+ */
+int fdisk_reset_table(struct fdisk_table *tb)
+{
+	if (!tb)
+		return -EINVAL;
+
+	DBG(TAB, ul_debugobj(tb, "reset"));
+
+	while (!list_empty(&tb->parts)) {
+		struct fdisk_partition *pa = list_entry(tb->parts.next,
+				                  struct fdisk_partition, parts);
+		fdisk_table_remove_partition(tb, pa);
+	}
+
+	tb->nents = 0;
+	return 0;
+}
+
+/**
+ * fdisk_ref_table:
+ * @tb: table pointer
+ *
+ * Incremparts reference counter.
+ */
+void fdisk_ref_table(struct fdisk_table *tb)
+{
+	if (tb)
+		tb->refcount++;
+}
+
+/**
+ * fdisk_unref_table:
+ * @tb: table pointer
+ *
+ * De-incremparts reference counter, on zero the @tb is automatically
+ * deallocated.
+ */
+void fdisk_unref_table(struct fdisk_table *tb)
+{
+	if (!tb)
+		return;
+
+	tb->refcount--;
+	if (tb->refcount <= 0) {
+		fdisk_reset_table(tb);
+
+		DBG(TAB, ul_debugobj(tb, "free"));
+		free(tb);
+	}
+}
+
+/**
+ * fdisk_table_is_empty:
+ * @tb: pointer to tab
+ *
+ * Returns: 1 if the table is without filesystems, or 0.
+ */
+int fdisk_table_is_empty(struct fdisk_table *tb)
+{
+	return tb == NULL || list_empty(&tb->parts) ? 1 : 0;
+}
+
+/**
+ * fdisk_table_get_nents:
+ * @tb: pointer to tab
+ *
+ * Returns: number of entries in table.
+ */
+size_t fdisk_table_get_nents(struct fdisk_table *tb)
+{
+	return tb ? tb->nents : 0;
+}
+
+/**
+ * fdisk_table_next_partition:
+ * @tb: tab pointer
+ * @itr: iterator
+ * @pa: returns the next tab entry
+ *
+ * Returns: 0 on success, negative number in case of error or 1 at the end of list.
+ *
+ * Example:
+ * <informalexample>
+ *   <programlisting>
+ *	while(fdisk_table_next_partition(tb, itr, &pa) == 0) {
+ *		...
+ *	}
+ *   </programlisting>
+ * </informalexample>
+ */
+int fdisk_table_next_partition(
+			struct fdisk_table *tb,
+			struct fdisk_iter *itr,
+			struct fdisk_partition **pa)
+{
+	int rc = 1;
+
+	assert(tb);
+	assert(itr);
+	assert(pa);
+
+	if (!tb || !itr || !pa)
+		return -EINVAL;
+	*pa = NULL;
+
+	if (!itr->head)
+		FDISK_ITER_INIT(itr, &tb->parts);
+	if (itr->p != itr->head) {
+		FDISK_ITER_ITERATE(itr, *pa, struct fdisk_partition, parts);
+		rc = 0;
+	}
+
+	return rc;
+}
+
+struct fdisk_partition *fdisk_table_get_partition(
+			struct fdisk_table *tb,
+			size_t n)
+{
+	struct fdisk_partition *pa = NULL;
+	struct fdisk_iter itr;
+
+	if (!tb)
+		return NULL;
+
+	fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
+
+	while (fdisk_table_next_partition(tb, &itr, &pa) == 0) {
+		if (n == 0)
+			return pa;
+		n--;
+	}
+
+	return NULL;
+}
+
+/**
+ * fdisk_table_add_partition
+ * @tb: tab pointer
+ * @pa: new entry
+ *
+ * Adds a new entry to table and increment @pa reference counter. Don't forget to
+ * use fdisk_unref_pa() after fdisk_table_add_partition() if you want to keep
+ * the @pa referenced by the table only.
+ *
+ * Returns: 0 on success or negative number in case of error.
+ */
+int fdisk_table_add_partition(struct fdisk_table *tb, struct fdisk_partition *pa)
+{
+	assert(tb);
+	assert(pa);
+
+	if (!tb || !pa)
+		return -EINVAL;
+
+	fdisk_ref_partition(pa);
+	list_add_tail(&pa->parts, &tb->parts);
+	tb->nents++;
+
+	DBG(TAB, ul_debugobj(tb, "add entry %p [start=%ju, end=%ju, size=%ju, %s %s %s]",
+			pa,
+			(uintmax_t) fdisk_partition_get_start(pa),
+			(uintmax_t) fdisk_partition_get_end(pa),
+			(uintmax_t) fdisk_partition_get_size(pa),
+			fdisk_partition_is_freespace(pa) ? "freespace" : "",
+			fdisk_partition_is_nested(pa)    ? "nested"    : "",
+			fdisk_partition_is_container(pa) ? "container" : "primary"));
+	return 0;
+}
+
+/* inserts @pa after @poz */
+static int table_insert_partition(
+			struct fdisk_table *tb,
+			struct fdisk_partition *poz,
+			struct fdisk_partition *pa)
+{
+	assert(tb);
+	assert(pa);
+
+	fdisk_ref_partition(pa);
+	if (poz)
+		list_add(&pa->parts, &poz->parts);
+	else
+		list_add(&pa->parts, &tb->parts);
+	tb->nents++;
+
+	DBG(TAB, ul_debugobj(tb, "insert entry %p pre=%p [start=%ju, end=%ju, size=%ju, %s %s %s]",
+			pa, poz ? poz : NULL,
+			(uintmax_t) fdisk_partition_get_start(pa),
+			(uintmax_t) fdisk_partition_get_end(pa),
+			(uintmax_t) fdisk_partition_get_size(pa),
+			fdisk_partition_is_freespace(pa) ? "freespace" : "",
+			fdisk_partition_is_nested(pa)    ? "nested"    : "",
+			fdisk_partition_is_container(pa) ? "container" : ""));
+	return 0;
+}
+
+/**
+ * fdisk_table_remove_partition
+ * @tb: tab pointer
+ * @pa: new entry
+ *
+ * Removes the @pa from the table and de-increment reference counter of the @pa. The
+ * partition with zero reference counter will be deallocated. Don't forget to use
+ * fdisk_ref_partition() before call fdisk_table_remove_partition() if you want
+ * to use @pa later.
+ *
+ * Returns: 0 on success or negative number in case of error.
+ */
+int fdisk_table_remove_partition(struct fdisk_table *tb, struct fdisk_partition *pa)
+{
+	assert(tb);
+	assert(pa);
+
+	if (!tb || !pa)
+		return -EINVAL;
+
+	DBG(TAB, ul_debugobj(tb, "remove entry %p", pa));
+	list_del(&pa->parts);
+	INIT_LIST_HEAD(&pa->parts);
+
+	fdisk_unref_partition(pa);
+	tb->nents--;
+
+	return 0;
+}
+
+/**
+ * fdisk_get_partitions
+ * @cxt: fdisk context
+ * @tb: returns table
+ *
+ * This function adds partitions from disklabel to @table, it allocates a new
+ * table if if @table points to NULL.
+ *
+ * Returns: 0 on success, otherwise, a corresponding error.
+ */
+int fdisk_get_partitions(struct fdisk_context *cxt, struct fdisk_table **tb)
+{
+	size_t i;
+
+	if (!cxt || !cxt->label || !tb)
+		return -EINVAL;
+	if (!cxt->label->op->get_part)
+		return -ENOSYS;
+
+	DBG(CXT, ul_debugobj(cxt, "get table"));
+
+	if (!*tb && !(*tb = fdisk_new_table()))
+		return -ENOMEM;
+
+	for (i = 0; i < cxt->label->nparts_max; i++) {
+		struct fdisk_partition *pa = NULL;
+
+		if (fdisk_get_partition(cxt, i, &pa) != 0)
+			continue;
+		if (fdisk_partition_is_used(pa))
+			fdisk_table_add_partition(*tb, pa);
+		fdisk_unref_partition(pa);
+	}
+
+	return 0;
+}
+
+static void debug_print_table(struct fdisk_table *tb)
+{
+	struct fdisk_iter itr;
+	struct fdisk_partition *pa;
+
+	fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
+	while (fdisk_table_next_partition(tb, &itr, &pa) == 0)
+		ul_debugobj(tb, "partition %p [partno=%zu, start=%ju, end=%ju, size=%ju] ",
+			    pa, pa->partno,
+			    (uintmax_t) fdisk_partition_get_start(pa),
+			    (uintmax_t) fdisk_partition_get_end(pa),
+			    (uintmax_t) fdisk_partition_get_size(pa));
+
+}
+
+
+typedef	int (*fdisk_partcmp_t)(struct fdisk_partition *, struct fdisk_partition *);
+
+static int cmp_parts_wrapper(struct list_head *a, struct list_head *b, void *data)
+{
+	struct fdisk_partition *pa = list_entry(a, struct fdisk_partition, parts),
+			       *pb = list_entry(b, struct fdisk_partition, parts);
+
+	fdisk_partcmp_t cmp = (fdisk_partcmp_t) data;
+
+	return cmp(pa, pb);
+}
+
+
+/**
+ * fdisk_table_sort_partitions:
+ * @tb: table
+ * @cmp: compare function
+ *
+ * Sort partition in the table.
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_table_sort_partitions(struct fdisk_table *tb,
+			int (*cmp)(struct fdisk_partition *,
+				   struct fdisk_partition *))
+{
+	if (!tb)
+		return -EINVAL;
+
+	DBG(TAB, ul_debugobj(tb, "Before sort:"));
+	ON_DBG(TAB, debug_print_table(tb));
+
+	list_sort(&tb->parts, cmp_parts_wrapper, (void *) cmp);
+
+	DBG(TAB, ul_debugobj(tb, "After sort:"));
+	ON_DBG(TAB, debug_print_table(tb));
+
+	return 0;
+}
+
+/* allocates a new freespace description */
+static int new_freespace(struct fdisk_context *cxt,
+			 fdisk_sector_t start,
+			 fdisk_sector_t end,
+			 struct fdisk_partition *parent,
+			 struct fdisk_partition **pa)
+{
+	assert(cxt);
+	assert(pa);
+
+	*pa = NULL;
+
+	if (start == end)
+		return 0;
+	*pa = fdisk_new_partition();
+	if (!*pa)
+		return -ENOMEM;
+
+	assert(start);
+	assert(end);
+	assert(end > start);
+
+	(*pa)->freespace = 1;
+	(*pa)->start = fdisk_align_lba_in_range(cxt, start, start, end);
+	(*pa)->size = end - (*pa)->start + 1ULL;
+
+	if (parent)
+		(*pa)->parent_partno = parent->partno;
+	return 0;
+}
+
+/* add freespace description to the right place within @tb */
+static int table_add_freespace(
+			struct fdisk_context *cxt,
+			struct fdisk_table *tb,
+			fdisk_sector_t start,
+			fdisk_sector_t end,
+			struct fdisk_partition *parent)
+{
+	struct fdisk_partition *pa, *x, *real_parent = NULL, *best = NULL;
+	struct fdisk_iter itr;
+	int rc = 0;
+
+	assert(tb);
+
+	rc = new_freespace(cxt, start, end, parent, &pa);
+	if (rc)
+		return -ENOMEM;
+	if (!pa)
+		return 0;
+
+	assert(fdisk_partition_has_start(pa));
+	assert(fdisk_partition_has_end(pa));
+
+	DBG(TAB, ul_debugobj(tb, "adding freespace"));
+
+	fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
+	if (parent && fdisk_partition_has_partno(parent)) {
+		while (fdisk_table_next_partition(tb, &itr, &x) == 0) {
+			if (!fdisk_partition_has_partno(x))
+				continue;
+			if (x->partno == parent->partno) {
+				real_parent = x;
+				break;
+			}
+		}
+		if (!real_parent) {
+			DBG(TAB, ul_debugobj(tb, "not found freespace parent (partno=%zu)",
+					parent->partno));
+			fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
+		}
+	}
+
+	while (fdisk_table_next_partition(tb, &itr, &x) == 0) {
+		fdisk_sector_t end, best_end = 0;
+
+		if (!fdisk_partition_has_end(x))
+			continue;
+
+		end = fdisk_partition_get_end(x);
+		if (best)
+			best_end = fdisk_partition_get_end(best);
+
+		if (end < pa->start && (!best || best_end < end))
+			best = x;
+	}
+
+	if (!best && real_parent)
+		best = real_parent;
+	rc = table_insert_partition(tb, best, pa);
+
+	fdisk_unref_partition(pa);
+
+	DBG(TAB, ul_debugobj(tb, "adding freespace DONE [rc=%d]", rc));
+	return rc;
+}
+
+/* analyze @cont(ainer) in @parts and add all detected freespace into @tb, note
+ * that @parts has to be sorted by partition starts */
+static int check_container_freespace(struct fdisk_context *cxt,
+				     struct fdisk_table *parts,
+				     struct fdisk_table *tb,
+				     struct fdisk_partition *cont)
+{
+	struct fdisk_iter itr;
+	struct fdisk_partition *pa;
+	fdisk_sector_t x, last, grain, lastplusoff;
+	int rc = 0;
+
+	assert(cxt);
+	assert(parts);
+	assert(tb);
+	assert(cont);
+	assert(fdisk_partition_has_start(cont));
+
+	DBG(TAB, ul_debugobj(tb, "analyze container 0x%p", cont));
+
+	last = fdisk_partition_get_start(cont);
+	grain = cxt->grain > cxt->sector_size ?	cxt->grain / cxt->sector_size : 1;
+	fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
+
+	DBG(CXT, ul_debugobj(cxt, "initialized:  last=%ju, grain=%ju", last, grain));
+
+	while (fdisk_table_next_partition(parts, &itr, &pa) == 0) {
+
+		DBG(CXT, ul_debugobj(cxt, "partno=%zu, start=%ju", pa->partno, pa->start));
+
+		if (!pa->used || !fdisk_partition_is_nested(pa)
+			      || !fdisk_partition_has_start(pa))
+			continue;
+
+		DBG(CXT, ul_debugobj(cxt, "freespace container analyze: partno=%zu, start=%ju, end=%ju",
+					pa->partno,
+					(uintmax_t) fdisk_partition_get_start(pa),
+					(uintmax_t) fdisk_partition_get_end(pa)));
+
+		lastplusoff = last + cxt->first_lba;
+		if (pa->start > lastplusoff && pa->start - lastplusoff > grain)
+			rc = table_add_freespace(cxt, tb, lastplusoff, pa->start, cont);
+		if (rc)
+			goto done;
+		last = fdisk_partition_get_end(pa);
+	}
+
+	/* free-space remaining in extended partition */
+	x = fdisk_partition_get_start(cont) + fdisk_partition_get_size(cont) - 1;
+	lastplusoff = last + cxt->first_lba;
+	if (lastplusoff < x && x - lastplusoff > grain) {
+		DBG(TAB, ul_debugobj(tb, "add remaining space in container 0x%p", cont));
+		rc = table_add_freespace(cxt, tb, lastplusoff, x, cont);
+	}
+
+done:
+	DBG(TAB, ul_debugobj(tb, "analyze container 0x%p DONE [rc=%d]", cont, rc));
+	return rc;
+}
+
+
+/**
+ * fdisk_get_freespaces
+ * @cxt: fdisk context
+ * @tb: returns table
+ *
+ * This function adds freespace (described by fdisk_partition) to @table, it
+ * allocates a new table if the @table points to NULL.
+ *
+ * Note that free space smaller than grain (see fdisk_get_grain()) is ignored.
+
+ * Returns: 0 on success, otherwise, a corresponding error.
+ */
+int fdisk_get_freespaces(struct fdisk_context *cxt, struct fdisk_table **tb)
+{
+	int rc = 0;
+	fdisk_sector_t last, grain;
+	struct fdisk_table *parts = NULL;
+	struct fdisk_partition *pa;
+	struct fdisk_iter itr;
+
+	DBG(CXT, ul_debugobj(cxt, "get freespace"));
+
+	if (!cxt || !cxt->label || !tb)
+		return -EINVAL;
+	if (!*tb && !(*tb = fdisk_new_table()))
+		return -ENOMEM;
+
+	rc = fdisk_get_partitions(cxt, &parts);
+	if (rc)
+		goto done;
+
+	fdisk_table_sort_partitions(parts, fdisk_partition_cmp_start);
+	fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
+	last = cxt->first_lba;
+	grain = cxt->grain > cxt->sector_size ?	cxt->grain / cxt->sector_size : 1;
+
+	DBG(CXT, ul_debugobj(cxt, "initialized:  last=%ju, grain=%ju", last, grain));
+
+	/* analyze gaps between partitions */
+	while (rc == 0 && fdisk_table_next_partition(parts, &itr, &pa) == 0) {
+
+		DBG(CXT, ul_debugobj(cxt, "partno=%zu, start=%ju", pa->partno, pa->start));
+
+		if (!pa->used || pa->wholedisk || fdisk_partition_is_nested(pa)
+			      || !fdisk_partition_has_start(pa))
+			continue;
+		DBG(CXT, ul_debugobj(cxt, "freespace analyze: partno=%zu, start=%ju, end=%ju",
+					pa->partno,
+					(uintmax_t) fdisk_partition_get_start(pa),
+					(uintmax_t) fdisk_partition_get_end(pa)));
+		if (last + grain <= pa->start) {
+			rc = table_add_freespace(cxt, *tb,
+				last + (last > cxt->first_lba ? 1 : 0),
+				pa->start - 1, NULL);
+		}
+		/* add gaps between logical partitions */
+		if (fdisk_partition_is_container(pa))
+			rc = check_container_freespace(cxt, parts, *tb, pa);
+		last = fdisk_partition_get_end(pa);
+	}
+
+	/* add free-space behind last partition to the end of the table (so
+	 * don't use table_add_freespace()) */
+	if (rc == 0 && last + grain < cxt->total_sectors - 1) {
+		DBG(CXT, ul_debugobj(cxt, "freespace behind last partition detected"));
+		rc = new_freespace(cxt,
+			last + (last > cxt->first_lba ? 1 : 0),
+			cxt->last_lba, NULL, &pa);
+		if (pa) {
+			fdisk_table_add_partition(*tb, pa);
+			fdisk_unref_partition(pa);
+		}
+	}
+
+done:
+	fdisk_unref_table(parts);
+
+	DBG(CXT, ul_debugobj(cxt, "get freespace DONE [rc=%d]", rc));
+	return rc;
+}
+
+/**
+ * fdisk_table_wrong_order:
+ * @tb: table
+ *
+ * Returns: 1 of the table is not in disk order
+ */
+int fdisk_table_wrong_order(struct fdisk_table *tb)
+{
+	struct fdisk_partition *pa;
+	struct fdisk_iter itr;
+	fdisk_sector_t last = 0;
+
+	DBG(TAB, ul_debugobj(tb, "wrong older check"));
+
+	fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
+	while (tb && fdisk_table_next_partition(tb, &itr, &pa) == 0) {
+		if (!fdisk_partition_has_start(pa))
+			continue;
+		if (pa->start < last)
+			return 1;
+		last = pa->start;
+	}
+	return 0;
+}
+
+/**
+ * fdisk_apply_table:
+ * @cxt: context
+ * @tb: table
+ *
+ * Add partitions from table @tb to the in-memory disk label. See
+ * fdisk_add_partition(), fdisk_delete_all_partitions(). The partitons
+ * that does not define start (or does not follow the default start)
+ * are ingored.
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int fdisk_apply_table(struct fdisk_context *cxt, struct fdisk_table *tb)
+{
+	struct fdisk_partition *pa;
+	struct fdisk_iter itr;
+	int rc = 0;
+
+	assert(cxt);
+	assert(tb);
+
+	DBG(TAB, ul_debugobj(tb, "applying to context %p", cxt));
+
+	fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
+	while (tb && fdisk_table_next_partition(tb, &itr, &pa) == 0) {
+		if (!fdisk_partition_has_start(pa) && !pa->start_follow_default)
+			continue;
+		rc = fdisk_add_partition(cxt, pa, NULL);
+		if (rc)
+			break;
+	}
+
+	return rc;
+}
+
diff --git a/libblkid/libfdisk/src/test.c b/libblkid/libfdisk/src/test.c
new file mode 100644
index 0000000..31ed7e0
--- /dev/null
+++ b/libblkid/libfdisk/src/test.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2008-2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ * Routines for TEST_PROGRAMs
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifndef TEST_PROGRAM
+#define TEST_PROGRAM
+#endif
+
+#include "fdiskP.h"
+
+int fdisk_run_test(struct fdisk_test *tests, int argc, char *argv[])
+{
+	int rc = -1;
+	struct fdisk_test *ts;
+
+	assert(tests);
+	assert(argc);
+	assert(argv);
+
+	if (argc < 2 ||
+	    strcmp(argv[1], "--help") == 0 ||
+	    strcmp(argv[1], "-h") == 0)
+		goto usage;
+
+	fdisk_init_debug(0);
+
+	for (ts = tests; ts->name; ts++) {
+		if (strcmp(ts->name, argv[1]) == 0) {
+			rc = ts->body(ts, argc - 1, argv + 1);
+			if (rc)
+				printf("FAILED [rc=%d]", rc);
+			break;
+		}
+	}
+
+	if (rc < 0 && ts->name == NULL)
+		goto usage;
+
+	return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+usage:
+	printf("\nUsage:\n\t%s <test> [testoptions]\nTests:\n",
+			program_invocation_short_name);
+	for (ts = tests; ts->name; ts++) {
+		printf("\t%-15s", ts->name);
+		if (ts->usage)
+			printf(" %s\n", ts->usage);
+	}
+	printf("\n");
+	return EXIT_FAILURE;
+}
diff --git a/libblkid/libfdisk/src/utils.c b/libblkid/libfdisk/src/utils.c
new file mode 100644
index 0000000..482a306
--- /dev/null
+++ b/libblkid/libfdisk/src/utils.c
@@ -0,0 +1,154 @@
+
+#include "fdiskP.h"
+#include "pathnames.h"
+
+#include <ctype.h>
+
+/**
+ * SECTION: utils
+ * @title: Utils
+ * @short_description: misc fdisk functions
+ */
+
+/*
+ * Zeros in-memory first sector buffer
+ */
+int fdisk_init_firstsector_buffer(struct fdisk_context *cxt)
+{
+	if (!cxt)
+		return -EINVAL;
+
+	if (!cxt->firstsector || cxt->firstsector_bufsz != cxt->sector_size) {
+		/* Let's allocate a new buffer if no allocated yet, or the
+		 * current buffer has incorrect size */
+		if (!cxt->parent || cxt->parent->firstsector != cxt->firstsector)
+			free(cxt->firstsector);
+
+		DBG(CXT, ul_debugobj(cxt, "initialize in-memory first sector "
+				"buffer [sector_size=%lu]", cxt->sector_size));
+		cxt->firstsector = calloc(1, cxt->sector_size);
+		if (!cxt->firstsector)
+			return -ENOMEM;
+
+		cxt->firstsector_bufsz = cxt->sector_size;
+		return 0;
+	}
+
+	DBG(CXT, ul_debugobj(cxt, "zeroize in-memory first sector buffer"));
+	memset(cxt->firstsector, 0, cxt->firstsector_bufsz);
+	return 0;
+}
+
+int fdisk_read_firstsector(struct fdisk_context *cxt)
+{
+	ssize_t r;
+	int rc;
+
+	assert(cxt);
+	assert(cxt->sector_size);
+
+	rc = fdisk_init_firstsector_buffer(cxt);
+	if (rc)
+		return rc;
+
+	assert(cxt->sector_size == cxt->firstsector_bufsz);
+
+	DBG(CXT, ul_debugobj(cxt, "reading first sector "
+				"buffer [sector_size=%lu]", cxt->sector_size));
+
+	r = lseek(cxt->dev_fd, 0, SEEK_SET);
+	if (r == -1)
+	{
+		DBG(CXT, ul_debugobj(cxt, "failed to seek to first sector %m"));
+		return -errno;
+	}
+
+	r = read(cxt->dev_fd, cxt->firstsector, cxt->sector_size);
+
+	if (r != cxt->sector_size) {
+		if (!errno)
+			errno = EINVAL;	/* probably too small file/device */
+		DBG(CXT, ul_debugobj(cxt, "failed to read first sector %m"));
+		return -errno;
+	}
+
+	return 0;
+}
+
+/**
+ * fdisk_partname:
+ * @dev: device name
+ * @partno: partition name
+ *
+ * Return: allocated buffer with partition name, use free() to deallocate.
+ */
+char *fdisk_partname(const char *dev, size_t partno)
+{
+	char *res = NULL;
+	const char *p = "";
+	int w = 0;
+
+	if (!dev || !*dev) {
+		if (asprintf(&res, "%zd", partno) > 0)
+			return res;
+		return NULL;
+	}
+
+	w = strlen(dev);
+	if (isdigit(dev[w - 1]))
+#ifdef __GNU__
+		p = "s";
+#else
+		p = "p";
+#endif
+
+	/* devfs kludge - note: fdisk partition names are not supposed
+	   to equal kernel names, so there is no reason to do this */
+	if (strcmp(dev + w - 4, "disc") == 0) {
+		w -= 4;
+		p = "part";
+	}
+
+	/* udev names partitions by appending -partN
+	   e.g. ata-SAMSUNG_SV8004H_0357J1FT712448-part1 */
+	if ((strncmp(dev, _PATH_DEV_BYID, sizeof(_PATH_DEV_BYID) - 1) == 0) ||
+	     strncmp(dev, _PATH_DEV_BYPATH, sizeof(_PATH_DEV_BYPATH) - 1) == 0) {
+	       p = "-part";
+	}
+
+	if (asprintf(&res, "%.*s%s%zu", w, dev, p, partno) > 0)
+		return res;
+
+	return NULL;
+}
+
+#ifdef TEST_PROGRAM
+struct fdisk_label *fdisk_new_dos_label(struct fdisk_context *cxt) { return NULL; }
+struct fdisk_label *fdisk_new_bsd_label(struct fdisk_context *cxt) { return NULL; }
+
+int test_partnames(struct fdisk_test *ts, int argc, char *argv[])
+{
+	size_t i;
+	const char *disk = argv[1];
+
+	for (i = 0; i < 5; i++) {
+		char *p = fdisk_partname(disk, i + 1);
+		if (p)
+			printf("%zu: '%s'\n", i + 1, p);
+		free(p);
+	}
+
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	struct fdisk_test tss[] = {
+		{ "--partnames",  test_partnames,  "<diskname>" },
+		{ NULL }
+	};
+
+	return fdisk_run_test(tss, argc, argv);
+}
+
+#endif
diff --git a/libblkid/libuuid/COPYING b/libblkid/libuuid/COPYING
new file mode 100644
index 0000000..0e902cf
--- /dev/null
+++ b/libblkid/libuuid/COPYING
@@ -0,0 +1,5 @@
+This library is free software; you can redistribute it and/or
+modify it under the terms of the Modified BSD License.
+
+The complete text of the license is available in the
+../Documentation/licenses/COPYING.BSD-3 file.
diff --git a/libblkid/libuuid/Makemodule.am b/libblkid/libuuid/Makemodule.am
new file mode 100644
index 0000000..166be5c
--- /dev/null
+++ b/libblkid/libuuid/Makemodule.am
@@ -0,0 +1,10 @@
+if BUILD_LIBUUID
+
+include libuuid/man/Makemodule.am
+include libuuid/src/Makemodule.am
+
+pkgconfig_DATA += libuuid/uuid.pc
+PATHFILES      += libuuid/uuid.pc
+EXTRA_DIST     += libuuid/COPYING
+
+endif # BUILD_LIBUUID
diff --git a/libblkid/libuuid/man/.gitignore b/libblkid/libuuid/man/.gitignore
new file mode 100644
index 0000000..7957ad2
--- /dev/null
+++ b/libblkid/libuuid/man/.gitignore
@@ -0,0 +1,3 @@
+uuid_generate_random.3
+uuid_generate_time.3
+uuid_generate_time_safe.3
diff --git a/libblkid/libuuid/man/Makemodule.am b/libblkid/libuuid/man/Makemodule.am
new file mode 100644
index 0000000..81287d5
--- /dev/null
+++ b/libblkid/libuuid/man/Makemodule.am
@@ -0,0 +1,14 @@
+
+dist_man_MANS += \
+	libuuid/man/uuid.3 \
+	libuuid/man/uuid_clear.3 \
+	libuuid/man/uuid_compare.3 \
+	libuuid/man/uuid_copy.3 \
+	libuuid/man/uuid_generate.3 \
+	libuuid/man/uuid_is_null.3 \
+	libuuid/man/uuid_parse.3 \
+	libuuid/man/uuid_time.3 \
+	libuuid/man/uuid_unparse.3 \
+	libuuid/man/uuid_generate_random.3 \
+	libuuid/man/uuid_generate_time.3 \
+	libuuid/man/uuid_generate_time_safe.3
diff --git a/libblkid/libuuid/man/uuid.3 b/libblkid/libuuid/man/uuid.3
new file mode 100644
index 0000000..37b0499
--- /dev/null
+++ b/libblkid/libuuid/man/uuid.3
@@ -0,0 +1,65 @@
+.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca)
+.\"
+.\" %Begin-Header%
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, and the entire permission notice in its entirety,
+.\"    including the disclaimer of warranties.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. The name of the author may not be used to endorse or promote
+.\"    products derived from this software without specific prior
+.\"    written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+.\" WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+.\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+.\" USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+.\" DAMAGE.
+.\" %End-Header%
+.\"
+.\" Created  Wed Mar 10 17:42:12 1999, Andreas Dilger
+.TH UUID 3 "May 2009" "util-linux" "Libuuid API"
+.SH NAME
+uuid \- DCE compatible Universally Unique Identifier library
+.SH SYNOPSIS
+.B #include <uuid.h>
+.SH DESCRIPTION
+The UUID library is used to generate unique identifiers for objects
+that may be accessible beyond the local system.  This library
+generates UUIDs compatible with those created by the Open Software
+Foundation (OSF) Distributed Computing Environment (DCE) utility
+.BR uuidgen .
+.sp
+The UUIDs generated by this library can be reasonably expected to be
+unique within a system, and unique across all systems.  They could
+be used, for instance, to generate unique HTTP cookies across multiple
+web servers without communication between the servers, and without fear
+of a name clash.
+.SH "CONFORMING TO"
+OSF DCE 1.1
+.SH AUTHOR
+Theodore Y.\& Ts'o
+.SH AVAILABILITY
+.B libuuid
+is part of the util-linux package since version 2.15.1 and is available from
+ftp://ftp.kernel.org/pub/linux/utils/util-linux/.
+.SH "SEE ALSO"
+.BR uuid_clear (3),
+.BR uuid_compare (3),
+.BR uuid_copy (3),
+.BR uuid_generate (3),
+.BR uuid_is_null (3),
+.BR uuid_parse (3),
+.BR uuid_time (3),
+.BR uuid_unparse (3)
diff --git a/libblkid/libuuid/man/uuid_clear.3 b/libblkid/libuuid/man/uuid_clear.3
new file mode 100644
index 0000000..70fca02
--- /dev/null
+++ b/libblkid/libuuid/man/uuid_clear.3
@@ -0,0 +1,62 @@
+.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca)
+.\"
+.\" %Begin-Header%
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, and the entire permission notice in its entirety,
+.\"    including the disclaimer of warranties.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. The name of the author may not be used to endorse or promote
+.\"    products derived from this software without specific prior
+.\"    written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+.\" WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+.\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+.\" USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+.\" DAMAGE.
+.\" %End-Header%
+.\"
+.\" Created  Wed Mar 10 17:42:12 1999, Andreas Dilger
+.TH UUID_CLEAR 3 "May 2009" "util-linux" "Libuuid API"
+.SH NAME
+uuid_clear \- reset value of UUID variable to the NULL value
+.SH SYNOPSIS
+.nf
+.B #include <uuid.h>
+.sp
+.BI "void uuid_clear(uuid_t " uu );
+.fi
+.SH DESCRIPTION
+The
+.B uuid_clear
+function sets the value of the supplied uuid variable
+.I uu
+to the NULL value.
+.SH AUTHOR
+Theodore Y.\& Ts'o
+.SH AVAILABILITY
+.B libuuid
+is part of the util-linux package since version 2.15.1 and is available from
+ftp://ftp.kernel.org/pub/linux/utils/util-linux/.
+.na
+.SH "SEE ALSO"
+.BR uuid (3),
+.BR uuid_compare (3),
+.BR uuid_copy (3),
+.BR uuid_generate (3),
+.BR uuid_is_null (3),
+.BR uuid_parse (3),
+.BR uuid_unparse (3)
+.ad
diff --git a/libblkid/libuuid/man/uuid_compare.3 b/libblkid/libuuid/man/uuid_compare.3
new file mode 100644
index 0000000..f91181a
--- /dev/null
+++ b/libblkid/libuuid/man/uuid_compare.3
@@ -0,0 +1,68 @@
+.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca)
+.\"
+.\" %Begin-Header%
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, and the entire permission notice in its entirety,
+.\"    including the disclaimer of warranties.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. The name of the author may not be used to endorse or promote
+.\"    products derived from this software without specific prior
+.\"    written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+.\" WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+.\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+.\" USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+.\" DAMAGE.
+.\" %End-Header%
+.\"
+.\" Created  Wed Mar 10 17:42:12 1999, Andreas Dilger
+.TH UUID_COMPARE 3 "May 2009" "util-linux" "Libuuid API"
+.SH NAME
+uuid_compare \- compare whether two UUIDs are the same
+.SH SYNOPSIS
+.nf
+.B #include <uuid.h>
+.sp
+.BI "int uuid_compare(uuid_t " uu1 ", uuid_t " uu2)
+.fi
+.SH DESCRIPTION
+The
+.B uuid_compare
+function compares the two supplied uuid variables
+.IR uu1 " and " uu2
+to each other.
+.SH RETURN VALUE
+Returns an integer less than, equal to, or greater than zero if
+.I uu1
+is found,  respectively, to be lexicographically less than, equal, or
+greater than
+.IR uu2 .
+.SH AUTHOR
+Theodore Y.\& Ts'o
+.SH AVAILABILITY
+.B libuuid
+is part of the util-linux package since version 2.15.1 and is available from
+ftp://ftp.kernel.org/pub/linux/utils/util-linux/.
+.na
+.SH "SEE ALSO"
+.BR uuid (3),
+.BR uuid_clear (3),
+.BR uuid_copy (3),
+.BR uuid_generate (3),
+.BR uuid_is_null (3),
+.BR uuid_parse (3),
+.BR uuid_unparse (3)
+.ad
diff --git a/libblkid/libuuid/man/uuid_copy.3 b/libblkid/libuuid/man/uuid_copy.3
new file mode 100644
index 0000000..5159fa6
--- /dev/null
+++ b/libblkid/libuuid/man/uuid_copy.3
@@ -0,0 +1,64 @@
+.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca)
+.\"
+.\" %Begin-Header%
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, and the entire permission notice in its entirety,
+.\"    including the disclaimer of warranties.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. The name of the author may not be used to endorse or promote
+.\"    products derived from this software without specific prior
+.\"    written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+.\" WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+.\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+.\" USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+.\" DAMAGE.
+.\" %End-Header%
+.\"
+.\" Created  Wed Mar 10 17:42:12 1999, Andreas Dilger
+.TH UUID_COPY 3 "May 2009" "util-linux" "Libuuid API"
+.SH NAME
+uuid_copy \- copy a UUID value
+.SH SYNOPSIS
+.nf
+.B #include <uuid.h>
+.sp
+.BI "void uuid_copy(uuid_t " dst ", uuid_t " src);
+.fi
+.SH DESCRIPTION
+The
+.B uuid_copy
+function copies the UUID variable
+.IR src " to " dst .
+.SH RETURN VALUE
+The copied UUID is returned in the location pointed to by
+.IR dst .
+.SH AUTHOR
+Theodore Y.\& Ts'o
+.SH AVAILABILITY
+.B libuuid
+is part of the util-linux package since version 2.15.1 and is available from
+ftp://ftp.kernel.org/pub/linux/utils/util-linux/.
+.na
+.SH "SEE ALSO"
+.BR uuid (3),
+.BR uuid_clear (3),
+.BR uuid_compare (3),
+.BR uuid_generate (3),
+.BR uuid_is_null (3),
+.BR uuid_parse (3),
+.BR uuid_unparse (3)
+.ad
diff --git a/libblkid/libuuid/man/uuid_generate.3 b/libblkid/libuuid/man/uuid_generate.3
new file mode 100644
index 0000000..19904d7
--- /dev/null
+++ b/libblkid/libuuid/man/uuid_generate.3
@@ -0,0 +1,126 @@
+.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca)
+.\"
+.\" %Begin-Header%
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, and the entire permission notice in its entirety,
+.\"    including the disclaimer of warranties.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. The name of the author may not be used to endorse or promote
+.\"    products derived from this software without specific prior
+.\"    written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+.\" WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+.\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+.\" USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+.\" DAMAGE.
+.\" %End-Header%
+.\"
+.\" Created  Wed Mar 10 17:42:12 1999, Andreas Dilger
+.TH UUID_GENERATE 3 "May 2009" "util-linux" "Libuuid API"
+.SH NAME
+uuid_generate, uuid_generate_random, uuid_generate_time,
+uuid_generate_time_safe \- create a new unique UUID value
+.SH SYNOPSIS
+.nf
+.B #include <uuid.h>
+.sp
+.BI "void uuid_generate(uuid_t " out );
+.BI "void uuid_generate_random(uuid_t " out );
+.BI "void uuid_generate_time(uuid_t " out );
+.BI "int uuid_generate_time_safe(uuid_t " out );
+.fi
+.SH DESCRIPTION
+The
+.B uuid_generate
+function creates a new universally unique identifier (UUID).  The uuid will
+be generated based on high-quality randomness from
+.IR /dev/urandom ,
+if available.  If it is not available, then
+.B uuid_generate
+will use an alternative algorithm which uses the current time, the
+local ethernet MAC address (if available), and random data generated
+using a pseudo-random generator.
+.sp
+The
+.B uuid_generate_random
+function forces the use of the all-random UUID format, even if
+a high-quality random number generator (i.e.,
+.IR /dev/urandom )
+is not available, in which case a pseudo-random
+generator will be substituted.  Note that the use of a pseudo-random
+generator may compromise the uniqueness of UUIDs
+generated in this fashion.
+.sp
+The
+.B uuid_generate_time
+function forces the use of the alternative algorithm which uses the
+current time and the local ethernet MAC address (if available).
+This algorithm used to be the default one used to generate UUID, but
+because of the use of the ethernet MAC address, it can leak
+information about when and where the UUID was generated.  This can cause
+privacy problems in some applications, so the
+.B uuid_generate
+function only uses this algorithm if a high-quality source of
+randomness is not available.  To guarantee uniqueness of UUIDs generated
+by concurrently running processes, the uuid library uses global
+clock state counter (if the process has permissions to gain exclusive access
+to this file) and/or the
+.B uuidd
+daemon, if it is running already or can be spawned by the process (if
+installed and the process has enough permissions to run it).  If neither of
+these two synchronization mechanisms can be used, it is theoretically possible
+that two concurrently running processes obtain the same UUID(s).  To tell
+whether the UUID has been generated in a safe manner, use
+.BR uuid_generate_time_safe .
+.sp
+The
+.B uuid_generate_time_safe
+is similar to
+.BR uuid_generate_time ,
+except that it returns a value which denotes whether any of the synchronization
+mechanisms (see above) has been used.
+.sp
+The UUID is 16 bytes (128 bits) long, which gives approximately 3.4x10^38
+unique values (there are approximately 10^80 elementary particles in
+the universe according to Carl Sagan's
+.IR Cosmos ).
+The new UUID can reasonably be considered unique among all UUIDs created
+on the local system, and among UUIDs created on other systems in the past
+and in the future.
+.SH RETURN VALUE
+The newly created UUID is returned in the memory location pointed to by
+.IR out .
+.B uuid_generate_time_safe
+returns zero if the UUID has been generated in a safe manner, \-1 otherwise.
+.SH "CONFORMING TO"
+OSF DCE 1.1
+.SH AUTHOR
+Theodore Y.\& Ts'o
+.SH AVAILABILITY
+.B libuuid
+is part of the util-linux package since version 2.15.1 and is available from
+ftp://ftp.kernel.org/pub/linux/utils/util-linux/.
+.SH "SEE ALSO"
+.BR uuid (3),
+.BR uuidgen (1),
+.BR uuidd (8),
+.BR uuid_clear (3),
+.BR uuid_compare (3),
+.BR uuid_copy (3),
+.BR uuid_is_null (3),
+.BR uuid_parse (3),
+.BR uuid_time (3),
+.BR uuid_unparse (3)
diff --git a/libblkid/libuuid/man/uuid_is_null.3 b/libblkid/libuuid/man/uuid_is_null.3
new file mode 100644
index 0000000..86a7a50
--- /dev/null
+++ b/libblkid/libuuid/man/uuid_is_null.3
@@ -0,0 +1,64 @@
+.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca)
+.\"
+.\" %Begin-Header%
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, and the entire permission notice in its entirety,
+.\"    including the disclaimer of warranties.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. The name of the author may not be used to endorse or promote
+.\"    products derived from this software without specific prior
+.\"    written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+.\" WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+.\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+.\" USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+.\" DAMAGE.
+.\" %End-Header%
+.\"
+.\" Created  Wed Mar 10 17:42:12 1999, Andreas Dilger
+.TH UUID_IS_NULL 3 "May 2009" "util-linux" "Libuuid API"
+.SH NAME
+uuid_is_null \- compare the value of the UUID to the NULL value
+.SH SYNOPSIS
+.nf
+.B #include <uuid.h>
+.sp
+.BI "int uuid_is_null(uuid_t " uu );
+.fi
+.SH DESCRIPTION
+The
+.B uuid_is_null
+function compares the value of the supplied UUID variable
+.I uu
+to the NULL value.  If the value is equal to the NULL UUID, 1 is returned,
+otherwise 0 is returned.
+.SH AUTHOR
+Theodore Y.\& Ts'o
+.SH AVAILABILITY
+.B libuuid
+is part of the util-linux package since version 2.15.1 and is available from
+ftp://ftp.kernel.org/pub/linux/utils/util-linux/.
+.na
+.SH "SEE ALSO"
+.BR uuid (3),
+.BR uuid_clear (3),
+.BR uuid_compare (3),
+.BR uuid_copy (3),
+.BR uuid_generate (3),
+.BR uuid_time (3),
+.BR uuid_parse (3),
+.BR uuid_unparse (3)
+.ad
diff --git a/libblkid/libuuid/man/uuid_parse.3 b/libblkid/libuuid/man/uuid_parse.3
new file mode 100644
index 0000000..31a5926
--- /dev/null
+++ b/libblkid/libuuid/man/uuid_parse.3
@@ -0,0 +1,73 @@
+.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca)
+.\"
+.\" %Begin-Header%
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, and the entire permission notice in its entirety,
+.\"    including the disclaimer of warranties.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. The name of the author may not be used to endorse or promote
+.\"    products derived from this software without specific prior
+.\"    written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+.\" WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+.\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+.\" USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+.\" DAMAGE.
+.\" %End-Header%
+.\"
+.\" Created  Wed Mar 10 17:42:12 1999, Andreas Dilger
+.TH UUID_PARSE 3 "May 2009" "util-linux" "Libuuid API"
+.SH NAME
+uuid_parse \- convert an input UUID string into binary representation
+.SH SYNOPSIS
+.nf
+.B #include <uuid.h>
+.sp
+.BI "int uuid_parse( char *" in ", uuid_t " uu );
+.fi
+.SH DESCRIPTION
+The
+.B uuid_parse
+function converts the UUID string given by
+.I in
+into the binary representation.  The input UUID is a string of the form
+1b4e28ba\-2fa1\-11d2\-883f\-b9a761bde3fb (in
+.BR printf (3)
+format "%08x\-%04x\-%04x\-%04x\-%012x", 36 bytes plus the trailing '\e0').
+.SH RETURN VALUE
+Upon successfully parsing the input string, 0 is returned, and the UUID is
+stored in the location pointed to by
+.IR uu ,
+otherwise \-1 is returned.
+.SH "CONFORMING TO"
+OSF DCE 1.1
+.SH AUTHOR
+Theodore Y.\& Ts'o
+.SH AVAILABILITY
+.B libuuid
+is part of the util-linux package since version 2.15.1 and is available from
+ftp://ftp.kernel.org/pub/linux/utils/util-linux/.
+.na
+.SH "SEE ALSO"
+.BR uuid (3),
+.BR uuid_clear (3),
+.BR uuid_compare (3),
+.BR uuid_copy (3),
+.BR uuid_generate (3),
+.BR uuid_is_null (3),
+.BR uuid_time (3),
+.BR uuid_unparse (3)
+.ad
diff --git a/libblkid/libuuid/man/uuid_time.3 b/libblkid/libuuid/man/uuid_time.3
new file mode 100644
index 0000000..483676b
--- /dev/null
+++ b/libblkid/libuuid/man/uuid_time.3
@@ -0,0 +1,78 @@
+.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca)
+.\"
+.\" %Begin-Header%
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, and the entire permission notice in its entirety,
+.\"    including the disclaimer of warranties.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. The name of the author may not be used to endorse or promote
+.\"    products derived from this software without specific prior
+.\"    written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+.\" WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+.\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+.\" USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+.\" DAMAGE.
+.\" %End-Header%
+.\"
+.\" Created  Wed Mar 10 17:42:12 1999, Andreas Dilger
+.TH UUID_TIME 3 "May 2009" "util-linux" "Libuuid API"
+.SH NAME
+uuid_time \- extract the time at which the UUID was created
+.SH SYNOPSIS
+.nf
+.B #include <uuid.h>
+.sp
+.BI "time_t uuid_time(uuid_t " uu ", struct timeval *" ret_tv )
+.fi
+.SH DESCRIPTION
+The
+.B uuid_time
+function extracts the time at which the supplied time-based UUID
+.I uu
+was created.  Note that the UUID creation time is only encoded within
+certain types of UUIDs.  This function can only reasonably expect to
+extract the creation time for UUIDs created with the
+.BR uuid_generate_time (3)
+and
+.BR uuid_generate_time_safe (3)
+functions.  It may or may not work with UUIDs created by other mechanisms.
+.SH "RETURN VALUES"
+The time at which the UUID was created, in seconds since January 1, 1970 GMT
+(the epoch), is returned (see
+.BR time "(2))."
+The time at which the UUID was created, in seconds and microseconds since
+the epoch, is also stored in the location pointed to by
+.I ret_tv
+(see
+.BR gettimeofday "(2))."
+.SH AUTHOR
+Theodore Y.\& Ts'o
+.SH AVAILABILITY
+.B libuuid
+is part of the util-linux package since version 2.15.1 and is available from
+ftp://ftp.kernel.org/pub/linux/utils/util-linux/.
+.na
+.SH "SEE ALSO"
+.BR uuid (3),
+.BR uuid_clear (3),
+.BR uuid_compare (3),
+.BR uuid_copy (3),
+.BR uuid_generate (3),
+.BR uuid_is_null (3),
+.BR uuid_parse (3),
+.BR uuid_unparse (3)
+.ad
diff --git a/libblkid/libuuid/man/uuid_unparse.3 b/libblkid/libuuid/man/uuid_unparse.3
new file mode 100644
index 0000000..1e0116d
--- /dev/null
+++ b/libblkid/libuuid/man/uuid_unparse.3
@@ -0,0 +1,81 @@
+.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca)
+.\"
+.\" %Begin-Header%
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, and the entire permission notice in its entirety,
+.\"    including the disclaimer of warranties.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. The name of the author may not be used to endorse or promote
+.\"    products derived from this software without specific prior
+.\"    written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+.\" WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+.\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+.\" USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+.\" DAMAGE.
+.\" %End-Header%
+.\"
+.\" Created  Wed Mar 10 17:42:12 1999, Andreas Dilger
+.TH UUID_UNPARSE 3 "May 2009" "util-linux" "Libuuid API"
+.SH NAME
+uuid_unparse \- convert an UUID from binary representation to a string
+.SH SYNOPSIS
+.nf
+.B #include <uuid.h>
+.sp
+.BI "void uuid_unparse(uuid_t " uu ", char *" out );
+.BI "void uuid_unparse_upper(uuid_t " uu ", char *" out );
+.BI "void uuid_unparse_lower(uuid_t " uu ", char *" out );
+.fi
+.SH DESCRIPTION
+The
+.B uuid_unparse
+function converts the supplied UUID
+.I uu
+from the binary representation into a 36-byte string (plus tailing '\e0')
+of the form 1b4e28ba\-2fa1\-11d2\-883f\-0016d3cca427 and stores this
+value in the character string pointed to by
+.IR out .
+The case of the hex digits returned by
+.B uuid_unparse
+may be upper or lower case, and is
+dependent on the system-dependent local default.
+.PP
+If the case of the
+hex digits is important then the functions
+.B uuid_unparse_upper
+and
+.B uuid_unparse_lower
+may be used.
+.SH "CONFORMING TO"
+OSF DCE 1.1
+.SH AUTHOR
+Theodore Y.\& Ts'o
+.SH AVAILABILITY
+.B libuuid
+is part of the util-linux package since version 2.15.1 and is available from
+ftp://ftp.kernel.org/pub/linux/utils/util-linux/.
+.na
+.SH "SEE ALSO"
+.BR uuid (3),
+.BR uuid_clear (3),
+.BR uuid_compare (3),
+.BR uuid_copy (3),
+.BR uuid_generate (3),
+.BR uuid_time (3),
+.BR uuid_is_null (3),
+.BR uuid_parse (3)
+.ad
diff --git a/libblkid/libuuid/src/Makemodule.am b/libblkid/libuuid/src/Makemodule.am
new file mode 100644
index 0000000..061aff2
--- /dev/null
+++ b/libblkid/libuuid/src/Makemodule.am
@@ -0,0 +1,61 @@
+
+check_PROGRAMS += test_uuid
+test_uuid_SOURCES = libuuid/src/test_uuid.c
+test_uuid_LDADD = libuuid.la $(SOCKET_LIBS)
+test_uuid_CFLAGS = -I$(ul_libuuid_incdir)
+
+# includes
+uuidincdir = $(includedir)/uuid
+uuidinc_HEADERS = libuuid/src/uuid.h
+
+usrlib_exec_LTLIBRARIES += libuuid.la
+
+libuuid_la_SOURCES = \
+	libuuid/src/clear.c \
+	libuuid/src/compare.c \
+	libuuid/src/copy.c \
+	libuuid/src/gen_uuid.c \
+	libuuid/src/isnull.c \
+	libuuid/src/pack.c \
+	libuuid/src/parse.c \
+	libuuid/src/unpack.c \
+	libuuid/src/unparse.c \
+	libuuid/src/uuidd.h \
+	libuuid/src/uuidd.h \
+	libuuid/src/uuidP.h \
+	libuuid/src/uuid_time.c \
+	$(uuidinc_HEADERS) \
+	lib/randutils.c
+
+libuuid_la_DEPENDENCIES = libuuid/src/libuuid.sym
+libuuid_la_LIBADD       = $(SOCKET_LIBS)
+
+libuuid_la_CFLAGS = \
+	 $(SOLIB_CFLAGS) \
+	 -I$(ul_libuuid_incdir) \
+	 -Ilibuuid/src
+
+libuuid_la_LDFLAGS = \
+	$(SOLIB_LDFLAGS) \
+	-Wl,--version-script=$(top_srcdir)/libuuid/src/libuuid.sym \
+	-version-info $(LIBUUID_VERSION_INFO)
+
+EXTRA_DIST += libuuid/src/libuuid.sym
+
+# move lib from $(usrlib_execdir) to $(libdir) if needed
+install-exec-hook-libuuid:
+	if test "$(usrlib_execdir)" != "$(libdir)" -a -f "$(DESTDIR)$(usrlib_execdir)/libuuid.so"; then \
+		mkdir -p $(DESTDIR)$(libdir); \
+		mv $(DESTDIR)$(usrlib_execdir)/libuuid.so.* $(DESTDIR)$(libdir); \
+		so_img_name=$$(readlink $(DESTDIR)$(usrlib_execdir)/libuuid.so); \
+		so_img_rel_target=$$(echo $(usrlib_execdir) | sed 's,\(^/\|\)[^/][^/]*,..,g'); \
+		(cd $(DESTDIR)$(usrlib_execdir) && \
+			rm -f libuuid.so && \
+			$(LN_S) $$so_img_rel_target$(libdir)/$$so_img_name libuuid.so); \
+	fi
+
+uninstall-hook-libuuid:
+	rm -f $(DESTDIR)$(libdir)/libuuid.so*
+
+INSTALL_EXEC_HOOKS += install-exec-hook-libuuid
+UNINSTALL_HOOKS += uninstall-hook-libuuid
diff --git a/libblkid/libuuid/src/clear.c b/libblkid/libuuid/src/clear.c
new file mode 100644
index 0000000..2d91fee
--- /dev/null
+++ b/libblkid/libuuid/src/clear.c
@@ -0,0 +1,43 @@
+/*
+ * clear.c -- Clear a UUID
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include "string.h"
+
+#include "uuidP.h"
+
+void uuid_clear(uuid_t uu)
+{
+	memset(uu, 0, 16);
+}
+
diff --git a/libblkid/libuuid/src/compare.c b/libblkid/libuuid/src/compare.c
new file mode 100644
index 0000000..8f3437a
--- /dev/null
+++ b/libblkid/libuuid/src/compare.c
@@ -0,0 +1,55 @@
+/*
+ * compare.c --- compare whether or not two UUIDs are the same
+ *
+ * Returns 0 if the two UUIDs are different, and 1 if they are the same.
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include "uuidP.h"
+#include <string.h>
+
+#define UUCMP(u1,u2) if (u1 != u2) return((u1 < u2) ? -1 : 1);
+
+int uuid_compare(const uuid_t uu1, const uuid_t uu2)
+{
+	struct uuid	uuid1, uuid2;
+
+	uuid_unpack(uu1, &uuid1);
+	uuid_unpack(uu2, &uuid2);
+
+	UUCMP(uuid1.time_low, uuid2.time_low);
+	UUCMP(uuid1.time_mid, uuid2.time_mid);
+	UUCMP(uuid1.time_hi_and_version, uuid2.time_hi_and_version);
+	UUCMP(uuid1.clock_seq, uuid2.clock_seq);
+	return memcmp(uuid1.node, uuid2.node, 6);
+}
+
diff --git a/libblkid/libuuid/src/copy.c b/libblkid/libuuid/src/copy.c
new file mode 100644
index 0000000..ead33aa
--- /dev/null
+++ b/libblkid/libuuid/src/copy.c
@@ -0,0 +1,45 @@
+/*
+ * copy.c --- copy UUIDs
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include "uuidP.h"
+
+void uuid_copy(uuid_t dst, const uuid_t src)
+{
+	unsigned char		*cp1;
+	const unsigned char	*cp2;
+	int			i;
+
+	for (i=0, cp1 = dst, cp2 = src; i < 16; i++)
+		*cp1++ = *cp2++;
+}
diff --git a/libblkid/libuuid/src/gen_uuid.c b/libblkid/libuuid/src/gen_uuid.c
new file mode 100644
index 0000000..eb79339
--- /dev/null
+++ b/libblkid/libuuid/src/gen_uuid.c
@@ -0,0 +1,545 @@
+/*
+ * gen_uuid.c --- generate a DCE-compatible uuid
+ *
+ * Copyright (C) 1996, 1997, 1998, 1999 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#ifdef _WIN32
+#define _WIN32_WINNT 0x0500
+#include <windows.h>
+#define UUID MYUUID
+#endif
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/stat.h>
+#ifdef HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NET_IF_DL_H
+#include <net/if_dl.h>
+#endif
+#if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H)
+#include <sys/syscall.h>
+#endif
+
+#include "all-io.h"
+#include "uuidP.h"
+#include "uuidd.h"
+#include "randutils.h"
+#include "c.h"
+
+#ifdef HAVE_TLS
+#define THREAD_LOCAL static __thread
+#else
+#define THREAD_LOCAL static
+#endif
+
+#ifdef _WIN32
+static void gettimeofday (struct timeval *tv, void *dummy)
+{
+	FILETIME	ftime;
+	uint64_t	n;
+
+	GetSystemTimeAsFileTime (&ftime);
+	n = (((uint64_t) ftime.dwHighDateTime << 32)
+	     + (uint64_t) ftime.dwLowDateTime);
+	if (n) {
+		n /= 10;
+		n -= ((369 * 365 + 89) * (uint64_t) 86400) * 1000000;
+	}
+
+	tv->tv_sec = n / 1000000;
+	tv->tv_usec = n % 1000000;
+}
+
+static int getuid (void)
+{
+	return 1;
+}
+#endif
+
+/*
+ * Get the ethernet hardware address, if we can find it...
+ *
+ * XXX for a windows version, probably should use GetAdaptersInfo:
+ * http://www.codeguru.com/cpp/i-n/network/networkinformation/article.php/c5451
+ * commenting out get_node_id just to get gen_uuid to compile under windows
+ * is not the right way to go!
+ */
+static int get_node_id(unsigned char *node_id)
+{
+#ifdef HAVE_NET_IF_H
+	int		sd;
+	struct ifreq	ifr, *ifrp;
+	struct ifconf	ifc;
+	char buf[1024];
+	int		n, i;
+	unsigned char	*a;
+#ifdef HAVE_NET_IF_DL_H
+	struct sockaddr_dl *sdlp;
+#endif
+
+/*
+ * BSD 4.4 defines the size of an ifreq to be
+ * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
+ * However, under earlier systems, sa_len isn't present, so the size is
+ * just sizeof(struct ifreq)
+ */
+#ifdef HAVE_SA_LEN
+#define ifreq_size(i) max(sizeof(struct ifreq),\
+     sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
+#else
+#define ifreq_size(i) sizeof(struct ifreq)
+#endif /* HAVE_SA_LEN */
+
+	sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+	if (sd < 0) {
+		return -1;
+	}
+	memset(buf, 0, sizeof(buf));
+	ifc.ifc_len = sizeof(buf);
+	ifc.ifc_buf = buf;
+	if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) {
+		close(sd);
+		return -1;
+	}
+	n = ifc.ifc_len;
+	for (i = 0; i < n; i+= ifreq_size(*ifrp) ) {
+		ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i);
+		strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
+#ifdef SIOCGIFHWADDR
+		if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
+			continue;
+		a = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
+#else
+#ifdef SIOCGENADDR
+		if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
+			continue;
+		a = (unsigned char *) ifr.ifr_enaddr;
+#else
+#ifdef HAVE_NET_IF_DL_H
+		sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr;
+		if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6))
+			continue;
+		a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen];
+#else
+		/*
+		 * XXX we don't have a way of getting the hardware
+		 * address
+		 */
+		close(sd);
+		return 0;
+#endif /* HAVE_NET_IF_DL_H */
+#endif /* SIOCGENADDR */
+#endif /* SIOCGIFHWADDR */
+		if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
+			continue;
+		if (node_id) {
+			memcpy(node_id, a, 6);
+			close(sd);
+			return 1;
+		}
+	}
+	close(sd);
+#endif
+	return 0;
+}
+
+/* Assume that the gettimeofday() has microsecond granularity */
+#define MAX_ADJUSTMENT 10
+
+/*
+ * Get clock from global sequence clock counter.
+ *
+ * Return -1 if the clock counter could not be opened/locked (in this case
+ * pseudorandom value is returned in @ret_clock_seq), otherwise return 0.
+ */
+static int get_clock(uint32_t *clock_high, uint32_t *clock_low,
+		     uint16_t *ret_clock_seq, int *num)
+{
+	THREAD_LOCAL int		adjustment = 0;
+	THREAD_LOCAL struct timeval	last = {0, 0};
+	THREAD_LOCAL int		state_fd = -2;
+	THREAD_LOCAL FILE		*state_f;
+	THREAD_LOCAL uint16_t		clock_seq;
+	struct timeval			tv;
+	uint64_t			clock_reg;
+	mode_t				save_umask;
+	int				len;
+	int				ret = 0;
+
+	if (state_fd == -2) {
+		save_umask = umask(0);
+		state_fd = open(LIBUUID_CLOCK_FILE, O_RDWR|O_CREAT|O_CLOEXEC, 0660);
+		(void) umask(save_umask);
+		if (state_fd != -1) {
+			state_f = fdopen(state_fd, "r+" UL_CLOEXECSTR);
+			if (!state_f) {
+				close(state_fd);
+				state_fd = -1;
+				ret = -1;
+			}
+		}
+		else
+			ret = -1;
+	}
+	if (state_fd >= 0) {
+		rewind(state_f);
+		while (flock(state_fd, LOCK_EX) < 0) {
+			if ((errno == EAGAIN) || (errno == EINTR))
+				continue;
+			fclose(state_f);
+			close(state_fd);
+			state_fd = -1;
+			ret = -1;
+			break;
+		}
+	}
+	if (state_fd >= 0) {
+		unsigned int cl;
+		unsigned long tv1, tv2;
+		int a;
+
+		if (fscanf(state_f, "clock: %04x tv: %lu %lu adj: %d\n",
+			   &cl, &tv1, &tv2, &a) == 4) {
+			clock_seq = cl & 0x3FFF;
+			last.tv_sec = tv1;
+			last.tv_usec = tv2;
+			adjustment = a;
+		}
+	}
+
+	if ((last.tv_sec == 0) && (last.tv_usec == 0)) {
+		random_get_bytes(&clock_seq, sizeof(clock_seq));
+		clock_seq &= 0x3FFF;
+		gettimeofday(&last, 0);
+		last.tv_sec--;
+	}
+
+try_again:
+	gettimeofday(&tv, 0);
+	if ((tv.tv_sec < last.tv_sec) ||
+	    ((tv.tv_sec == last.tv_sec) &&
+	     (tv.tv_usec < last.tv_usec))) {
+		clock_seq = (clock_seq+1) & 0x3FFF;
+		adjustment = 0;
+		last = tv;
+	} else if ((tv.tv_sec == last.tv_sec) &&
+	    (tv.tv_usec == last.tv_usec)) {
+		if (adjustment >= MAX_ADJUSTMENT)
+			goto try_again;
+		adjustment++;
+	} else {
+		adjustment = 0;
+		last = tv;
+	}
+
+	clock_reg = tv.tv_usec*10 + adjustment;
+	clock_reg += ((uint64_t) tv.tv_sec)*10000000;
+	clock_reg += (((uint64_t) 0x01B21DD2) << 32) + 0x13814000;
+
+	if (num && (*num > 1)) {
+		adjustment += *num - 1;
+		last.tv_usec += adjustment / 10;
+		adjustment = adjustment % 10;
+		last.tv_sec += last.tv_usec / 1000000;
+		last.tv_usec = last.tv_usec % 1000000;
+	}
+
+	if (state_fd >= 0) {
+		rewind(state_f);
+		len = fprintf(state_f,
+			      "clock: %04x tv: %016lu %08lu adj: %08d\n",
+			      clock_seq, last.tv_sec, last.tv_usec, adjustment);
+		fflush(state_f);
+		if (ftruncate(state_fd, len) < 0) {
+			fprintf(state_f, "                   \n");
+			fflush(state_f);
+		}
+		rewind(state_f);
+		flock(state_fd, LOCK_UN);
+	}
+
+	*clock_high = clock_reg >> 32;
+	*clock_low = clock_reg;
+	*ret_clock_seq = clock_seq;
+	return ret;
+}
+
+#if defined(HAVE_UUIDD) && defined(HAVE_SYS_UN_H)
+/*
+ * Try using the uuidd daemon to generate the UUID
+ *
+ * Returns 0 on success, non-zero on failure.
+ */
+static int get_uuid_via_daemon(int op, uuid_t out, int *num)
+{
+	char op_buf[64];
+	int op_len;
+	int s;
+	ssize_t ret;
+	int32_t reply_len = 0, expected = 16;
+	struct sockaddr_un srv_addr;
+
+	if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+		return -1;
+
+	srv_addr.sun_family = AF_UNIX;
+	strcpy(srv_addr.sun_path, UUIDD_SOCKET_PATH);
+
+	if (connect(s, (const struct sockaddr *) &srv_addr,
+		    sizeof(struct sockaddr_un)) < 0)
+		goto fail;
+
+	op_buf[0] = op;
+	op_len = 1;
+	if (op == UUIDD_OP_BULK_TIME_UUID) {
+		memcpy(op_buf+1, num, sizeof(*num));
+		op_len += sizeof(*num);
+		expected += sizeof(*num);
+	}
+
+	ret = write(s, op_buf, op_len);
+	if (ret < 1)
+		goto fail;
+
+	ret = read_all(s, (char *) &reply_len, sizeof(reply_len));
+	if (ret < 0)
+		goto fail;
+
+	if (reply_len != expected)
+		goto fail;
+
+	ret = read_all(s, op_buf, reply_len);
+
+	if (op == UUIDD_OP_BULK_TIME_UUID)
+		memcpy(op_buf+16, num, sizeof(int));
+
+	memcpy(out, op_buf, 16);
+
+	close(s);
+	return ((ret == expected) ? 0 : -1);
+
+fail:
+	close(s);
+	return -1;
+}
+
+#else /* !defined(HAVE_UUIDD) && defined(HAVE_SYS_UN_H) */
+static int get_uuid_via_daemon(int op, uuid_t out, int *num)
+{
+	return -1;
+}
+#endif
+
+int __uuid_generate_time(uuid_t out, int *num)
+{
+	static unsigned char node_id[6];
+	static int has_init = 0;
+	struct uuid uu;
+	uint32_t	clock_mid;
+	int ret;
+
+	if (!has_init) {
+		if (get_node_id(node_id) <= 0) {
+			random_get_bytes(node_id, 6);
+			/*
+			 * Set multicast bit, to prevent conflicts
+			 * with IEEE 802 addresses obtained from
+			 * network cards
+			 */
+			node_id[0] |= 0x01;
+		}
+		has_init = 1;
+	}
+	ret = get_clock(&clock_mid, &uu.time_low, &uu.clock_seq, num);
+	uu.clock_seq |= 0x8000;
+	uu.time_mid = (uint16_t) clock_mid;
+	uu.time_hi_and_version = ((clock_mid >> 16) & 0x0FFF) | 0x1000;
+	memcpy(uu.node, node_id, 6);
+	uuid_pack(&uu, out);
+	return ret;
+}
+
+/*
+ * Generate time-based UUID and store it to @out
+ *
+ * Tries to guarantee uniqueness of the generated UUIDs by obtaining them from the uuidd daemon,
+ * or, if uuidd is not usable, by using the global clock state counter (see get_clock()).
+ * If neither of these is possible (e.g. because of insufficient permissions), it generates
+ * the UUID anyway, but returns -1. Otherwise, returns 0.
+ */
+static int uuid_generate_time_generic(uuid_t out) {
+#ifdef HAVE_TLS
+	THREAD_LOCAL int		num = 0;
+	THREAD_LOCAL struct uuid	uu;
+	THREAD_LOCAL time_t		last_time = 0;
+	time_t				now;
+
+	if (num > 0) {
+		now = time(0);
+		if (now > last_time+1)
+			num = 0;
+	}
+	if (num <= 0) {
+		num = 1000;
+		if (get_uuid_via_daemon(UUIDD_OP_BULK_TIME_UUID,
+					out, &num) == 0) {
+			last_time = time(0);
+			uuid_unpack(out, &uu);
+			num--;
+			return 0;
+		}
+		num = 0;
+	}
+	if (num > 0) {
+		uu.time_low++;
+		if (uu.time_low == 0) {
+			uu.time_mid++;
+			if (uu.time_mid == 0)
+				uu.time_hi_and_version++;
+		}
+		num--;
+		uuid_pack(&uu, out);
+		return 0;
+	}
+#else
+	if (get_uuid_via_daemon(UUIDD_OP_TIME_UUID, out, 0) == 0)
+		return 0;
+#endif
+
+	return __uuid_generate_time(out, 0);
+}
+
+/*
+ * Generate time-based UUID and store it to @out.
+ *
+ * Discards return value from uuid_generate_time_generic()
+ */
+void uuid_generate_time(uuid_t out)
+{
+	(void)uuid_generate_time_generic(out);
+}
+
+
+int uuid_generate_time_safe(uuid_t out)
+{
+	return uuid_generate_time_generic(out);
+}
+
+
+void __uuid_generate_random(uuid_t out, int *num)
+{
+	uuid_t	buf;
+	struct uuid uu;
+	int i, n;
+
+	if (!num || !*num)
+		n = 1;
+	else
+		n = *num;
+
+	for (i = 0; i < n; i++) {
+		random_get_bytes(buf, sizeof(buf));
+		uuid_unpack(buf, &uu);
+
+		uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;
+		uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF)
+			| 0x4000;
+		uuid_pack(&uu, out);
+		out += sizeof(uuid_t);
+	}
+}
+
+void uuid_generate_random(uuid_t out)
+{
+	int	num = 1;
+	/* No real reason to use the daemon for random uuid's -- yet */
+
+	__uuid_generate_random(out, &num);
+}
+
+/*
+ * Check whether good random source (/dev/random or /dev/urandom)
+ * is available.
+ */
+static int have_random_source(void)
+{
+	struct stat s;
+
+	return (!stat("/dev/random", &s) || !stat("/dev/urandom", &s));
+}
+
+
+/*
+ * This is the generic front-end to uuid_generate_random and
+ * uuid_generate_time.  It uses uuid_generate_random only if
+ * /dev/urandom is available, since otherwise we won't have
+ * high-quality randomness.
+ */
+void uuid_generate(uuid_t out)
+{
+	if (have_random_source())
+		uuid_generate_random(out);
+	else
+		uuid_generate_time(out);
+}
diff --git a/libblkid/libuuid/src/isnull.c b/libblkid/libuuid/src/isnull.c
new file mode 100644
index 0000000..931e7e7
--- /dev/null
+++ b/libblkid/libuuid/src/isnull.c
@@ -0,0 +1,48 @@
+/*
+ * isnull.c --- Check whether or not the UUID is null
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include "uuidP.h"
+
+/* Returns 1 if the uuid is the NULL uuid */
+int uuid_is_null(const uuid_t uu)
+{
+	const unsigned char 	*cp;
+	int			i;
+
+	for (i=0, cp = uu; i < 16; i++)
+		if (*cp++)
+			return 0;
+	return 1;
+}
+
diff --git a/libblkid/libuuid/src/libuuid.sym b/libblkid/libuuid/src/libuuid.sym
new file mode 100644
index 0000000..28a2076
--- /dev/null
+++ b/libblkid/libuuid/src/libuuid.sym
@@ -0,0 +1,48 @@
+/*
+ * The symbol versioning ensures that a new application requiring symbol 'foo'
+ * can't run with old libbrary.so not providing 'foo' - the global SONAME
+ * version info can't enforce this since we never change the SONAME.
+ *
+ * The original libuuid from e2fsprogs (<=1.41.5) does not to use
+ * symbol versioning -- all the original symbols are in UUID_1.0 now.
+ *
+ * Copyright (C) 2011-2014 Karel Zak <kzak@redhat.com>
+ */
+UUID_1.0 {
+global:
+	uuid_clear;
+	uuid_compare;
+	uuid_copy;
+	uuid_generate;
+	uuid_generate_random;
+	uuid_generate_time;
+	uuid_is_null;
+	uuid_parse;
+	uuid_unparse;
+	uuid_unparse_lower;
+	uuid_unparse_upper;
+	uuid_time;
+	uuid_type;
+	uuid_variant;
+};
+
+/*
+ * version(s) since util-linux 2.20
+ */
+UUID_2.20 {
+global:
+	uuid_generate_time_safe;
+} UUID_1.0;
+
+
+/*
+ * __uuid_* this is not part of the official API, this is
+ * uuidd (uuid daemon) specific stuff. Hell.
+ */
+UUIDD_PRIVATE {
+global:
+	__uuid_generate_time;
+	__uuid_generate_random;
+local:
+	*;
+};
diff --git a/libblkid/libuuid/src/pack.c b/libblkid/libuuid/src/pack.c
new file mode 100644
index 0000000..6e12476
--- /dev/null
+++ b/libblkid/libuuid/src/pack.c
@@ -0,0 +1,69 @@
+/*
+ * Internal routine for packing UUIDs
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include <string.h>
+#include "uuidP.h"
+
+void uuid_pack(const struct uuid *uu, uuid_t ptr)
+{
+	uint32_t	tmp;
+	unsigned char	*out = ptr;
+
+	tmp = uu->time_low;
+	out[3] = (unsigned char) tmp;
+	tmp >>= 8;
+	out[2] = (unsigned char) tmp;
+	tmp >>= 8;
+	out[1] = (unsigned char) tmp;
+	tmp >>= 8;
+	out[0] = (unsigned char) tmp;
+
+	tmp = uu->time_mid;
+	out[5] = (unsigned char) tmp;
+	tmp >>= 8;
+	out[4] = (unsigned char) tmp;
+
+	tmp = uu->time_hi_and_version;
+	out[7] = (unsigned char) tmp;
+	tmp >>= 8;
+	out[6] = (unsigned char) tmp;
+
+	tmp = uu->clock_seq;
+	out[9] = (unsigned char) tmp;
+	tmp >>= 8;
+	out[8] = (unsigned char) tmp;
+
+	memcpy(out+10, uu->node, 6);
+}
+
diff --git a/libblkid/libuuid/src/parse.c b/libblkid/libuuid/src/parse.c
new file mode 100644
index 0000000..074383e
--- /dev/null
+++ b/libblkid/libuuid/src/parse.c
@@ -0,0 +1,79 @@
+/*
+ * parse.c --- UUID parsing
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "uuidP.h"
+
+int uuid_parse(const char *in, uuid_t uu)
+{
+	struct uuid	uuid;
+	int 		i;
+	const char	*cp;
+	char		buf[3];
+
+	if (strlen(in) != 36)
+		return -1;
+	for (i=0, cp = in; i <= 36; i++,cp++) {
+		if ((i == 8) || (i == 13) || (i == 18) ||
+		    (i == 23)) {
+			if (*cp == '-')
+				continue;
+			else
+				return -1;
+		}
+		if (i== 36)
+			if (*cp == 0)
+				continue;
+		if (!isxdigit(*cp))
+			return -1;
+	}
+	uuid.time_low = strtoul(in, NULL, 16);
+	uuid.time_mid = strtoul(in+9, NULL, 16);
+	uuid.time_hi_and_version = strtoul(in+14, NULL, 16);
+	uuid.clock_seq = strtoul(in+19, NULL, 16);
+	cp = in+24;
+	buf[2] = 0;
+	for (i=0; i < 6; i++) {
+		buf[0] = *cp++;
+		buf[1] = *cp++;
+		uuid.node[i] = strtoul(buf, NULL, 16);
+	}
+
+	uuid_pack(&uuid, uu);
+	return 0;
+}
diff --git a/libblkid/libuuid/src/test_uuid.c b/libblkid/libuuid/src/test_uuid.c
new file mode 100644
index 0000000..e03138f
--- /dev/null
+++ b/libblkid/libuuid/src/test_uuid.c
@@ -0,0 +1,180 @@
+/*
+ * tst_uuid.c --- test program from the UUID library
+ *
+ * Copyright (C) 1996, 1997, 1998 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#ifdef _WIN32
+#define _WIN32_WINNT 0x0500
+#include <windows.h>
+#define UUID MYUUID
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "uuid.h"
+
+static int test_uuid(const char * uuid, int isValid)
+{
+	static const char * validStr[2] = {"invalid", "valid"};
+	uuid_t uuidBits;
+	int parsedOk;
+
+	parsedOk = uuid_parse(uuid, uuidBits) == 0;
+
+	printf("%s is %s", uuid, validStr[isValid]);
+	if (parsedOk != isValid) {
+		printf(" but uuid_parse says %s\n", validStr[parsedOk]);
+		return 1;
+	}
+	printf(", OK\n");
+	return 0;
+}
+
+#ifdef __GNUC__
+#define ATTR(x) __attribute__(x)
+#else
+#define ATTR(x)
+#endif
+
+int
+main(int argc ATTR((unused)) , char **argv ATTR((unused)))
+{
+	uuid_t		buf, tst;
+	char		str[100];
+	struct timeval	tv;
+	time_t		time_reg;
+	unsigned char	*cp;
+	int i;
+	int failed = 0;
+	int type, variant;
+
+	uuid_generate(buf);
+	uuid_unparse(buf, str);
+	printf("UUID generate = %s\n", str);
+	printf("UUID: ");
+	for (i=0, cp = (unsigned char *) &buf; i < 16; i++) {
+		printf("%02x", *cp++);
+	}
+	printf("\n");
+	type = uuid_type(buf); 	variant = uuid_variant(buf);
+	printf("UUID type = %d, UUID variant = %d\n", type, variant);
+	if (variant != UUID_VARIANT_DCE) {
+		printf("Incorrect UUID Variant; was expecting DCE!\n");
+		failed++;
+	}
+	printf("\n");
+
+	uuid_generate_random(buf);
+	uuid_unparse(buf, str);
+	printf("UUID random string = %s\n", str);
+	printf("UUID: ");
+	for (i=0, cp = (unsigned char *) &buf; i < 16; i++) {
+		printf("%02x", *cp++);
+	}
+	printf("\n");
+	type = uuid_type(buf); 	variant = uuid_variant(buf);
+	printf("UUID type = %d, UUID variant = %d\n", type, variant);
+	if (variant != UUID_VARIANT_DCE) {
+		printf("Incorrect UUID Variant; was expecting DCE!\n");
+		failed++;
+	}
+	if (type != 4) {
+		printf("Incorrect UUID type; was expecting "
+		       "4 (random type)!\n");
+		failed++;
+	}
+	printf("\n");
+
+	uuid_generate_time(buf);
+	uuid_unparse(buf, str);
+	printf("UUID string = %s\n", str);
+	printf("UUID time: ");
+	for (i=0, cp = (unsigned char *) &buf; i < 16; i++) {
+		printf("%02x", *cp++);
+	}
+	printf("\n");
+	type = uuid_type(buf); 	variant = uuid_variant(buf);
+	printf("UUID type = %d, UUID variant = %d\n", type, variant);
+	if (variant != UUID_VARIANT_DCE) {
+		printf("Incorrect UUID Variant; was expecting DCE!\n");
+		failed++;
+	}
+	if (type != 1) {
+		printf("Incorrect UUID type; was expecting "
+		       "1 (time-based type)!\\n");
+		failed++;
+	}
+	tv.tv_sec = 0;
+	tv.tv_usec = 0;
+	time_reg = uuid_time(buf, &tv);
+	printf("UUID time is: (%ld, %ld): %s\n", tv.tv_sec, tv.tv_usec,
+	       ctime(&time_reg));
+	uuid_parse(str, tst);
+	if (!uuid_compare(buf, tst))
+		printf("UUID parse and compare succeeded.\n");
+	else {
+		printf("UUID parse and compare failed!\n");
+		failed++;
+	}
+	uuid_clear(tst);
+	if (uuid_is_null(tst))
+		printf("UUID clear and is null succeeded.\n");
+	else {
+		printf("UUID clear and is null failed!\n");
+		failed++;
+	}
+	uuid_copy(buf, tst);
+	if (!uuid_compare(buf, tst))
+		printf("UUID copy and compare succeeded.\n");
+	else {
+		printf("UUID copy and compare failed!\n");
+		failed++;
+	}
+	failed += test_uuid("84949cc5-4701-4a84-895b-354c584a981b", 1);
+	failed += test_uuid("84949CC5-4701-4A84-895B-354C584A981B", 1);
+	failed += test_uuid("84949cc5-4701-4a84-895b-354c584a981bc", 0);
+	failed += test_uuid("84949cc5-4701-4a84-895b-354c584a981", 0);
+	failed += test_uuid("84949cc5x4701-4a84-895b-354c584a981b", 0);
+	failed += test_uuid("84949cc504701-4a84-895b-354c584a981b", 0);
+	failed += test_uuid("84949cc5-470104a84-895b-354c584a981b", 0);
+	failed += test_uuid("84949cc5-4701-4a840895b-354c584a981b", 0);
+	failed += test_uuid("84949cc5-4701-4a84-895b0354c584a981b", 0);
+	failed += test_uuid("g4949cc5-4701-4a84-895b-354c584a981b", 0);
+	failed += test_uuid("84949cc5-4701-4a84-895b-354c584a981g", 0);
+
+	if (failed) {
+		printf("%d failures.\n", failed);
+		exit(1);
+	}
+	return 0;
+}
diff --git a/libblkid/libuuid/src/unpack.c b/libblkid/libuuid/src/unpack.c
new file mode 100644
index 0000000..beaaff3
--- /dev/null
+++ b/libblkid/libuuid/src/unpack.c
@@ -0,0 +1,63 @@
+/*
+ * Internal routine for unpacking UUID
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include <string.h>
+#include "uuidP.h"
+
+void uuid_unpack(const uuid_t in, struct uuid *uu)
+{
+	const uint8_t	*ptr = in;
+	uint32_t		tmp;
+
+	tmp = *ptr++;
+	tmp = (tmp << 8) | *ptr++;
+	tmp = (tmp << 8) | *ptr++;
+	tmp = (tmp << 8) | *ptr++;
+	uu->time_low = tmp;
+
+	tmp = *ptr++;
+	tmp = (tmp << 8) | *ptr++;
+	uu->time_mid = tmp;
+
+	tmp = *ptr++;
+	tmp = (tmp << 8) | *ptr++;
+	uu->time_hi_and_version = tmp;
+
+	tmp = *ptr++;
+	tmp = (tmp << 8) | *ptr++;
+	uu->clock_seq = tmp;
+
+	memcpy(uu->node, ptr, 6);
+}
+
diff --git a/libblkid/libuuid/src/unparse.c b/libblkid/libuuid/src/unparse.c
new file mode 100644
index 0000000..a95bbb0
--- /dev/null
+++ b/libblkid/libuuid/src/unparse.c
@@ -0,0 +1,76 @@
+/*
+ * unparse.c -- convert a UUID to string
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+
+#include "uuidP.h"
+
+static const char *fmt_lower =
+	"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
+
+static const char *fmt_upper =
+	"%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X";
+
+#ifdef UUID_UNPARSE_DEFAULT_UPPER
+#define FMT_DEFAULT fmt_upper
+#else
+#define FMT_DEFAULT fmt_lower
+#endif
+
+static void uuid_unparse_x(const uuid_t uu, char *out, const char *fmt)
+{
+	struct uuid uuid;
+
+	uuid_unpack(uu, &uuid);
+	sprintf(out, fmt,
+		uuid.time_low, uuid.time_mid, uuid.time_hi_and_version,
+		uuid.clock_seq >> 8, uuid.clock_seq & 0xFF,
+		uuid.node[0], uuid.node[1], uuid.node[2],
+		uuid.node[3], uuid.node[4], uuid.node[5]);
+}
+
+void uuid_unparse_lower(const uuid_t uu, char *out)
+{
+	uuid_unparse_x(uu, out,	fmt_lower);
+}
+
+void uuid_unparse_upper(const uuid_t uu, char *out)
+{
+	uuid_unparse_x(uu, out,	fmt_upper);
+}
+
+void uuid_unparse(const uuid_t uu, char *out)
+{
+	uuid_unparse_x(uu, out, FMT_DEFAULT);
+}
diff --git a/libblkid/libuuid/src/uuid.h b/libblkid/libuuid/src/uuid.h
new file mode 100644
index 0000000..30bd4c0
--- /dev/null
+++ b/libblkid/libuuid/src/uuid.h
@@ -0,0 +1,104 @@
+/*
+ * Public include file for the UUID library
+ *
+ * Copyright (C) 1996, 1997, 1998 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#ifndef _UUID_UUID_H
+#define _UUID_UUID_H
+
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/time.h>
+#endif
+#include <time.h>
+
+typedef unsigned char uuid_t[16];
+
+/* UUID Variant definitions */
+#define UUID_VARIANT_NCS	0
+#define UUID_VARIANT_DCE	1
+#define UUID_VARIANT_MICROSOFT	2
+#define UUID_VARIANT_OTHER	3
+
+/* UUID Type definitions */
+#define UUID_TYPE_DCE_TIME   1
+#define UUID_TYPE_DCE_RANDOM 4
+
+/* Allow UUID constants to be defined */
+#ifdef __GNUC__
+#define UUID_DEFINE(name,u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15) \
+	static const uuid_t name __attribute__ ((unused)) = {u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15}
+#else
+#define UUID_DEFINE(name,u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15) \
+	static const uuid_t name = {u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15}
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* clear.c */
+extern void uuid_clear(uuid_t uu);
+
+/* compare.c */
+extern int uuid_compare(const uuid_t uu1, const uuid_t uu2);
+
+/* copy.c */
+extern void uuid_copy(uuid_t dst, const uuid_t src);
+
+/* gen_uuid.c */
+extern void uuid_generate(uuid_t out);
+extern void uuid_generate_random(uuid_t out);
+extern void uuid_generate_time(uuid_t out);
+extern int uuid_generate_time_safe(uuid_t out);
+
+/* isnull.c */
+extern int uuid_is_null(const uuid_t uu);
+
+/* parse.c */
+extern int uuid_parse(const char *in, uuid_t uu);
+
+/* unparse.c */
+extern void uuid_unparse(const uuid_t uu, char *out);
+extern void uuid_unparse_lower(const uuid_t uu, char *out);
+extern void uuid_unparse_upper(const uuid_t uu, char *out);
+
+/* uuid_time.c */
+extern time_t uuid_time(const uuid_t uu, struct timeval *ret_tv);
+extern int uuid_type(const uuid_t uu);
+extern int uuid_variant(const uuid_t uu);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UUID_UUID_H */
diff --git a/libblkid/libuuid/src/uuidP.h b/libblkid/libuuid/src/uuidP.h
new file mode 100644
index 0000000..86a5e26
--- /dev/null
+++ b/libblkid/libuuid/src/uuidP.h
@@ -0,0 +1,61 @@
+/*
+ * uuid.h -- private header file for uuids
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include <inttypes.h>
+#include <sys/types.h>
+
+#include "uuid.h"
+
+#define LIBUUID_CLOCK_FILE	"/var/lib/libuuid/clock.txt"
+
+/*
+ * Offset between 15-Oct-1582 and 1-Jan-70
+ */
+#define TIME_OFFSET_HIGH 0x01B21DD2
+#define TIME_OFFSET_LOW  0x13814000
+
+struct uuid {
+	uint32_t	time_low;
+	uint16_t	time_mid;
+	uint16_t	time_hi_and_version;
+	uint16_t	clock_seq;
+	uint8_t	node[6];
+};
+
+
+/*
+ * prototypes
+ */
+void uuid_pack(const struct uuid *uu, uuid_t ptr);
+void uuid_unpack(const uuid_t in, struct uuid *uu);
diff --git a/libblkid/libuuid/src/uuid_time.c b/libblkid/libuuid/src/uuid_time.c
new file mode 100644
index 0000000..f25f5c9
--- /dev/null
+++ b/libblkid/libuuid/src/uuid_time.c
@@ -0,0 +1,171 @@
+/*
+ * uuid_time.c --- Interpret the time field from a uuid.  This program
+ * 	violates the UUID abstraction barrier by reaching into the guts
+ *	of a UUID and interpreting it.
+ *
+ * Copyright (C) 1998, 1999 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#ifdef _WIN32
+#define _WIN32_WINNT 0x0500
+#include <windows.h>
+#define UUID MYUUID
+#endif
+
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <sys/types.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <time.h>
+
+#include "uuidP.h"
+
+time_t uuid_time(const uuid_t uu, struct timeval *ret_tv)
+{
+	struct timeval		tv;
+	struct uuid		uuid;
+	uint32_t		high;
+	uint64_t		clock_reg;
+
+	uuid_unpack(uu, &uuid);
+
+	high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16);
+	clock_reg = uuid.time_low | ((uint64_t) high << 32);
+
+	clock_reg -= (((uint64_t) 0x01B21DD2) << 32) + 0x13814000;
+	tv.tv_sec = clock_reg / 10000000;
+	tv.tv_usec = (clock_reg % 10000000) / 10;
+
+	if (ret_tv)
+		*ret_tv = tv;
+
+	return tv.tv_sec;
+}
+
+int uuid_type(const uuid_t uu)
+{
+	struct uuid		uuid;
+
+	uuid_unpack(uu, &uuid);
+	return ((uuid.time_hi_and_version >> 12) & 0xF);
+}
+
+int uuid_variant(const uuid_t uu)
+{
+	struct uuid		uuid;
+	int			var;
+
+	uuid_unpack(uu, &uuid);
+	var = uuid.clock_seq;
+
+	if ((var & 0x8000) == 0)
+		return UUID_VARIANT_NCS;
+	if ((var & 0x4000) == 0)
+		return UUID_VARIANT_DCE;
+	if ((var & 0x2000) == 0)
+		return UUID_VARIANT_MICROSOFT;
+	return UUID_VARIANT_OTHER;
+}
+
+#ifdef DEBUG
+static const char *variant_string(int variant)
+{
+	switch (variant) {
+	case UUID_VARIANT_NCS:
+		return "NCS";
+	case UUID_VARIANT_DCE:
+		return "DCE";
+	case UUID_VARIANT_MICROSOFT:
+		return "Microsoft";
+	default:
+		return "Other";
+	}
+}
+
+
+int
+main(int argc, char **argv)
+{
+	uuid_t		buf;
+	time_t		time_reg;
+	struct timeval	tv;
+	int		type, variant;
+
+	if (argc != 2) {
+		fprintf(stderr, "Usage: %s uuid\n", argv[0]);
+		exit(1);
+	}
+	if (uuid_parse(argv[1], buf)) {
+		fprintf(stderr, "Invalid UUID: %s\n", argv[1]);
+		exit(1);
+	}
+	variant = uuid_variant(buf);
+	type = uuid_type(buf);
+	time_reg = uuid_time(buf, &tv);
+
+	printf("UUID variant is %d (%s)\n", variant, variant_string(variant));
+	if (variant != UUID_VARIANT_DCE) {
+		printf("Warning: This program only knows how to interpret "
+		       "DCE UUIDs.\n\tThe rest of the output is likely "
+		       "to be incorrect!!\n");
+	}
+	printf("UUID type is %d", type);
+	switch (type) {
+	case 1:
+		printf(" (time based)\n");
+		break;
+	case 2:
+		printf(" (DCE)\n");
+		break;
+	case 3:
+		printf(" (name-based)\n");
+		break;
+	case 4:
+		printf(" (random)\n");
+		break;
+	default:
+		printf("\n");
+	}
+	if (type != 1) {
+		printf("Warning: not a time-based UUID, so UUID time "
+		       "decoding will likely not work!\n");
+	}
+	printf("UUID time is: (%ld, %ld): %s\n", tv.tv_sec, tv.tv_usec,
+	       ctime(&time_reg));
+
+	return 0;
+}
+#endif
diff --git a/libblkid/libuuid/src/uuidd.h b/libblkid/libuuid/src/uuidd.h
new file mode 100644
index 0000000..2f70968
--- /dev/null
+++ b/libblkid/libuuid/src/uuidd.h
@@ -0,0 +1,54 @@
+/*
+ * Definitions used by the uuidd daemon
+ *
+ * Copyright (C) 2007 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#ifndef _UUID_UUIDD_H
+#define _UUID_UUIDD_H
+
+#define UUIDD_DIR		_PATH_LOCALSTATEDIR "/uuidd"
+#define UUIDD_SOCKET_PATH	UUIDD_DIR "/request"
+#define UUIDD_PIDFILE_PATH	UUIDD_DIR "/uuidd.pid"
+#define UUIDD_PATH		"/usr/sbin/uuidd"
+
+#define UUIDD_OP_GETPID			0
+#define UUIDD_OP_GET_MAXOP		1
+#define UUIDD_OP_TIME_UUID		2
+#define UUIDD_OP_RANDOM_UUID		3
+#define UUIDD_OP_BULK_TIME_UUID		4
+#define UUIDD_OP_BULK_RANDOM_UUID	5
+#define UUIDD_MAX_OP			UUIDD_OP_BULK_RANDOM_UUID
+
+extern int __uuid_generate_time(uuid_t out, int *num);
+extern void __uuid_generate_random(uuid_t out, int *num);
+
+#endif /* _UUID_UUID_H */
diff --git a/libblkid/libuuid/uuid.pc.in b/libblkid/libuuid/uuid.pc.in
new file mode 100644
index 0000000..875de19
--- /dev/null
+++ b/libblkid/libuuid/uuid.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@usrlib_execdir@
+includedir=@includedir@
+
+Name: uuid
+Description: Universally unique id library
+Version: @LIBUUID_VERSION@
+Requires:
+Cflags: -I${includedir}/uuid
+Libs: -L${libdir} -luuid
diff --git a/libblkid/llseek.c b/libblkid/llseek.c
deleted file mode 100644
index be4fdd3..0000000
--- a/libblkid/llseek.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * llseek.c -- stub calling the llseek system call
- *
- * Copyright (C) 1994, 1995, 1996, 1997 Theodore Ts'o.
- *
- * %Begin-Header%
- * This file may be redistributed under the terms of the
- * GNU Lesser General Public License.
- * %End-Header%
- */
-
-#define _LARGEFILE_SOURCE
-#define _LARGEFILE64_SOURCE
-
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef __MSDOS__
-#include <io.h>
-#endif
-
-#include "blkidP.h"
-
-#ifdef __linux__
-
-#define my_llseek lseek64
-#include <linux/unistd.h>
-
-#ifndef __NR__llseek
-#define __NR__llseek            140
-#endif
-
-blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int whence)
-{
-	blkid_loff_t result;
-	static int do_compat = 0;
-
-	if ((sizeof(off_t) >= sizeof(blkid_loff_t)) ||
-	    (offset < ((blkid_loff_t) 1 << ((sizeof(off_t)*8) -1))))
-		return lseek(fd, (off_t) offset, whence);
-
-	if (do_compat) {
-		errno = EOVERFLOW;
-		return -1;
-	}
-
-	if (result == -1 && errno == ENOSYS) {
-		/*
-		 * Just in case this code runs on top of an old kernel
-		 * which does not support the llseek system call
-		 */
-		do_compat++;
-		errno = EOVERFLOW;
-	}
-	return result;
-}
-
-#else /* !linux */
-
-#ifndef EOVERFLOW
-#ifdef EXT2_ET_INVALID_ARGUMENT
-#define EOVERFLOW EXT2_ET_INVALID_ARGUMENT
-#else
-#define EOVERFLOW 112
-#endif
-#endif
-
-blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int origin)
-{
-#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE)
-	return lseek64 (fd, offset, origin);
-#else
-	if ((sizeof(off_t) < sizeof(blkid_loff_t)) &&
-	    (offset >= ((blkid_loff_t) 1 << ((sizeof(off_t)*8) - 1)))) {
-		errno = EOVERFLOW;
-		return -1;
-	}
-	return lseek(fd, (off_t) offset, origin);
-#endif
-}
-
-#endif	/* linux */
-
-
diff --git a/libblkid/minix1.c b/libblkid/minix1.c
deleted file mode 100644
index 54e7139..0000000
--- a/libblkid/minix1.c
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 1999 by Andries Brouwer
- * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
- * Copyright (C) 2001 by Andreas Dilger
- * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
- * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
- *
- * This file may be redistributed under the terms of the
- * GNU Lesser General Public License.
- */
-
-#include <string.h>
-#include "superblocks.h"
-#include "minix.h"
-
-static int probe_minix(blkid_probe pr, const struct blkid_idmag *mag)
-{
-	unsigned char *ext;
-	int version;
-
-	/* for more details see magic strings below */
-	switch(mag->magic[1]) {
-	case '\023':
-		version = 1;
-		break;
-	case '\044':
-		version = 2;
-		break;
-	case '\115':
-		version = 3;
-		break;
-	default:
-		return -1;
-		break;
-	}
-
-	if (version <= 2) {
-		struct minix_super_block *sb;
-		uint32_t zones;
-
-		sb = blkid_probe_get_sb(pr, mag, struct minix_super_block);
-		if (!sb || sb->s_imap_blocks == 0 || sb->s_zmap_blocks == 0)
-			return -1;
-
-		zones = version == 2 ? sb->s_zones : sb->s_nzones;
-
-		/* sanity checks to be sure that the FS is really minix */
-		if (sb->s_imap_blocks * MINIX_BLOCK_SIZE * 8 < sb->s_ninodes + 1)
-			return -1;
-		if (sb->s_zmap_blocks * MINIX_BLOCK_SIZE * 8 < zones - sb->s_firstdatazone + 1)
-			return -1;
-
-	} else if (version == 3) {
-		struct minix3_super_block *sb;
-
-		sb = blkid_probe_get_sb(pr, mag, struct minix3_super_block);
-		if (!sb || sb->s_imap_blocks == 0 || sb->s_zmap_blocks == 0)
-			return -1;
-
-	}
-
-	/* unfortunately, some parts of ext3 is sometimes possible to
-	 * interpreted as minix superblock. So check for extN magic
-	 * string. (For extN magic string and offsets see ext.c.)
-	 */
-	ext = blkid_probe_get_buffer(pr, 0x400 + 0x38, 2);
-	if (ext && memcmp(ext, "\123\357", 2) == 0)
-		return -1;
-
-	blkid_probe_sprintf_version(pr, "%d", version);
-	return 0;
-}
-
-const struct blkid_idinfo minix_idinfo =
-{
-	.name		= "minix",
-	.usage		= BLKID_USAGE_FILESYSTEM,
-	.probefunc	= probe_minix,
-	.magics		=
-	{
-		/* version 1 */
-		{ .magic = "\177\023", .len = 2, .kboff = 1, .sboff = 0x10 },
-		{ .magic = "\217\023", .len = 2, .kboff = 1, .sboff = 0x10 },
-
-		/* version 2 */
-		{ .magic = "\150\044", .len = 2, .kboff = 1, .sboff = 0x10 },
-		{ .magic = "\170\044", .len = 2, .kboff = 1, .sboff = 0x10 },
-
-		/* version 3 */
-		{ .magic = "\132\115", .len = 2, .kboff = 1, .sboff = 0x18 },
-		{ NULL }
-	}
-};
-
diff --git a/libblkid/procutils.c b/libblkid/procutils.c
deleted file mode 100644
index 52e9ee3..0000000
--- a/libblkid/procutils.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2011 Davidlohr Bueso <dave@gnu.org>
- *
- * procutils.c: General purpose procfs parsing utilities
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Library Public License as published by
- * the Free Software Foundation; either version 2, 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 Library Public License for more details.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <ctype.h>
-
-#include "procutils.h"
-#include "c.h"
-
-/*
- * @pid: process ID for which we want to obtain the threads group
- *
- * Returns: newly allocated tasks structure
- */
-struct proc_tasks *proc_open_tasks(pid_t pid)
-{
-	struct proc_tasks *tasks;
-	char path[PATH_MAX];
-
-	sprintf(path, "/proc/%d/task/", pid);
-
-	tasks = malloc(sizeof(struct proc_tasks));
-	if (tasks) {
-		tasks->dir = opendir(path);
-		if (tasks->dir)
-			return tasks;
-	}
-
-	free(tasks);
-	return NULL;
-}
-
-/*
- * @tasks: allocated tasks structure
- *
- * Returns: nothing
- */
-void proc_close_tasks(struct proc_tasks *tasks)
-{
-	if (tasks && tasks->dir)
-		closedir(tasks->dir);
-	free(tasks);
-}
-
-/*
- * @tasks: allocated task structure
- * @tid: [output] one of the thread IDs belonging to the thread group
- *        If when an error occurs, it is set to 0.
- *
- * Returns: 0 on success, 1 on end, -1 on failure or no more threads
- */
-int proc_next_tid(struct proc_tasks *tasks, pid_t *tid)
-{
-	struct dirent *d;
-	char *end;
-
-	if (!tasks || !tid)
-		return -1;
-
-	*tid = 0;
-	errno = 0;
-
-	do {
-		d = readdir(tasks->dir);
-		if (!d)
-			return errno ? -1 : 1;		/* error or end-of-dir */
-
-		if (!isdigit((unsigned char) *d->d_name))
-			continue;
-
-		*tid = (pid_t) strtol(d->d_name, &end, 10);
-		if (errno || d->d_name == end || (end && *end))
-			return -1;
-
-	} while (!*tid);
-
-	return 0;
-}
-
-#ifdef TEST_PROGRAM
-
-int main(int argc, char *argv[])
-{
-	pid_t tid, pid;
-	struct proc_tasks *ts;
-
-	if (argc != 2) {
-		fprintf(stderr, "usage: %s <pid>\n", argv[0]);
-		return EXIT_FAILURE;
-	}
-
-	pid = strtol(argv[1], (char **) NULL, 10);
-	printf("PID=%d, TIDs:", pid);
-
-	ts = proc_open_tasks(pid);
-	if (!ts)
-		err(EXIT_FAILURE, "open list of tasks failed");
-
-	while (proc_next_tid(ts, &tid) == 0)
-		printf(" %d", tid);
-
-	printf("\n");
-        proc_close_tasks(ts);
-	return EXIT_SUCCESS;
-}
-#endif /* TEST_PROGRAM */
diff --git a/libblkid/procutils.h b/libblkid/procutils.h
deleted file mode 100644
index ca7087a..0000000
--- a/libblkid/procutils.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef UTIL_LINUX_PROCUTILS
-#define UTIL_LINUX_PROCUTILS
-
-#include <dirent.h>
-
-struct proc_tasks {
-	DIR *dir;
-};
-
-extern struct proc_tasks *proc_open_tasks(pid_t pid);
-extern void proc_close_tasks(struct proc_tasks *tasks);
-extern int proc_next_tid(struct proc_tasks *tasks, pid_t *tid);
-
-#endif /* UTIL_LINUX_PROCUTILS */
diff --git a/libblkid/samples/.gitignore b/libblkid/samples/.gitignore
new file mode 100644
index 0000000..4efeb62
--- /dev/null
+++ b/libblkid/samples/.gitignore
@@ -0,0 +1,4 @@
+mkfs
+partitions
+superblocks
+topology
diff --git a/libblkid/samples/Makemodule.am b/libblkid/samples/Makemodule.am
new file mode 100644
index 0000000..0ffbf14
--- /dev/null
+++ b/libblkid/samples/Makemodule.am
@@ -0,0 +1,22 @@
+
+check_PROGRAMS += \
+	sample-mkfs \
+	sample-partitions \
+	sample-superblocks \
+	sample-topology
+
+sample_mkfs_SOURCES = libblkid/samples/mkfs.c
+sample_mkfs_LDADD = libblkid.la
+sample_mkfs_CFLAGS = -I$(ul_libblkid_incdir)
+
+sample_partitions_SOURCES = libblkid/samples/partitions.c
+sample_partitions_LDADD = libblkid.la
+sample_partitions_CFLAGS = -I$(ul_libblkid_incdir)
+
+sample_superblocks_SOURCES = libblkid/samples/superblocks.c
+sample_superblocks_LDADD = libblkid.la
+sample_superblocks_CFLAGS = -I$(ul_libblkid_incdir)
+
+sample_topology_SOURCES = libblkid/samples/topology.c
+sample_topology_LDADD = libblkid.la
+sample_topology_CFLAGS = -I$(ul_libblkid_incdir)
diff --git a/libblkid/samples/mkfs.c b/libblkid/samples/mkfs.c
new file mode 100644
index 0000000..5c3ebe7
--- /dev/null
+++ b/libblkid/samples/mkfs.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <blkid.h>
+
+#include "c.h"
+
+int main(int argc, char *argv[])
+{
+	int rc;
+	char *devname;
+	blkid_probe pr;
+	blkid_topology tp;
+
+	if (argc < 2) {
+		fprintf(stderr, "usage: %s <device>  "
+			"-- checks based on libblkid for mkfs-like programs.\n",
+			program_invocation_short_name);
+		return EXIT_FAILURE;
+	}
+
+	devname = argv[1];
+	pr = blkid_new_probe_from_filename(devname);
+	if (!pr)
+		err(EXIT_FAILURE, "%s: faild to create a new libblkid probe",
+				devname);
+
+	/*
+	 * check Filesystems / Partitions overwrite
+	 */
+
+	/* enable partitions probing (superblocks are enabled by default) */
+	blkid_probe_enable_partitions(pr, TRUE);
+
+	rc = blkid_do_fullprobe(pr);
+	if (rc == -1)
+		errx(EXIT_FAILURE, "%s: blkid_do_fullprobe() failed", devname);
+	else if (rc == 0) {
+		const char *type;
+
+		if (!blkid_probe_lookup_value(pr, "TYPE", &type, NULL))
+			errx(EXIT_FAILURE, "%s: appears to contain an existing "
+					"%s superblock", devname, type);
+
+		if (!blkid_probe_lookup_value(pr, "PTTYPE", &type, NULL))
+			errx(EXIT_FAILURE, "%s: appears to contain an partition "
+					"table (%s)", devname, type);
+	}
+
+	/*
+	 * get topology details
+	 */
+	tp = blkid_probe_get_topology(pr);
+	if (!tp)
+		errx(EXIT_FAILURE, "%s: failed to read topology", devname);
+
+
+	/* ... your mkfs.<type> code or so ...
+
+	off = blkid_topology_get_alignment_offset(tp);
+
+	 */
+
+	blkid_free_probe(pr);
+
+	return EXIT_SUCCESS;
+}
diff --git a/libblkid/samples/partitions.c b/libblkid/samples/partitions.c
new file mode 100644
index 0000000..fe0ad48
--- /dev/null
+++ b/libblkid/samples/partitions.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <blkid.h>
+#include "c.h"
+
+int main(int argc, char *argv[])
+{
+	int i, nparts;
+	char *devname;
+	blkid_probe pr;
+	blkid_partlist ls;
+	blkid_parttable root_tab;
+
+	if (argc < 2) {
+		fprintf(stderr, "usage: %s <device|file>  "
+				"-- prints partitions\n",
+				program_invocation_short_name);
+		return EXIT_FAILURE;
+	}
+
+	devname = argv[1];
+	pr = blkid_new_probe_from_filename(devname);
+	if (!pr)
+		err(EXIT_FAILURE, "%s: faild to create a new libblkid probe",
+				devname);
+	/* Binary interface */
+	ls = blkid_probe_get_partitions(pr);
+	if (!ls)
+		errx(EXIT_FAILURE, "%s: failed to read partitions\n", devname);
+
+	/*
+	 * Print info about the primary (root) partition table
+	 */
+	root_tab = blkid_partlist_get_table(ls);
+	if (!root_tab)
+		errx(EXIT_FAILURE, "%s: does not contains any "
+				 "known partition table\n", devname);
+
+	printf("size: %jd, sector size: %u, PT: %s, offset: %jd, id=%s\n---\n",
+		blkid_probe_get_size(pr),
+		blkid_probe_get_sectorsize(pr),
+		blkid_parttable_get_type(root_tab),
+		blkid_parttable_get_offset(root_tab),
+		blkid_parttable_get_id(root_tab));
+
+	/*
+	 * List partitions
+	 */
+	nparts = blkid_partlist_numof_partitions(ls);
+	if (!nparts)
+		goto done;
+
+	for (i = 0; i < nparts; i++) {
+		const char *p;
+		blkid_partition par = blkid_partlist_get_partition(ls, i);
+		blkid_parttable tab = blkid_partition_get_table(par);
+
+		printf("#%d: %10llu %10llu  0x%x",
+			blkid_partition_get_partno(par),
+			(unsigned long long) blkid_partition_get_start(par),
+			(unsigned long long) blkid_partition_get_size(par),
+			blkid_partition_get_type(par));
+
+		if (root_tab != tab)
+			/* subpartition (BSD, Minix, ...) */
+			printf(" (%s)", blkid_parttable_get_type(tab));
+
+		p = blkid_partition_get_name(par);
+		if (p)
+			printf(" name='%s'", p);
+		p = blkid_partition_get_uuid(par);
+		if (p)
+			printf(" uuid='%s'", p);
+		p = blkid_partition_get_type_string(par);
+		if (p)
+			printf(" type='%s'", p);
+
+		putc('\n', stdout);
+	}
+
+done:
+	blkid_free_probe(pr);
+	return EXIT_SUCCESS;
+}
diff --git a/libblkid/samples/superblocks.c b/libblkid/samples/superblocks.c
new file mode 100644
index 0000000..20e39c9
--- /dev/null
+++ b/libblkid/samples/superblocks.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <blkid.h>
+
+#include "c.h"
+
+int main(int argc, char *argv[])
+{
+	int rc;
+	char *devname;
+	blkid_probe pr;
+
+	if (argc < 2) {
+		fprintf(stderr, "usage: %s <device>  "
+				"-- prints superblocks details about the device\n",
+				program_invocation_short_name);
+		return EXIT_FAILURE;
+	}
+
+	devname = argv[1];
+	pr = blkid_new_probe_from_filename(devname);
+	if (!pr)
+		err(EXIT_FAILURE, "%s: faild to create a new libblkid probe",
+				devname);
+
+	/* enable topology probing */
+	blkid_probe_enable_superblocks(pr, TRUE);
+
+	/* set all flags */
+	blkid_probe_set_superblocks_flags(pr,
+			BLKID_SUBLKS_LABEL | BLKID_SUBLKS_LABELRAW |
+			BLKID_SUBLKS_UUID | BLKID_SUBLKS_UUIDRAW |
+			BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE |
+			BLKID_SUBLKS_USAGE | BLKID_SUBLKS_VERSION |
+			BLKID_SUBLKS_MAGIC);
+
+	rc = blkid_do_safeprobe(pr);
+	if (rc == -1)
+		errx(EXIT_FAILURE, "%s: blkid_do_safeprobe() failed", devname);
+	else if (rc == 1)
+		warnx("%s: cannot gather information about superblocks", devname);
+	else {
+		int i, nvals = blkid_probe_numof_values(pr);
+
+		for (i = 0; i < nvals; i++) {
+			const char *name, *data;
+
+			blkid_probe_get_value(pr, i, &name, &data, NULL);
+			printf("\t%s = %s\n", name, data);
+		}
+	}
+
+	blkid_free_probe(pr);
+	return EXIT_SUCCESS;
+}
diff --git a/libblkid/samples/topology.c b/libblkid/samples/topology.c
new file mode 100644
index 0000000..de1c3a5
--- /dev/null
+++ b/libblkid/samples/topology.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <blkid.h>
+
+#include "c.h"
+
+int main(int argc, char *argv[])
+{
+	int rc;
+	char *devname;
+	blkid_probe pr;
+	blkid_topology tp;
+
+	if (argc < 2) {
+		fprintf(stderr, "usage: %s <device>  "
+				"-- prints topology details about the device\n",
+				program_invocation_short_name);
+		return EXIT_FAILURE;
+	}
+
+	devname = argv[1];
+	pr = blkid_new_probe_from_filename(devname);
+	if (!pr)
+		err(EXIT_FAILURE, "%s: faild to create a new libblkid probe",
+				devname);
+	/*
+	 * Binary interface
+	 */
+	tp = blkid_probe_get_topology(pr);
+	if (tp) {
+		printf("----- binary interface:\n");
+		printf("\talignment offset     : %lu\n",
+				blkid_topology_get_alignment_offset(tp));
+		printf("\tminimum io size      : %lu\n",
+				blkid_topology_get_minimum_io_size(tp));
+		printf("\toptimal io size      : %lu\n",
+				blkid_topology_get_optimal_io_size(tp));
+		printf("\tlogical sector size  : %lu\n",
+				blkid_topology_get_logical_sector_size(tp));
+		printf("\tphysical sector size : %lu\n",
+				blkid_topology_get_physical_sector_size(tp));
+	}
+
+	/*
+	 * NAME=value interface
+	 */
+
+	/* enable topology probing */
+	blkid_probe_enable_topology(pr, TRUE);
+
+	/* disable superblocks probing (enabled by default) */
+	blkid_probe_enable_superblocks(pr, FALSE);
+
+	rc = blkid_do_fullprobe(pr);
+	if (rc == -1)
+		errx(EXIT_FAILURE, "%s: blkid_do_fullprobe() failed", devname);
+	else if (rc == 1)
+		warnx("%s: missing topology information", devname);
+	else {
+		int i, nvals = blkid_probe_numof_values(pr);
+
+		printf("----- NAME=value interface (values: %d):\n", nvals);
+
+		for (i = 0; i < nvals; i++) {
+			const char *name, *data;
+
+			blkid_probe_get_value(pr, i, &name, &data, NULL);
+			printf("\t%s = %s\n", name, data);
+		}
+	}
+
+	blkid_free_probe(pr);
+	return EXIT_SUCCESS;
+}
diff --git a/libblkid/sgi.c b/libblkid/sgi.c
deleted file mode 100644
index b89e463..0000000
--- a/libblkid/sgi.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * sgi partition parsing code
- *
- * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
- *
- * This file may be redistributed under the terms of the
- * GNU Lesser General Public License.
- *
- */
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdint.h>
-
-#include "partitions.h"
-
-#define SGI_MAXPARTITIONS	16
-
-/* partition type */
-#define SGI_TYPE_VOLHDR		0x00
-#define SGI_TYPE_VOLULME	0x06	/* entire disk */
-
-struct sgi_device_parameter {
-	unsigned char skew;
-	unsigned char gap1;
-	unsigned char gap2;
-	unsigned char sparecyl;
-
-	uint16_t pcylcount;
-	uint16_t head_vol0;
-	uint16_t ntrks;		/* tracks in cyl 0 or vol 0 */
-
-	unsigned char cmd_tag_queue_depth;
-	unsigned char unused0;
-
-	uint16_t unused1;
-	uint16_t nsect;		/* sectors/tracks in cyl 0 or vol 0 */
-	uint16_t bytes;
-	uint16_t ilfact;
-	uint32_t flags;		/* controller flags */
-	uint32_t datarate;
-	uint32_t retries_on_error;
-	uint32_t ms_per_word;
-	uint16_t xylogics_gap1;
-	uint16_t xylogics_syncdelay;
-	uint16_t xylogics_readdelay;
-	uint16_t xylogics_gap2;
-	uint16_t xylogics_readgate;
-	uint16_t xylogics_writecont;
-} __attribute__((packed));
-
-struct sgi_disklabel {
-	uint32_t magic;			/* magic number */
-	uint16_t root_part_num;		/* # root partition */
-	uint16_t swap_part_num;		/* # swap partition */
-	unsigned char boot_file[16];	/* name of boot file */
-
-	struct sgi_device_parameter	devparam;	/* not used now */
-
-	struct sgi_volume {
-		unsigned char name[8];	/* name of volume */
-		uint32_t block_num;	/* logical block number */
-		uint32_t num_bytes;	/* how big, in bytes */
-	} __attribute__((packed)) volume[15];
-
-	struct sgi_partition {
-		uint32_t num_blocks;	/* size in logical blocks */
-		uint32_t first_block;	/* first logical block */
-		uint32_t type;		/* type of this partition */
-	} __attribute__((packed)) partitions[SGI_MAXPARTITIONS];
-
-	/* checksum is the 32bit 2's complement sum of the disklabel */
-	uint32_t csum;			/* disk label checksum */
-	uint32_t padding;		/* padding */
-} __attribute__((packed));
-
-static uint32_t count_checksum(struct sgi_disklabel *label)
-{
-	int i;
-	uint32_t *ptr = (uint32_t *) label;
-	uint32_t sum = 0;
-
-	i = sizeof(*label) / sizeof(*ptr);
-
-	while (i--)
-		sum += be32_to_cpu(ptr[i]);
-
-	return sum;
-}
-
-
-static int probe_sgi_pt(blkid_probe pr,
-		const struct blkid_idmag *mag __attribute__((__unused__)))
-{
-	struct sgi_disklabel *l;
-	struct sgi_partition *p;
-	blkid_parttable tab = NULL;
-	blkid_partlist ls;
-	int i;
-
-	l = (struct sgi_disklabel *) blkid_probe_get_sector(pr, 0);
-	if (!l)
-		goto nothing;
-
-	if (count_checksum(l)) {
-		DBG(DEBUG_LOWPROBE, printf(
-			"detected corrupted sgi disk label -- ignore\n"));
-		goto nothing;
-	}
-
-	if (blkid_partitions_need_typeonly(pr))
-		/* caller does not ask for details about partitions */
-		return 0;
-
-	ls = blkid_probe_get_partlist(pr);
-	if (!ls)
-		goto err;
-
-	tab = blkid_partlist_new_parttable(ls, "sgi", 0);
-	if (!tab)
-		goto err;
-
-	for(i = 0, p = &l->partitions[0]; i < SGI_MAXPARTITIONS; i++, p++) {
-		uint32_t size = be32_to_cpu(p->num_blocks);
-		uint32_t start = be32_to_cpu(p->first_block);
-		uint32_t type = be32_to_cpu(p->type);
-		blkid_partition par;
-
-		if (size == 0 || type == SGI_TYPE_VOLULME ||
-			         type == SGI_TYPE_VOLHDR) {
-			blkid_partlist_increment_partno(ls);
-			continue;
-		}
-		par = blkid_partlist_add_partition(ls, tab, start, size);
-		if (!par)
-			goto err;
-
-		blkid_partition_set_type(par, type);
-	}
-
-	return 0;
-
-nothing:
-	return 1;
-err:
-	return -1;
-}
-
-const struct blkid_idinfo sgi_pt_idinfo =
-{
-	.name		= "sgi",
-	.probefunc	= probe_sgi_pt,
-	.magics		=
-	{
-		{ .magic = "\x0B\xE5\xA9\x41", .len = 4	},
-		{ NULL }
-	}
-};
-
diff --git a/libblkid/squashfs.c b/libblkid/squashfs.c
deleted file mode 100644
index 45f1029..0000000
--- a/libblkid/squashfs.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
- *
- * Inspired by libvolume_id by
- *     Kay Sievers <kay.sievers@vrfy.org>
- *
- * This file may be redistributed under the terms of the
- * GNU Lesser General Public License.
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdint.h>
-
-#include "bitops.h"	/* swab16() */
-#include "superblocks.h"
-
-struct sqsh_super_block {
-	uint32_t	s_magic;
-	uint32_t	inodes;
-	uint32_t	bytes_used_2;
-	uint32_t	uid_start_2;
-	uint32_t	guid_start_2;
-	uint32_t	inode_table_start_2;
-	uint32_t	directory_table_start_2;
-	uint16_t	s_major;
-	uint16_t	s_minor;
-} __attribute__((packed));
-
-static int probe_squashfs(blkid_probe pr, const struct blkid_idmag *mag)
-{
-	struct sqsh_super_block *sq;
-
-	sq = blkid_probe_get_sb(pr, mag, struct sqsh_super_block);
-	if (!sq)
-		return -1;
-
-	if (strcmp(mag->magic, "sqsh") == 0 ||
-	    strcmp(mag->magic, "qshs") == 0)
-		blkid_probe_sprintf_version(pr, "%u.%u",
-				sq->s_major,
-				sq->s_minor);
-	else
-		blkid_probe_sprintf_version(pr, "%u.%u",
-				swab16(sq->s_major),
-				swab16(sq->s_minor));
-	return 0;
-}
-
-const struct blkid_idinfo squashfs_idinfo =
-{
-	.name		= "squashfs",
-	.usage		= BLKID_USAGE_FILESYSTEM,
-	.probefunc	= probe_squashfs,
-	.magics		=
-	{
-		{ .magic = "sqsh", .len = 4 },
-		{ .magic = "hsqs", .len = 4 }, /* swap */
-
-		/* LZMA version */
-		{ .magic = "qshs", .len = 4 },
-		{ .magic = "shsq", .len = 4 }, /* swap */
-		{ NULL }
-	}
-};
-
-
diff --git a/libblkid/src/.gitignore b/libblkid/src/.gitignore
new file mode 100644
index 0000000..af34f58
--- /dev/null
+++ b/libblkid/src/.gitignore
@@ -0,0 +1 @@
+blkid.h
diff --git a/libblkid/bitops.h b/libblkid/src/bitops.h
similarity index 100%
rename from libblkid/bitops.h
rename to libblkid/src/bitops.h
diff --git a/libblkid/blkdev.h b/libblkid/src/blkdev.h
similarity index 100%
rename from libblkid/blkdev.h
rename to libblkid/src/blkdev.h
diff --git a/libblkid/blkid.h b/libblkid/src/blkid.h.in
similarity index 77%
copy from libblkid/blkid.h
copy to libblkid/src/blkid.h.in
index b283009..4f5fe2a 100644
--- a/libblkid/blkid.h
+++ b/libblkid/src/blkid.h.in
@@ -26,13 +26,12 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#define _SC_HOST_NAME_MAX 255
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-#define BLKID_VERSION   "2.22.0"
-#define BLKID_DATE      "04-Sep-2012"
+#define BLKID_VERSION   "@LIBBLKID_VERSION@"
+#define BLKID_DATE      "@LIBBLKID_DATE@"
 
 /**
  * blkid_dev:
@@ -139,6 +138,7 @@
 #endif
 
 /* cache.c */
+extern void blkid_init_debug(int mask);
 extern void blkid_put_cache(blkid_cache cache);
 extern int blkid_get_cache(blkid_cache *cache, const char *filename);
 extern void blkid_gc_cache(blkid_cache cache);
@@ -147,8 +147,7 @@
 extern const char *blkid_dev_devname(blkid_dev dev)
 			__ul_attribute__((warn_unused_result));
 
-extern blkid_dev_iterate blkid_dev_iterate_begin(blkid_cache cache)
-			__ul_attribute__((nonnull));
+extern blkid_dev_iterate blkid_dev_iterate_begin(blkid_cache cache);
 extern int blkid_dev_set_search(blkid_dev_iterate iter,
 				char *search_type, char *search_value);
 extern int blkid_dev_next(blkid_dev_iterate iterate, blkid_dev *dev);
@@ -169,8 +168,7 @@
 extern blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags);
 
 /* getsize.c */
-extern blkid_loff_t blkid_get_dev_size(int fd)
-			__ul_attribute__((warn_unused_result));
+extern blkid_loff_t blkid_get_dev_size(int fd);
 
 /* verify.c */
 extern blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev);
@@ -186,25 +184,21 @@
 			__ul_attribute__((warn_unused_result));
 
 /* tag.c */
-extern blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev)
-			__ul_attribute__((warn_unused_result));
+extern blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev);
 extern int blkid_tag_next(blkid_tag_iterate iterate,
 			      const char **type, const char **value);
 extern void blkid_tag_iterate_end(blkid_tag_iterate iterate);
-extern int blkid_dev_has_tag(blkid_dev dev, const char *type, const char *value)
-			__ul_attribute__((nonnull(1,2)));
+extern int blkid_dev_has_tag(blkid_dev dev, const char *type, const char *value);
 
 extern blkid_dev blkid_find_dev_with_tag(blkid_cache cache,
 					 const char *type,
-					 const char *value)
-			__ul_attribute__((warn_unused_result));
+					 const char *value);
 
 extern int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val);
 
 /* version.c */
 extern int blkid_parse_version_string(const char *ver_string)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 extern int blkid_get_library_version(const char **ver_string,
 				     const char **date_string);
 
@@ -233,34 +227,25 @@
 	                blkid_loff_t off, blkid_loff_t size);
 
 extern dev_t blkid_probe_get_devno(blkid_probe pr)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 
 extern dev_t blkid_probe_get_wholedisk_devno(blkid_probe pr)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 
 extern int blkid_probe_is_wholedisk(blkid_probe pr)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 
-extern blkid_loff_t blkid_probe_get_size(blkid_probe pr)
-			__ul_attribute__((warn_unused_result));
-extern blkid_loff_t blkid_probe_get_offset(blkid_probe pr)
-			__ul_attribute__((warn_unused_result));
-extern unsigned int blkid_probe_get_sectorsize(blkid_probe pr)
-			__ul_attribute__((warn_unused_result));
-extern blkid_loff_t blkid_probe_get_sectors(blkid_probe pr)
-			__ul_attribute__((warn_unused_result));
+extern blkid_loff_t blkid_probe_get_size(blkid_probe pr);
+extern blkid_loff_t blkid_probe_get_offset(blkid_probe pr);
+extern unsigned int blkid_probe_get_sectorsize(blkid_probe pr);
+extern blkid_loff_t blkid_probe_get_sectors(blkid_probe pr);
 
-extern int blkid_probe_get_fd(blkid_probe pr)
-			__ul_attribute__((warn_unused_result));
+extern int blkid_probe_get_fd(blkid_probe pr);
 
 /*
  * superblocks probing
  */
-extern int blkid_known_fstype(const char *fstype)
-			__ul_attribute__((warn_unused_result));
+extern int blkid_known_fstype(const char *fstype);
 
 extern int blkid_superblocks_get_name(size_t idx, const char **name, int *usage);
 
@@ -275,6 +260,7 @@
 #define BLKID_SUBLKS_USAGE	(1 << 7) /* define USAGE result value */
 #define BLKID_SUBLKS_VERSION	(1 << 8) /* read FS type from superblock */
 #define BLKID_SUBLKS_MAGIC	(1 << 9) /* define SBMAGIC and SBMAGIC_OFFSET */
+#define BLKID_SUBLKS_BADCSUM	(1 << 10) /* allow a bad checksum */
 
 #define BLKID_SUBLKS_DEFAULT	(BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID | \
 				 BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE)
@@ -305,30 +291,23 @@
 extern int blkid_probe_enable_topology(blkid_probe pr, int enable);
 
 /* binary interface */
-extern blkid_topology blkid_probe_get_topology(blkid_probe pr)
-			__ul_attribute__((warn_unused_result));
+extern blkid_topology blkid_probe_get_topology(blkid_probe pr);
 
 extern unsigned long blkid_topology_get_alignment_offset(blkid_topology tp)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 extern unsigned long blkid_topology_get_minimum_io_size(blkid_topology tp)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 extern unsigned long blkid_topology_get_optimal_io_size(blkid_topology tp)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 extern unsigned long blkid_topology_get_logical_sector_size(blkid_topology tp)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 extern unsigned long blkid_topology_get_physical_sector_size(blkid_topology tp)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 
 /*
  * partitions probing
  */
-extern int blkid_known_pttype(const char *pttype)
-			__ul_attribute__((warn_unused_result));
+extern int blkid_known_pttype(const char *pttype);
 
 extern int blkid_probe_enable_partitions(blkid_probe pr, int enable);
 
@@ -343,62 +322,41 @@
 extern int blkid_probe_set_partitions_flags(blkid_probe pr, int flags);
 
 /* binary interface */
-extern blkid_partlist blkid_probe_get_partitions(blkid_probe pr)
-			__ul_attribute__((warn_unused_result));
+extern blkid_partlist blkid_probe_get_partitions(blkid_probe pr);
 
-extern int blkid_partlist_numof_partitions(blkid_partlist ls)
-			__ul_attribute__((warn_unused_result));
-extern blkid_parttable blkid_partlist_get_table(blkid_partlist ls)
-			__ul_attribute__((warn_unused_result));
-extern blkid_partition blkid_partlist_get_partition(blkid_partlist ls, int n)
-			__ul_attribute__((warn_unused_result));
-extern blkid_partition blkid_partlist_devno_to_partition(blkid_partlist ls, dev_t devno)
-			__ul_attribute__((warn_unused_result));
-extern blkid_parttable blkid_partition_get_table(blkid_partition par)
-			__ul_attribute__((warn_unused_result));
+extern int blkid_partlist_numof_partitions(blkid_partlist ls);
+extern blkid_parttable blkid_partlist_get_table(blkid_partlist ls);
+extern blkid_partition blkid_partlist_get_partition(blkid_partlist ls, int n);
+extern blkid_partition blkid_partlist_get_partition_by_partno(blkid_partlist ls, int n);
+extern blkid_partition blkid_partlist_devno_to_partition(blkid_partlist ls, dev_t devno);
+extern blkid_parttable blkid_partition_get_table(blkid_partition par);
 
-extern const char *blkid_partition_get_name(blkid_partition par)
-			__ul_attribute__((warn_unused_result));
-extern const char *blkid_partition_get_uuid(blkid_partition par)
-			__ul_attribute__((warn_unused_result));
-extern int blkid_partition_get_partno(blkid_partition par)
-			__ul_attribute__((warn_unused_result));
-extern blkid_loff_t blkid_partition_get_start(blkid_partition par)
-			__ul_attribute__((warn_unused_result));
-extern blkid_loff_t blkid_partition_get_size(blkid_partition par)
-			__ul_attribute__((warn_unused_result));
+extern const char *blkid_partition_get_name(blkid_partition par);
+extern const char *blkid_partition_get_uuid(blkid_partition par);
+extern int blkid_partition_get_partno(blkid_partition par);
+extern blkid_loff_t blkid_partition_get_start(blkid_partition par);
+extern blkid_loff_t blkid_partition_get_size(blkid_partition par);
 
 extern int blkid_partition_get_type(blkid_partition par)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 
-extern const char *blkid_partition_get_type_string(blkid_partition par)
-			__ul_attribute__((warn_unused_result));
+extern const char *blkid_partition_get_type_string(blkid_partition par);
 
 extern unsigned long long blkid_partition_get_flags(blkid_partition par)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 
 extern int blkid_partition_is_logical(blkid_partition par)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 extern int blkid_partition_is_extended(blkid_partition par)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 extern int blkid_partition_is_primary(blkid_partition par)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 
-extern const char *blkid_parttable_get_type(blkid_parttable tab)
-			__ul_attribute__((warn_unused_result));
+extern const char *blkid_parttable_get_type(blkid_parttable tab);
+extern const char *blkid_parttable_get_id(blkid_parttable tab);
 
-extern const char *blkid_parttable_get_id(blkid_parttable tab)
-			__ul_attribute__((warn_unused_result));
-
-extern blkid_loff_t blkid_parttable_get_offset(blkid_parttable tab)
-			__ul_attribute__((warn_unused_result));
-extern blkid_partition blkid_parttable_get_parent(blkid_parttable tab)
-			__ul_attribute__((warn_unused_result));
+extern blkid_loff_t blkid_parttable_get_offset(blkid_parttable tab);
+extern blkid_partition blkid_parttable_get_parent(blkid_parttable tab);
 
 /*
  * NAME=value low-level interface
@@ -407,15 +365,13 @@
 extern int blkid_do_safeprobe(blkid_probe pr);
 extern int blkid_do_fullprobe(blkid_probe pr);
 
-extern int blkid_probe_numof_values(blkid_probe pr)
-			__ul_attribute__((warn_unused_result));
+extern int blkid_probe_numof_values(blkid_probe pr);
 extern int blkid_probe_get_value(blkid_probe pr, int num, const char **name,
                         const char **data, size_t *len);
 extern int blkid_probe_lookup_value(blkid_probe pr, const char *name,
                         const char **data, size_t *len);
 extern int blkid_probe_has_value(blkid_probe pr, const char *name)
-			__ul_attribute__((nonnull))
-			__ul_attribute__((warn_unused_result));
+			__ul_attribute__((nonnull));
 
 extern int blkid_do_wipe(blkid_probe pr, int dryrun);
 extern int blkid_probe_step_back(blkid_probe pr);
diff --git a/libblkid/blkidP.h b/libblkid/src/blkidP.h
similarity index 93%
rename from libblkid/blkidP.h
rename to libblkid/src/blkidP.h
index 2d5e8cb..fbf4e71 100644
--- a/libblkid/blkidP.h
+++ b/libblkid/src/blkidP.h
@@ -13,9 +13,6 @@
 #ifndef _BLKID_BLKIDP_H
 #define _BLKID_BLKIDP_H
 
-/* support debug output if LIBBLKID_DEBUG env. variable is set */
-#define CONFIG_BLKID_DEBUG 1
-
 /* Always confirm that /dev/disk-by symlinks match with LABEL/UUID on device */
 /* #define CONFIG_BLKID_VERIFY_UDEV 1 */
 
@@ -30,6 +27,7 @@
 #include "bitops.h"	/* $(top_srcdir)/include/ */
 #include "blkdev.h"
 
+#include "debug.h"
 #include "blkid.h"
 #include "list.h"
 
@@ -221,12 +219,10 @@
 #define BLKID_FL_PRIVATE_FD	(1 << 1)	/* see blkid_new_probe_from_filename() */
 #define BLKID_FL_TINY_DEV	(1 << 2)	/* <= 1.47MiB (floppy or so) */
 #define BLKID_FL_CDROM_DEV	(1 << 3)	/* is a CD/DVD drive */
+#define BLKID_FL_NOSCAN_DEV	(1 << 4)	/* do not scan this device */
 
 /* private per-probing flags */
 #define BLKID_PROBE_FL_IGNORE_PT (1 << 1)	/* ignore partition table */
-#define BLKID_PROBE_FL_IGNORE_BACKUP (1 << 2)	/* ignore backup superblocks or PT */
-
-extern int blkid_probe_ignore_backup(blkid_probe pr);
 
 extern blkid_probe blkid_clone_probe(blkid_probe parent);
 extern blkid_probe blkid_probe_get_wholedisk_probe(blkid_probe pr);
@@ -300,6 +296,9 @@
 /* old systems */
 #define BLKID_CACHE_FILE_OLD	"/etc/blkid.tab"
 
+#define BLKID_PROBE_OK	 0
+#define BLKID_PROBE_NONE 1
+
 #define BLKID_ERR_IO	 5
 #define BLKID_ERR_PROC	 9
 #define BLKID_ERR_MEM	12
@@ -317,38 +316,28 @@
 #define BLKID_PRI_LVM	20
 #define BLKID_PRI_MD	10
 
-#if defined(TEST_PROGRAM) && !defined(CONFIG_BLKID_DEBUG)
-#define CONFIG_BLKID_DEBUG
-#endif
+#define BLKID_DEBUG_HELP	(1 << 0)
+#define BLKID_DEBUG_INIT	(1 << 1)
+#define BLKID_DEBUG_CACHE	(1 << 2)
+#define BLKID_DEBUG_CONFIG	(1 << 3)
+#define BLKID_DEBUG_DEV		(1 << 4)
+#define BLKID_DEBUG_DEVNAME	(1 << 5)
+#define BLKID_DEBUG_DEVNO	(1 << 6)
+#define BLKID_DEBUG_EVALUATE	(1 << 7)
+#define BLKID_DEBUG_LOWPROBE	(1 << 8)
+#define BLKID_DEBUG_PROBE	(1 << 9)
+#define BLKID_DEBUG_READ	(1 << 10)
+#define BLKID_DEBUG_SAVE	(1 << 11)
+#define BLKID_DEBUG_TAG		(1 << 12)
+#define BLKID_DEBUG_ALL		0xFFFF		/* (1 << 16) aka FFFF is expected by API */
 
-#define DEBUG_CACHE	0x0001
-#define DEBUG_DUMP	0x0002
-#define DEBUG_DEV	0x0004
-#define DEBUG_DEVNAME	0x0008
-#define DEBUG_DEVNO	0x0010
-#define DEBUG_PROBE	0x0020
-#define DEBUG_READ	0x0040
-#define DEBUG_RESOLVE	0x0080
-#define DEBUG_SAVE	0x0100
-#define DEBUG_TAG	0x0200
-#define DEBUG_LOWPROBE	0x0400
-#define DEBUG_CONFIG	0x0800
-#define DEBUG_EVALUATE	0x1000
-#define DEBUG_INIT	0x8000
-#define DEBUG_ALL	0xFFFF
+UL_DEBUG_DECLARE_MASK(libblkid);
+#define DBG(m, x)	__UL_DBG(libblkid, BLKID_DEBUG_, m, x)
+#define ON_DBG(m, x)    __UL_DBG_CALL(libblkid, BLKID_DEBUG_, m, x)
 
-#ifdef CONFIG_BLKID_DEBUG
-extern int blkid_debug_mask;
-extern void blkid_init_debug(int mask);
 extern void blkid_debug_dump_dev(blkid_dev dev);
 extern void blkid_debug_dump_tag(blkid_tag tag);
 
-#define DBG(m,x)	do { if ((m) & blkid_debug_mask) x; } while (0)
-
-#else /* !CONFIG_BLKID_DEBUG */
-#define DBG(m,x)
-#define blkid_init_debug(x)
-#endif /* CONFIG_BLKID_DEBUG */
 
 /* devno.c */
 struct dir_list {
@@ -503,8 +492,13 @@
 				size_t len, unsigned char *magic)
 			__attribute__((nonnull));
 
+extern int blkid_probe_verify_csum(blkid_probe pr, uint64_t csum, uint64_t expected)
+			__attribute__((nonnull));
+
 extern void blkid_unparse_uuid(const unsigned char *uuid, char *str, size_t len)
 			__attribute__((nonnull));
+extern int blkid_uuid_is_empty(const unsigned char *buf, size_t len);
+
 extern size_t blkid_rtrim_whitespace(unsigned char *str)
 			__attribute__((nonnull));
 extern size_t blkid_ltrim_whitespace(unsigned char *str)
diff --git a/libblkid/c.h b/libblkid/src/c.h
similarity index 93%
rename from libblkid/c.h
rename to libblkid/src/c.h
index 037a099..6fcbc6d 100644
--- a/libblkid/c.h
+++ b/libblkid/src/c.h
@@ -110,6 +110,14 @@
 	_max1 > _max2 ? _max1 : _max2; })
 #endif
 
+#ifndef cmp_numbers
+# define cmp_numbers(x, y) __extension__ ({     \
+        __typeof__(x) _a = (x);                 \
+        __typeof__(y) _b = (y);                 \
+        (void) (&_a == &_b);                    \
+        _a == _b ? 0 : _a > _b ? 1 : -1; })
+#endif
+
 #ifndef offsetof
 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
 #endif
@@ -215,6 +223,13 @@
  * Fallback defines for old versions of glibc
  */
 #include <fcntl.h>
+
+#ifdef O_CLOEXEC
+#define UL_CLOEXECSTR   "e"
+#else
+#define UL_CLOEXECSTR   ""
+#endif
+
 #ifndef O_CLOEXEC
 #define O_CLOEXEC 0
 #endif
@@ -232,7 +247,7 @@
  */
 static inline size_t get_hostname_max(void)
 {
-	long len = sysconf(_SC_HOST_NAME_MAX);
+	long len = sysconf(255);
 
 	if (0 < len)
 		return len;
diff --git a/libblkid/cache.c b/libblkid/src/cache.c
similarity index 80%
rename from libblkid/cache.c
rename to libblkid/src/cache.c
index cc2cf8e..b576df8 100644
--- a/libblkid/cache.c
+++ b/libblkid/src/cache.c
@@ -24,8 +24,6 @@
 #include "blkidP.h"
 #include "env.h"
 
-int blkid_debug_mask = 0;
-
 /**
  * SECTION:cache
  * @title: Cache
@@ -50,51 +48,6 @@
  * locate these devices without enumerating only visible devices, so the use of
  * the cache file is required in this situation.
  */
-
-#if 0 /* ifdef CONFIG_BLKID_DEBUG */
-static blkid_debug_dump_cache(int mask, blkid_cache cache)
-{
-	struct list_head *p;
-
-	if (!cache) {
-		printf("cache: NULL\n");
-		return;
-	}
-
-	printf("cache: time = %lu\n", cache->bic_time);
-	printf("cache: flags = 0x%08X\n", cache->bic_flags);
-
-	list_for_each(p, &cache->bic_devs) {
-		blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs);
-		blkid_debug_dump_dev(dev);
-	}
-}
-#endif
-
-#ifdef CONFIG_BLKID_DEBUG
-void blkid_init_debug(int mask)
-{
-	if (blkid_debug_mask & DEBUG_INIT)
-		return;
-
-	if (!mask)
-	{
-		char *dstr = getenv("LIBBLKID_DEBUG");
-
-		if (!dstr)
-			dstr = getenv("BLKID_DEBUG");	/* for backward compatibility */
-		if (dstr)
-			blkid_debug_mask = strtoul(dstr, 0, 0);
-	} else
-		blkid_debug_mask = mask;
-
-	if (blkid_debug_mask)
-		printf("libblkid: debug mask set to 0x%04x.\n", blkid_debug_mask);
-
-	blkid_debug_mask |= DEBUG_INIT;
-}
-#endif
-
 static const char *get_default_cache_filename(void)
 {
 	struct stat st;
@@ -146,7 +99,7 @@
 
 	blkid_init_debug(0);
 
-	DBG(DEBUG_CACHE, printf("creating blkid cache (using %s)\n",
+	DBG(CACHE, ul_debug("creating blkid cache (using %s)",
 				filename ? filename : "default cache"));
 
 	if (!(cache = (blkid_cache) calloc(1, sizeof(struct blkid_struct_cache))))
@@ -180,9 +133,9 @@
 
 	(void) blkid_flush_cache(cache);
 
-	DBG(DEBUG_CACHE, printf("freeing cache struct\n"));
+	DBG(CACHE, ul_debug("freeing cache struct"));
 
-	/* DBG(DEBUG_CACHE, blkid_debug_dump_cache(cache)); */
+	/* DBG(CACHE, ul_debug_dump_cache(cache)); */
 
 	while (!list_empty(&cache->bic_devs)) {
 		blkid_dev dev = list_entry(cache->bic_devs.next,
@@ -201,7 +154,7 @@
 						   struct blkid_struct_tag,
 						   bit_names);
 
-			DBG(DEBUG_CACHE, printf("warning: unfreed tag %s=%s\n",
+			DBG(CACHE, ul_debug("warning: unfreed tag %s=%s",
 						bad->bit_name, bad->bit_val));
 			blkid_free_tag(bad);
 		}
@@ -231,13 +184,11 @@
 	list_for_each_safe(p, pnext, &cache->bic_devs) {
 		blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs);
 		if (stat(dev->bid_name, &st) < 0) {
-			DBG(DEBUG_CACHE,
-			    printf("freeing %s\n", dev->bid_name));
+			DBG(CACHE, ul_debug("freeing %s", dev->bid_name));
 			blkid_free_dev(dev);
 			cache->bic_flags |= BLKID_BIC_FL_CHANGED;
 		} else {
-			DBG(DEBUG_CACHE,
-			    printf("Device %s exists\n", dev->bid_name));
+			DBG(CACHE, ul_debug("Device %s exists", dev->bid_name));
 		}
 	}
 }
@@ -248,7 +199,7 @@
 	blkid_cache cache = NULL;
 	int ret;
 
-	blkid_init_debug(DEBUG_ALL);
+	blkid_init_debug(BLKID_DEBUG_ALL);
 
 	if ((argc > 2)) {
 		fprintf(stderr, "Usage: %s [filename] \n", argv[0]);
diff --git a/libblkid/canonicalize.h b/libblkid/src/canonicalize.h
similarity index 100%
rename from libblkid/canonicalize.h
rename to libblkid/src/canonicalize.h
diff --git a/libblkid/closestream.h b/libblkid/src/closestream.h
similarity index 74%
copy from libblkid/closestream.h
copy to libblkid/src/closestream.h
index d61b83b..7842456 100644
--- a/libblkid/closestream.h
+++ b/libblkid/src/closestream.h
@@ -24,8 +24,9 @@
 	const int some_pending = (__fpending(stream) != 0);
 	const int prev_fail = (ferror(stream) != 0);
 	const int fclose_fail = (fclose(stream) != 0);
+
 	if (prev_fail || (fclose_fail && (some_pending || errno != EBADF))) {
-		if (!fclose_fail)
+		if (!fclose_fail && !(errno == EPIPE))
 			errno = 0;
 		return EOF;
 	}
@@ -48,4 +49,23 @@
 		_exit(EXIT_FAILURE);
 }
 
+#ifndef HAVE_FSYNC
+static inline int
+fsync(int fd __attribute__((__unused__)))
+{
+	return 0;
+}
+#endif
+
+static inline int
+close_fd(int fd)
+{
+	const int fsync_fail = (fsync(fd) != 0);
+	const int close_fail = (close(fd) != 0);
+
+	if (fsync_fail || close_fail)
+		return EOF;
+	return 0;
+}
+
 #endif /* UTIL_LINUX_CLOSESTREAM_H */
diff --git a/libblkid/src/colors.h b/libblkid/src/colors.h
new file mode 100644
index 0000000..97efc48
--- /dev/null
+++ b/libblkid/src/colors.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2012 Ondrej Oprala <ooprala@redhat.com>
+ * Copyright (C) 2012-2014 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be distributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#ifndef UTIL_LINUX_COLORS_H
+#define UTIL_LINUX_COLORS_H
+
+#include <stdio.h>
+#include <unistd.h>
+
+#define UL_COLOR_RESET		"\033[0m"
+#define UL_COLOR_BOLD		"\033[1m"
+#define UL_COLOR_HALFBRIGHT	"\033[2m"
+#define UL_COLOR_UNDERSCORE	"\033[4m"
+#define UL_COLOR_BLINK		"\033[5m"
+#define UL_COLOR_REVERSE	"\033[7m"
+
+/* Standard colors */
+#define UL_COLOR_BLACK		"\033[30m"
+#define UL_COLOR_RED		"\033[31m"
+#define UL_COLOR_GREEN		"\033[32m"
+#define UL_COLOR_BROWN		"\033[33m"	/* well, brown */
+#define UL_COLOR_BLUE		"\033[34m"
+#define UL_COLOR_MAGENTA	"\033[35m"
+#define UL_COLOR_CYAN		"\033[36m"
+#define UL_COLOR_GRAY		"\033[37m"
+
+/* Bold variants */
+#define UL_COLOR_DARK_GRAY	"\033[1;30m"
+#define UL_COLOR_BOLD_RED	"\033[1;31m"
+#define UL_COLOR_BOLD_GREEN	"\033[1;32m"
+#define UL_COLOR_BOLD_YELLOW	"\033[1;33m"
+#define UL_COLOR_BOLD_BLUE	"\033[1;34m"
+#define UL_COLOR_BOLD_MAGENTA	"\033[1;35m"
+#define UL_COLOR_BOLD_CYAN	"\033[1;36m"
+
+#define UL_COLOR_WHITE		"\033[1;37m"
+
+/* --color[=WHEN] */
+enum colortmode {
+	UL_COLORMODE_AUTO = 0,
+	UL_COLORMODE_NEVER,
+	UL_COLORMODE_ALWAYS,
+	UL_COLORMODE_UNDEF,
+
+	__UL_NCOLORMODES	/* last */
+};
+
+extern int colormode_from_string(const char *str);
+extern int colormode_or_err(const char *str, const char *errmsg);
+
+/* Initialize the global variable UL_COLOR_TERM_OK */
+extern int colors_init(int mode, const char *util_name);
+
+/* Returns 1 or 0 */
+extern int colors_wanted(void);
+
+/* temporary enable/disable colors */
+extern void colors_off(void);
+extern void colors_on(void);
+
+
+/* Set the color */
+extern void color_fenable(const char *seq, FILE *f);
+
+extern void color_scheme_fenable(const char *name, const char *dflt, FILE *f);
+extern const char *color_scheme_get_sequence(const char *name, const char *dflt);
+
+static inline void color_enable(const char *seq)
+{
+	color_fenable(seq, stdout);
+}
+
+static inline void color_scheme_enable(const char *name, const char *dflt)
+{
+	color_scheme_fenable(name, dflt, stdout);
+}
+
+/* Reset colors to default */
+extern void color_fdisable(FILE *f);
+
+static inline void color_disable(void)
+{
+	color_fdisable(stdout);
+}
+
+/* converts "red" to UL_COLOR_RED, etc. */
+extern const char *color_sequence_from_colorname(const char *str);
+
+
+#endif /* UTIL_LINUX_COLORS_H */
diff --git a/libblkid/config.c b/libblkid/src/config.c
similarity index 85%
rename from libblkid/config.c
rename to libblkid/src/config.c
index edad6cd..3c7f312 100644
--- a/libblkid/config.c
+++ b/libblkid/src/config.c
@@ -50,8 +50,8 @@
 	}
 	return 0;
 err:
-	DBG(DEBUG_CONFIG, printf(
-		"config file: unknown evaluation method '%s'.\n", s));
+	DBG(CONFIG, ul_debug(
+		"config file: unknown evaluation method '%s'.", s));
 	return -1;
 }
 
@@ -71,8 +71,8 @@
 			if (feof(fd))
 				s = strchr (buf, '\0');
 			else {
-				DBG(DEBUG_CONFIG, fprintf(stderr,
-					"libblkid: config file: missing newline at line '%s'.\n",
+				DBG(CONFIG, ul_debug(
+					"config file: missing newline at line '%s'.",
 					buf));
 				return -1;
 			}
@@ -102,8 +102,8 @@
 		if (*s && parse_evaluate(conf, s) == -1)
 			return -1;
 	} else {
-		DBG(DEBUG_CONFIG, printf(
-			"config file: unknown option '%s'.\n", s));
+		DBG(CONFIG, ul_debug(
+			"config file: unknown option '%s'.", s));
 		return -1;
 	}
 	return 0;
@@ -125,19 +125,16 @@
 		return NULL;
 	conf->uevent = -1;
 
-	DBG(DEBUG_CONFIG, fprintf(stderr,
-		"reading config file: %s.\n", filename));
+	DBG(CONFIG, ul_debug("reading config file: %s.", filename));
 
-	f = fopen(filename, "r");
+	f = fopen(filename, "r" UL_CLOEXECSTR);
 	if (!f) {
-		DBG(DEBUG_CONFIG, fprintf(stderr,
-			"%s: does not exist, using built-in default\n", filename));
+		DBG(CONFIG, ul_debug("%s: does not exist, using built-in default", filename));
 		goto dflt;
 	}
 	while (!feof(f)) {
 		if (parse_next(f, conf)) {
-			DBG(DEBUG_CONFIG, fprintf(stderr,
-				"%s: parse error\n", filename));
+			DBG(CONFIG, ul_debug("%s: parse error", filename));
 			goto err;
 		}
 	}
@@ -178,7 +175,7 @@
 	struct blkid_config *conf;
 	char *filename = NULL;
 
-	blkid_init_debug(DEBUG_ALL);
+	blkid_init_debug(BLKID_DEBUG_ALL);
 
 	if (argc == 2)
 		filename = argv[1];
diff --git a/libblkid/crc32.h b/libblkid/src/crc32.h
similarity index 86%
copy from libblkid/crc32.h
copy to libblkid/src/crc32.h
index b454be9..2616910 100644
--- a/libblkid/crc32.h
+++ b/libblkid/src/crc32.h
@@ -1,6 +1,7 @@
 #ifndef UL_NG_CRC32_H
 #define UL_NG_CRC32_H
 
+#include <sys/types.h>
 #include <stdint.h>
 
 extern uint32_t crc32(uint32_t seed, const unsigned char *buf, size_t len);
diff --git a/libblkid/src/debug.h b/libblkid/src/debug.h
new file mode 100644
index 0000000..0229ab3
--- /dev/null
+++ b/libblkid/src/debug.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
+ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be distributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#ifndef UTIL_LINUX_DEBUG_H
+#define UTIL_LINUX_DEBUG_H
+
+
+/*
+ * util-linux debug macros
+ *
+ * The debug stuff is based on <name>_debug_mask that controls what outputs is
+ * expected. The mask is usually initialized by <NAME>_DEBUG= env.variable
+ *
+ * After successful initialization the flag <PREFIX>_DEBUG_INIT is always set
+ * to the mask (this flag is required). The <PREFIX> is usually library API
+ * prefix (e.g. MNT_) or program name (e.g. CFDISK_)
+ *
+ * In the code is possible to use
+ *
+ *	DBG(FOO, ul_debug("this is output for foo"));
+ *
+ * where for the FOO has to be defined <PREFIX>_DEBUG_FOO.
+ *
+ * It's possible to initialize the mask by comma delimited strings with
+ * subsystem names (e.g. "LIBMOUNT_DEBUG=options,tab"). In this case is
+ * necessary to define mask names array. This functionality is optional.
+ *
+ * It's stringly recommended to use UL_* macros to define/declare/use
+ * the debug stuff.
+ *
+ * See disk-utils/cfdisk.c: cfdisk_init_debug()  for programs debug
+ *  or libmount/src/init.c: mnt_init_debug()     for library debug
+ *
+ */
+
+#include <stdarg.h>
+#include <string.h>
+
+struct ul_debug_maskname {
+	const char *name;
+	int mask;
+	const char *help;
+};
+#define UL_DEBUG_EMPTY_MASKNAMES {{ NULL, 0, NULL }}
+#define UL_DEBUG_DEFINE_MASKNAMES(m) static const struct ul_debug_maskname m ## _masknames[]
+#define UL_DEBUG_MASKNAMES(m)	m ## _masknames
+
+#define UL_DEBUG_DEFINE_MASK(m) int m ## _debug_mask
+#define UL_DEBUG_DECLARE_MASK(m) extern UL_DEBUG_DEFINE_MASK(m)
+
+/* p - flag prefix, m - flag postfix */
+#define UL_DEBUG_DEFINE_FLAG(p, m) p ## m
+
+/* l - library name, p - flag prefix, m - flag postfix, x - function */
+#define __UL_DBG(l, p, m, x) \
+	do { \
+		if ((p ## m) & l ## _debug_mask) { \
+			fprintf(stderr, "%d: %s: %8s: ", getpid(), # l, # m); \
+			x; \
+		} \
+	} while (0)
+
+#define __UL_DBG_CALL(l, p, m, x) \
+	do { \
+		if ((p ## m) & l ## _debug_mask) { \
+			x; \
+		} \
+	} while (0)
+
+#define __UL_DBG_FLUSH(l, p) \
+	do { \
+		if (l ## _debug_mask && \
+		    l ## _debug_mask != p ## INIT) { \
+			fflush(stderr); \
+		} \
+	} while (0)
+
+
+#define __UL_INIT_DEBUG(lib, pref, mask, env) \
+	do { \
+		if (lib ## _debug_mask & pref ## INIT) \
+		; \
+		else if (!mask) { \
+			char *str = getenv(# env); \
+			if (str) \
+				lib ## _debug_mask = ul_debug_parse_envmask(lib ## _masknames, str); \
+		} else \
+			lib ## _debug_mask = mask; \
+		lib ## _debug_mask |= pref ## INIT; \
+	} while (0)
+
+
+static inline void __attribute__ ((__format__ (__printf__, 1, 2)))
+ul_debug(const char *mesg, ...)
+{
+	va_list ap;
+	va_start(ap, mesg);
+	vfprintf(stderr, mesg, ap);
+	va_end(ap);
+	fputc('\n', stderr);
+}
+
+static inline void __attribute__ ((__format__ (__printf__, 2, 3)))
+ul_debugobj(void *handler, const char *mesg, ...)
+{
+	va_list ap;
+
+	if (handler)
+		fprintf(stderr, "[%p]: ", handler);
+	va_start(ap, mesg);
+	vfprintf(stderr, mesg, ap);
+	va_end(ap);
+	fputc('\n', stderr);
+}
+
+static inline int ul_debug_parse_envmask(
+			const struct ul_debug_maskname flagnames[],
+			const char *mask)
+{
+	int res;
+	char *ptr;
+
+	/* let's check for a numeric mask first */
+	res = strtoul(mask, &ptr, 0);
+
+	/* perhaps it's a comma-separated string? */
+	if (ptr && *ptr && flagnames && flagnames[0].name) {
+		char *msbuf, *ms, *name;
+		res = 0;
+
+		ms = msbuf = strdup(mask);
+		if (!ms)
+			return res;
+
+		while ((name = strtok_r(ms, ",", &ptr))) {
+			const struct ul_debug_maskname *d;
+			ms = ptr;
+
+			for (d = flagnames; d && d->name; d++) {
+				if (strcmp(name, d->name) == 0) {
+					res |= d->mask;
+					break;
+				}
+			}
+			/* nothing else we can do by OR-ing the mask */
+			if (res == 0xffff)
+				break;
+		}
+		free(msbuf);
+	} else if (ptr && strcmp(ptr, "all") == 0)
+		res = 0xffff;
+
+	return res;
+}
+
+static inline void ul_debug_print_masks(
+			const char *env,
+			const struct ul_debug_maskname flagnames[])
+{
+	const struct ul_debug_maskname *d;
+
+	if (!flagnames)
+		return;
+
+	fprintf(stderr, "Available \"%s=<name>[,...]|<mask>\" debug masks:\n",
+			env);
+	for (d = flagnames; d && d->name; d++) {
+		if (!d->help)
+			continue;
+		fprintf(stderr, "   %-8s [0x%04x] : %s\n",
+				d->name, d->mask, d->help);
+	}
+}
+
+#endif /* UTIL_LINUX_DEBUG_H */
diff --git a/libblkid/dev.c b/libblkid/src/dev.c
similarity index 86%
rename from libblkid/dev.c
rename to libblkid/src/dev.c
index 62dfc24..9491331 100644
--- a/libblkid/dev.c
+++ b/libblkid/src/dev.c
@@ -48,10 +48,10 @@
 	if (!dev)
 		return;
 
-	DBG(DEBUG_DEV,
-	    printf("  freeing dev %s (%s)\n", dev->bid_name, dev->bid_type ?
+	DBG(DEV,
+	    ul_debug("  freeing dev %s (%s)", dev->bid_name, dev->bid_type ?
 		   dev->bid_type : "(null)"));
-	DBG(DEBUG_DEV, blkid_debug_dump_dev(dev));
+	DBG(DEV, blkid_debug_dump_dev(dev));
 
 	list_del(&dev->bid_devs);
 	while (!list_empty(&dev->bid_tags)) {
@@ -67,12 +67,11 @@
 /*
  * Given a blkid device, return its name
  */
-extern const char *blkid_dev_devname(blkid_dev dev)
+const char *blkid_dev_devname(blkid_dev dev)
 {
 	return dev ? dev->bid_name : NULL;
 }
 
-#ifdef CONFIG_BLKID_DEBUG
 void blkid_debug_dump_dev(blkid_dev dev)
 {
 	struct list_head *p;
@@ -82,23 +81,21 @@
 		return;
 	}
 
-	printf("  dev: name = %s\n", dev->bid_name);
-	printf("  dev: DEVNO=\"0x%0llx\"\n", (long long)dev->bid_devno);
-	printf("  dev: TIME=\"%ld.%ld\"\n", (long)dev->bid_time, (long)dev->bid_utime);
-	printf("  dev: PRI=\"%d\"\n", dev->bid_pri);
-	printf("  dev: flags = 0x%08X\n", dev->bid_flags);
+	fprintf(stderr, "  dev: name = %s\n", dev->bid_name);
+	fprintf(stderr, "  dev: DEVNO=\"0x%0llx\"\n", (long long)dev->bid_devno);
+	fprintf(stderr, "  dev: TIME=\"%ld.%ld\"\n", (long)dev->bid_time, (long)dev->bid_utime);
+	fprintf(stderr, "  dev: PRI=\"%d\"\n", dev->bid_pri);
+	fprintf(stderr, "  dev: flags = 0x%08X\n", dev->bid_flags);
 
 	list_for_each(p, &dev->bid_tags) {
 		blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags);
 		if (tag)
-			printf("    tag: %s=\"%s\"\n", tag->bit_name,
+			fprintf(stderr, "    tag: %s=\"%s\"\n", tag->bit_name,
 			       tag->bit_val);
 		else
-			printf("    tag: NULL\n");
+			fprintf(stderr, "    tag: NULL\n");
 	}
-	printf("\n");
 }
-#endif
 
 /*
  * dev iteration routines for the public libblkid interface.
@@ -125,10 +122,15 @@
 	struct list_head	*p;
 };
 
-extern blkid_dev_iterate blkid_dev_iterate_begin(blkid_cache cache)
+blkid_dev_iterate blkid_dev_iterate_begin(blkid_cache cache)
 {
 	blkid_dev_iterate iter;
 
+	if (!cache) {
+		errno = EINVAL;
+		return NULL;
+	}
+
 	iter = malloc(sizeof(struct blkid_struct_dev_iterate));
 	if (iter) {
 		iter->magic = DEV_ITERATE_MAGIC;
@@ -140,7 +142,7 @@
 	return iter;
 }
 
-extern int blkid_dev_set_search(blkid_dev_iterate iter,
+int blkid_dev_set_search(blkid_dev_iterate iter,
 				 char *search_type, char *search_value)
 {
 	char *new_type, *new_value;
@@ -167,7 +169,7 @@
 /*
  * Return 0 on success, -1 on error
  */
-extern int blkid_dev_next(blkid_dev_iterate iter,
+int blkid_dev_next(blkid_dev_iterate iter,
 			  blkid_dev *ret_dev)
 {
 	blkid_dev		dev;
@@ -188,7 +190,7 @@
 	return -1;
 }
 
-extern void blkid_dev_iterate_end(blkid_dev_iterate iter)
+void blkid_dev_iterate_end(blkid_dev_iterate iter)
 {
 	if (!iter || iter->magic != DEV_ITERATE_MAGIC)
 		return;
diff --git a/libblkid/devname.c b/libblkid/src/devname.c
similarity index 91%
rename from libblkid/devname.c
rename to libblkid/src/devname.c
index b27b661..fdbb5c9 100644
--- a/libblkid/devname.c
+++ b/libblkid/src/devname.c
@@ -60,8 +60,7 @@
 		if (strcmp(tmp->bid_name, devname))
 			continue;
 
-		DBG(DEBUG_DEVNAME,
-		    printf("found devname %s in cache\n", tmp->bid_name));
+		DBG(DEVNAME, ul_debug("found devname %s in cache", tmp->bid_name));
 		dev = tmp;
 		break;
 	}
@@ -258,9 +257,9 @@
 	int ma, mi;
 	dev_t ret = 0;
 
-	DBG(DEBUG_DEVNAME, printf("opening %s\n", lvm_device));
-	if ((lvf = fopen(lvm_device, "r")) == NULL) {
-		DBG(DEBUG_DEVNAME, printf("%s: (%d) %m\n", lvm_device, errno));
+	DBG(DEVNAME, ul_debug("opening %s", lvm_device));
+	if ((lvf = fopen(lvm_device, "r" UL_CLOEXECSTR)) == NULL) {
+		DBG(DEVNAME, ul_debug("%s: (%d) %m", lvm_device, errno));
 		return 0;
 	}
 
@@ -285,7 +284,7 @@
 	if ((vg_list = opendir(VG_DIR)) == NULL)
 		return;
 
-	DBG(DEBUG_DEVNAME, printf("probing LVM devices under %s\n", VG_DIR));
+	DBG(DEVNAME, ul_debug("probing LVM devices under %s", VG_DIR));
 
 	while ((vg_iter = readdir(vg_list)) != NULL) {
 		DIR		*lv_list;
@@ -323,7 +322,7 @@
 				lv_name);
 			dev = lvm_get_devno(lvm_device);
 			sprintf(lvm_device, "%s/%s", vg_name, lv_name);
-			DBG(DEBUG_DEVNAME, printf("LVM dev %s: devno 0x%04X\n",
+			DBG(DEVNAME, ul_debug("LVM dev %s: devno 0x%04X",
 						  lvm_device,
 						  (unsigned int) dev));
 			probe_one(cache, lvm_device, dev, BLKID_PRI_LVM,
@@ -347,7 +346,7 @@
 	FILE *procpt;
 	char device[110];
 
-	procpt = fopen(PROC_EVMS_VOLUMES, "r");
+	procpt = fopen(PROC_EVMS_VOLUMES, "r" UL_CLOEXECSTR);
 	if (!procpt)
 		return 0;
 	while (fgets(line, sizeof(line), procpt)) {
@@ -355,7 +354,7 @@
 			    &ma, &mi, &sz, device) != 4)
 			continue;
 
-		DBG(DEBUG_DEVNAME, printf("Checking partition %s (%d, %d)\n",
+		DBG(DEVNAME, ul_debug("Checking partition %s (%d, %d)",
 					  device, ma, mi));
 
 		probe_one(cache, device, makedev(ma, mi), BLKID_PRI_EVMS,
@@ -372,12 +371,12 @@
 	const char **dirname;
 
 	for (dirname = dirlist; *dirname; dirname++) {
-		DBG(DEBUG_DEVNAME, printf("probing UBI volumes under %s\n",
-					  *dirname));
-
 		DIR		*dir;
 		struct dirent	*iter;
 
+		DBG(DEVNAME, ul_debug("probing UBI volumes under %s",
+					  *dirname));
+
 		dir = opendir(*dirname);
 		if (dir == NULL)
 			continue ;
@@ -405,7 +404,7 @@
 
 			if (!S_ISCHR(st.st_mode) || !minor(dev))
 				continue;
-			DBG(DEBUG_DEVNAME, printf("UBI vol %s/%s: devno 0x%04X\n",
+			DBG(DEVNAME, ul_debug("UBI vol %s/%s: devno 0x%04X",
 				  *dirname, name, (int) dev));
 			probe_one(cache, name, dev, BLKID_PRI_UBI, only_if_new, 0);
 		}
@@ -446,7 +445,7 @@
 #endif
 	ubi_probe_all(cache, only_if_new);
 
-	proc = fopen(PROC_PARTITIONS, "r");
+	proc = fopen(PROC_PARTITIONS, "r" UL_CLOEXECSTR);
 	if (!proc)
 		return -BLKID_ERR_PROC;
 
@@ -460,7 +459,7 @@
 			continue;
 		devs[which] = makedev(ma, mi);
 
-		DBG(DEBUG_DEVNAME, printf("read partition name %s\n", ptname));
+		DBG(DEVNAME, ul_debug("read partition name %s", ptname));
 
 		/* Skip whole disk devs unless they have no partitions.
 		 * If base name of device has changed, also
@@ -478,8 +477,7 @@
 
 		/* ends in a digit, clearly a partition, so check */
 		if (isdigit(ptname[lens[which] - 1])) {
-			DBG(DEBUG_DEVNAME,
-			    printf("partition dev %s, devno 0x%04X\n",
+			DBG(DEVNAME, ul_debug("partition dev %s, devno 0x%04X",
 				   ptname, (unsigned int) devs[which]));
 
 			if (sz > 1)
@@ -501,8 +499,7 @@
 				tmp = list_entry(p, struct blkid_struct_dev,
 						 bid_devs);
 				if (tmp->bid_devno == devs[last]) {
-					DBG(DEBUG_DEVNAME,
-						printf("freeing %s\n",
+					DBG(DEVNAME, ul_debug("freeing %s",
 						       tmp->bid_name));
 					blkid_free_dev(tmp);
 					cache->bic_flags |= BLKID_BIC_FL_CHANGED;
@@ -517,8 +514,7 @@
 		 * check last as well.
 		 */
 		if (lens[last] && strncmp(ptnames[last], ptname, lens[last])) {
-			DBG(DEBUG_DEVNAME,
-			    printf("whole dev %s, devno 0x%04X\n",
+			DBG(DEVNAME, ul_debug("whole dev %s, devno 0x%04X",
 				   ptnames[last], (unsigned int) devs[last]));
 			probe_one(cache, ptnames[last], devs[last], 0,
 				  only_if_new, 0);
@@ -568,7 +564,8 @@
 			continue;
 
 		if (sysfs_init(&sysfs, devno, NULL) == 0) {
-			sysfs_read_int(&sysfs, "removable", &removable);
+			if (sysfs_read_int(&sysfs, "removable", &removable) != 0)
+				removable = 0;
 			sysfs_deinit(&sysfs);
 		}
 
@@ -593,13 +590,13 @@
 {
 	int ret;
 
-	DBG(DEBUG_PROBE, printf("Begin blkid_probe_all()\n"));
+	DBG(PROBE, ul_debug("Begin blkid_probe_all()"));
 	ret = probe_all(cache, 0);
 	if (ret == 0) {
 		cache->bic_time = time(0);
 		cache->bic_flags |= BLKID_BIC_FL_PROBED;
 	}
-	DBG(DEBUG_PROBE, printf("End blkid_probe_all() [rc=%d]\n", ret));
+	DBG(PROBE, ul_debug("End blkid_probe_all() [rc=%d]", ret));
 	return ret;
 }
 
@@ -615,9 +612,9 @@
 {
 	int ret;
 
-	DBG(DEBUG_PROBE, printf("Begin blkid_probe_all_new()\n"));
+	DBG(PROBE, ul_debug("Begin blkid_probe_all_new()"));
 	ret = probe_all(cache, 1);
-	DBG(DEBUG_PROBE, printf("End blkid_probe_all_new() [rc=%d]\n", ret));
+	DBG(PROBE, ul_debug("End blkid_probe_all_new() [rc=%d]", ret));
 	return ret;
 }
 
@@ -643,9 +640,9 @@
 {
 	int ret;
 
-	DBG(DEBUG_PROBE, printf("Begin blkid_probe_all_removable()\n"));
+	DBG(PROBE, ul_debug("Begin blkid_probe_all_removable()"));
 	ret = probe_all_removable(cache);
-	DBG(DEBUG_PROBE, printf("End blkid_probe_all_removable() [rc=%d]\n", ret));
+	DBG(PROBE, ul_debug("End blkid_probe_all_removable() [rc=%d]", ret));
 	return ret;
 }
 
@@ -655,7 +652,7 @@
 	blkid_cache cache = NULL;
 	int ret;
 
-	blkid_init_debug(DEBUG_ALL);
+	blkid_init_debug(BLKID_DEBUG_ALL);
 	if (argc != 1) {
 		fprintf(stderr, "Usage: %s\n"
 			"Probe all devices and exit\n", argv[0]);
diff --git a/libblkid/devno.c b/libblkid/src/devno.c
similarity index 94%
rename from libblkid/devno.c
rename to libblkid/src/devno.c
index 906c91f..f4a36e4 100644
--- a/libblkid/devno.c
+++ b/libblkid/src/devno.c
@@ -131,8 +131,7 @@
 
 		if (S_ISBLK(st.st_mode) && st.st_rdev == devno) {
 			*devname = blkid_strconcat(dirname, "/", dp->d_name);
-			DBG(DEBUG_DEVNO,
-			    printf("found 0x%llx at %s\n", (long long)devno,
+			DBG(DEVNO, ul_debug("found 0x%llx at %s", (long long)devno,
 				   *devname));
 			break;
 		}
@@ -194,7 +193,7 @@
 		struct dir_list *current = list;
 
 		list = list->next;
-		DBG(DEBUG_DEVNO, printf("directory %s\n", current->name));
+		DBG(DEVNO, ul_debug("directory %s", current->name));
 		blkid__scan_dir(current->name, devno, &new_list, &devname);
 		free(current->name);
 		free(current);
@@ -237,12 +236,10 @@
 		path = scandev_devno_to_devpath(devno);
 
 	if (!path) {
-		DBG(DEBUG_DEVNO,
-		    printf("blkid: couldn't find devno 0x%04lx\n",
+		DBG(DEVNO, ul_debug("blkid: couldn't find devno 0x%04lx",
 			   (unsigned long) devno));
 	} else {
-		DBG(DEBUG_DEVNO,
-		    printf("found devno 0x%04llx as %s\n", (long long)devno, path));
+		DBG(DEVNO, ul_debug("found devno 0x%04llx as %s", (long long)devno, path));
 	}
 
 	return path;
@@ -300,7 +297,7 @@
 	char buf[128];
 	int match = 0;
 
-	f = fopen(_PATH_PROC_DEVICES, "r");
+	f = fopen(_PATH_PROC_DEVICES, "r" UL_CLOEXECSTR);
 	if (!f)
 		return 0;
 
@@ -324,12 +321,11 @@
 
 	fclose(f);
 
-	DBG(DEBUG_DEVNO, printf("major %d %s associated with '%s' driver\n",
+	DBG(DEVNO, ul_debug("major %d %s associated with '%s' driver",
 			major, match ? "is" : "is NOT", drvname));
 	return match;
 }
 
-
 #ifdef TEST_PROGRAM
 int main(int argc, char** argv)
 {
@@ -339,7 +335,7 @@
 	dev_t	devno, disk_devno;
 	const char *errmsg = "Couldn't parse %s: %s\n";
 
-	blkid_init_debug(DEBUG_ALL);
+	blkid_init_debug(BLKID_DEBUG_ALL);
 	if ((argc != 2) && (argc != 3)) {
 		fprintf(stderr, "Usage:\t%s device_number\n\t%s major minor\n"
 			"Resolve a device number to a device name\n",
diff --git a/libblkid/encode.c b/libblkid/src/encode.c
similarity index 100%
rename from libblkid/encode.c
rename to libblkid/src/encode.c
diff --git a/libblkid/env.h b/libblkid/src/env.h
similarity index 100%
rename from libblkid/env.h
rename to libblkid/src/env.h
diff --git a/libblkid/evaluate.c b/libblkid/src/evaluate.c
similarity index 89%
rename from libblkid/evaluate.c
rename to libblkid/src/evaluate.c
index 2e1ca57..ffbe097 100644
--- a/libblkid/evaluate.c
+++ b/libblkid/src/evaluate.c
@@ -24,6 +24,7 @@
 
 #include "pathnames.h"
 #include "canonicalize.h"
+#include "closestream.h"
 
 #include "blkidP.h"
 
@@ -83,7 +84,7 @@
 	if (!rc)
 		rc = memcmp(value, data, len);
 done:
-	DBG(DEBUG_EVALUATE, printf("%s: %s verification %s\n",
+	DBG(EVALUATE, ul_debug("%s: %s verification %s",
 			devname, name, rc == 0 ? "PASS" : "FAILED"));
 	if (fd >= 0)
 		close(fd);
@@ -108,7 +109,7 @@
 	FILE *f;
 	int rc = -1;
 
-	DBG(DEBUG_EVALUATE, printf("%s: uevent '%s' requested\n", devname, action));
+	DBG(EVALUATE, ul_debug("%s: uevent '%s' requested", devname, action));
 
 	if (!devname || !action)
 		return -1;
@@ -118,14 +119,15 @@
 	snprintf(uevent, sizeof(uevent), "/sys/dev/block/%d:%d/uevent",
 			major(st.st_rdev), minor(st.st_rdev));
 
-	f = fopen(uevent, "w");
+	f = fopen(uevent, "w" UL_CLOEXECSTR);
 	if (f) {
 		rc = 0;
 		if (fputs(action, f) >= 0)
 			rc = 0;
-		fclose(f);
+		if (close_stream(f) != 0)
+			DBG(EVALUATE, ul_debug("write failed: %s", uevent));
 	}
-	DBG(DEBUG_EVALUATE, printf("%s: send uevent %s\n",
+	DBG(EVALUATE, ul_debug("%s: send uevent %s",
 			uevent, rc == 0 ? "SUCCES" : "FAILED"));
 	return rc;
 }
@@ -137,8 +139,7 @@
 	size_t len;
 	struct stat st;
 
-	DBG(DEBUG_EVALUATE,
-	    printf("evaluating by udev %s=%s\n", token, value));
+	DBG(EVALUATE, ul_debug("evaluating by udev %s=%s", token, value));
 
 	if (!strcmp(token, "UUID"))
 		strcpy(dev, _PATH_DEV_BYUUID "/");
@@ -149,8 +150,7 @@
 	else if (!strcmp(token, "PARTUUID"))
 		strcpy(dev, _PATH_DEV_BYPARTUUID "/");
 	else {
-		DBG(DEBUG_EVALUATE,
-		    printf("unsupported token %s\n", token));
+		DBG(EVALUATE, ul_debug("unsupported token %s", token));
 		return NULL;	/* unsupported tag */
 	}
 
@@ -158,8 +158,7 @@
 	if (blkid_encode_string(value, &dev[len], sizeof(dev) - len) != 0)
 		return NULL;
 
-	DBG(DEBUG_EVALUATE,
-	    printf("expected udev link: %s\n", dev));
+	DBG(EVALUATE, ul_debug("expected udev link: %s", dev));
 
 	if (stat(dev, &st))
 		goto failed;	/* link or device does not exist */
@@ -178,7 +177,7 @@
 	return path;
 
 failed:
-	DBG(DEBUG_EVALUATE, printf("failed to evaluate by udev\n"));
+	DBG(EVALUATE, ul_debug("failed to evaluate by udev"));
 
 	if (uevent && path)
 		blkid_send_uevent(path, "change");
@@ -192,8 +191,7 @@
 	blkid_cache c = cache ? *cache : NULL;
 	char *res;
 
-	DBG(DEBUG_EVALUATE,
-	    printf("evaluating by blkid scan %s=%s\n", token, value));
+	DBG(EVALUATE, ul_debug("evaluating by blkid scan %s=%s", token, value));
 
 	if (!c) {
 		char *cachefile = blkid_get_cache_filename(conf);
@@ -234,8 +232,7 @@
 	if (!cache || !*cache)
 		blkid_init_debug(0);
 
-	DBG(DEBUG_EVALUATE,
-	    printf("evaluating  %s%s%s\n", token, value ? "=" : "",
+	DBG(EVALUATE, ul_debug("evaluating  %s%s%s", token, value ? "=" : "",
 		   value ? value : ""));
 
 	if (!value) {
@@ -263,8 +260,7 @@
 			break;
 	}
 
-	DBG(DEBUG_EVALUATE,
-	    printf("%s=%s evaluated as %s\n", token, value, ret));
+	DBG(EVALUATE, ul_debug("%s=%s evaluated as %s", token, value, ret));
 out:
 	blkid_free_config(conf);
 	free(t);
diff --git a/libblkid/exec_shell.h b/libblkid/src/exec_shell.h
similarity index 100%
rename from libblkid/exec_shell.h
rename to libblkid/src/exec_shell.h
diff --git a/libblkid/src/fileutils.h b/libblkid/src/fileutils.h
new file mode 100644
index 0000000..3353f69
--- /dev/null
+++ b/libblkid/src/fileutils.h
@@ -0,0 +1,33 @@
+#ifndef UTIL_LINUX_FILEUTILS
+#define UTIL_LINUX_FILEUTILS
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "c.h"
+
+extern int xmkstemp(char **tmpname, char *dir);
+
+static inline FILE *xfmkstemp(char **tmpname, char *dir)
+{
+	int fd;
+	FILE *ret;
+
+	fd = xmkstemp(tmpname, dir);
+	if (fd == -1)
+		return NULL;
+
+	if (!(ret = fdopen(fd, "w+" UL_CLOEXECSTR))) {
+		close(fd);
+		return NULL;
+	}
+	return ret;
+}
+
+extern int get_fd_tabsize(void);
+
+extern int mkdir_p(const char *path, mode_t mode);
+extern char *stripoff_last_component(char *path);
+
+#endif /* UTIL_LINUX_FILEUTILS */
diff --git a/libblkid/getsize.c b/libblkid/src/getsize.c
similarity index 100%
rename from libblkid/getsize.c
rename to libblkid/src/getsize.c
diff --git a/libblkid/src/init.c b/libblkid/src/init.c
new file mode 100644
index 0000000..eead6c7
--- /dev/null
+++ b/libblkid/src/init.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2008-2013 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+/**
+ * SECTION: init
+ * @title: Library initialization
+ * @short_description: initialize debuging
+ */
+
+#include <stdarg.h>
+
+#include "blkidP.h"
+
+UL_DEBUG_DEFINE_MASK(libblkid);
+UL_DEBUG_DEFINE_MASKNAMES(libblkid) =
+{
+	{ "all", BLKID_DEBUG_ALL,	"info about all subsystems" },
+	{ "cache", BLKID_DEBUG_CACHE,	"blkid tags cache" },
+	{ "config", BLKID_DEBUG_CONFIG, "config file utils" },
+	{ "dev", BLKID_DEBUG_DEV,       "device utils" },
+	{ "devname", BLKID_DEBUG_DEVNAME, "/proc/partitions evaluation" },
+	{ "devno", BLKID_DEBUG_DEVNO,	"convertions to device name" },
+	{ "evaluate", BLKID_DEBUG_EVALUATE, "tags resolving" },
+	{ "help", BLKID_DEBUG_HELP,	"this help" },
+	{ "lowprobe", BLKID_DEBUG_LOWPROBE, "superblock/raids/partitions probing" },
+	{ "probe", BLKID_DEBUG_PROBE,	"devices verification" },
+	{ "read", BLKID_DEBUG_READ,	"cache parsing" },
+	{ "save", BLKID_DEBUG_SAVE,	"cache writing" },
+	{ "tag", BLKID_DEBUG_TAG,	"tags utils" },
+	{ NULL, 0, NULL }
+};
+
+/**
+ * blkid_init_debug:
+ * @mask: debug mask (0xffff to enable full debuging)
+ *
+ * If the @mask is not specified then this function reads
+ * LIBBLKID_DEBUG environment variable to get the mask.
+ *
+ * Already initialized debugging stuff cannot be changed. It does not
+ * have effect to call this function twice.
+ */
+void blkid_init_debug(int mask)
+{
+	if (libblkid_debug_mask)
+		return;
+
+	__UL_INIT_DEBUG(libblkid, BLKID_DEBUG_, mask, LIBBLKID_DEBUG);
+
+	if (libblkid_debug_mask != BLKID_DEBUG_INIT
+	    && libblkid_debug_mask != (BLKID_DEBUG_HELP|BLKID_DEBUG_INIT)) {
+		const char *ver = NULL;
+		const char *date = NULL;
+
+		blkid_get_library_version(&ver, &date);
+		DBG(INIT, ul_debug("library debug mask: 0x%04x", libblkid_debug_mask));
+		DBG(INIT, ul_debug("library version: %s [%s]", ver, date));
+
+	}
+	ON_DBG(HELP, ul_debug_print_masks("LIBBLKID_DEBUG",
+				UL_DEBUG_MASKNAMES(libblkid)));
+}
diff --git a/libblkid/ismounted.h b/libblkid/src/ismounted.h
similarity index 100%
rename from libblkid/ismounted.h
rename to libblkid/src/ismounted.h
diff --git a/libblkid/src/libblkid.sym b/libblkid/src/libblkid.sym
new file mode 100644
index 0000000..6b3cf08
--- /dev/null
+++ b/libblkid/src/libblkid.sym
@@ -0,0 +1,166 @@
+/*
+ * The symbol versioning ensures that a new application requiring symbol 'foo'
+ * can't run with old library.so not providing 'foo' - the global SONAME
+ * version info can't enforce this since we never change the SONAME.
+ *
+ * The original libblkid from e2fsprogs (<=1.41.4) does not to use
+ * symbol versioning -- all the original symbols are in BLKID_1.0 now.
+ *
+ * Copyright (C) 2009-2014 Karel Zak <kzak@redhat.com> 
+ */
+BLKID_1.0 {
+global:
+	blkid_dev_devname;
+	blkid_dev_has_tag;
+	blkid_dev_iterate_begin;
+	blkid_dev_iterate_end;
+	blkid_dev_next;
+	blkid_devno_to_devname;
+	blkid_dev_set_search;
+	blkid_find_dev_with_tag;
+	blkid_gc_cache;
+	blkid_get_cache;
+	blkid_get_dev;
+	blkid_get_devname;
+	blkid_get_dev_size;
+	blkid_get_library_version;
+	blkid_get_tag_value;
+	blkid_known_fstype;
+	blkid_parse_tag_string;
+	blkid_parse_version_string;
+	blkid_probe_all;
+	blkid_probe_all_new;
+	blkid_put_cache;
+	blkid_tag_iterate_begin;
+	blkid_tag_iterate_end;
+	blkid_tag_next;
+	blkid_verify;
+local:
+	*;
+};
+
+
+/*
+ * symbols since util-linux 2.15
+ */
+BLKID_2.15 {
+global:
+	blkid_do_probe;
+	blkid_do_safeprobe;
+	blkid_encode_string;
+	blkid_evaluate_tag;
+	blkid_free_probe;
+	blkid_new_probe;
+	blkid_probe_filter_types;
+	blkid_probe_filter_usage;
+	blkid_probe_get_value;
+	blkid_probe_has_value;
+	blkid_probe_invert_filter;
+	blkid_probe_lookup_value;
+	blkid_probe_numof_values;
+	blkid_probe_reset_filter;
+	blkid_probe_set_device;
+	blkid_probe_set_request;
+	blkid_reset_probe;
+	blkid_safe_string;
+	blkid_send_uevent;
+} BLKID_1.0;
+
+/*
+ * symbols since util-linux 2.17
+ */
+BLKID_2.17 {
+global:
+	blkid_devno_to_wholedisk;
+	blkid_do_fullprobe;
+	blkid_known_pttype;
+	blkid_new_probe_from_filename;
+	blkid_partition_get_name;
+	blkid_partition_get_partno;
+	blkid_partition_get_size;
+	blkid_partition_get_start;
+	blkid_partition_get_table;
+	blkid_partition_get_type;
+	blkid_partition_get_type_string;
+	blkid_partition_get_uuid;
+	blkid_partition_is_extended;
+	blkid_partition_is_logical;
+	blkid_partition_is_primary;
+	blkid_partlist_get_partition;
+	blkid_partlist_numof_partitions;
+	blkid_parttable_get_offset;
+	blkid_parttable_get_parent;
+	blkid_parttable_get_type;
+	blkid_probe_enable_partitions;
+	blkid_probe_enable_superblocks;
+	blkid_probe_enable_topology;
+	blkid_probe_filter_partitions_type;
+	blkid_probe_filter_superblocks_type;
+	blkid_probe_filter_superblocks_usage;
+	blkid_probe_get_devno;
+	blkid_probe_get_partitions;
+	blkid_probe_get_sectorsize;
+	blkid_probe_get_sectors;
+	blkid_probe_get_size;
+	blkid_probe_get_topology;
+	blkid_probe_invert_partitions_filter;
+	blkid_probe_invert_superblocks_filter;
+	blkid_probe_reset_partitions_filter;
+	blkid_probe_reset_superblocks_filter;
+	blkid_probe_set_partitions_flags;
+	blkid_probe_set_superblocks_flags;
+	blkid_topology_get_alignment_offset;
+	blkid_topology_get_logical_sector_size;
+	blkid_topology_get_minimum_io_size;
+	blkid_topology_get_optimal_io_size;
+	blkid_topology_get_physical_sector_size;
+} BLKID_2.15;
+
+/*
+ * symbols since util-linux 2.18
+ */
+BLKID_2.18 {
+global:
+	blkid_partition_get_flags;
+	blkid_partlist_devno_to_partition;
+	blkid_partlist_get_table;
+	blkid_probe_all_removable;
+	blkid_probe_get_fd;
+	blkid_probe_get_offset;
+	blkid_probe_get_wholedisk_devno;
+	blkid_probe_is_wholedisk;
+} BLKID_2.17;
+
+/*
+ * symbols since util-linux 2.20
+ */
+BLKID_2.20 {
+global:
+	blkid_evaluate_spec;
+	blkid_superblocks_get_name;
+} BLKID_2.18;
+
+/*
+ * symbols since util-linux 2.21
+ */
+BLKID_2.21 {
+global:
+	blkid_do_wipe;
+} BLKID_2.20;
+
+/*
+ * symbols since util-linux 2.23
+ */
+BLKID_2.23 {
+global:
+	blkid_probe_step_back;
+	blkid_parttable_get_id;
+	blkid_init_debug;
+} BLKID_2.21;
+
+/*
+ * symbols since util-linux 2.25
+ */
+BLKID_2.25 {
+	blkid_partlist_get_partition_by_partno;
+} BLKID_2.23;
diff --git a/libblkid/linux_version.h b/libblkid/src/linux_version.h
similarity index 100%
rename from libblkid/linux_version.h
rename to libblkid/src/linux_version.h
diff --git a/libblkid/list.h b/libblkid/src/list.h
similarity index 100%
rename from libblkid/list.h
rename to libblkid/src/list.h
diff --git a/libblkid/src/llseek.c b/libblkid/src/llseek.c
new file mode 100644
index 0000000..6733478
--- /dev/null
+++ b/libblkid/src/llseek.c
@@ -0,0 +1,142 @@
+/*
+ * llseek.c -- stub calling the llseek system call
+ *
+ * Copyright (C) 1994, 1995, 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ * %End-Header%
+ */
+
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef __MSDOS__
+#include <io.h>
+#endif
+
+#include "blkidP.h"
+
+#ifdef __linux__
+
+#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE)
+
+#define my_llseek lseek64
+
+#elif defined(HAVE_LLSEEK)
+#include <syscall.h>
+
+#ifndef HAVE_LLSEEK_PROTOTYPE
+extern long long llseek(int fd, long long offset, int origin);
+#endif
+
+#define my_llseek llseek
+
+#else	/* ! HAVE_LLSEEK */
+
+#if SIZEOF_LONG == SIZEOF_LONG_LONG
+
+#define llseek lseek
+
+#else /* SIZEOF_LONG != SIZEOF_LONG_LONG */
+
+#include <linux/unistd.h>
+
+#ifndef __NR__llseek
+#define __NR__llseek            140
+#endif
+
+#ifndef __i386__
+static int _llseek(unsigned int, unsigned long, unsigned long,
+		   blkid_loff_t *, unsigned int);
+
+static _syscall5(int, _llseek, unsigned int, fd, unsigned long, offset_high,
+		 unsigned long, offset_low, blkid_loff_t *, result,
+		 unsigned int, origin)
+#endif
+/*
+static blkid_loff_t my_llseek(int fd, blkid_loff_t offset, int origin)
+{
+	blkid_loff_t result;
+	int retval;
+
+#ifndef __i386__
+	retval = _llseek(fd, ((unsigned long long) offset) >> 32,
+			 ((unsigned long long)offset) & 0xffffffff,
+			 &result, origin);
+#else
+	retval = syscall(__NR__llseek, fd, ((unsigned long long) offset) >> 32,
+			 ((unsigned long long)offset) & 0xffffffff,
+			 &result, origin);
+#endif
+	return (retval == -1 ? (blkid_loff_t) retval : result);
+}
+*/
+#endif	/* __alpha__ || __ia64__ */
+
+#endif /* HAVE_LLSEEK */
+
+blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int whence)
+{
+	blkid_loff_t result;
+	static int do_compat = 0;
+
+	if ((sizeof(off_t) >= sizeof(blkid_loff_t)) ||
+	    (offset < ((blkid_loff_t) 1 << ((sizeof(off_t)*8) -1))))
+		return lseek(fd, (off_t) offset, whence);
+
+	if (do_compat) {
+		errno = EOVERFLOW;
+		return -1;
+	}
+
+	result = lseek64(fd, offset, whence);
+	if (result == -1 && errno == ENOSYS) {
+		/*
+		 * Just in case this code runs on top of an old kernel
+		 * which does not support the llseek system call
+		 */
+		do_compat++;
+		errno = EOVERFLOW;
+	}
+	return result;
+}
+
+#else /* !linux */
+
+#ifndef EOVERFLOW
+#ifdef EXT2_ET_INVALID_ARGUMENT
+#define EOVERFLOW EXT2_ET_INVALID_ARGUMENT
+#else
+#define EOVERFLOW 112
+#endif
+#endif
+
+blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int origin)
+{
+#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE)
+	return lseek64 (fd, offset, origin);
+#else
+	if ((sizeof(off_t) < sizeof(blkid_loff_t)) &&
+	    (offset >= ((blkid_loff_t) 1 << ((sizeof(off_t)*8) - 1)))) {
+		errno = EOVERFLOW;
+		return -1;
+	}
+	return lseek(fd, (off_t) offset, origin);
+#endif
+}
+
+#endif	/* linux */
+
+
diff --git a/libblkid/loopdev.h b/libblkid/src/loopdev.h
similarity index 96%
copy from libblkid/loopdev.h
copy to libblkid/src/loopdev.h
index 6efa0c7..573a569 100644
--- a/libblkid/loopdev.h
+++ b/libblkid/src/loopdev.h
@@ -45,7 +45,7 @@
 #define LO_KEY_SIZE	32
 
 /*
- * Linux LOOP_{SET,GET}_STATUS64 ioclt struct
+ * Linux LOOP_{SET,GET}_STATUS64 ioctl struct
  */
 struct loop_info64 {
 	uint64_t	lo_device;
@@ -97,8 +97,8 @@
 	int		flags;		/* LOOPDEV_FL_* flags */
 	unsigned int	has_info:1;	/* .info contains data */
 	unsigned int	extra_check:1;	/* unusual stuff for iterator */
-	unsigned int	debug:1;	/* debug mode ON/OFF */
 	unsigned int	info_failed:1;	/* LOOP_GET_STATUS ioctl failed */
+	unsigned int    control_ok:1;	/* /dev/loop-control success */
 
 	struct sysfs_cxt	sysfs;	/* pointer to /sys/dev/block/<maj:min>/ */
 	struct loop_info64	info;	/* for GET/SET ioctl */
@@ -144,11 +144,11 @@
 extern int loopcxt_init(struct loopdev_cxt *lc, int flags)
 				__attribute__ ((warn_unused_result));
 extern void loopcxt_deinit(struct loopdev_cxt *lc);
-extern void loopcxt_enable_debug(struct loopdev_cxt *lc, int enable);
 
 extern int loopcxt_set_device(struct loopdev_cxt *lc, const char *device)
 				__attribute__ ((warn_unused_result));
 extern int loopcxt_has_device(struct loopdev_cxt *lc);
+extern int loopcxt_add_device(struct loopdev_cxt *lc);
 extern char *loopcxt_strdup_device(struct loopdev_cxt *lc);
 extern const char *loopcxt_get_device(struct loopdev_cxt *lc);
 extern struct sysfs_cxt *loopcxt_get_sysfs(struct loopdev_cxt *lc);
@@ -163,6 +163,7 @@
 
 extern int loopcxt_setup_device(struct loopdev_cxt *lc);
 extern int loopcxt_delete_device(struct loopdev_cxt *lc);
+extern int loopcxt_set_capacity(struct loopdev_cxt *lc);
 
 int loopcxt_set_offset(struct loopdev_cxt *lc, uint64_t offset);
 int loopcxt_set_sizelimit(struct loopdev_cxt *lc, uint64_t sizelimit);
diff --git a/libblkid/mangle.h b/libblkid/src/mangle.h
similarity index 100%
rename from libblkid/mangle.h
rename to libblkid/src/mangle.h
diff --git a/libblkid/match.h b/libblkid/src/match.h
similarity index 100%
rename from libblkid/match.h
rename to libblkid/src/match.h
diff --git a/libblkid/mbsalign.h b/libblkid/src/mbsalign.h
similarity index 68%
copy from libblkid/mbsalign.h
copy to libblkid/src/mbsalign.h
index fd957b3..5eaf606 100644
--- a/libblkid/mbsalign.h
+++ b/libblkid/src/mbsalign.h
@@ -1,9 +1,10 @@
 /* Align/Truncate a string in a given screen width
    Copyright (C) 2009-2010 Free Software Foundation, Inc.
+   Copyright (C) 2010-2013 Karel Zak <kzak@redhat.com>
 
    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
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 2.1 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -13,8 +14,9 @@
 
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
-
-#include <stddef.h>
+#ifndef UTIL_LINUX_MBSALIGN_H
+# define UTIL_LINUX_MBSALIGN_H
+# include <stddef.h>
 
 typedef enum { MBS_ALIGN_LEFT, MBS_ALIGN_RIGHT, MBS_ALIGN_CENTER } mbs_align_t;
 
@@ -43,3 +45,12 @@
 extern size_t mbsalign (const char *src, char *dest,
 			size_t dest_size,  size_t *width,
 			mbs_align_t align, int flags);
+
+extern size_t mbs_safe_nwidth(const char *buf, size_t bufsz, size_t *sz);
+extern size_t mbs_safe_width(const char *s);
+
+extern char *mbs_safe_encode(const char *s, size_t *width);
+extern char *mbs_safe_encode_to_buffer(const char *s, size_t *width, char *buf);
+extern size_t mbs_safe_encode_size(size_t bytes);
+
+#endif /* UTIL_LINUX_MBSALIGN_H */
diff --git a/libblkid/md5.h b/libblkid/src/md5.h
similarity index 100%
rename from libblkid/md5.h
rename to libblkid/src/md5.h
diff --git a/libblkid/nls.h b/libblkid/src/nls.h
similarity index 100%
rename from libblkid/nls.h
rename to libblkid/src/nls.h
diff --git a/libblkid/aix.c b/libblkid/src/partitions/aix.c
similarity index 91%
rename from libblkid/aix.c
rename to libblkid/src/partitions/aix.c
index de397bf..4efdfa3 100644
--- a/libblkid/aix.c
+++ b/libblkid/src/partitions/aix.c
@@ -22,19 +22,17 @@
 
 	if (blkid_partitions_need_typeonly(pr))
 		/* caller does not ask for details about partitions */
-		return 0;
+		return BLKID_PROBE_OK;
 
 	ls = blkid_probe_get_partlist(pr);
 	if (!ls)
-		goto err;
+		return BLKID_PROBE_NONE;
 
 	tab = blkid_partlist_new_parttable(ls, "aix", 0);
 	if (!tab)
-		goto err;
+		return -ENOMEM;
 
-	return 0;
-err:
-	return -1;
+	return BLKID_PROBE_OK;
 }
 
 /*
@@ -42,7 +40,7 @@
  * magic number at begin of the disk.
  *
  * Note, Linux kernel is tring to be smart and AIX signature is ignored when
- * there is a valid DOS partitions table. We don't support such behaviour. All
+ * there is a valid DOS partitions table. We don't support such behavior. All
  * fdisk-like programs has to properly wipe the fist sector. Everything other
  * is a bug.
  */
diff --git a/libblkid/aix.h b/libblkid/src/partitions/aix.h
similarity index 100%
rename from libblkid/aix.h
rename to libblkid/src/partitions/aix.h
diff --git a/libblkid/src/partitions/bsd.c b/libblkid/src/partitions/bsd.c
new file mode 100644
index 0000000..d83f2cf
--- /dev/null
+++ b/libblkid/src/partitions/bsd.c
@@ -0,0 +1,179 @@
+/*
+ * BSD/OSF partition parsing code
+ *
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ * Inspired by fdisk, partx, Linux kernel, libparted and openbsd header files.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "partitions.h"
+#include "pt-bsd.h"
+
+/* Returns 'blkid_idmag' in 512-sectors */
+#define BLKID_MAG_SECTOR(_mag)  (((_mag)->kboff / 2)  + ((_mag)->sboff >> 9))
+
+/* Returns 'blkid_idmag' in bytes */
+#define BLKID_MAG_OFFSET(_mag)  ((_mag)->kboff << 10) + ((_mag)->sboff)
+
+/* Returns 'blkid_idmag' offset in bytes within the last sector */
+#define BLKID_MAG_LASTOFFSET(_mag) \
+		 (BLKID_MAG_OFFSET(_mag) - (BLKID_MAG_SECTOR(_mag) << 9))
+
+static int probe_bsd_pt(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct bsd_disklabel *l;
+	struct bsd_partition *p;
+	const char *name = "bsd" ;
+	blkid_parttable tab = NULL;
+	blkid_partition parent;
+	blkid_partlist ls;
+	int i, nparts = BSD_MAXPARTITIONS;
+	unsigned char *data;
+	int rc = BLKID_PROBE_NONE;
+
+	if (blkid_partitions_need_typeonly(pr))
+		/* caller does not ask for details about partitions */
+		return rc;
+
+	data = blkid_probe_get_sector(pr, BLKID_MAG_SECTOR(mag));
+	if (!data) {
+		if (errno)
+			rc = -errno;
+		goto nothing;
+	}
+
+	l = (struct bsd_disklabel *) data + BLKID_MAG_LASTOFFSET(mag);
+
+	ls = blkid_probe_get_partlist(pr);
+	if (!ls)
+		goto nothing;
+
+	/* try to determine the real type of BSD system according to
+	 * (parental) primary partition */
+	parent = blkid_partlist_get_parent(ls);
+	if (parent) {
+		switch(blkid_partition_get_type(parent)) {
+		case MBR_FREEBSD_PARTITION:
+			name = "freebsd";
+			break;
+		case MBR_NETBSD_PARTITION:
+			name = "netbsd";
+			break;
+		case MBR_OPENBSD_PARTITION:
+			name = "openbsd";
+			break;
+		default:
+			DBG(LOWPROBE, ul_debug(
+				"WARNING: BSD label detected on unknown (0x%x) "
+				"primary partition",
+				blkid_partition_get_type(parent)));
+			break;
+		}
+	}
+
+	tab = blkid_partlist_new_parttable(ls, name, BLKID_MAG_OFFSET(mag));
+	if (!tab) {
+		rc = -ENOMEM;
+		goto nothing;
+	}
+
+	if (le16_to_cpu(l->d_npartitions) < BSD_MAXPARTITIONS)
+		nparts = le16_to_cpu(l->d_npartitions);
+
+	else if (le16_to_cpu(l->d_npartitions) > BSD_MAXPARTITIONS)
+		DBG(LOWPROBE, ul_debug(
+			"WARNING: ignore %d more BSD partitions",
+			le16_to_cpu(l->d_npartitions) - BSD_MAXPARTITIONS));
+
+	for (i = 0, p = l->d_partitions; i < nparts; i++, p++) {
+		blkid_partition par;
+		uint32_t start, size;
+
+		/* TODO: in fdisk-mode returns all non-zero (p_size) partitions */
+		if (p->p_fstype == BSD_FS_UNUSED)
+			continue;
+
+		start = le32_to_cpu(p->p_offset);
+		size = le32_to_cpu(p->p_size);
+
+		if (parent && blkid_partition_get_start(parent) == start
+			   && blkid_partition_get_size(parent) == size) {
+			DBG(LOWPROBE, ul_debug(
+				"WARNING: BSD partition (%d) same like parent, "
+				"ignore", i));
+			continue;
+		}
+		if (parent && !blkid_is_nested_dimension(parent, start, size)) {
+			DBG(LOWPROBE, ul_debug(
+				"WARNING: BSD partition (%d) overflow "
+				"detected, ignore", i));
+			continue;
+		}
+
+		par = blkid_partlist_add_partition(ls, tab, start, size);
+		if (!par) {
+			rc = -ENOMEM;
+			goto nothing;
+		}
+
+		blkid_partition_set_type(par, p->p_fstype);
+	}
+
+	return BLKID_PROBE_OK;
+
+nothing:
+	return rc;
+}
+
+
+/*
+ * All BSD variants use the same magic string (little-endian),
+ * and the same disklabel.
+ *
+ * The difference between {Free,Open,...}BSD is in the (parental)
+ * primary partition type.
+ *
+ * See also: http://en.wikipedia.org/wiki/BSD_disklabel
+ *
+ * The location of BSD disk label is architecture specific and in defined by
+ * LABELSECTOR and LABELOFFSET macros in the disklabel.h file. The location
+ * also depends on BSD variant, FreeBSD uses only one location, NetBSD and
+ * OpenBSD are more creative...
+ *
+ * The basic overview:
+ *
+ * arch                    | LABELSECTOR | LABELOFFSET
+ * ------------------------+-------------+------------
+ * amd64 arm hppa hppa64   |             |
+ * i386, macppc, mvmeppc   |      1      |      0
+ * sgi, aviion, sh, socppc |             |
+ * ------------------------+-------------+------------
+ * alpha luna88k mac68k    |      0      |     64
+ * sparc(OpenBSD) vax      |             |
+ * ------------------------+-------------+------------
+ * sparc64 sparc(NetBSD)   |      0      |    128
+ * ------------------------+-------------+------------
+ *
+ * ...and more (see http://fxr.watson.org/fxr/ident?v=NETBSD;i=LABELSECTOR)
+ *
+ */
+const struct blkid_idinfo bsd_pt_idinfo =
+{
+	.name		= "bsd",
+	.probefunc	= probe_bsd_pt,
+	.magics		=
+	{
+		{ .magic = "\x57\x45\x56\x82", .len = 4, .sboff = 512 },
+		{ .magic = "\x57\x45\x56\x82", .len = 4, .sboff = 64 },
+		{ .magic = "\x57\x45\x56\x82", .len = 4, .sboff = 128 },
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/dos.c b/libblkid/src/partitions/dos.c
similarity index 69%
rename from libblkid/dos.c
rename to libblkid/src/partitions/dos.c
index 5887769..2539908 100644
--- a/libblkid/dos.c
+++ b/libblkid/src/partitions/dos.c
@@ -14,7 +14,6 @@
 #include <stdint.h>
 
 #include "partitions.h"
-#include "dos.h"
 #include "aix.h"
 
 /* see superblocks/vfat.c */
@@ -24,19 +23,19 @@
 	unsigned char type;
 	const struct blkid_idinfo *id;
 } dos_nested[] = {
-	{ BLKID_FREEBSD_PARTITION, &bsd_pt_idinfo },
-	{ BLKID_NETBSD_PARTITION, &bsd_pt_idinfo },
-	{ BLKID_OPENBSD_PARTITION, &bsd_pt_idinfo },
-	{ BLKID_UNIXWARE_PARTITION, &unixware_pt_idinfo },
-	{ BLKID_SOLARIS_X86_PARTITION, &solaris_x86_pt_idinfo },
-	{ BLKID_MINIX_PARTITION, &minix_pt_idinfo }
+	{ MBR_FREEBSD_PARTITION, &bsd_pt_idinfo },
+	{ MBR_NETBSD_PARTITION, &bsd_pt_idinfo },
+	{ MBR_OPENBSD_PARTITION, &bsd_pt_idinfo },
+	{ MBR_UNIXWARE_PARTITION, &unixware_pt_idinfo },
+	{ MBR_SOLARIS_X86_PARTITION, &solaris_x86_pt_idinfo },
+	{ MBR_MINIX_PARTITION, &minix_pt_idinfo }
 };
 
 static inline int is_extended(struct dos_partition *p)
 {
-	return (p->sys_type == BLKID_DOS_EXTENDED_PARTITION ||
-		p->sys_type == BLKID_W95_EXTENDED_PARTITION ||
-		p->sys_type == BLKID_LINUX_EXTENDED_PARTITION);
+	return (p->sys_ind == MBR_DOS_EXTENDED_PARTITION ||
+		p->sys_ind == MBR_W95_EXTENDED_PARTITION ||
+		p->sys_ind == MBR_LINUX_EXTENDED_PARTITION);
 }
 
 static int parse_dos_extended(blkid_probe pr, blkid_parttable tab,
@@ -53,15 +52,18 @@
 		uint32_t start, size;
 
 		if (++ct_nodata > 100)
-			return 0;
+			return BLKID_PROBE_OK;
 		data = blkid_probe_get_sector(pr, cur_start);
-		if (!data)
+		if (!data) {
+			if (errno)
+				return -errno;
 			goto leave;	/* malformed partition? */
+		}
 
-		if (!is_valid_mbr_signature(data))
+		if (!mbr_is_valid_magic(data))
 			goto leave;
 
-		p0 = (struct dos_partition *) (data + BLKID_MSDOS_PT_OFFSET);
+		p0 = mbr_get_partition(data, 0);
 
 		/* Usually, the first entry is the real data partition,
 		 * the 2nd entry is the next extended partition, or empty,
@@ -80,8 +82,8 @@
 			blkid_partition par;
 
 			/* the start is relative to the parental ext.partition */
-			start = dos_partition_start(p) * ssf;
-			size = dos_partition_size(p) * ssf;
+			start = dos_partition_get_start(p) * ssf;
+			size = dos_partition_get_size(p) * ssf;
 			abs_start = cur_start + start;	/* absolute start */
 
 			if (!size || is_extended(p))
@@ -99,10 +101,11 @@
 
 			par = blkid_partlist_add_partition(ls, tab, abs_start, size);
 			if (!par)
-				goto err;
+				return -ENOMEM;
 
-			blkid_partition_set_type(par, p->sys_type);
+			blkid_partition_set_type(par, p->sys_ind);
 			blkid_partition_set_flags(par, p->boot_ind);
+			blkid_partition_gen_uuid(par);
 			ct_nodata = 0;
 		}
 		/* The first nested ext.partition should be a link to the next
@@ -110,8 +113,8 @@
 		 * is junk.
 		 */
 		for (p = p0, i = 0; i < 4; i++, p++) {
-			start = dos_partition_start(p) * ssf;
-			size = dos_partition_size(p) * ssf;
+			start = dos_partition_get_start(p) * ssf;
+			size = dos_partition_get_size(p) * ssf;
 
 			if (size && is_extended(p))
 				break;
@@ -123,9 +126,7 @@
 		cur_size = size;
 	}
 leave:
-	return 0;
-err:
-	return -1;
+	return BLKID_PROBE_OK;
 }
 
 static int probe_dos_pt(blkid_probe pr,
@@ -138,10 +139,15 @@
 	struct dos_partition *p0, *p;
 	unsigned char *data;
 	uint32_t start, size, id;
+	char idstr[37];
+
 
 	data = blkid_probe_get_sector(pr, 0);
-	if (!data)
+	if (!data) {
+		if (errno)
+			return -errno;
 		goto nothing;
+	}
 
 	/* ignore disks with AIX magic number -- for more details see aix.c */
 	if (memcmp(data, BLKID_AIX_MAGIC_STRING, BLKID_AIX_MAGIC_STRLEN) == 0)
@@ -152,19 +158,19 @@
 	 * either the boot sector of a FAT filesystem or a DOS-type
 	 * partition table.
 	 */
-	if (blkid_probe_is_vfat(pr)) {
-		DBG(DEBUG_LOWPROBE, printf("probably FAT -- ignore\n"));
+	if (blkid_probe_is_vfat(pr) == 1) {
+		DBG(LOWPROBE, ul_debug("probably FAT -- ignore"));
 		goto nothing;
 	}
 
-	p0 = (struct dos_partition *) (data + BLKID_MSDOS_PT_OFFSET);
+	p0 = mbr_get_partition(data, 0);
 
 	/*
 	 * Reject PT where boot indicator is not 0 or 0x80.
 	 */
 	for (p = p0, i = 0; i < 4; i++, p++)
 		if (p->boot_ind != 0 && p->boot_ind != 0x80) {
-			DBG(DEBUG_LOWPROBE, printf("missing boot indicator -- ignore\n"));
+			DBG(LOWPROBE, ul_debug("missing boot indicator -- ignore"));
 			goto nothing;
 		}
 
@@ -172,23 +178,32 @@
 	 * GPT uses valid MBR
 	 */
 	for (p = p0, i = 0; i < 4; i++, p++) {
-		if (p->sys_type == BLKID_GPT_PARTITION) {
-			DBG(DEBUG_LOWPROBE, printf("probably GPT -- ignore\n"));
+		if (p->sys_ind == MBR_GPT_PARTITION) {
+			DBG(LOWPROBE, ul_debug("probably GPT -- ignore"));
 			goto nothing;
 		}
 	}
 
-	blkid_probe_use_wiper(pr, BLKID_MSDOS_PT_OFFSET,
-				  512 - BLKID_MSDOS_PT_OFFSET);
+	blkid_probe_use_wiper(pr, MBR_PT_OFFSET, 512 - MBR_PT_OFFSET);
+
+	id = mbr_get_id(data);
+	if (id)
+		snprintf(idstr, sizeof(idstr), "%08x", id);
 
 	/*
 	 * Well, all checks pass, it's MS-DOS partiton table
 	 */
-	if (blkid_partitions_need_typeonly(pr))
-		/* caller does not ask for details about partitions */
+	if (blkid_partitions_need_typeonly(pr)) {
+		/* Non-binary interface -- caller does not ask for details
+		 * about partitions, just set generic varibles only. */
+		if (id)
+			blkid_partitions_strcpy_ptuuid(pr, idstr);
 		return 0;
+	}
 
 	ls = blkid_probe_get_partlist(pr);
+	if (!ls)
+		goto nothing;
 
 	/* sector size factor (the start and size are in the real sectors, but
 	 * we need to convert all sizes to 512 logical sectors
@@ -196,25 +211,19 @@
 	ssf = blkid_probe_get_sectorsize(pr) / 512;
 
 	/* allocate a new partition table */
-	tab = blkid_partlist_new_parttable(ls, "dos", BLKID_MSDOS_PT_OFFSET);
+	tab = blkid_partlist_new_parttable(ls, "dos", MBR_PT_OFFSET);
 	if (!tab)
-		goto err;
+		return -ENOMEM;
 
-	id = dos_parttable_id(data);
-	if (id) {
-		char buf[37];
-
-		snprintf(buf, sizeof(buf), "0x%08x", id);
-		blkid_parttable_set_id(tab, (unsigned char *) buf);
-	}
-
+	if (id)
+		blkid_parttable_set_id(tab, (unsigned char *) idstr);
 
 	/* Parse primary partitions */
 	for (p = p0, i = 0; i < 4; i++, p++) {
 		blkid_partition par;
 
-		start = dos_partition_start(p) * ssf;
-		size = dos_partition_size(p) * ssf;
+		start = dos_partition_get_start(p) * ssf;
+		size = dos_partition_get_size(p) * ssf;
 
 		if (!size) {
 			/* Linux kernel ignores empty partitions, but partno for
@@ -224,10 +233,11 @@
 		}
 		par = blkid_partlist_add_partition(ls, tab, start, size);
 		if (!par)
-			goto err;
+			return -ENOMEM;
 
-		blkid_partition_set_type(par, p->sys_type);
+		blkid_partition_set_type(par, p->sys_ind);
 		blkid_partition_set_flags(par, p->boot_ind);
+		blkid_partition_gen_uuid(par);
 	}
 
 	/* Linux uses partition numbers greater than 4
@@ -237,42 +247,42 @@
 
 	/* Parse logical partitions */
 	for (p = p0, i = 0; i < 4; i++, p++) {
-		start = dos_partition_start(p) * ssf;
-		size = dos_partition_size(p) * ssf;
+		start = dos_partition_get_start(p) * ssf;
+		size = dos_partition_get_size(p) * ssf;
 
 		if (!size)
 			continue;
 		if (is_extended(p) &&
 		    parse_dos_extended(pr, tab, start, size, ssf) == -1)
-			goto err;
+			goto nothing;
 	}
 
 	/* Parse subtypes (nested partitions) on large disks */
 	if (!blkid_probe_is_tiny(pr)) {
 		for (p = p0, i = 0; i < 4; i++, p++) {
 			size_t n;
+			int rc;
 
-			if (!dos_partition_size(p) || is_extended(p))
+			if (!dos_partition_get_size(p) || is_extended(p))
 				continue;
 
 			for (n = 0; n < ARRAY_SIZE(dos_nested); n++) {
-				if (dos_nested[n].type != p->sys_type)
+				if (dos_nested[n].type != p->sys_ind)
 					continue;
 
-				if (blkid_partitions_do_subprobe(pr,
+				rc = blkid_partitions_do_subprobe(pr,
 						blkid_partlist_get_partition(ls, i),
-						dos_nested[n].id) == -1)
-					goto err;
+						dos_nested[n].id);
+				if (rc < 0)
+					return rc;
 				break;
 			}
 		}
 	}
-	return 0;
+	return BLKID_PROBE_OK;
 
 nothing:
-	return 1;
-err:
-	return -1;
+	return BLKID_PROBE_NONE;
 }
 
 
diff --git a/libblkid/gpt.c b/libblkid/src/partitions/gpt.c
similarity index 79%
rename from libblkid/gpt.c
rename to libblkid/src/partitions/gpt.c
index 7288d68..665577f 100644
--- a/libblkid/gpt.c
+++ b/libblkid/src/partitions/gpt.c
@@ -17,10 +17,10 @@
 #include <stdlib.h>
 #include <stdint.h>
 #include <stddef.h>
+#include <limits.h>
 
 #include "partitions.h"
 #include "crc32.h"
-#include "dos.h"
 
 #define GPT_PRIMARY_LBA	1
 
@@ -156,32 +156,37 @@
  * Note that the PMBR detection is optional (enabled by default) and could be
  * disabled by BLKID_PARTS_FOPCE_GPT flag (see also blkid_paertitions_set_flags()).
  */
-static int is_pmbr_valid(blkid_probe pr)
+static int is_pmbr_valid(blkid_probe pr, int *has)
 {
 	int flags = blkid_partitions_get_flags(pr);
 	unsigned char *data;
 	struct dos_partition *p;
 	int i;
 
+	if (has)
+		*has = 0;
 	if (flags & BLKID_PARTS_FORCE_GPT)
 		goto ok;			/* skip PMBR check */
 
 	data = blkid_probe_get_sector(pr, 0);
-	if (!data)
+	if (!data) {
+		if (errno)
+			return -errno;
+		goto failed;
+	}
+
+	if (!mbr_is_valid_magic(data))
 		goto failed;
 
-	if (!is_valid_mbr_signature(data))
-		goto failed;
-
-	p = (struct dos_partition *) (data + BLKID_MSDOS_PT_OFFSET);
-
-	for (i = 0; i < 4; i++, p++) {
-		if (p->sys_type == BLKID_GPT_PARTITION)
+	for (i = 0, p = mbr_get_partition(data, 0); i < 4; i++, p++) {
+		if (p->sys_ind == MBR_GPT_PARTITION)
 			goto ok;
 	}
 failed:
 	return 0;
 ok:
+	if (has)
+		*has = 1;
 	return 1;
 }
 
@@ -232,14 +237,14 @@
 	h->header_crc32 = orgcrc;
 
 	if (crc != le32_to_cpu(orgcrc)) {
-		DBG(DEBUG_LOWPROBE, printf("GPT header corrupted\n"));
+		DBG(LOWPROBE, ul_debug("GPT header corrupted"));
 		return NULL;
 	}
 
 	/* Valid header has to be at MyLBA */
 	if (le64_to_cpu(h->my_lba) != lba) {
-		DBG(DEBUG_LOWPROBE, printf(
-			"GPT->MyLBA mismatch with real position\n"));
+		DBG(LOWPROBE, ul_debug(
+			"GPT->MyLBA mismatch with real position"));
 		return NULL;
 	}
 
@@ -248,24 +253,27 @@
 
 	/* Check if First and Last usable LBA makes sense */
 	if (lu < fu || fu > lastlba || lu > lastlba) {
-		DBG(DEBUG_LOWPROBE, printf(
-			"GPT->{First,Last}UsableLBA out of range\n"));
+		DBG(LOWPROBE, ul_debug(
+			"GPT->{First,Last}UsableLBA out of range"));
 		return NULL;
 	}
 
 	/* The header has to be outside usable range */
 	if (fu < lba && lba < lu) {
-		DBG(DEBUG_LOWPROBE, printf("GPT header is inside usable area\n"));
+		DBG(LOWPROBE, ul_debug("GPT header is inside usable area"));
+		return NULL;
+	}
+
+	if (le32_to_cpu(h->num_partition_entries) == 0 ||
+	    le32_to_cpu(h->sizeof_partition_entry) == 0 ||
+	    ULONG_MAX / le32_to_cpu(h->num_partition_entries) < le32_to_cpu(h->sizeof_partition_entry)) {
+		DBG(LOWPROBE, ul_debug("GPT entries undefined"));
 		return NULL;
 	}
 
 	/* Size of blocks with GPT entries */
 	esz = le32_to_cpu(h->num_partition_entries) *
 			le32_to_cpu(h->sizeof_partition_entry);
-	if (!esz) {
-		DBG(DEBUG_LOWPROBE, printf("GPT entries undefined\n"));
-		return NULL;
-	}
 
 	/* The header seems valid, save it
 	 * (we don't care about zeros in hdr->reserved2 area) */
@@ -276,14 +284,14 @@
 	*ents = (struct gpt_entry *) get_lba_buffer(pr,
 				le64_to_cpu(h->partition_entries_lba), esz);
 	if (!*ents) {
-		DBG(DEBUG_LOWPROBE, printf("GPT entries unreadable\n"));
+		DBG(LOWPROBE, ul_debug("GPT entries unreadable"));
 		return NULL;
 	}
 
 	/* Validate entries */
 	crc = count_crc32((unsigned char *) *ents, esz);
 	if (crc != le32_to_cpu(h->partition_entry_array_crc32)) {
-		DBG(DEBUG_LOWPROBE, printf("GPT entries corrupted\n"));
+		DBG(LOWPROBE, ul_debug("GPT entries corrupted"));
 		return NULL;
 	}
 
@@ -301,42 +309,55 @@
 	uint64_t fu, lu;
 	uint32_t ssf, i;
 	efi_guid_t guid;
+	int ret;
 
 	if (last_lba(pr, &lastlba))
 		goto nothing;
 
-	if (!is_pmbr_valid(pr))
+	ret = is_pmbr_valid(pr, NULL);
+	if (ret < 0)
+		return ret;
+	else if (ret == 0)
 		goto nothing;
 
+	errno = 0;
 	h = get_gpt_header(pr, &hdr, &e, (lba = GPT_PRIMARY_LBA), lastlba);
-	if (!h)
+	if (!h && !errno)
 		h = get_gpt_header(pr, &hdr, &e, (lba = lastlba), lastlba);
 
-	if (!h)
+	if (!h) {
+		if (errno)
+			return -errno;
 		goto nothing;
+	}
 
 	blkid_probe_use_wiper(pr, lba * blkid_probe_get_size(pr), 8);
 
-	if (blkid_probe_set_magic(pr, lba << 9,
+	if (blkid_probe_set_magic(pr, blkid_probe_get_sectorsize(pr) * lba,
 			      sizeof(GPT_HEADER_SIGNATURE_STR) - 1,
 			      (unsigned char *) GPT_HEADER_SIGNATURE_STR))
 		goto err;
 
-	if (blkid_partitions_need_typeonly(pr))
-		/* caller does not ask for details about partitions */
-		return 0;
+	guid = h->disk_guid;
+	swap_efi_guid(&guid);
+
+	if (blkid_partitions_need_typeonly(pr)) {
+		/* Non-binary interface -- caller does not ask for details
+		 * about partitions, just set generic varibles only. */
+		blkid_partitions_set_ptuuid(pr, (unsigned char *) &guid);
+		return BLKID_PROBE_OK;
+	}
 
 	ls = blkid_probe_get_partlist(pr);
 	if (!ls)
-		goto err;
+		goto nothing;
 
-	tab = blkid_partlist_new_parttable(ls, "gpt", lba << 9);
+	tab = blkid_partlist_new_parttable(ls, "gpt",
+				blkid_probe_get_sectorsize(pr) * lba);
 	if (!tab)
 		goto err;
 
-	guid = h->disk_guid;
-	swap_efi_guid(&guid);
-	blkid_parttable_set_id(tab, (const unsigned char *) &guid);
+	blkid_parttable_set_uuid(tab, (const unsigned char *) &guid);
 
 	ssf = blkid_probe_get_sectorsize(pr) / 512;
 
@@ -357,8 +378,8 @@
 		}
 		/* the partition has to inside usable range */
 		if (start < fu || start + size - 1 > lu) {
-			DBG(DEBUG_LOWPROBE, printf(
-				"GPT entry[%d] overflows usable area - ignore\n",
+			DBG(LOWPROBE, ul_debug(
+				"GPT entry[%d] overflows usable area - ignore",
 				i));
 			blkid_partlist_increment_partno(ls);
 			continue;
@@ -381,15 +402,16 @@
 		swap_efi_guid(&guid);
 		blkid_partition_set_type_uuid(par, (const unsigned char *) &guid);
 
-		blkid_partition_set_flags(par, e->attributes);
+		blkid_partition_set_flags(par, le64_to_cpu(e->attributes));
 	}
 
-	return 0;
+	return BLKID_PROBE_OK;
 
 nothing:
-	return 1;
+	return BLKID_PROBE_NONE;
+
 err:
-	return -1;
+	return -ENOMEM;
 }
 
 
@@ -410,3 +432,39 @@
 	.magics		= BLKID_NONE_MAGIC
 };
 
+
+
+/* probe for *alone* protective MBR */
+static int probe_pmbr_pt(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	int has = 0;
+	struct gpt_entry *e;
+	uint64_t lastlba = 0;
+	struct gpt_header hdr;
+
+	if (last_lba(pr, &lastlba))
+		goto nothing;
+
+	is_pmbr_valid(pr, &has);
+	if (!has)
+		goto nothing;
+
+	if (!get_gpt_header(pr, &hdr, &e, GPT_PRIMARY_LBA, lastlba) &&
+	    !get_gpt_header(pr, &hdr, &e, lastlba, lastlba))
+		return 0;
+nothing:
+	return 1;
+}
+
+const struct blkid_idinfo pmbr_pt_idinfo =
+{
+	.name		= "PMBR",
+	.probefunc	= probe_pmbr_pt,
+	.magics		=
+	{
+		{ .magic = "\x55\xAA", .len = 2, .sboff = 510 },
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/mac.c b/libblkid/src/partitions/mac.c
similarity index 93%
rename from libblkid/mac.c
rename to libblkid/src/partitions/mac.c
index e18896c..4282605 100644
--- a/libblkid/mac.c
+++ b/libblkid/src/partitions/mac.c
@@ -87,8 +87,11 @@
 	 * the first block on the disk.
 	 */
 	md = (struct mac_driver_desc *) blkid_probe_get_sector(pr, 0);
-	if (!md)
+	if (!md) {
+		if (errno)
+			return -errno;
 		goto nothing;
+	}
 
 	block_size = be16_to_cpu(md->block_size);
 
@@ -96,8 +99,11 @@
 	 * the second block on the disk.
 	 */
 	p = (struct mac_partition *) get_mac_block(pr, block_size, 1);
-	if (!p)
+	if (!p) {
+		if (errno)
+			return -errno;
 		goto nothing;
+	}
 
 	/* check the first partition signature */
 	if (!has_part_signature(p))
@@ -109,7 +115,7 @@
 
 	ls = blkid_probe_get_partlist(pr);
 	if (!ls)
-		goto err;
+		goto nothing;
 
 	tab = blkid_partlist_new_parttable(ls, "mac", 0);
 	if (!tab)
@@ -124,15 +130,18 @@
 		uint32_t size;
 
 		p = (struct mac_partition *) get_mac_block(pr, block_size, i);
-		if (!p)
+		if (!p) {
+			if (errno)
+				return -errno;
 			goto nothing;
+		}
 		if (!has_part_signature(p))
 			goto nothing;
 
 		if (be32_to_cpu(p->map_count) != nblks) {
-			DBG(DEBUG_LOWPROBE, printf(
+			DBG(LOWPROBE, ul_debug(
 				"mac: inconsisten map_count in partition map, "
-			        "entry[0]: %d, entry[%d]: %d\n",
+				"entry[0]: %d, entry[%d]: %d",
 				nblks, i - 1,
 				be32_to_cpu(p->map_count)));
 		}
@@ -157,12 +166,12 @@
 						sizeof(p->type));
 	}
 
-	return 0;
+	return BLKID_PROBE_OK;
 
 nothing:
-	return 1;
+	return BLKID_PROBE_NONE;
 err:
-	return -1;
+	return -ENOMEM;
 }
 
 /*
diff --git a/libblkid/minix2.c b/libblkid/src/partitions/minix.c
similarity index 72%
rename from libblkid/minix2.c
rename to libblkid/src/partitions/minix.c
index bd57a6d..43c9d9a 100644
--- a/libblkid/minix2.c
+++ b/libblkid/src/partitions/minix.c
@@ -12,7 +12,6 @@
 #include <stdint.h>
 
 #include "partitions.h"
-#include "dos.h"
 #include "minix.h"
 
 static int probe_minix_pt(blkid_probe pr,
@@ -26,12 +25,15 @@
 	int i;
 
 	data = blkid_probe_get_sector(pr, 0);
-	if (!data)
+	if (!data) {
+		if (errno)
+			return -errno;
 		goto nothing;
+	}
 
 	ls = blkid_probe_get_partlist(pr);
 	if (!ls)
-		goto err;
+		goto nothing;
 
 	/* Parent is required, because Minix uses the same PT as DOS and
 	 * difference is only in primary partition (parent) type.
@@ -40,33 +42,33 @@
 	if (!parent)
 		goto nothing;
 
-	if (blkid_partition_get_type(parent) != BLKID_MINIX_PARTITION)
+	if (blkid_partition_get_type(parent) != MBR_MINIX_PARTITION)
 		goto nothing;
 
 	if (blkid_partitions_need_typeonly(pr))
 		/* caller does not ask for details about partitions */
-		return 0;
+		return BLKID_PROBE_OK;
 
-	p = (struct dos_partition *) (data + BLKID_MSDOS_PT_OFFSET);
-
-	tab = blkid_partlist_new_parttable(ls, "minix", BLKID_MSDOS_PT_OFFSET);
+	tab = blkid_partlist_new_parttable(ls, "minix", MBR_PT_OFFSET);
 	if (!tab)
 		goto err;
 
-	for (i = 0; i < MINIX_MAXPARTITIONS; i++, p++) {
+	for (i = 0, p = mbr_get_partition(data, 0);
+			i < MINIX_MAXPARTITIONS; i++, p++) {
+
 		uint32_t start, size;
 		blkid_partition par;
 
-		if (p->sys_type != BLKID_MINIX_PARTITION)
+		if (p->sys_ind != MBR_MINIX_PARTITION)
 			continue;
 
-		start = dos_partition_start(p);
-		size = dos_partition_size(p);
+		start = dos_partition_get_start(p);
+		size = dos_partition_get_size(p);
 
 		if (parent && !blkid_is_nested_dimension(parent, start, size)) {
-			DBG(DEBUG_LOWPROBE, printf(
+			DBG(LOWPROBE, ul_debug(
 				"WARNING: minix partition (%d) overflow "
-				"detected, ignore\n", i));
+				"detected, ignore", i));
 			continue;
 		}
 
@@ -74,16 +76,16 @@
 		if (!par)
 			goto err;
 
-		blkid_partition_set_type(par, p->sys_type);
+		blkid_partition_set_type(par, p->sys_ind);
 		blkid_partition_set_flags(par, p->boot_ind);
 	}
 
-	return 0;
+	return BLKID_PROBE_OK;
 
 nothing:
-	return 1;
+	return BLKID_PROBE_NONE;
 err:
-	return -1;
+	return -ENOMEM;
 }
 
 /* same as DOS */
diff --git a/libblkid/partitions.c b/libblkid/src/partitions/partitions.c
similarity index 83%
rename from libblkid/partitions.c
rename to libblkid/src/partitions/partitions.c
index 93ec4d2..4853f97 100644
--- a/libblkid/partitions.c
+++ b/libblkid/src/partitions/partitions.c
@@ -37,11 +37,13 @@
  *
  * @PTTYPE: partition table type (dos, gpt, etc.).
  *
+ * @PTUUID: partition table id (uuid for gpt, hex for dos).
+
  * @PART_ENTRY_SCHEME: partition table type
  *
  * @PART_ENTRY_NAME: partition name (gpt and mac only)
  *
- * @PART_ENTRY_UUID: partition UUID (gpt only)
+ * @PART_ENTRY_UUID: partition UUID (gpt, or pseudo IDs for MBR)
  *
  * @PART_ENTRY_TYPE: partition type, 0xNN (e.g 0x82) or type UUID (gpt only) or type string (mac)
  *
@@ -125,6 +127,7 @@
 	&sun_pt_idinfo,
 	&dos_pt_idinfo,
 	&gpt_pt_idinfo,
+	&pmbr_pt_idinfo,	/* always after GPT */
 	&mac_pt_idinfo,
 	&ultrix_pt_idinfo,
 	&bsd_pt_idinfo,
@@ -160,7 +163,7 @@
 /* exported as opaque type "blkid_parttable" */
 struct blkid_struct_parttable {
 	const char	*type;		/* partition table type */
-	blkid_loff_t	offset;		/* begin of the partition table */
+	blkid_loff_t	offset;		/* begin of the partition table (in bytes) */
 	int		nparts;		/* number of partitions */
 	blkid_partition	parent;		/* parent of nested partition table */
 	char		id[37];		/* PT identifier (e.g. UUID for GPT) */
@@ -170,8 +173,8 @@
 
 /* exported as opaque type "blkid_partition" */
 struct blkid_struct_partition {
-	blkid_loff_t	start;		/* begin of the partition */
-	blkid_loff_t	size;		/* size of the partitions */
+	blkid_loff_t	start;		/* begin of the partition (512-bytes sectors) */
+	blkid_loff_t	size;		/* size of the partitions (512-bytes sectors) */
 
 	int		type;		/* partition type */
 	char		typestr[37];	/* partition type string (GPT and Mac) */
@@ -361,7 +364,7 @@
 	ls->next_partno = 1;
 	INIT_LIST_HEAD(&ls->l_tabs);
 
-	DBG(DEBUG_LOWPROBE, printf("partlist reset\n"));
+	DBG(LOWPROBE, ul_debug("partlist reset"));
 }
 
 static blkid_partlist partitions_init_data(struct blkid_chain *chn)
@@ -380,8 +383,7 @@
 
 	reset_partlist(ls);
 
-	DBG(DEBUG_LOWPROBE,
-		printf("parts: initialized partitions list (%p, size=%d)\n",
+	DBG(LOWPROBE, ul_debug("parts: initialized partitions list (%p, size=%d)",
 		ls, ls->nparts_max));
 	return ls;
 }
@@ -416,9 +418,8 @@
 	INIT_LIST_HEAD(&tab->t_tabs);
 	list_add_tail(&tab->t_tabs, &ls->l_tabs);
 
-	DBG(DEBUG_LOWPROBE,
-		printf("parts: create a new partition table "
-		       "(%p, type=%s, offset=%"PRId64")\n", tab, type, offset));
+	DBG(LOWPROBE, ul_debug("parts: create a new partition table "
+		       "(%p, type=%s, offset=%"PRId64")", tab, type, offset));
 	return tab;
 }
 
@@ -430,10 +431,11 @@
 		/* Linux kernel has DISK_MAX_PARTS=256, but it's too much for
 		 * generic Linux machine -- let start with 32 partititions.
 		 */
-		ls->parts = realloc(ls->parts, (ls->nparts_max + 32) *
+		void *tmp = realloc(ls->parts, (ls->nparts_max + 32) *
 					sizeof(struct blkid_struct_partition));
-		if (!ls->parts)
+		if (!tmp)
 			return NULL;
+		ls->parts = tmp;
 		ls->nparts_max += 32;
 	}
 
@@ -459,9 +461,8 @@
 	par->start = start;
 	par->size = size;
 
-	DBG(DEBUG_LOWPROBE,
-		printf("parts: add partition (%p start=%"
-		PRId64 ", size=%" PRId64 ", table=%p)\n",
+	DBG(LOWPROBE, ul_debug("parts: add partition (%p start=%"
+		PRId64 ", size=%" PRId64 ", table=%p)",
 		par, par->start, par->size, tab));
 	return par;
 }
@@ -535,37 +536,41 @@
 {
 	const struct blkid_idmag *mag = NULL;
 	blkid_loff_t off;
-	int rc = 1;		/* = nothing detected */
+	int rc = BLKID_PROBE_NONE;		/* default is nothing */
 
 	if (pr->size <= 0 || (id->minsz && id->minsz > pr->size))
 		goto nothing;	/* the device is too small */
+	if (pr->flags & BLKID_FL_NOSCAN_DEV)
+		goto nothing;
 
-	if (blkid_probe_get_idmag(pr, id, &off, &mag))
+	rc = blkid_probe_get_idmag(pr, id, &off, &mag);
+	if (rc != BLKID_PROBE_OK)
 		goto nothing;
 
 	/* final check by probing function */
 	if (id->probefunc) {
-		DBG(DEBUG_LOWPROBE, printf(
-			"%s: ---> call probefunc()\n", id->name));
+		DBG(LOWPROBE, ul_debug(
+			"%s: ---> call probefunc()", id->name));
 		rc = id->probefunc(pr, mag);
-	        if (rc == -1) {
+		if (rc < 0) {
 			/* reset after error */
 			reset_partlist(blkid_probe_get_partlist(pr));
 			if (chn && !chn->binary)
 				blkid_probe_chain_reset_vals(pr, chn);
-			DBG(DEBUG_LOWPROBE, printf(
-				"%s probefunc failed\n", id->name));
+			DBG(LOWPROBE, ul_debug("%s probefunc failed, rc %d",
+						  id->name, rc));
 		}
-		if (rc == 0 && mag && chn && !chn->binary)
+		if (rc == BLKID_PROBE_OK && mag && chn && !chn->binary)
 			rc = blkid_probe_set_magic(pr, off, mag->len,
 					(unsigned char *) mag->magic);
 
-		DBG(DEBUG_LOWPROBE, printf(
-			"%s: <--- (rc = %d)\n", id->name, rc));
+		DBG(LOWPROBE, ul_debug("%s: <--- (rc = %d)", id->name, rc));
 	}
 
-nothing:
 	return rc;
+
+nothing:
+	return BLKID_PROBE_NONE;
 }
 
 /*
@@ -573,21 +578,24 @@
  */
 static int partitions_probe(blkid_probe pr, struct blkid_chain *chn)
 {
-	int rc = 1;
+	int rc = BLKID_PROBE_NONE;
 	size_t i;
 
 	if (!pr || chn->idx < -1)
-		return -1;
+		return -EINVAL;
+
 	blkid_probe_chain_reset_vals(pr, chn);
 
+	if (pr->flags & BLKID_FL_NOSCAN_DEV)
+		return BLKID_PROBE_NONE;
+
 	if (chn->binary)
 		partitions_init_data(chn);
 
 	if (!pr->wipe_size && (pr->prob_flags & BLKID_PROBE_FL_IGNORE_PT))
 		goto details_only;
 
-	DBG(DEBUG_LOWPROBE,
-		printf("--> starting probing loop [PARTS idx=%d]\n",
+	DBG(LOWPROBE, ul_debug("--> starting probing loop [PARTS idx=%d]",
 		chn->idx));
 
 	i = chn->idx < 0 ? 0 : chn->idx + 1U;
@@ -602,40 +610,53 @@
 			continue;
 
 		/* apply checks from idinfo */
-		if (idinfo_probe(pr, idinfos[i], chn) != 0)
+		rc = idinfo_probe(pr, idinfos[i], chn);
+		if (rc < 0)
+			break;
+		if (rc != BLKID_PROBE_OK)
 			continue;
 
 		name = idinfos[i]->name;
 
-		/* all checks passed */
 		if (!chn->binary)
+			/*
+			 * Non-binary interface, set generic variables. Note
+			 * that the another variables could be set in prober
+			 * functions.
+			 */
 			blkid_probe_set_value(pr, "PTTYPE",
 						(unsigned char *) name,
 						strlen(name) + 1);
-		DBG(DEBUG_LOWPROBE,
-			printf("<-- leaving probing loop (type=%s) [PARTS idx=%d]\n",
+
+		DBG(LOWPROBE, ul_debug("<-- leaving probing loop (type=%s) [PARTS idx=%d]",
 			name, chn->idx));
-		rc = 0;
+		rc = BLKID_PROBE_OK;
 		break;
 	}
 
-	if (rc == 1) {
-		DBG(DEBUG_LOWPROBE,
-			printf("<-- leaving probing loop (failed) [PARTS idx=%d]\n",
-			chn->idx));
+	if (rc != BLKID_PROBE_OK) {
+		DBG(LOWPROBE, ul_debug("<-- leaving probing loop (failed=%d) [PARTS idx=%d]",
+			rc, chn->idx));
 	}
 
 details_only:
 	/*
 	 * Gather PART_ENTRY_* values if the current device is a partition.
 	 */
-	if (!chn->binary &&
+	if ((rc == BLKID_PROBE_OK || rc == BLKID_PROBE_NONE) && !chn->binary &&
 	    (blkid_partitions_get_flags(pr) & BLKID_PARTS_ENTRY_DETAILS)) {
 
-		if (!blkid_partitions_probe_partition(pr))
-			rc = 0;
+		int xrc = blkid_partitions_probe_partition(pr);
+
+		/* partition entry probing is optional, and "not-found" from
+		 * this sub-probing must not to overwrite previous success. */
+		if (xrc < 0)
+			rc = xrc;			/* always propagate errors */
+		else if (rc == BLKID_PROBE_NONE)
+			rc = xrc;
 	}
 
+	DBG(LOWPROBE, ul_debug("partitions probe done [rc=%d]",	rc));
 	return rc;
 }
 
@@ -644,32 +665,34 @@
 		const struct blkid_idinfo *id)
 {
 	blkid_probe prc;
-	int rc = 1;
+	int rc;
 	blkid_partlist ls;
 	blkid_loff_t sz, off;
 
-	DBG(DEBUG_LOWPROBE, printf(
-		"parts: ----> %s subprobe requested (parent=%p)\n",
+	DBG(LOWPROBE, ul_debug(
+		"parts: ----> %s subprobe requested (parent=%p)",
 		id->name, parent));
 
 	if (!pr || !parent || !parent->size)
-		return -1;
+		return -EINVAL;
+	if (pr->flags & BLKID_FL_NOSCAN_DEV)
+		return BLKID_PROBE_NONE;
 
 	/* range defined by parent */
 	sz = ((blkid_loff_t) parent->size) << 9;
 	off = ((blkid_loff_t) parent->start) << 9;
 
 	if (off < pr->off || pr->off + pr->size < off + sz) {
-		DBG(DEBUG_LOWPROBE, printf(
-			"ERROR: parts: <---- '%s' subprobe: overflow detected.\n",
+		DBG(LOWPROBE, ul_debug(
+			"ERROR: parts: <---- '%s' subprobe: overflow detected.",
 			id->name));
-		return -1;
+		return -ENOSPC;
 	}
 
 	/* create private prober */
 	prc = blkid_clone_probe(pr);
 	if (!prc)
-		return -1;
+		return -ENOMEM;
 
 	blkid_probe_set_dimension(prc, off, sz);
 
@@ -693,8 +716,8 @@
 
 	blkid_free_probe(prc);	/* free cloned prober */
 
-	DBG(DEBUG_LOWPROBE, printf(
-		"parts: <---- %s subprobe done (parent=%p, rc=%d)\n",
+	DBG(LOWPROBE, ul_debug(
+		"parts: <---- %s subprobe done (parent=%p, rc=%d)",
 		id->name, parent, rc));
 
 	return rc;
@@ -702,12 +725,16 @@
 
 static int blkid_partitions_probe_partition(blkid_probe pr)
 {
-	int rc = 1;
 	blkid_probe disk_pr = NULL;
 	blkid_partlist ls;
 	blkid_partition par;
 	dev_t devno;
 
+	DBG(LOWPROBE, ul_debug("parts: start probing for partition entry"));
+
+	if (pr->flags & BLKID_FL_NOSCAN_DEV)
+		goto nothing;
+
 	devno = blkid_probe_get_devno(pr);
 	if (!devno)
 		goto nothing;
@@ -722,7 +749,9 @@
 		goto nothing;
 
 	par = blkid_partlist_devno_to_partition(ls, devno);
-	if (par) {
+	if (!par)
+		goto nothing;
+	else {
 		const char *v;
 		blkid_parttable tab = blkid_partition_get_table(par);
 		dev_t disk = blkid_probe_get_devno(disk_pr);
@@ -768,9 +797,15 @@
 		blkid_probe_sprintf_value(pr, "PART_ENTRY_DISK", "%u:%u",
 				major(disk), minor(disk));
 	}
-	rc = 0;
+
+	DBG(LOWPROBE, ul_debug("parts: end probing for partition entry [success]"));
+	return BLKID_PROBE_OK;
+
 nothing:
-	return rc;
+	DBG(LOWPROBE, ul_debug("parts: end probing for partition entry [nothing]"));
+	return BLKID_PROBE_NONE;
+
+
 }
 
 /*
@@ -780,15 +815,18 @@
 int blkid_probe_is_covered_by_pt(blkid_probe pr,
 				 blkid_loff_t offset, blkid_loff_t size)
 {
-	blkid_probe prc;
+	blkid_probe prc = NULL;
 	blkid_partlist ls = NULL;
 	blkid_loff_t start, end;
 	int nparts, i, rc = 0;
 
-	DBG(DEBUG_LOWPROBE, printf(
-		"=> checking if off=%jd size=%jd covered by PT\n",
+	DBG(LOWPROBE, ul_debug(
+		"=> checking if off=%jd size=%jd covered by PT",
 		offset, size));
 
+	if (pr->flags & BLKID_FL_NOSCAN_DEV)
+		goto done;
+
 	prc = blkid_clone_probe(pr);
 	if (!prc)
 		goto done;
@@ -809,8 +847,8 @@
 		blkid_partition par = &ls->parts[i];
 
 		if (par->start + par->size > (pr->size >> 9)) {
-			DBG(DEBUG_LOWPROBE, printf("partition #%d overflows "
-				"device (off=%" PRId64 " size=%" PRId64 ")\n",
+			DBG(LOWPROBE, ul_debug("partition #%d overflows "
+				"device (off=%" PRId64 " size=%" PRId64 ")",
 				par->partno, par->start, par->size));
 			goto done;
 		}
@@ -828,7 +866,7 @@
 done:
 	blkid_free_probe(prc);
 
-	DBG(DEBUG_LOWPROBE, printf("<= %s covered by PT\n", rc ? "IS" : "NOT"));
+	DBG(LOWPROBE, ul_debug("<= %s covered by PT", rc ? "IS" : "NOT"));
 	return rc;
 }
 
@@ -903,6 +941,35 @@
 }
 
 /**
+ * blkid_partlist_get_partition_by_partno
+ * @ls: partitions list
+ * @n: the partition number (e.g. 'N' from sda'N')
+ *
+ * This does not assume any order of the input blkid_partlist.  And correctly
+ * handles "out of order" partition tables.  partition N is located after
+ * partition N+1 on the disk.
+ *
+ * Returns: partition object or NULL in case or error.
+ */
+blkid_partition blkid_partlist_get_partition_by_partno(blkid_partlist ls, int n)
+{
+	int i, nparts;
+	blkid_partition par;
+
+	if (!ls)
+		return NULL;
+
+	nparts = blkid_partlist_numof_partitions(ls);
+	for (i = 0; i < nparts; i++) {
+		par = blkid_partlist_get_partition(ls, i);
+		if (n == blkid_partition_get_partno(par))
+			return par;
+	}
+	return NULL;
+}
+
+
+/**
  * blkid_partlist_devno_to_partition:
  * @ls: partitions list
  * @devno: requested partition
@@ -924,12 +991,11 @@
 	if (!ls)
 		return NULL;
 
-	DBG(DEBUG_LOWPROBE,
-		printf("triyng to convert devno 0x%llx to partition\n",
+	DBG(LOWPROBE, ul_debug("triyng to convert devno 0x%llx to partition",
 			(long long) devno));
 
 	if (sysfs_init(&sysfs, devno, NULL)) {
-		DBG(DEBUG_LOWPROBE, printf("failed t init sysfs context\n"));
+		DBG(LOWPROBE, ul_debug("failed t init sysfs context"));
 		return NULL;
 	}
 	rc = sysfs_read_u64(&sysfs, "size", &size);
@@ -961,7 +1027,7 @@
 		return NULL;
 
 	if (partno) {
-		DBG(DEBUG_LOWPROBE, printf("mapped by DM, using partno %d\n", partno));
+		DBG(LOWPROBE, ul_debug("mapped by DM, using partno %d", partno));
 
 		/*
 		 * Partition mapped by kpartx does not provide "start" offset
@@ -983,7 +1049,7 @@
 		 return NULL;
 	}
 
-	DBG(DEBUG_LOWPROBE, printf("searching by offset/size\n"));
+	DBG(LOWPROBE, ul_debug("searching by offset/size"));
 
 	for (i = 0; i < ls->nparts; i++) {
 		blkid_partition par = &ls->parts[i];
@@ -999,23 +1065,74 @@
 
 	}
 
-	DBG(DEBUG_LOWPROBE, printf("not found partition for device\n"));
+	DBG(LOWPROBE, ul_debug("not found partition for device"));
 	return NULL;
 }
 
+
+int blkid_parttable_set_uuid(blkid_parttable tab, const unsigned char *id)
+{
+	if (!tab)
+		return -1;
+
+	blkid_unparse_uuid(id, tab->id, sizeof(tab->id));
+	return 0;
+}
+
 int blkid_parttable_set_id(blkid_parttable tab, const unsigned char *id)
 {
 	if (!tab)
 		return -1;
 
-	if (strcmp(tab->type, "gpt") == 0)
-		blkid_unparse_uuid(id, tab->id, sizeof(tab->id));
-	else if (strcmp(tab->type, "dos") == 0)
-		strncpy(tab->id, (const char *) id, sizeof(tab->id));
+	strncpy(tab->id, (const char *) id, sizeof(tab->id));
+	return 0;
+}
+
+/* set PTUUID variable for non-binary API */
+int blkid_partitions_set_ptuuid(blkid_probe pr, unsigned char *uuid)
+{
+	struct blkid_chain *chn = blkid_probe_get_chain(pr);
+	struct blkid_prval *v;
+
+	if (chn->binary || blkid_uuid_is_empty(uuid, 16))
+		return 0;
+
+	v = blkid_probe_assign_value(pr, "PTUUID");
+
+	blkid_unparse_uuid(uuid, (char *) v->data, sizeof(v->data));
+	v->len = 37;
 
 	return 0;
 }
 
+/* set PTUUID variable for non-binary API for tables where
+ * the ID is just a string */
+int blkid_partitions_strcpy_ptuuid(blkid_probe pr, char *str)
+{
+	struct blkid_chain *chn = blkid_probe_get_chain(pr);
+	struct blkid_prval *v;
+	size_t len;
+
+	if (chn->binary || !str || !*str)
+		return 0;
+
+	len = strlen((char *) str);
+	if (len > BLKID_PROBVAL_BUFSIZ)
+		len = BLKID_PROBVAL_BUFSIZ;
+
+	v = blkid_probe_assign_value(pr, "PTUUID");
+	if (v) {
+		if (len == BLKID_PROBVAL_BUFSIZ)
+			len--;		/* make a space for \0 */
+
+		memcpy((char *) v->data, str, len);
+		v->data[len] = '\0';
+		v->len = len + 1;
+		return 0;
+	}
+	return -1;
+}
+
 /**
  * blkid_parttable_get_id:
  * @tab: partition table
@@ -1026,7 +1143,7 @@
  */
 const char *blkid_parttable_get_id(blkid_parttable tab)
 {
-	return tab && tab->id && *tab->id ? tab->id : NULL;
+	return tab && *tab->id ? tab->id : NULL;
 }
 
 
@@ -1143,9 +1260,9 @@
 		if (par->partno > 4)
 			return 'L';	/* logical */
 
-	        if(par->type == BLKID_DOS_EXTENDED_PARTITION ||
-                   par->type == BLKID_W95_EXTENDED_PARTITION ||
-		   par->type == BLKID_LINUX_EXTENDED_PARTITION)
+	        if(par->type == MBR_DOS_EXTENDED_PARTITION ||
+                   par->type == MBR_W95_EXTENDED_PARTITION ||
+		   par->type == MBR_LINUX_EXTENDED_PARTITION)
 			return 'E';
 	}
 	return 'P';
@@ -1233,6 +1350,16 @@
 	return 0;
 }
 
+int blkid_partition_gen_uuid(blkid_partition par)
+{
+	if (!par || !par->tab || !*par->tab->id)
+		return -1;
+
+	snprintf(par->uuid, sizeof(par->uuid), "%s-%02x",
+			par->tab->id, par->partno);
+	return 0;
+}
+
 /**
  * blkid_partition_get_name:
  * @par: partition
diff --git a/libblkid/partitions.h b/libblkid/src/partitions/partitions.h
similarity index 85%
rename from libblkid/partitions.h
rename to libblkid/src/partitions/partitions.h
index 496bd4a..3651bbb 100644
--- a/libblkid/partitions.h
+++ b/libblkid/src/partitions/partitions.h
@@ -2,13 +2,14 @@
 #define BLKID_PARTITIONS_H
 
 #include "blkidP.h"
-#include "blkid_parttypes.h"
+#include "pt-mbr.h"
 
 extern int blkid_partitions_get_flags(blkid_probe pr);
 
 extern blkid_parttable blkid_partlist_new_parttable(blkid_partlist ls,
 				const char *type, blkid_loff_t offset);
 
+extern int blkid_parttable_set_uuid(blkid_parttable tab, const unsigned char *id);
 extern int blkid_parttable_set_id(blkid_parttable tab, const unsigned char *id);
 
 extern blkid_partition blkid_partlist_add_partition(blkid_partlist ls,
@@ -24,6 +25,10 @@
 			blkid_partition parent, const struct blkid_idinfo *id);
 
 extern int blkid_partitions_need_typeonly(blkid_probe pr);
+extern int blkid_partitions_set_ptuuid(blkid_probe pr, unsigned char *uuid);
+extern int blkid_partitions_strcpy_ptuuid(blkid_probe pr, char *str);
+
+
 extern int blkid_is_nested_dimension(blkid_partition par,
                         blkid_loff_t start, blkid_loff_t size);
 
@@ -35,6 +40,7 @@
 
 extern int blkid_partition_set_uuid(blkid_partition par,
 		const unsigned char *uuid);
+extern int blkid_partition_gen_uuid(blkid_partition par);
 
 extern int blkid_partition_set_type(blkid_partition par, int type);
 
@@ -59,6 +65,7 @@
 extern const struct blkid_idinfo dos_pt_idinfo;
 extern const struct blkid_idinfo minix_pt_idinfo;
 extern const struct blkid_idinfo gpt_pt_idinfo;
+extern const struct blkid_idinfo pmbr_pt_idinfo;
 extern const struct blkid_idinfo ultrix_pt_idinfo;
 
 #endif /* BLKID_PARTITIONS_H */
diff --git a/libblkid/src/partitions/sgi.c b/libblkid/src/partitions/sgi.c
new file mode 100644
index 0000000..99c0bf1
--- /dev/null
+++ b/libblkid/src/partitions/sgi.c
@@ -0,0 +1,87 @@
+/*
+ * sgi partition parsing code
+ *
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "partitions.h"
+#include "pt-sgi.h"
+
+static int probe_sgi_pt(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	struct sgi_disklabel *l;
+	struct sgi_partition *p;
+	blkid_parttable tab = NULL;
+	blkid_partlist ls;
+	int i;
+
+	l = (struct sgi_disklabel *) blkid_probe_get_sector(pr, 0);
+	if (!l) {
+		if (errno)
+			return -errno;
+		goto nothing;
+	}
+
+	if (sgi_pt_checksum(l)) {
+		DBG(LOWPROBE, ul_debug(
+			"detected corrupted sgi disk label -- ignore"));
+		goto nothing;
+	}
+
+	if (blkid_partitions_need_typeonly(pr))
+		/* caller does not ask for details about partitions */
+		return BLKID_PROBE_OK;
+
+	ls = blkid_probe_get_partlist(pr);
+	if (!ls)
+		goto nothing;
+
+	tab = blkid_partlist_new_parttable(ls, "sgi", 0);
+	if (!tab)
+		goto err;
+
+	for(i = 0, p = &l->partitions[0]; i < SGI_MAXPARTITIONS; i++, p++) {
+		uint32_t size = be32_to_cpu(p->num_blocks);
+		uint32_t start = be32_to_cpu(p->first_block);
+		uint32_t type = be32_to_cpu(p->type);
+		blkid_partition par;
+
+		if (!size) {
+			blkid_partlist_increment_partno(ls);
+			continue;
+		}
+		par = blkid_partlist_add_partition(ls, tab, start, size);
+		if (!par)
+			goto err;
+
+		blkid_partition_set_type(par, type);
+	}
+
+	return BLKID_PROBE_OK;
+
+nothing:
+	return BLKID_PROBE_NONE;
+err:
+	return -ENOMEM;
+}
+
+const struct blkid_idinfo sgi_pt_idinfo =
+{
+	.name		= "sgi",
+	.probefunc	= probe_sgi_pt,
+	.magics		=
+	{
+		{ .magic = "\x0B\xE5\xA9\x41", .len = 4	},
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/solaris_x86.c b/libblkid/src/partitions/solaris_x86.c
similarity index 92%
rename from libblkid/solaris_x86.c
rename to libblkid/src/partitions/solaris_x86.c
index 7824f4e..4ac9be5 100644
--- a/libblkid/solaris_x86.c
+++ b/libblkid/src/partitions/solaris_x86.c
@@ -69,23 +69,26 @@
 	uint16_t nparts;
 
 	l = (struct solaris_vtoc *) blkid_probe_get_sector(pr, SOLARIS_SECTOR);
-	if (!l)
+	if (!l) {
+		if (errno)
+			return -errno;
 		goto nothing;
+	}
 
 	if (le32_to_cpu(l->v_version) != 1) {
-		DBG(DEBUG_LOWPROBE, printf(
-			"WARNING: unsupported solaris x86 version %d, ignore\n",
+		DBG(LOWPROBE, ul_debug(
+			"WARNING: unsupported solaris x86 version %d, ignore",
 			le32_to_cpu(l->v_version)));
 		goto nothing;
 	}
 
 	if (blkid_partitions_need_typeonly(pr))
 		/* caller does not ask for details about partitions */
-		return 0;
+		return BLKID_PROBE_OK;
 
 	ls = blkid_probe_get_partlist(pr);
 	if (!ls)
-		goto err;
+		goto nothing;
 
 	parent = blkid_partlist_get_parent(ls);
 
@@ -112,9 +115,9 @@
 			start += blkid_partition_get_start(parent);
 
 		if (parent && !blkid_is_nested_dimension(parent, start, size)) {
-			DBG(DEBUG_LOWPROBE, printf(
+			DBG(LOWPROBE, ul_debug(
 				"WARNING: solaris partition (%d) overflow "
-				"detected, ignore\n", i));
+				"detected, ignore", i));
 			continue;
 		}
 
@@ -126,12 +129,12 @@
 		blkid_partition_set_flags(par, le16_to_cpu(p->s_flag));
 	}
 
-	return 0;
+	return BLKID_PROBE_OK;
 
 nothing:
-	return 1;
+	return BLKID_PROBE_NONE;
 err:
-	return -1;
+	return -ENOMEM;
 }
 
 const struct blkid_idinfo solaris_x86_pt_idinfo =
diff --git a/libblkid/src/partitions/sun.c b/libblkid/src/partitions/sun.c
new file mode 100644
index 0000000..22ee450
--- /dev/null
+++ b/libblkid/src/partitions/sun.c
@@ -0,0 +1,125 @@
+/*
+ * sun (solaris-sparc) partition parsing code
+ *
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+
+#include "pt-sun.h"
+#include "partitions.h"
+
+static int probe_sun_pt(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	struct sun_disklabel *l;
+	struct sun_partition *p;
+	blkid_parttable tab = NULL;
+	blkid_partlist ls;
+	uint16_t nparts;
+	blkid_loff_t spc;
+	int i, use_vtoc;
+
+	l = (struct sun_disklabel *) blkid_probe_get_sector(pr, 0);
+	if (!l) {
+		if (errno)
+			return -errno;
+		goto nothing;
+	}
+
+	if (sun_pt_checksum(l)) {
+		DBG(LOWPROBE, ul_debug(
+			"detected corrupted sun disk label -- ignore"));
+		goto nothing;
+	}
+
+	if (blkid_partitions_need_typeonly(pr))
+		/* caller does not ask for details about partitions */
+		return BLKID_PROBE_OK;
+
+	ls = blkid_probe_get_partlist(pr);
+	if (!ls)
+		goto nothing;
+
+	tab = blkid_partlist_new_parttable(ls, "sun", 0);
+	if (!tab)
+		goto err;
+
+	/* sectors per cylinder (partition offset is in cylinders...) */
+	spc = be16_to_cpu(l->nhead) * be16_to_cpu(l->nsect);
+
+	DBG(LOWPROBE, ul_debug("Sun VTOC sanity=%u version=%u nparts=%u",
+			be32_to_cpu(l->vtoc.sanity),
+			be32_to_cpu(l->vtoc.version),
+			be16_to_cpu(l->vtoc.nparts)));
+
+	/* Check to see if we can use the VTOC table */
+	use_vtoc = ((be32_to_cpu(l->vtoc.sanity) == SUN_VTOC_SANITY) &&
+		    (be32_to_cpu(l->vtoc.version) == SUN_VTOC_VERSION) &&
+		    (be16_to_cpu(l->vtoc.nparts) <= SUN_MAXPARTITIONS));
+
+	/* Use 8 partition entries if not specified in validated VTOC */
+	nparts = use_vtoc ? be16_to_cpu(l->vtoc.nparts) : SUN_MAXPARTITIONS;
+
+	/*
+	 * So that old Linux-Sun partitions continue to work,
+	 * alow the VTOC to be used under the additional condition ...
+	 */
+	use_vtoc = use_vtoc || !(l->vtoc.sanity || l->vtoc.version || l->vtoc.nparts);
+
+	for (i = 0, p = l->partitions; i < nparts; i++, p++) {
+
+		blkid_loff_t start, size;
+		uint16_t type = 0, flags = 0;
+		blkid_partition par;
+
+		start = be32_to_cpu(p->start_cylinder) * spc;
+		size = be32_to_cpu(p->num_sectors);
+		if (use_vtoc) {
+			type = be16_to_cpu(l->vtoc.infos[i].id);
+			flags = be16_to_cpu(l->vtoc.infos[i].flags);
+		}
+
+		if (type == SUN_TAG_WHOLEDISK || !size) {
+			blkid_partlist_increment_partno(ls);
+			continue;
+		}
+		par = blkid_partlist_add_partition(ls, tab, start, size);
+		if (!par)
+			goto err;
+
+		if (type)
+			blkid_partition_set_type(par, type);
+		if (flags)
+			blkid_partition_set_flags(par, flags);
+	}
+	return BLKID_PROBE_OK;
+
+nothing:
+	return BLKID_PROBE_NONE;
+err:
+	return -ENOMEM;
+}
+
+
+const struct blkid_idinfo sun_pt_idinfo =
+{
+	.name		= "sun",
+	.probefunc	= probe_sun_pt,
+	.magics		=
+	{
+		{
+		  .magic = "\xDA\xBE",		/* big-endian magic string */
+		  .len = 2,
+		  .sboff = offsetof(struct sun_disklabel, magic)
+		},
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/ultrix.c b/libblkid/src/partitions/ultrix.c
similarity index 92%
rename from libblkid/ultrix.c
rename to libblkid/src/partitions/ultrix.c
index 853ae6e..9c060be 100644
--- a/libblkid/ultrix.c
+++ b/libblkid/src/partitions/ultrix.c
@@ -44,8 +44,11 @@
 	int i;
 
 	data = blkid_probe_get_sector(pr, ULTRIX_SECTOR);
-	if (!data)
+	if (!data) {
+		if (errno)
+			return -errno;
 		goto nothing;
+	}
 
 	l = (struct ultrix_disklabel *) (data + ULTRIX_OFFSET);
 
@@ -59,11 +62,11 @@
 
 	if (blkid_partitions_need_typeonly(pr))
 		/* caller does not ask for details about partitions */
-		return 0;
+		return BLKID_PROBE_OK;
 
 	ls = blkid_probe_get_partlist(pr);
 	if (!ls)
-		goto err;
+		goto nothing;
 
 	tab = blkid_partlist_new_parttable(ls, "ultrix", 0);
 	if (!tab)
@@ -80,11 +83,11 @@
 		}
 	}
 
-	return 0;
+	return BLKID_PROBE_OK;
 nothing:
-	return 1;
+	return BLKID_PROBE_NONE;
 err:
-	return -1;
+	return -ENOMEM;
 }
 
 const struct blkid_idinfo ultrix_pt_idinfo =
diff --git a/libblkid/unixware.c b/libblkid/src/partitions/unixware.c
similarity index 96%
rename from libblkid/unixware.c
rename to libblkid/src/partitions/unixware.c
index e9bcba3..6742bcf 100644
--- a/libblkid/unixware.c
+++ b/libblkid/src/partitions/unixware.c
@@ -106,19 +106,22 @@
 
 	l = (struct unixware_disklabel *)
 			blkid_probe_get_sector(pr, UNIXWARE_SECTOR);
-	if (!l)
+	if (!l) {
+		if (errno)
+			return -errno;
 		goto nothing;
+	}
 
 	if (le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_VTOCMAGIC)
 		goto nothing;
 
 	if (blkid_partitions_need_typeonly(pr))
 		/* caller does not ask for details about partitions */
-		return 0;
+		return BLKID_PROBE_OK;
 
 	ls = blkid_probe_get_partlist(pr);
 	if (!ls)
-		goto err;
+		goto nothing;
 
 	parent = blkid_partlist_get_parent(ls);
 
@@ -147,9 +150,9 @@
 		size = le32_to_cpu(p->nr_sects);
 
 		if (parent && !blkid_is_nested_dimension(parent, start, size)) {
-			DBG(DEBUG_LOWPROBE, printf(
+			DBG(LOWPROBE, ul_debug(
 				"WARNING: unixware partition (%d) overflow "
-				"detected, ignore\n", i));
+				"detected, ignore", i));
 			continue;
 		}
 
@@ -161,12 +164,12 @@
 		blkid_partition_set_flags(par, flg);
 	}
 
-	return 0;
+	return BLKID_PROBE_OK;
 
 nothing:
-	return 1;
+	return BLKID_PROBE_NONE;
 err:
-	return -1;
+	return -ENOMEM;
 }
 
 
diff --git a/libblkid/pathnames.h b/libblkid/src/pathnames.h
similarity index 90%
copy from libblkid/pathnames.h
copy to libblkid/src/pathnames.h
index 6d300a9..0d21b98 100644
--- a/libblkid/pathnames.h
+++ b/libblkid/src/pathnames.h
@@ -31,11 +31,14 @@
 #define	_PATH_HUSHLOGIN		".hushlogin"
 #define	_PATH_HUSHLOGINS	"/etc/hushlogins"
 
+#define _PATH_NOLOGIN_TXT	"/etc/nologin.txt"
+
 #ifndef _PATH_MAILDIR
 #define	_PATH_MAILDIR		"/var/spool/mail"
 #endif
 #define	_PATH_MOTDFILE		"/etc/motd"
 #define	_PATH_NOLOGIN		"/etc/nologin"
+#define	_PATH_VAR_NOLOGIN	"/var/run/nologin"
 
 #define _PATH_LOGIN		"/bin/login"
 #define _PATH_INITTAB		"/etc/inittab"
@@ -48,6 +51,9 @@
 #define _PATH_SECURE		"/etc/securesingle"
 #define _PATH_USERTTY           "/etc/usertty"
 
+#define _PATH_TERMCOLORS_DIRNAME "terminal-colors.d"
+#define _PATH_TERMCOLORS_DIR	"/etc/" _PATH_TERMCOLORS_DIRNAME
+
 /* used in login-utils/shutdown.c */
 
 /* used in login-utils/setpwnam.h and login-utils/islocal.c */
@@ -63,6 +69,7 @@
 
 /* used in term-utils/agetty.c */
 #define _PATH_ISSUE		"/etc/issue"
+#define _PATH_OS_RELEASE	"/etc/os-release"
 #define _PATH_NUMLOCK_ON	_PATH_LOCALSTATEDIR "/numlock-on"
 
 #define _PATH_LOGINDEFS		"/etc/login.defs"
@@ -84,6 +91,9 @@
 #define _PATH_PROC_LOCKS        "/proc/locks"
 #define _PATH_PROC_CDROMINFO	"/proc/sys/dev/cdrom/info"
 
+#define _PATH_PROC_UIDMAP	"/proc/self/uid_map"
+#define _PATH_PROC_GIDMAP	"/proc/self/gid_map"
+
 #define _PATH_PROC_ATTR_CURRENT	"/proc/self/attr/current"
 #define _PATH_PROC_ATTR_EXEC	"/proc/self/attr/exec"
 #define _PATH_PROC_CAPLASTCAP	"/proc/sys/kernel/cap_last_cap"
@@ -125,6 +135,8 @@
 # define _PATH_DEV		"/dev/"
 #endif
 
+#define _PATH_DEV_MEM		"/dev/mem"
+
 #define _PATH_DEV_LOOP		"/dev/loop"
 #define _PATH_DEV_LOOPCTL	"/dev/loop-control"
 #define _PATH_DEV_TTY		"/dev/tty"
@@ -139,7 +151,12 @@
 #define _PATH_DEV_BYPARTUUID	"/dev/disk/by-partuuid"
 
 /* hwclock paths */
-#define _PATH_ADJPATH		"/etc/adjtime"
+#ifdef CONFIG_ADJTIME_PATH
+# define _PATH_ADJTIME		CONFIG_ADJTIME_PATH
+#else
+# define _PATH_ADJTIME		"/etc/adjtime"
+#endif
+
 #define _PATH_LASTDATE		"/var/lib/lastdate"
 #ifdef __ia64__
 # define _PATH_RTC_DEV		"/dev/efirtc"
diff --git a/libblkid/probe.c b/libblkid/src/probe.c
similarity index 89%
rename from libblkid/probe.c
rename to libblkid/src/probe.c
index 77e8b86..76ac099 100644
--- a/libblkid/probe.c
+++ b/libblkid/src/probe.c
@@ -103,13 +103,17 @@
 #include <inttypes.h>
 #include <stdint.h>
 #include <stdarg.h>
+#include <limits.h>
 
 #ifdef HAVE_LIBUUID
 # include <uuid.h>
 #endif
 
 #include "blkidP.h"
+#include <blkid.h>
 #include "all-io.h"
+#include "sysfs.h"
+#include "strutils.h"
 
 /* chains */
 extern const struct blkid_chaindrv superblocks_drv;
@@ -143,7 +147,7 @@
 	if (!pr)
 		return NULL;
 
-	DBG(DEBUG_LOWPROBE, printf("allocate a new probe %p\n", pr));
+	DBG(LOWPROBE, ul_debug("allocate a new probe %p", pr));
 
 	/* initialize chains */
 	for (i = 0; i < BLKID_NCHAINS; i++) {
@@ -168,7 +172,7 @@
 	if (!parent)
 		return NULL;
 
-	DBG(DEBUG_LOWPROBE, printf("allocate a probe clone\n"));
+	DBG(LOWPROBE, ul_debug("allocate a probe clone"));
 
 	pr = blkid_new_probe();
 	if (!pr)
@@ -258,7 +262,7 @@
 	blkid_probe_reset_buffer(pr);
 	blkid_free_probe(pr->disk_probe);
 
-	DBG(DEBUG_LOWPROBE, printf("free probe %p\n", pr));
+	DBG(LOWPROBE, ul_debug("free probe %p", pr));
 	free(pr);
 }
 
@@ -336,6 +340,16 @@
 	return pr->cur_chain;
 }
 
+static const char *blkid_probe_get_probername(blkid_probe pr)
+{
+	struct blkid_chain *chn = blkid_probe_get_chain(pr);
+
+	if (chn && chn->idx >= 0 && chn->idx < chn->driver->nidinfos)
+		return chn->driver->idinfos[chn->idx]->name;
+
+	return NULL;
+}
+
 void *blkid_probe_get_binary_data(blkid_probe pr, struct blkid_chain *chn)
 {
 	int rc, org_prob_flags;
@@ -368,8 +382,7 @@
 	if (rc != 0)
 		return NULL;
 
-	DBG(DEBUG_LOWPROBE,
-		printf("returning %s binary data\n", chn->driver->name));
+	DBG(LOWPROBE, ul_debug("returning %s binary data", chn->driver->name));
 	return chn->data;
 }
 
@@ -415,7 +428,7 @@
 	for (i = 0; i < chn->driver->nidinfos; i++) {
 		const struct blkid_idinfo *id = chn->driver->idinfos[i];
 
-		DBG(DEBUG_LOWPROBE, printf("%d: %s: %s\n",
+		DBG(LOWPROBE, ul_debug("%d: %s: %s",
 			i,
 			id->name,
 			blkid_bmp_get_item(chn->fltr, i)
@@ -474,7 +487,7 @@
 	for (i = 0; i < blkid_bmp_nwords(chn->driver->nidinfos); i++)
 		chn->fltr[i] = ~chn->fltr[i];
 
-	DBG(DEBUG_LOWPROBE, printf("probing filter inverted\n"));
+	DBG(LOWPROBE, ul_debug("probing filter inverted"));
 	/* blkid_probe_dump_filter(pr, chain); */
 	return 0;
 }
@@ -516,8 +529,7 @@
 		}
 	}
 
-	DBG(DEBUG_LOWPROBE,
-		printf("%s: a new probing type-filter initialized\n",
+	DBG(LOWPROBE, ul_debug("%s: a new probing type-filter initialized",
 		chn->driver->name));
 	/* blkid_probe_dump_filter(pr, chain); */
 	return 0;
@@ -529,8 +541,10 @@
 	struct list_head *p;
 	struct blkid_bufinfo *bf = NULL;
 
-	if (pr->size <= 0)
+	if (pr->size <= 0) {
+		errno = EINVAL;
 		return NULL;
+	}
 
 	if (pr->parent &&
 	    pr->parent->devno == pr->devno &&
@@ -552,8 +566,7 @@
 				list_entry(p, struct blkid_bufinfo, bufs);
 
 		if (x->off <= off && off + len <= x->off + x->len) {
-			DBG(DEBUG_LOWPROBE,
-				printf("\treuse buffer: off=%jd len=%jd pr=%p\n",
+			DBG(LOWPROBE, ul_debug("\treuse buffer: off=%jd len=%jd pr=%p",
 							x->off, x->len, pr));
 			bf = x;
 			break;
@@ -562,31 +575,44 @@
 	if (!bf) {
 		ssize_t ret;
 
-		if (blkid_llseek(pr->fd, pr->off + off, SEEK_SET) < 0)
+		if (blkid_llseek(pr->fd, pr->off + off, SEEK_SET) < 0) {
+			errno = 0;
 			return NULL;
+		}
+
+		/* someone trying to overflow some buffers? */
+		if (len > ULONG_MAX - sizeof(struct blkid_bufinfo)) {
+			errno = ENOMEM;
+			return NULL;
+		}
 
 		/* allocate info and space for data by why call */
 		bf = calloc(1, sizeof(struct blkid_bufinfo) + len);
-		if (!bf)
+		if (!bf) {
+			errno = ENOMEM;
 			return NULL;
+		}
 
 		bf->data = ((unsigned char *) bf) + sizeof(struct blkid_bufinfo);
 		bf->len = len;
 		bf->off = off;
 		INIT_LIST_HEAD(&bf->bufs);
 
-		DBG(DEBUG_LOWPROBE,
-			printf("\tbuffer read: off=%jd len=%jd pr=%p\n",
+		DBG(LOWPROBE, ul_debug("\tbuffer read: off=%jd len=%jd pr=%p",
 				off, len, pr));
 
 		ret = read(pr->fd, bf->data, len);
 		if (ret != (ssize_t) len) {
+			DBG(LOWPROBE, ul_debug("\tbuffer read: return %zd error %m", ret));
 			free(bf);
+			if (ret >= 0)
+				errno = 0;
 			return NULL;
 		}
 		list_add_tail(&bf->bufs, &pr->buffers);
 	}
 
+	errno = 0;
 	return off ? bf->data + (off - bf->off) : bf->data;
 }
 
@@ -598,7 +624,7 @@
 	if (!pr || list_empty(&pr->buffers))
 		return;
 
-	DBG(DEBUG_LOWPROBE, printf("reseting probing buffers pr=%p\n", pr));
+	DBG(LOWPROBE, ul_debug("reseting probing buffers pr=%p", pr));
 
 	while (!list_empty(&pr->buffers)) {
 		struct blkid_bufinfo *bf = list_entry(pr->buffers.next,
@@ -609,9 +635,8 @@
 		free(bf);
 	}
 
-	DBG(DEBUG_LOWPROBE,
-		printf("buffers summary: %"PRIu64" bytes "
-			"by %"PRIu64" read() call(s)\n",
+	DBG(LOWPROBE, ul_debug("buffers summary: %"PRIu64" bytes "
+			"by %"PRIu64" read() call(s)",
 			len_ct, read_ct));
 
 	INIT_LIST_HEAD(&pr->buffers);
@@ -684,6 +709,7 @@
 	if (!S_ISBLK(sb.st_mode) && !S_ISCHR(sb.st_mode) && !S_ISREG(sb.st_mode))
 		goto err;
 
+
 	pr->mode = sb.st_mode;
 	if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode))
 		pr->devno = sb.st_rdev;
@@ -693,8 +719,7 @@
 	else {
 		if (S_ISBLK(sb.st_mode)) {
 			if (blkdev_get_size(fd, (unsigned long long *) &pr->size)) {
-				DBG(DEBUG_LOWPROBE, printf(
-					"failed to get device size\n"));
+				DBG(LOWPROBE, ul_debug("failed to get device size"));
 				goto err;
 			}
 		} else if (S_ISCHR(sb.st_mode))
@@ -713,24 +738,28 @@
 	if (pr->size <= 1440 * 1024 && !S_ISCHR(sb.st_mode))
 		pr->flags |= BLKID_FL_TINY_DEV;
 
+	if (S_ISBLK(sb.st_mode) && sysfs_devno_is_lvm_private(sb.st_rdev)) {
+		DBG(LOWPROBE, ul_debug("ignore private LVM device"));
+		pr->flags |= BLKID_FL_NOSCAN_DEV;
+	}
+
 #ifdef CDROM_GET_CAPABILITY
-	if (S_ISBLK(sb.st_mode) &&
+	else if (S_ISBLK(sb.st_mode) &&
 	    !blkid_probe_is_tiny(pr) &&
 	    blkid_probe_is_wholedisk(pr) &&
 	    ioctl(fd, CDROM_GET_CAPABILITY, NULL) >= 0)
 		pr->flags |= BLKID_FL_CDROM_DEV;
 #endif
 
-	DBG(DEBUG_LOWPROBE, printf("ready for low-probing, offset=%jd, size=%jd\n",
+	DBG(LOWPROBE, ul_debug("ready for low-probing, offset=%jd, size=%jd",
 				pr->off, pr->size));
-	DBG(DEBUG_LOWPROBE, printf("whole-disk: %s, regfile: %s\n",
+	DBG(LOWPROBE, ul_debug("whole-disk: %s, regfile: %s",
 		blkid_probe_is_wholedisk(pr) ?"YES" : "NO",
 		S_ISREG(pr->mode) ? "YES" : "NO"));
 
 	return 0;
 err:
-	DBG(DEBUG_LOWPROBE,
-		printf("failed to prepare a device for low-probing\n"));
+	DBG(LOWPROBE, ul_debug("failed to prepare a device for low-probing"));
 	return -1;
 
 }
@@ -752,9 +781,9 @@
 	if (!pr)
 		return -1;
 
-	DBG(DEBUG_LOWPROBE, printf(
+	DBG(LOWPROBE, ul_debug(
 		"changing probing area pr=%p: size=%llu, off=%llu "
-		"-to-> size=%llu, off=%llu\n",
+		"-to-> size=%llu, off=%llu",
 		pr,
 		(unsigned long long) pr->size,
 		(unsigned long long) pr->off,
@@ -773,6 +802,11 @@
 	return 0;
 }
 
+/*
+ * Check for matching magic value.
+ * Returns BLKID_PROBE_OK if found, BLKID_PROBE_NONE if not found
+ * or no magic present, or negative value on error.
+ */
 int blkid_probe_get_idmag(blkid_probe pr, const struct blkid_idinfo *id,
 			blkid_loff_t *offset, const struct blkid_idmag **res)
 {
@@ -791,31 +825,32 @@
 		off = (mag->kboff + (mag->sboff >> 10)) << 10;
 		buf = blkid_probe_get_buffer(pr, off, 1024);
 
+		if (!buf && errno)
+			return -errno;
 		if (buf && !memcmp(mag->magic,
 				buf + (mag->sboff & 0x3ff), mag->len)) {
-			DBG(DEBUG_LOWPROBE, printf(
-				"\tmagic sboff=%u, kboff=%ld\n",
+			DBG(LOWPROBE, ul_debug("\tmagic sboff=%u, kboff=%ld",
 				mag->sboff, mag->kboff));
 			if (offset)
 				*offset = off + (mag->sboff & 0x3ff);
 			if (res)
 				*res = mag;
-			return 0;
+			return BLKID_PROBE_OK;
 		}
 		mag++;
 	}
 
 	if (id && id->magics[0].magic)
 		/* magic string(s) defined, but not found */
-		return 1;
+		return BLKID_PROBE_NONE;
 
-	return 0;
+	return BLKID_PROBE_OK;
 }
 
 static inline void blkid_probe_start(blkid_probe pr)
 {
 	if (pr) {
-		DBG(DEBUG_LOWPROBE, printf("%p: start probe\n", pr));
+		DBG(LOWPROBE, ul_debug("%p: start probe", pr));
 		pr->cur_chain = NULL;
 		pr->prob_flags = 0;
 		blkid_probe_set_wiper(pr, 0, 0);
@@ -825,7 +860,7 @@
 static inline void blkid_probe_end(blkid_probe pr)
 {
 	if (pr) {
-		DBG(DEBUG_LOWPROBE, printf("%p: end probe\n", pr));
+		DBG(LOWPROBE, ul_debug("%p: end probe", pr));
 		pr->cur_chain = NULL;
 		pr->prob_flags = 0;
 		blkid_probe_set_wiper(pr, 0, 0);
@@ -880,6 +915,9 @@
 	if (!pr)
 		return -1;
 
+	if (pr->flags & BLKID_FL_NOSCAN_DEV)
+		return 1;
+
 	do {
 		struct blkid_chain *chn = pr->cur_chain;
 
@@ -909,7 +947,7 @@
 
 		chn->binary = FALSE;		/* for sure... */
 
-		DBG(DEBUG_LOWPROBE, printf("chain probe %s %s (idx=%d)\n",
+		DBG(LOWPROBE, ul_debug("chain probe %s %s (idx=%d)",
 				chn->driver->name,
 				chn->enabled? "ENABLED" : "DISABLED",
 				chn->idx));
@@ -932,7 +970,8 @@
  *
  * This function erases the current signature detected by @pr. The @pr has to
  * be open in O_RDWR mode, BLKID_SUBLKS_MAGIC or/and BLKID_PARTS_MAGIC flags
- * has to be enabled.
+ * has to be enabled (if you want to errase also superblock with broken check
+ * sums then use BLKID_SUBLKS_BADCSUM too).
  *
  * After successful signature removing the @pr prober will be moved one step
  * back and the next blkid_do_probe() call will again call previously called
@@ -999,7 +1038,7 @@
 	if (len > sizeof(buf))
 		len = sizeof(buf);
 
-	DBG(DEBUG_LOWPROBE, printf(
+	DBG(LOWPROBE, ul_debug(
 	    "do_wipe [offset=0x%jx, len=%zd, chain=%s, idx=%d, dryrun=%s]\n",
 	    offset, len, chn->driver->name, chn->idx, dryrun ? "yes" : "not"));
 
@@ -1020,7 +1059,7 @@
 }
 
 /**
- * blkid_probe_step_back():
+ * blkid_probe_step_back:
  * @pr: prober
  *
  * This function move pointer to the probing chain one step back -- it means
@@ -1038,6 +1077,9 @@
  *      blkid_probe_enable_superblocks(pr, 1);
  *      blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_MAGIC);
  *
+ *      blkid_probe_enable_partitions(pr, 1);
+ *      blkid_probe_set_partitions_flags(pr, BLKID_PARTS_MAGIC);
+ *
  *	while (blkid_do_probe(pr) == 0) {
  *		const char *ostr = NULL;
  *		size_t len = 0;
@@ -1080,8 +1122,7 @@
 
 	if (chn->idx >= 0) {
 		chn->idx--;
-		DBG(DEBUG_LOWPROBE,
-			printf("step back: moving %s chain index to %d\n",
+		DBG(LOWPROBE, ul_debug("step back: moving %s chain index to %d",
 			chn->driver->name,
 			chn->idx));
 	}
@@ -1093,7 +1134,7 @@
 		 */
 		size_t idx = chn->driver->id > 0 ? chn->driver->id - 1 : 0;
 
-		DBG(DEBUG_LOWPROBE, printf("step back: moving to previous chain\n"));
+		DBG(LOWPROBE, ul_debug("step back: moving to previous chain"));
 
 		if (idx > 0)
 			pr->cur_chain = &pr->chains[idx];
@@ -1128,18 +1169,18 @@
 
 	if (!pr)
 		return -1;
+	if (pr->flags & BLKID_FL_NOSCAN_DEV)
+		return 1;
 
 	blkid_probe_start(pr);
 
-	pr->prob_flags |= BLKID_PROBE_FL_IGNORE_BACKUP;
-
 	for (i = 0; i < BLKID_NCHAINS; i++) {
 		struct blkid_chain *chn;
 
 		chn = pr->cur_chain = &pr->chains[i];
 		chn->binary = FALSE;		/* for sure... */
 
-		DBG(DEBUG_LOWPROBE, printf("chain safeprobe %s %s\n",
+		DBG(LOWPROBE, ul_debug("chain safeprobe %s %s",
 				chn->driver->name,
 				chn->enabled? "ENABLED" : "DISABLED"));
 
@@ -1184,6 +1225,8 @@
 
 	if (!pr)
 		return -1;
+	if (pr->flags & BLKID_FL_NOSCAN_DEV)
+		return 1;
 
 	blkid_probe_start(pr);
 
@@ -1193,7 +1236,7 @@
 		chn = pr->cur_chain = &pr->chains[i];
 		chn->binary = FALSE;		/* for sure... */
 
-		DBG(DEBUG_LOWPROBE, printf("chain fullprobe %s: %s\n",
+		DBG(LOWPROBE, ul_debug("chain fullprobe %s: %s",
 				chn->driver->name,
 				chn->enabled? "ENABLED" : "DISABLED"));
 
@@ -1242,8 +1285,7 @@
 	v->chain = pr->cur_chain;
 	pr->nvals++;
 
-	DBG(DEBUG_LOWPROBE,
-		printf("assigning %s [%s]\n", name, v->chain->driver->name));
+	DBG(LOWPROBE, ul_debug("assigning %s [%s]", name, v->chain->driver->name));
 	return v;
 }
 
@@ -1256,8 +1298,7 @@
 
 	v = &pr->vals[pr->nvals - 1];
 
-	DBG(DEBUG_LOWPROBE,
-		printf("un-assigning %s [%s]\n", v->name, v->chain->driver->name));
+	DBG(LOWPROBE, ul_debug("un-assigning %s [%s]", v->name, v->chain->driver->name));
 
 	memset(v, 0, sizeof(struct blkid_prval));
 	pr->nvals--;
@@ -1349,6 +1390,31 @@
 	return rc;
 }
 
+int blkid_probe_verify_csum(blkid_probe pr, uint64_t csum, uint64_t expected)
+{
+	if (csum != expected) {
+		struct blkid_chain *chn = blkid_probe_get_chain(pr);
+
+		DBG(LOWPROBE, ul_debug(
+				"incorrect checksum for type %s,"
+				" got %jX, expected %jX",
+				blkid_probe_get_probername(pr),
+				csum, expected));
+		/*
+		 * Accept bad checksum if BLKID_SUBLKS_BADCSUM flags is set
+		 */
+		if (chn->driver->id == BLKID_CHAIN_SUBLKS
+		    && (chn->flags & BLKID_SUBLKS_BADCSUM)) {
+			blkid_probe_set_value(pr, "SBBADCSUM", (unsigned char *) "1", 2);
+			goto accept;
+		}
+		return 0;	/* bad checksum */
+	}
+
+accept:
+	return 1;
+}
+
 /**
  * blkid_probe_get_devno:
  * @pr: probe
@@ -1428,7 +1494,7 @@
 		if (!disk_path)
 			return NULL;
 
-		DBG(DEBUG_LOWPROBE, printf("allocate a wholedisk probe\n"));
+		DBG(LOWPROBE, ul_debug("allocate a wholedisk probe"));
 
 		pr->disk_probe = blkid_new_probe_from_filename(disk_path);
 
@@ -1553,7 +1619,7 @@
 	if (len)
 		*len = v->len;
 
-	DBG(DEBUG_LOWPROBE, printf("returning %s value\n", v->name));
+	DBG(LOWPROBE, ul_debug("returning %s value", v->name));
 	return 0;
 }
 
@@ -1616,7 +1682,7 @@
 		struct blkid_prval *v = &pr->vals[i];
 
 		if (v->name && strcmp(name, v->name) == 0) {
-			DBG(DEBUG_LOWPROBE, printf("returning %s value\n", v->name));
+			DBG(LOWPROBE, ul_debug("returning %s value", v->name));
 			return v;
 		}
 	}
@@ -1645,6 +1711,16 @@
 }
 #endif
 
+/* like uuid_is_null() from libuuid, but works with arbitrary size of UUID */
+int blkid_uuid_is_empty(const unsigned char *buf, size_t len)
+{
+	size_t i;
+
+	for (i = 0; i < len; i++)
+		if (buf[i])
+			return 0;
+	return 1;
+}
 
 /* Removes whitespace from the right-hand side of a string (trailing
  * whitespace).
@@ -1653,14 +1729,7 @@
  */
 size_t blkid_rtrim_whitespace(unsigned char *str)
 {
-	size_t i = strlen((char *) str);
-
-	while (i--) {
-		if (!isspace(str[i]))
-			break;
-	}
-	str[++i] = '\0';
-	return i;
+	return rtrim_whitespace(str);
 }
 
 /* Removes whitespace from the left-hand side of a string.
@@ -1669,18 +1738,9 @@
  */
 size_t blkid_ltrim_whitespace(unsigned char *str)
 {
-	size_t len;
-	unsigned char *p;
-
-	for (p = str; p && isspace(*p); p++);
-
-	len = strlen((char *) p);
-
-	if (len && p > str)
-		memmove(str, p, len + 1);
-
-	return len;
+	return ltrim_whitespace(str);
 }
+
 /*
  * Some mkfs-like utils wipe some parts (usually begin) of the device.
  * For example LVM (pvcreate) or mkswap(8). This information could be used
@@ -1716,7 +1776,7 @@
 		return;
 
 	if (!size) {
-		DBG(DEBUG_LOWPROBE, printf("zeroize wiper\n"));
+		DBG(LOWPROBE, ul_debug("zeroize wiper"));
 		pr->wipe_size = pr->wipe_off = 0;
 		pr->wipe_chain = NULL;
 		return;
@@ -1732,8 +1792,8 @@
 	pr->wipe_off = off;
 	pr->wipe_chain = chn;
 
-	DBG(DEBUG_LOWPROBE,
-		printf("wiper set to %s::%s off=%jd size=%jd\n",
+	DBG(LOWPROBE,
+		ul_debug("wiper set to %s::%s off=%jd size=%jd",
 			chn->driver->name,
 			chn->driver->idinfos[chn->idx]->name,
 			pr->wipe_off, pr->wipe_size));
@@ -1766,14 +1826,9 @@
 	struct blkid_chain *chn = NULL;
 
 	if (blkid_probe_is_wiped(pr, &chn, off, size) && chn) {
-		DBG(DEBUG_LOWPROBE, printf("previously wiped area modified "
-				       " -- ignore previous results\n"));
+		DBG(LOWPROBE, ul_debug("previously wiped area modified "
+				       " -- ignore previous results"));
 		blkid_probe_set_wiper(pr, 0, 0);
 		blkid_probe_chain_reset_vals(pr, chn);
 	}
 }
-
-int blkid_probe_ignore_backup(blkid_probe pr)
-{
-	return pr && (pr->prob_flags & BLKID_PROBE_FL_IGNORE_BACKUP);
-}
diff --git a/libblkid/src/pt-bsd.h b/libblkid/src/pt-bsd.h
new file mode 100644
index 0000000..9bf47a5
--- /dev/null
+++ b/libblkid/src/pt-bsd.h
@@ -0,0 +1,156 @@
+#ifndef UTIL_LINUX_PT_BSD_H
+#define UTIL_LINUX_PT_BSD_H
+
+#define BSD_MAXPARTITIONS	16
+#define BSD_FS_UNUSED		0
+
+#ifndef BSD_DISKMAGIC
+# define BSD_DISKMAGIC     ((uint32_t) 0x82564557)
+#endif
+
+#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec"
+
+#if defined (__alpha__) || defined (__powerpc__) || \
+    defined (__ia64__) || defined (__hppa__)
+# define BSD_LABELSECTOR   0
+# define BSD_LABELOFFSET   64
+#else
+# define BSD_LABELSECTOR   1
+# define BSD_LABELOFFSET   0
+#endif
+
+#define	BSD_BBSIZE        8192		/* size of boot area, with label */
+#define	BSD_SBSIZE        8192		/* max size of fs superblock */
+
+struct bsd_disklabel {
+	uint32_t	d_magic;		/* the magic number */
+	int16_t		d_type;			/* drive type */
+	int16_t		d_subtype;		/* controller/d_type specific */
+	char		d_typename[16];		/* type name, e.g. "eagle" */
+	char		d_packname[16];		/* pack identifier */
+
+			/* disk geometry: */
+	uint32_t	d_secsize;		/* # of bytes per sector */
+	uint32_t	d_nsectors;		/* # of data sectors per track */
+	uint32_t	d_ntracks;		/* # of tracks per cylinder */
+	uint32_t	d_ncylinders;		/* # of data cylinders per unit */
+	uint32_t	d_secpercyl;		/* # of data sectors per cylinder */
+	uint32_t	d_secperunit;		/* # of data sectors per unit */
+
+	/*
+	 * Spares (bad sector replacements) below
+	 * are not counted in d_nsectors or d_secpercyl.
+	 * Spare sectors are assumed to be physical sectors
+	 * which occupy space at the end of each track and/or cylinder.
+	 */
+	uint16_t	d_sparespertrack;	/* # of spare sectors per track */
+	uint16_t	d_sparespercyl;		/* # of spare sectors per cylinder */
+
+	/*
+	 * Alternate cylinders include maintenance, replacement,
+	 * configuration description areas, etc.
+	 */
+	uint32_t	d_acylinders;		/* # of alt. cylinders per unit */
+
+			/* hardware characteristics: */
+	/*
+	 * d_interleave, d_trackskew and d_cylskew describe perturbations
+	 * in the media format used to compensate for a slow controller.
+	 * Interleave is physical sector interleave, set up by the formatter
+	 * or controller when formatting.  When interleaving is in use,
+	 * logically adjacent sectors are not physically contiguous,
+	 * but instead are separated by some number of sectors.
+	 * It is specified as the ratio of physical sectors traversed
+	 * per logical sector.  Thus an interleave of 1:1 implies contiguous
+	 * layout, while 2:1 implies that logical sector 0 is separated
+	 * by one sector from logical sector 1.
+	 * d_trackskew is the offset of sector 0 on track N
+	 * relative to sector 0 on track N-1 on the same cylinder.
+	 * Finally, d_cylskew is the offset of sector 0 on cylinder N
+	 * relative to sector 0 on cylinder N-1.
+	 */
+	uint16_t	d_rpm;			/* rotational speed */
+	uint16_t	d_interleave;		/* hardware sector interleave */
+	uint16_t	d_trackskew;		/* sector 0 skew, per track */
+	uint16_t	d_cylskew;		/* sector 0 skew, per cylinder */
+	uint32_t	d_headswitch;		/* head switch time, usec */
+	uint32_t	d_trkseek;		/* track-to-track seek, usec */
+	uint32_t	d_flags;		/* generic flags */
+	uint32_t	d_drivedata[5];		/* drive-type specific information */
+	uint32_t	d_spare[5];		/* reserved for future use */
+	uint32_t	d_magic2;		/* the magic number (again) */
+	uint16_t	d_checksum;		/* xor of data incl. partitions */
+
+			/* filesystem and partition information: */
+	uint16_t	d_npartitions;	        /* number of partitions in following */
+	uint32_t	d_bbsize;	        /* size of boot area at sn0, bytes */
+	uint32_t	d_sbsize;	        /* max size of fs superblock, bytes */
+
+	struct bsd_partition	 {		/* the partition table */
+		uint32_t	p_size;	        /* number of sectors in partition */
+		uint32_t	p_offset;       /* starting sector */
+		uint32_t	p_fsize;        /* filesystem basic fragment size */
+		uint8_t		p_fstype;	/* filesystem type, see below */
+		uint8_t		p_frag;		/* filesystem fragments per block */
+		uint16_t	p_cpg;	        /* filesystem cylinders per group */
+	} __attribute__((packed)) d_partitions[BSD_MAXPARTITIONS];	/* actually may be more */
+} __attribute__((packed));
+
+
+/* d_type values: */
+#define	BSD_DTYPE_SMD		1		/* SMD, XSMD; VAX hp/up */
+#define	BSD_DTYPE_MSCP		2		/* MSCP */
+#define	BSD_DTYPE_DEC		3		/* other DEC (rk, rl) */
+#define	BSD_DTYPE_SCSI		4		/* SCSI */
+#define	BSD_DTYPE_ESDI		5		/* ESDI interface */
+#define	BSD_DTYPE_ST506		6		/* ST506 etc. */
+#define	BSD_DTYPE_HPIB		7		/* CS/80 on HP-IB */
+#define BSD_DTYPE_HPFL		8		/* HP Fiber-link */
+#define	BSD_DTYPE_FLOPPY	10		/* floppy */
+
+/* d_subtype values: */
+#define BSD_DSTYPE_INDOSPART	0x8		/* is inside dos partition */
+#define BSD_DSTYPE_DOSPART(s)	((s) & 3)	/* dos partition number */
+#define BSD_DSTYPE_GEOMETRY	0x10		/* drive params in label */
+
+/*
+ * Filesystem type and version.
+ * Used to interpret other filesystem-specific
+ * per-partition information.
+ */
+#define	BSD_FS_UNUSED	0		/* unused */
+#define	BSD_FS_SWAP    	1		/* swap */
+#define	BSD_FS_V6      	2		/* Sixth Edition */
+#define	BSD_FS_V7      	3		/* Seventh Edition */
+#define	BSD_FS_SYSV    	4		/* System V */
+#define	BSD_FS_V71K    	5		/* V7 with 1K blocks (4.1, 2.9) */
+#define	BSD_FS_V8      	6		/* Eighth Edition, 4K blocks */
+#define	BSD_FS_BSDFFS	7		/* 4.2BSD fast file system */
+#define	BSD_FS_BSDLFS	9		/* 4.4BSD log-structured file system */
+#define	BSD_FS_OTHER	10		/* in use, but unknown/unsupported */
+#define	BSD_FS_HPFS	11		/* OS/2 high-performance file system */
+#define	BSD_FS_ISO9660	12		/* ISO-9660 filesystem (cdrom) */
+#define BSD_FS_ISOFS	BSD_FS_ISO9660
+#define	BSD_FS_BOOT	13		/* partition contains bootstrap */
+#define BSD_FS_ADOS	14		/* AmigaDOS fast file system */
+#define BSD_FS_HFS	15		/* Macintosh HFS */
+#define BSD_FS_ADVFS	16		/* Digital Unix AdvFS */
+
+/* this is annoying, but it's also the way it is :-( */
+#ifdef __alpha__
+#define	BSD_FS_EXT2	8		/* ext2 file system */
+#else
+#define	BSD_FS_MSDOS	8		/* MS-DOS file system */
+#endif
+
+/*
+ * flags shared by various drives:
+ */
+#define	BSD_D_REMOVABLE	0x01		/* removable media */
+#define	BSD_D_ECC      	0x02		/* supports ECC */
+#define	BSD_D_BADSECT	0x04		/* supports bad sector forw. */
+#define	BSD_D_RAMDISK	0x08		/* disk emulator */
+#define	BSD_D_CHAIN    	0x10		/* can do back-back transfers */
+#define	BSD_D_DOSPART	0x20		/* within MSDOS partition */
+
+#endif /* UTIL_LINUX_PT_BSD_H */
diff --git a/libblkid/src/pt-mbr.h b/libblkid/src/pt-mbr.h
new file mode 100644
index 0000000..1279e3c
--- /dev/null
+++ b/libblkid/src/pt-mbr.h
@@ -0,0 +1,178 @@
+#ifndef UTIL_LINUX_PT_MBR_H
+#define UTIL_LINUX_PT_MBR_H
+
+struct dos_partition {
+	unsigned char boot_ind;		/* 0x80 - active */
+	unsigned char bh, bs, bc;	/* begin CHS */
+	unsigned char sys_ind;
+	unsigned char eh, es, ec;	/* end CHS */
+	unsigned char start_sect[4];
+	unsigned char nr_sects[4];
+} __attribute__((packed));
+
+#define MBR_PT_OFFSET		0x1be
+
+static inline struct dos_partition *mbr_get_partition(unsigned char *mbr, int i)
+{
+	return (struct dos_partition *)
+		(mbr + MBR_PT_OFFSET + (i * sizeof(struct dos_partition)));
+}
+
+/* assemble badly aligned little endian integer */
+static inline unsigned int __dos_assemble_4le(const unsigned char *p)
+{
+	return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
+}
+
+static inline void __dos_store_4le(unsigned char *p, unsigned int val)
+{
+	p[0] = (val & 0xff);
+	p[1] = ((val >> 8) & 0xff);
+	p[2] = ((val >> 16) & 0xff);
+	p[3] = ((val >> 24) & 0xff);
+}
+
+static inline unsigned int dos_partition_get_start(struct dos_partition *p)
+{
+	return __dos_assemble_4le(&(p->start_sect[0]));
+}
+
+static inline void dos_partition_set_start(struct dos_partition *p, unsigned int n)
+{
+	__dos_store_4le(p->start_sect, n);
+}
+
+static inline unsigned int dos_partition_get_size(struct dos_partition *p)
+{
+	return __dos_assemble_4le(&(p->nr_sects[0]));
+}
+
+static inline void dos_partition_set_size(struct dos_partition *p, unsigned int n)
+{
+	__dos_store_4le(p->nr_sects, n);
+}
+
+static inline int mbr_is_valid_magic(const unsigned char *mbr)
+{
+	return mbr[510] == 0x55 && mbr[511] == 0xaa ? 1 : 0;
+}
+
+static inline void mbr_set_magic(unsigned char *b)
+{
+	b[510] = 0x55;
+	b[511] = 0xaa;
+}
+
+static inline unsigned int mbr_get_id(const unsigned char *mbr)
+{
+	return __dos_assemble_4le(&mbr[440]);
+}
+
+static inline void mbr_set_id(unsigned char *b, unsigned int id)
+{
+	__dos_store_4le(&b[440], id);
+}
+
+enum {
+	MBR_EMPTY_PARTITION		= 0x00,
+	MBR_FAT12_PARTITION		= 0x01,
+	MBR_XENIX_ROOT_PARTITION	= 0x02,
+	MBR_XENIX_USR_PARTITION		= 0x03,
+	MBR_FAT16_LESS32M_PARTITION	= 0x04,
+	MBR_DOS_EXTENDED_PARTITION	= 0x05,
+	MBR_FAT16_PARTITION		= 0x06, /* DOS 16-bit >=32M */
+	MBR_HPFS_NTFS_PARTITION		= 0x07, /* OS/2 IFS, eg, HPFS or NTFS or QNX */
+	MBR_AIX_PARTITION		= 0x08, /* AIX boot (AIX -- PS/2 port) or SplitDrive */
+	MBR_AIX_BOOTABLE_PARTITION	= 0x09, /* AIX data or Coherent */
+	MBR_OS2_BOOTMNGR_PARTITION	= 0x0a, /* OS/2 Boot Manager */
+	MBR_W95_FAT32_PARTITION		= 0x0b,
+	MBR_W95_FAT32_LBA_PARTITION	= 0x0c, /* LBA really is `Extended Int 13h' */
+	MBR_W95_FAT16_LBA_PARTITION	= 0x0e,
+	MBR_W95_EXTENDED_PARTITION	= 0x0f,
+	MBR_OPUS_PARTITION		= 0x10,
+	MBR_HIDDEN_FAT12_PARTITION	= 0x11,
+	MBR_COMPAQ_DIAGNOSTICS_PARTITION = 0x12,
+	MBR_HIDDEN_FAT16_L32M_PARTITION	= 0x14,
+	MBR_HIDDEN_FAT16_PARTITION	= 0x16,
+	MBR_HIDDEN_HPFS_NTFS_PARTITION	= 0x17,
+	MBR_AST_SMARTSLEEP_PARTITION	= 0x18,
+	MBR_HIDDEN_W95_FAT32_PARTITION	= 0x1b,
+	MBR_HIDDEN_W95_FAT32LBA_PARTITION = 0x1c,
+	MBR_HIDDEN_W95_FAT16LBA_PARTITION = 0x1e,
+	MBR_NEC_DOS_PARTITION		= 0x24,
+	MBR_PLAN9_PARTITION		= 0x39,
+	MBR_PARTITIONMAGIC_PARTITION	= 0x3c,
+	MBR_VENIX80286_PARTITION	= 0x40,
+	MBR_PPC_PREP_BOOT_PARTITION	= 0x41,
+	MBR_SFS_PARTITION		= 0x42,
+	MBR_QNX_4X_PARTITION		= 0x4d,
+	MBR_QNX_4X_2ND_PARTITION	= 0x4e,
+	MBR_QNX_4X_3RD_PARTITION	= 0x4f,
+	MBR_DM_PARTITION		= 0x50,
+	MBR_DM6_AUX1_PARTITION		= 0x51, /* (or Novell) */
+	MBR_CPM_PARTITION		= 0x52, /* CP/M or Microport SysV/AT */
+	MBR_DM6_AUX3_PARTITION		= 0x53,
+	MBR_DM6_PARTITION		= 0x54,
+	MBR_EZ_DRIVE_PARTITION		= 0x55,
+	MBR_GOLDEN_BOW_PARTITION	= 0x56,
+	MBR_PRIAM_EDISK_PARTITION	= 0x5c,
+	MBR_SPEEDSTOR_PARTITION		= 0x61,
+	MBR_GNU_HURD_PARTITION		= 0x63, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
+	MBR_UNIXWARE_PARTITION		= MBR_GNU_HURD_PARTITION,
+	MBR_NETWARE_286_PARTITION	= 0x64,
+	MBR_NETWARE_386_PARTITION	= 0x65,
+	MBR_DISKSECURE_MULTIBOOT_PARTITION = 0x70,
+	MBR_PC_IX_PARTITION		= 0x75,
+	MBR_OLD_MINIX_PARTITION		= 0x80, /* Minix 1.4a and earlier */
+	MBR_MINIX_PARTITION		= 0x81, /* Minix 1.4b and later */
+	MBR_LINUX_SWAP_PARTITION	= 0x82,
+	MBR_SOLARIS_X86_PARTITION	= MBR_LINUX_SWAP_PARTITION,
+	MBR_LINUX_DATA_PARTITION	= 0x83,
+	MBR_OS2_HIDDEN_DRIVE_PARTITION	= 0x84,
+	MBR_LINUX_EXTENDED_PARTITION	= 0x85,
+	MBR_NTFS_VOL_SET1_PARTITION	= 0x86,
+	MBR_NTFS_VOL_SET2_PARTITION	= 0x87,
+	MBR_LINUX_PLAINTEXT_PARTITION	= 0x88,
+	MBR_LINUX_LVM_PARTITION		= 0x8e,
+	MBR_AMOEBA_PARTITION		= 0x93,
+	MBR_AMOEBA_BBT_PARTITION	= 0x94, /* (bad block table) */
+	MBR_BSD_OS_PARTITION		= 0x9f, /* BSDI */
+	MBR_THINKPAD_HIBERNATION_PARTITION = 0xa0,
+	MBR_FREEBSD_PARTITION		= 0xa5, /* various BSD flavours */
+	MBR_OPENBSD_PARTITION		= 0xa6,
+	MBR_NEXTSTEP_PARTITION		= 0xa7,
+	MBR_DARWIN_UFS_PARTITION	= 0xa8,
+	MBR_NETBSD_PARTITION		= 0xa9,
+	MBR_DARWIN_BOOT_PARTITION	= 0xab,
+	MBR_HFS_HFS_PARTITION		= 0xaf,
+	MBR_BSDI_FS_PARTITION		= 0xb7,
+	MBR_BSDI_SWAP_PARTITION		= 0xb8,
+	MBR_BOOTWIZARD_HIDDEN_PARTITION	= 0xbb,
+	MBR_SOLARIS_BOOT_PARTITION	= 0xbe,
+	MBR_SOLARIS_PARTITION		= 0xbf,
+	MBR_DRDOS_FAT12_PARTITION	= 0xc1,
+	MBR_DRDOS_FAT16_L32M_PARTITION	= 0xc4,
+	MBR_DRDOS_FAT16_PARTITION	= 0xc6,
+	MBR_SYRINX_PARTITION		= 0xc7,
+	MBR_NONFS_DATA_PARTITION	= 0xda,
+	MBR_CPM_CTOS_PARTITION		= 0xdb, /* CP/M or Concurrent CP/M or Concurrent DOS or CTOS */
+	MBR_DELL_UTILITY_PARTITION	= 0xde, /* Dell PowerEdge Server utilities */
+	MBR_BOOTIT_PARTITION		= 0xdf, /* BootIt EMBRM */
+	MBR_DOS_ACCESS_PARTITION	= 0xe1, /* DOS access or SpeedStor 12-bit FAT extended partition */
+	MBR_DOS_RO_PARTITION		= 0xe3, /* DOS R/O or SpeedStor */
+	MBR_SPEEDSTOR_EXTENDED_PARTITION = 0xe4, /* SpeedStor 16-bit FAT extended partition < 1024 cyl. */
+	MBR_BEOS_FS_PARTITION		= 0xeb,
+	MBR_GPT_PARTITION		= 0xee, /* Intel EFI GUID Partition Table */
+	MBR_EFI_SYSTEM_PARTITION	= 0xef, /* Intel EFI System Partition */
+	MBR_LINUX_PARISC_BOOT_PARTITION	= 0xf0, /* Linux/PA-RISC boot loader */
+	MBR_SPEEDSTOR1_PARTITION	= 0xf1,
+	MBR_SPEEDSTOR2_PARTITION	= 0xf4, /* SpeedStor large partition */
+	MBR_DOS_SECONDARY_PARTITION	= 0xf2, /* DOS 3.3+ secondary */
+	MBR_VMWARE_VMFS_PARTITION	= 0xfb,
+	MBR_VMWARE_VMKCORE_PARTITION	= 0xfc, /* VMware kernel dump partition */
+	MBR_LINUX_RAID_PARTITION	= 0xfd, /* New (2.2.x) raid partition with autodetect using persistent superblock */
+	MBR_LANSTEP_PARTITION		= 0xfe, /* SpeedStor >1024 cyl. or LANstep */
+	MBR_XENIX_BBT_PARTITION		= 0xff, /* Xenix Bad Block Table */
+};
+
+#endif /* UTIL_LINUX_PT_MBR_H */
diff --git a/libblkid/read.c b/libblkid/src/read.c
similarity index 88%
rename from libblkid/read.c
rename to libblkid/src/read.c
index 8914cad..81ab0df 100644
--- a/libblkid/read.c
+++ b/libblkid/src/read.c
@@ -150,7 +150,7 @@
 		return 0;
 
 	if (!strncmp(p, "<device", 7)) {
-		DBG(DEBUG_READ, printf("found device header: %8s\n", p));
+		DBG(READ, ul_debug("found device header: %8s", p));
 		p += 7;
 
 		*cp = p;
@@ -169,7 +169,7 @@
 	*cp = skip_over_blank(*cp);
 
 	if (!strncmp(*cp, "</device>", 9)) {
-		DBG(DEBUG_READ, printf("found device trailer %9s\n", *cp));
+		DBG(READ, ul_debug("found device trailer %9s", *cp));
 		*cp += 9;
 		return 0;
 	}
@@ -193,14 +193,13 @@
 
 	start = tmp = strchr(*cp, '>');
 	if (!start) {
-		DBG(DEBUG_READ,
-		    printf("blkid: short line parsing dev: %s\n", *cp));
+		DBG(READ, ul_debug("blkid: short line parsing dev: %s", *cp));
 		return -BLKID_ERR_CACHE;
 	}
 	start = skip_over_blank(start + 1);
 	end = skip_over_word(start);
 
-	DBG(DEBUG_READ, printf("device should be %*s\n",
+	DBG(READ, ul_debug("device should be %*s",
 			       (int)(end - start), start));
 
 	if (**cp == '>')
@@ -211,13 +210,12 @@
 	*tmp = '\0';
 
 	if (!(tmp = strrchr(end, '<')) || parse_end(&tmp) < 0) {
-		DBG(DEBUG_READ,
-		    printf("blkid: missing </device> ending: %s\n", end));
+		DBG(READ, ul_debug("blkid: missing </device> ending: %s", end));
 	} else if (tmp)
 		*tmp = '\0';
 
 	if (end - start <= 1) {
-		DBG(DEBUG_READ, printf("blkid: empty device name: %s\n", *cp));
+		DBG(READ, ul_debug("blkid: empty device name: %s", *cp));
 		return -BLKID_ERR_CACHE;
 	}
 
@@ -225,7 +223,7 @@
 	if (name == NULL)
 		return -BLKID_ERR_MEM;
 
-	DBG(DEBUG_READ, printf("found dev %s\n", name));
+	DBG(READ, ul_debug("found dev %s", name));
 
 	if (!(*dev = blkid_get_dev(cache, name, BLKID_DEV_CREATE))) {
 		free(name);
@@ -254,16 +252,30 @@
 	*value = skip_over_blank(*value + 1);
 
 	if (**value == '"') {
-		end = strchr(*value + 1, '"');
-		if (!end) {
-			DBG(DEBUG_READ,
-			    printf("unbalanced quotes at: %s\n", *value));
+		char *p = end = *value + 1;
+
+		/* convert 'foo\"bar'  to 'foo"bar' */
+		while (*p) {
+			if (*p == '\\') {
+				p++;
+				*end = *p;
+			} else {
+				*end = *p;
+				if (*p == '"')
+					break;
+			}
+			p++;
+			end++;
+		}
+
+		if (*end != '"') {
+			DBG(READ, ul_debug("unbalanced quotes at: %s", *value));
 			*cp = *value;
 			return -BLKID_ERR_CACHE;
 		}
 		(*value)++;
 		*end = '\0';
-		end++;
+		end = ++p;
 	} else {
 		end = skip_over_word(*value);
 		if (*end) {
@@ -329,7 +341,7 @@
 	} else
 		ret = blkid_set_tag(dev, name, value, strlen(value));
 
-	DBG(DEBUG_READ, printf("    tag: %s=\"%s\"\n", name, value));
+	DBG(READ, ul_debug("    tag: %s=\"%s\"", name, value));
 
 	return ret < 0 ? ret : 1;
 }
@@ -355,7 +367,7 @@
 
 	*dev_p = NULL;
 
-	DBG(DEBUG_READ, printf("line: %s\n", cp));
+	DBG(READ, ul_debug("line: %s", cp));
 
 	if ((ret = parse_dev(cache, dev_p, &cp)) <= 0)
 		return ret;
@@ -367,13 +379,12 @@
 	}
 
 	if (dev->bid_type == NULL) {
-		DBG(DEBUG_READ,
-		    printf("blkid: device %s has no TYPE\n",dev->bid_name));
+		DBG(READ, ul_debug("blkid: device %s has no TYPE",dev->bid_name));
 		blkid_free_dev(dev);
 		goto done;
 	}
 
-	DBG(DEBUG_READ, blkid_debug_dump_dev(dev));
+	DBG(READ, blkid_debug_dump_dev(dev));
 
 done:
 	return ret;
@@ -404,15 +415,15 @@
 		goto errout;
 	if ((st.st_mtime == cache->bic_ftime) ||
 	    (cache->bic_flags & BLKID_BIC_FL_CHANGED)) {
-		DBG(DEBUG_CACHE, printf("skipping re-read of %s\n",
+		DBG(CACHE, ul_debug("skipping re-read of %s",
 					cache->bic_filename));
 		goto errout;
 	}
 
-	DBG(DEBUG_CACHE, printf("reading cache file %s\n",
+	DBG(CACHE, ul_debug("reading cache file %s",
 				cache->bic_filename));
 
-	file = fdopen(fd, "r");
+	file = fdopen(fd, "r" UL_CLOEXECSTR);
 	if (!file)
 		goto errout;
 
@@ -432,8 +443,7 @@
 		}
 
 		if (blkid_parse_line(cache, &dev, buf) < 0) {
-			DBG(DEBUG_READ,
-			    printf("blkid: bad format on line %d\n", lineno));
+			DBG(READ, ul_debug("blkid: bad format on line %d", lineno));
 			continue;
 		}
 	}
@@ -483,7 +493,7 @@
 	blkid_cache cache = NULL;
 	int ret;
 
-	blkid_init_debug(DEBUG_ALL);
+	blkid_init_debug(BLKID_DEBUG_ALL);
 	if (argc > 2) {
 		fprintf(stderr, "Usage: %s [filename]\n"
 			"Test parsing of the cache (filename)\n", argv[0]);
diff --git a/libblkid/resolve.c b/libblkid/src/resolve.c
similarity index 93%
rename from libblkid/resolve.c
rename to libblkid/src/resolve.c
index 96749b3..59f0fea 100644
--- a/libblkid/resolve.c
+++ b/libblkid/src/resolve.c
@@ -32,7 +32,7 @@
 	blkid_cache c = cache;
 	char *ret = NULL;
 
-	DBG(DEBUG_RESOLVE, printf("looking for %s on %s\n", tagname, devname));
+	DBG(TAG, ul_debug("looking for %s on %s", tagname, devname));
 
 	if (!devname)
 		return NULL;
@@ -68,8 +68,7 @@
 	if (!cache && blkid_get_cache(&c, NULL) < 0)
 		return NULL;
 
-	DBG(DEBUG_RESOLVE,
-	    printf("looking for %s%s%s %s\n", token, value ? "=" : "",
+	DBG(TAG, ul_debug("looking for %s%s%s %s", token, value ? "=" : "",
 		   value ? value : "", cache ? "in cache" : "from disk"));
 
 	if (!value) {
@@ -103,7 +102,7 @@
 	char *value;
 	blkid_cache cache;
 
-	blkid_init_debug(DEBUG_ALL);
+	blkid_init_debug(BLKID_DEBUG_ALL);
 	if (argc != 2 && argc != 3) {
 		fprintf(stderr, "Usage:\t%s tagname=value\n"
 			"\t%s tagname devname\n"
diff --git a/libblkid/save.c b/libblkid/src/save.c
similarity index 76%
rename from libblkid/save.c
rename to libblkid/src/save.c
index c94cc2a..c2a9753 100644
--- a/libblkid/save.c
+++ b/libblkid/src/save.c
@@ -21,8 +21,26 @@
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
 #endif
+
+#include "closestream.h"
+
 #include "blkidP.h"
 
+
+static void save_quoted(const char *data, FILE *file)
+{
+	const char *p;
+
+	fputc('"', file);
+	for (p = data; p && *p; p++) {
+		if ((unsigned char) *p == 0x22 ||		/* " */
+		    (unsigned char) *p == 0x5c)			/* \ */
+			fputc('\\', file);
+
+		fputc(*p, file);
+	}
+	fputc('"', file);
+}
 static int save_dev(blkid_dev dev, FILE *file)
 {
 	struct list_head *p;
@@ -30,8 +48,7 @@
 	if (!dev || dev->bid_name[0] != '/')
 		return 0;
 
-	DBG(DEBUG_SAVE,
-	    printf("device %s, type %s\n", dev->bid_name, dev->bid_type ?
+	DBG(SAVE, ul_debug("device %s, type %s", dev->bid_name, dev->bid_type ?
 		   dev->bid_type : "(null)"));
 
 	fprintf(file, "<device DEVNO=\"0x%04lx\" TIME=\"%ld.%ld\"",
@@ -41,9 +58,14 @@
 
 	if (dev->bid_pri)
 		fprintf(file, " PRI=\"%d\"", dev->bid_pri);
+
 	list_for_each(p, &dev->bid_tags) {
 		blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags);
-		fprintf(file, " %s=\"%s\"", tag->bit_name,tag->bit_val);
+
+		fputc(' ', file);			/* space between tags */
+		fputs(tag->bit_name, file);		/* tag NAME */
+		fputc('=', file);			/* separator between NAME and VALUE */
+		save_quoted(tag->bit_val, file);	/* tag "VALUE" */
 	}
 	fprintf(file, ">%s</device>\n", dev->bid_name);
 
@@ -68,7 +90,7 @@
 
 	if (list_empty(&cache->bic_devs) ||
 	    !(cache->bic_flags & BLKID_BIC_FL_CHANGED)) {
-		DBG(DEBUG_SAVE, printf("skipping cache file write\n"));
+		DBG(SAVE, ul_debug("skipping cache file write"));
 		return 0;
 	}
 
@@ -87,8 +109,7 @@
 						S_IRUSR|S_IRGRP|S_IROTH|
 						S_IXUSR|S_IXGRP|S_IXOTH) != 0
 		    && errno != EEXIST) {
-			DBG(DEBUG_SAVE,
-				printf("can't create %s directory for cache file\n",
+			DBG(SAVE, ul_debug("can't create %s directory for cache file",
 					BLKID_RUNTIME_DIR));
 			return 0;
 		}
@@ -97,8 +118,7 @@
 	/* If we can't write to the cache file, then don't even try */
 	if (((ret = stat(filename, &st)) < 0 && errno != ENOENT) ||
 	    (ret == 0 && access(filename, W_OK) < 0)) {
-		DBG(DEBUG_SAVE,
-		    printf("can't write to cache file %s\n", filename));
+		DBG(SAVE, ul_debug("can't write to cache file %s", filename));
 		return 0;
 	}
 
@@ -116,8 +136,8 @@
 			fd = mkstemp(tmp);
 			if (fd >= 0) {
 				if (fchmod(fd, 0644) != 0)
-					DBG(DEBUG_SAVE,	printf("%s: fchmod failed\n", filename));
-				else if ((file = fdopen(fd, "w")))
+					DBG(SAVE, ul_debug("%s: fchmod failed", filename));
+				else if ((file = fdopen(fd, "w" UL_CLOEXECSTR)))
 					opened = tmp;
 				if (!file)
 					close(fd);
@@ -126,12 +146,11 @@
 	}
 
 	if (!file) {
-		file = fopen(filename, "w");
+		file = fopen(filename, "w" UL_CLOEXECSTR);
 		opened = filename;
 	}
 
-	DBG(DEBUG_SAVE,
-	    printf("writing cache file %s (really %s)\n",
+	DBG(SAVE, ul_debug("writing cache file %s (really %s)",
 		   filename, opened));
 
 	if (!file) {
@@ -152,12 +171,13 @@
 		ret = 1;
 	}
 
-	fclose(file);
+	if (close_stream(file) != 0)
+		DBG(SAVE, ul_debug("write failed: %s", filename));
+
 	if (opened != filename) {
 		if (ret < 0) {
 			unlink(opened);
-			DBG(DEBUG_SAVE,
-			    printf("unlinked temp cache %s\n", opened));
+			DBG(SAVE, ul_debug("unlinked temp cache %s", opened));
 		} else {
 			char *backup;
 
@@ -166,20 +186,17 @@
 				sprintf(backup, "%s.old", filename);
 				unlink(backup);
 				if (link(filename, backup)) {
-					DBG(DEBUG_SAVE,
-						printf("can't link %s to %s\n",
+					DBG(SAVE, ul_debug("can't link %s to %s",
 							filename, backup));
 				}
 				free(backup);
 			}
 			if (rename(opened, filename)) {
 				ret = errno;
-				DBG(DEBUG_SAVE,
-					printf("can't rename %s to %s\n",
+				DBG(SAVE, ul_debug("can't rename %s to %s",
 						opened, filename));
 			} else {
-				DBG(DEBUG_SAVE,
-				    printf("moved temp cache %s\n", opened));
+				DBG(SAVE, ul_debug("moved temp cache %s", opened));
 			}
 		}
 	}
@@ -197,7 +214,7 @@
 	blkid_cache cache = NULL;
 	int ret;
 
-	blkid_init_debug(DEBUG_ALL);
+	blkid_init_debug(BLKID_DEBUG_ALL);
 	if (argc > 2) {
 		fprintf(stderr, "Usage: %s [filename]\n"
 			"Test loading/saving a cache (filename)\n", argv[0]);
diff --git a/libblkid/src/strutils.h b/libblkid/src/strutils.h
new file mode 100644
index 0000000..4d8463a
--- /dev/null
+++ b/libblkid/src/strutils.h
@@ -0,0 +1,204 @@
+#ifndef UTIL_LINUX_STRUTILS
+#define UTIL_LINUX_STRUTILS
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include <sys/types.h>
+#include <ctype.h>
+
+/* default strtoxx_or_err() exit code */
+#ifndef STRTOXX_EXIT_CODE
+# define STRTOXX_EXIT_CODE EXIT_FAILURE
+#endif
+
+
+extern int parse_size(const char *str, uintmax_t *res, int *power);
+extern int strtosize(const char *str, uintmax_t *res);
+extern uintmax_t strtosize_or_err(const char *str, const char *errmesg);
+
+extern int16_t strtos16_or_err(const char *str, const char *errmesg);
+extern uint16_t strtou16_or_err(const char *str, const char *errmesg);
+
+extern int32_t strtos32_or_err(const char *str, const char *errmesg);
+extern uint32_t strtou32_or_err(const char *str, const char *errmesg);
+
+extern int64_t strtos64_or_err(const char *str, const char *errmesg);
+extern uint64_t strtou64_or_err(const char *str, const char *errmesg);
+
+extern double strtod_or_err(const char *str, const char *errmesg);
+
+extern long strtol_or_err(const char *str, const char *errmesg);
+extern unsigned long strtoul_or_err(const char *str, const char *errmesg);
+
+extern void strtotimeval_or_err(const char *str, struct timeval *tv,
+		const char *errmesg);
+
+extern int isdigit_string(const char *str);
+
+#ifndef HAVE_MEMPCPY
+extern void *mempcpy(void *restrict dest, const void *restrict src, size_t n);
+#endif
+#ifndef HAVE_STRNLEN
+extern size_t strnlen(const char *s, size_t maxlen);
+#endif
+#ifndef HAVE_STRNDUP
+extern char *strndup(const char *s, size_t n);
+#endif
+#ifndef HAVE_STRNCHR
+extern char *strnchr(const char *s, size_t maxlen, int c);
+#endif
+
+/* caller guarantees n > 0 */
+static inline void xstrncpy(char *dest, const char *src, size_t n)
+{
+	strncpy(dest, src, n-1);
+	dest[n-1] = 0;
+}
+
+static inline char *strdup_to_offset(void *stru, size_t offset, const char *str)
+{
+	char *n = NULL;
+	char **o = (char **) ((char *) stru + offset);
+
+	if (str) {
+		n = strdup(str);
+		if (!n)
+			return NULL;
+	}
+
+	free(*o);
+	*o = n;
+	return n;
+}
+
+#define strdup_to_struct_member(_s, _m, _str) \
+		strdup_to_offset((void *) _s, offsetof(__typeof__(*(_s)), _m), _str)
+
+extern void strmode(mode_t mode, char *str);
+
+/* Options for size_to_human_string() */
+enum
+{
+        SIZE_SUFFIX_1LETTER = 0,
+        SIZE_SUFFIX_3LETTER = 1,
+        SIZE_SUFFIX_SPACE   = 2
+};
+
+extern char *size_to_human_string(int options, uint64_t bytes);
+
+extern int string_to_idarray(const char *list, int ary[], size_t arysz,
+			   int (name2id)(const char *, size_t));
+extern int string_add_to_idarray(const char *list, int ary[],
+				 size_t arysz, int *ary_pos,
+				 int (name2id)(const char *, size_t));
+
+extern int string_to_bitarray(const char *list, char *ary,
+			    int (*name2bit)(const char *, size_t));
+
+extern int string_to_bitmask(const char *list,
+			     unsigned long *mask,
+			     long (*name2flag)(const char *, size_t));
+extern int parse_range(const char *str, int *lower, int *upper, int def);
+
+extern int streq_except_trailing_slash(const char *s1, const char *s2);
+
+/*
+ * Match string beginning.
+ */
+static inline const char *startswith(const char *s, const char *prefix)
+{
+	size_t sz = prefix ? strlen(prefix) : 0;
+
+        if (s && sz && strncmp(s, prefix, sz) == 0)
+                return s + sz;
+	return NULL;
+}
+
+/*
+ * Case insensitive match string beginning.
+ */
+static inline const char *startswith_no_case(const char *s, const char *prefix)
+{
+	size_t sz = prefix ? strlen(prefix) : 0;
+
+        if (s && sz && strncasecmp(s, prefix, sz) == 0)
+                return s + sz;
+	return NULL;
+}
+
+/*
+ * Match string ending.
+ */
+static inline const char *endswith(const char *s, const char *postfix)
+{
+	size_t sl = s ? strlen(s) : 0;
+	size_t pl = postfix ? strlen(postfix) : 0;
+
+	if (pl == 0)
+		return (char *)s + sl;
+	if (sl < pl)
+		return NULL;
+	if (memcmp(s + sl - pl, postfix, pl) != 0)
+		return NULL;
+	return (char *)s + sl - pl;
+}
+
+/*
+ * Skip leading white space.
+ */
+static inline const char *skip_space(const char *p)
+{
+	while (isspace(*p))
+		++p;
+	return p;
+}
+
+static inline const char *skip_blank(const char *p)
+{
+	while (isblank(*p))
+		++p;
+	return p;
+}
+
+
+/* Removes whitespace from the right-hand side of a string (trailing
+ * whitespace).
+ *
+ * Returns size of the new string (without \0).
+ */
+static inline size_t rtrim_whitespace(unsigned char *str)
+{
+	size_t i = strlen((char *) str);
+
+	while (i) {
+		i--;
+		if (!isspace(str[i])) {
+			i++;
+			break;
+		}
+	}
+	str[i] = '\0';
+	return i;
+}
+
+/* Removes whitespace from the left-hand side of a string.
+ *
+ * Returns size of the new string (without \0).
+ */
+static inline size_t ltrim_whitespace(unsigned char *str)
+{
+	size_t len;
+	unsigned char *p;
+
+	for (p = str; p && isspace(*p); p++);
+
+	len = strlen((char *) p);
+
+	if (len && p > str)
+		memmove(str, p, len + 1);
+
+	return len;
+}
+
+#endif
diff --git a/libblkid/adaptec_raid.c b/libblkid/src/superblocks/adaptec_raid.c
similarity index 90%
rename from libblkid/adaptec_raid.c
rename to libblkid/src/superblocks/adaptec_raid.c
index 02e900d..65fd5b8 100644
--- a/libblkid/adaptec_raid.c
+++ b/libblkid/src/superblocks/adaptec_raid.c
@@ -80,10 +80,10 @@
 	struct adaptec_metadata *ad;
 
 	if (pr->size < 0x10000)
-		return -1;
+		return BLKID_PROBE_NONE;
 
 	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
-		return -1;
+		return BLKID_PROBE_NONE;
 
 	off = ((pr->size / 0x200)-1) * 0x200;
 	ad = (struct adaptec_metadata *)
@@ -91,17 +91,19 @@
 					off,
 					sizeof(struct adaptec_metadata));
 	if (!ad)
-		return -1;
+		return errno ? -errno : BLKID_PROBE_NONE;;
+
 	if (ad->smagic != be32_to_cpu(AD_SIGNATURE))
-		return -1;
+		return BLKID_PROBE_NONE;
 	if (ad->b0idcode != be32_to_cpu(AD_MAGIC))
-		return -1;
+		return BLKID_PROBE_NONE;
 	if (blkid_probe_sprintf_version(pr, "%u", ad->resver) != 0)
-		return -1;
+		return BLKID_PROBE_NONE;
 	if (blkid_probe_set_magic(pr, off, sizeof(ad->b0idcode),
 				(unsigned char *) &ad->b0idcode))
-		return -1;
-	return 0;
+		return BLKID_PROBE_NONE;
+
+	return BLKID_PROBE_OK;
 }
 
 const struct blkid_idinfo adraid_idinfo = {
diff --git a/libblkid/src/superblocks/bcache.c b/libblkid/src/superblocks/bcache.c
new file mode 100644
index 0000000..b3e397b
--- /dev/null
+++ b/libblkid/src/superblocks/bcache.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2013 Rolf Fokkens <rolf@fokkens.nl>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ * Based on code fragments from bcache-tools by Kent Overstreet:
+ * http://evilpiepirate.org/git/bcache-tools.git
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+
+#include "superblocks.h"
+#include "crc64.h"
+
+#define SB_LABEL_SIZE      32
+#define SB_JOURNAL_BUCKETS 256U
+
+#define node(i, j)         ((i)->d + (j))
+#define end(i)             node(i, (i)->keys)
+
+static const char bcache_magic[] = {
+	0xc6, 0x85, 0x73, 0xf6, 0x4e, 0x1a, 0x45, 0xca,
+	0x82, 0x65, 0xf5, 0x7f, 0x48, 0xba, 0x6d, 0x81
+};
+
+struct bcache_super_block {
+	uint64_t		csum;
+	uint64_t		offset;	/* sector where this sb was written */
+	uint64_t		version;
+
+	uint8_t			magic[16];
+
+	uint8_t			uuid[16];
+	union {
+		uint8_t		set_uuid[16];
+		uint64_t	set_magic;
+	};
+	uint8_t			label[SB_LABEL_SIZE];
+
+	uint64_t		flags;
+	uint64_t		seq;
+	uint64_t		pad[8];
+
+	union {
+	struct {
+		/* Cache devices */
+		uint64_t	nbuckets;	/* device size */
+
+		uint16_t	block_size;	/* sectors */
+		uint16_t	bucket_size;	/* sectors */
+
+		uint16_t	nr_in_set;
+		uint16_t	nr_this_dev;
+	};
+	struct {
+		/* Backing devices */
+		uint64_t	data_offset;
+
+		/*
+		 * block_size from the cache device section is still used by
+		 * backing devices, so don't add anything here until we fix
+		 * things to not need it for backing devices anymore
+		 */
+	};
+	};
+
+	uint32_t		last_mount;	/* time_t */
+
+	uint16_t		first_bucket;
+	union {
+		uint16_t	njournal_buckets;
+		uint16_t	keys;
+	};
+	uint64_t		d[SB_JOURNAL_BUCKETS];	/* journal buckets */
+};
+
+/* magic string */
+#define BCACHE_SB_MAGIC     bcache_magic
+/* magic string len */
+#define BCACHE_SB_MAGIC_LEN sizeof (bcache_magic)
+/* super block offset */
+#define BCACHE_SB_OFF       0x1000
+/* supper block offset in kB */
+#define BCACHE_SB_KBOFF     (BCACHE_SB_OFF >> 10)
+/* magic string offset within super block */
+#define BCACHE_SB_MAGIC_OFF offsetof (struct bcache_super_block, magic)
+
+static uint64_t bcache_crc64(struct bcache_super_block *bcs)
+{
+	unsigned char *data = (unsigned char *) bcs;
+	size_t sz;
+
+	data += 8;		/* skip csum field */
+	sz = (unsigned char *) end(bcs) - data;
+
+	return crc64(0xFFFFFFFFFFFFFFFFULL, data, sz) ^ 0xFFFFFFFFFFFFFFFFULL;
+}
+
+static int probe_bcache (blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct bcache_super_block *bcs;
+
+	bcs = blkid_probe_get_sb(pr, mag, struct bcache_super_block);
+	if (!bcs)
+		return errno ? -errno : BLKID_PROBE_NONE;
+
+	if (le64_to_cpu(bcs->offset) != BCACHE_SB_OFF / 512)
+		return BLKID_PROBE_NONE;
+	if (!blkid_probe_verify_csum(pr, bcache_crc64(bcs), le64_to_cpu(bcs->csum)))
+		return BLKID_PROBE_NONE;
+
+	if (blkid_probe_set_uuid(pr, bcs->uuid) < 0)
+		return BLKID_PROBE_NONE;
+
+	return BLKID_PROBE_OK;
+};
+
+const struct blkid_idinfo bcache_idinfo =
+{
+	.name		= "bcache",
+	.usage		= BLKID_USAGE_OTHER,
+	.probefunc	= probe_bcache,
+	.minsz		= 8192,
+	.magics		=
+	{
+		{ .magic = BCACHE_SB_MAGIC
+		, .len   = BCACHE_SB_MAGIC_LEN
+		, .kboff = BCACHE_SB_KBOFF
+		, .sboff = BCACHE_SB_MAGIC_OFF
+		} ,
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/befs.c b/libblkid/src/superblocks/befs.c
similarity index 95%
rename from libblkid/befs.c
rename to libblkid/src/superblocks/befs.c
index 847860a..e4453bc 100644
--- a/libblkid/befs.c
+++ b/libblkid/src/superblocks/befs.c
@@ -15,8 +15,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <inttypes.h>
-#include <byteswap.h>
-#include "bitops.h"
+
 #include "superblocks.h"
 
 #define B_OS_NAME_LENGTH	0x20
@@ -31,6 +30,7 @@
 #define B_UINT64_TYPE		0x554c4c47	/* ULLG */
 #define KEY_NAME		"be:volume_id"
 #define KEY_SIZE		8
+
 #define FS16_TO_CPU(value, fs_is_le) (fs_is_le ? le16_to_cpu(value) \
 							: be16_to_cpu(value))
 #define FS32_TO_CPU(value, fs_is_le) (fs_is_le ? le32_to_cpu(value) \
@@ -261,21 +261,23 @@
 	int64_t node_pointer;
 	int32_t first, last, mid, cmp;
 
+	errno = 0;
 	bh = (struct bplustree_header *) get_tree_node(pr, bs, &bi->data, 0,
 					sizeof(struct bplustree_header), fs_le);
 	if (!bh)
-		return -1;
+		return errno ? -errno : -ENOENT;
 
 	if ((int32_t) FS32_TO_CPU(bh->magic, fs_le) != BPLUSTREE_MAGIC)
-		return -1;
+		return -ENOENT;
 
 	node_pointer = FS64_TO_CPU(bh->root_node_pointer, fs_le);
 
 	do {
+		errno = 0;
 		bn = (struct bplustree_node *) get_tree_node(pr, bs, &bi->data,
 			node_pointer, FS32_TO_CPU(bh->node_size, fs_le), fs_le);
 		if (!bn)
-			return -1;
+			return errno ? -errno : -ENOENT;
 
 		keylengths = (uint16_t *) ((uint8_t *) bn
 				+ ((sizeof(struct bplustree_node)
@@ -336,10 +338,10 @@
 
 	bi = (struct befs_inode *) get_block_run(pr, bs, &bs->root_dir, fs_le);
 	if (!bi)
-		return -1;
+		return errno ? -errno : BLKID_PROBE_NONE;
 
 	if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1)
-		return -1;
+		return BLKID_PROBE_NONE;
 
 	sd = (struct small_data *) bi->small_data;
 
@@ -376,24 +378,24 @@
 		bi = (struct befs_inode *) get_block_run(pr, bs,
 							&bi->attributes, fs_le);
 		if (!bi)
-			return -1;
+			return errno ? -errno : BLKID_PROBE_NONE;
 
 		if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1)
-			return -1;
+			return BLKID_PROBE_NONE;
 
 		value = get_key_value(pr, bs, bi, KEY_NAME, fs_le);
-
 		if (value < 0)
-			return value;
+			return value == -ENOENT ? BLKID_PROBE_NONE : value;
+
 		else if (value > 0) {
 			bi = (struct befs_inode *) blkid_probe_get_buffer(pr,
 				value << FS32_TO_CPU(bs->block_shift, fs_le),
 				FS32_TO_CPU(bs->block_size, fs_le));
 			if (!bi)
-				return -1;
+				return errno ? -errno : BLKID_PROBE_NONE;
 
 			if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1)
-				return -1;
+				return 1;
 
 			if (FS32_TO_CPU(bi->type, fs_le) == B_UINT64_TYPE
 				&& FS64_TO_CPU(bi->data.size, fs_le) == KEY_SIZE
@@ -404,7 +406,7 @@
 				attr_data = (uint64_t *) get_block_run(pr, bs,
 						&bi->data.direct[0], fs_le);
 				if (!attr_data)
-					return -1;
+					return errno ? -errno : BLKID_PROBE_NONE;
 
 				*uuid = *attr_data;
 			}
@@ -424,7 +426,7 @@
 					mag->sboff - B_OS_NAME_LENGTH,
 					sizeof(struct befs_super_block));
 	if (!bs)
-		return -1;
+		return errno ? -errno : BLKID_PROBE_NONE;
 
 	if (le32_to_cpu(bs->magic1) == SUPER_BLOCK_MAGIC1
 		&& le32_to_cpu(bs->magic2) == SUPER_BLOCK_MAGIC2
@@ -439,11 +441,11 @@
 		fs_le = 0;
 		version = "big-endian";
 	} else
-		return -1;
+		return BLKID_PROBE_NONE;
 
 	ret = get_uuid(pr, bs, &volume_id, fs_le);
 
-	if (ret < 0)
+	if (ret != 0)
 		return ret;
 
 	/*
@@ -459,7 +461,7 @@
 		blkid_probe_sprintf_uuid(pr, (unsigned char *) &volume_id,
 					sizeof(volume_id), "%016" PRIx64,
 					FS64_TO_CPU(volume_id, fs_le));
-	return 0;
+	return BLKID_PROBE_OK;
 }
 
 const struct blkid_idinfo befs_idinfo =
diff --git a/libblkid/bfs.c b/libblkid/src/superblocks/bfs.c
similarity index 100%
rename from libblkid/bfs.c
rename to libblkid/src/superblocks/bfs.c
diff --git a/libblkid/btrfs.c b/libblkid/src/superblocks/btrfs.c
similarity index 86%
rename from libblkid/btrfs.c
rename to libblkid/src/superblocks/btrfs.c
index 5813035..7ce3dff 100644
--- a/libblkid/btrfs.c
+++ b/libblkid/src/superblocks/btrfs.c
@@ -63,14 +63,9 @@
 {
 	struct btrfs_super_block *bfs;
 
-	if (mag->kboff > 64 && blkid_probe_ignore_backup(pr)) {
-		DBG(DEBUG_LOWPROBE, printf("btrfs: found backup superblock, ignore\n"));
-		return 1;
-	}
-
 	bfs = blkid_probe_get_sb(pr, mag, struct btrfs_super_block);
 	if (!bfs)
-		return -1;
+		return errno ? -errno : 1;
 
 	if (*bfs->label)
 		blkid_probe_set_label(pr,
@@ -92,8 +87,6 @@
 	.magics		=
 	{
 	  { .magic = "_BHRfS_M", .len = 8, .sboff = 0x40, .kboff = 64 },
-	  { .magic = "_BHRfS_M", .len = 8, .sboff = 0x40, .kboff = 64 * 1024 },
-	  { .magic = "_BHRfS_M", .len = 8, .sboff = 0x40, .kboff = 256 * 1024 * 1024 },
 	  { NULL }
 	}
 };
diff --git a/libblkid/cramfs.c b/libblkid/src/superblocks/cramfs.c
similarity index 97%
rename from libblkid/cramfs.c
rename to libblkid/src/superblocks/cramfs.c
index b58ed08..6d01b0b 100644
--- a/libblkid/cramfs.c
+++ b/libblkid/src/superblocks/cramfs.c
@@ -40,7 +40,7 @@
 
 	cs = blkid_probe_get_sb(pr, mag, struct cramfs_super);
 	if (!cs)
-		return -1;
+		return errno ? -errno : 1;
 
 	blkid_probe_set_label(pr, cs->name, sizeof(cs->name));
 	return 0;
diff --git a/libblkid/ddf_raid.c b/libblkid/src/superblocks/ddf_raid.c
similarity index 94%
rename from libblkid/ddf_raid.c
rename to libblkid/src/superblocks/ddf_raid.c
index 24df421..fc2c39d 100644
--- a/libblkid/ddf_raid.c
+++ b/libblkid/src/superblocks/ddf_raid.c
@@ -81,7 +81,7 @@
 	uint64_t off, lba;
 
 	if (pr->size < 0x30000)
-		return -1;
+		return 1;
 
 	for (i = 0; i < ARRAY_SIZE(hdrs); i++) {
 		off = ((pr->size / 0x200) - hdrs[i]) * 0x200;
@@ -90,8 +90,7 @@
 					off,
 					sizeof(struct ddf_header));
 		if (!ddf)
-			return -1;
-
+			return errno ? -errno : 1;
 		if (ddf->signature == cpu_to_be32(DDF_MAGIC) ||
 		    ddf->signature == cpu_to_le32(DDF_MAGIC))
 			break;
@@ -99,7 +98,7 @@
 	}
 
 	if (!ddf)
-		return -1;
+		return 1;
 
 	lba = ddf->signature == cpu_to_be32(DDF_MAGIC) ?
 			be64_to_cpu(ddf->primary_lba) :
@@ -111,8 +110,11 @@
 
 		buf = blkid_probe_get_buffer(pr,
 					lba << 9, sizeof(ddf->signature));
-		if (!buf || memcmp(buf, &ddf->signature, 4))
-			return -1;
+		if (!buf)
+			return errno ? -errno : 1;
+
+		if (memcmp(buf, &ddf->signature, 4) != 0)
+			return 1;
 	}
 
 	blkid_probe_strncpy_uuid(pr, ddf->guid, sizeof(ddf->guid));
@@ -121,11 +123,11 @@
 	*(version + sizeof(ddf->ddf_rev)) = '\0';
 
 	if (blkid_probe_set_version(pr, version) != 0)
-		return -1;
+		return 1;
 	if (blkid_probe_set_magic(pr, off,
 			sizeof(ddf->signature),
 			(unsigned char *) &ddf->signature))
-		return -1;
+		return 1;
 	return 0;
 }
 
diff --git a/libblkid/drbd.c b/libblkid/src/superblocks/drbd.c
similarity index 97%
rename from libblkid/drbd.c
rename to libblkid/src/superblocks/drbd.c
index 43e544e..e88e9f3 100644
--- a/libblkid/drbd.c
+++ b/libblkid/src/superblocks/drbd.c
@@ -75,18 +75,18 @@
 
 	/* Small devices cannot be drbd (?) */
 	if (pr->size < 0x10000)
-		return -1;
+		return 1;
 
 	md = (struct md_on_disk_08 *)
 			blkid_probe_get_buffer(pr,
 					off,
 					sizeof(struct md_on_disk_08));
 	if (!md)
-		return -1;
+		return errno ? -errno : 1;
 
 	if (be32_to_cpu(md->magic) != DRBD_MD_MAGIC_08 &&
 			be32_to_cpu(md->magic) != DRBD_MD_MAGIC_84_UNCLEAN)
-		return -1;
+		return 1;
 
 	/*
 	 * DRBD does not have "real" uuids; the following resembles DRBD's
@@ -102,7 +102,7 @@
 				off + offsetof(struct md_on_disk_08, magic),
 				sizeof(md->magic),
 				(unsigned char *) &md->magic))
-		return -1;
+		return 1;
 
 	return 0;
 }
diff --git a/libblkid/drbdproxy_datalog.c b/libblkid/src/superblocks/drbdproxy_datalog.c
similarity index 97%
rename from libblkid/drbdproxy_datalog.c
rename to libblkid/src/superblocks/drbdproxy_datalog.c
index afe4725..af59722 100644
--- a/libblkid/drbdproxy_datalog.c
+++ b/libblkid/src/superblocks/drbdproxy_datalog.c
@@ -33,7 +33,7 @@
 
 	lh = (struct log_header_t *) blkid_probe_get_buffer(pr, 0, sizeof(*lh));
 	if (!lh)
-		return -1;
+		return errno ? -errno : 1;
 
 	blkid_probe_set_uuid(pr, lh->uuid);
 	blkid_probe_sprintf_version(pr, "v%jd", le64_to_cpu(lh->version));
diff --git a/libblkid/exfat.c b/libblkid/src/superblocks/exfat.c
similarity index 96%
rename from libblkid/exfat.c
rename to libblkid/src/superblocks/exfat.c
index 215c671..b526560 100644
--- a/libblkid/exfat.c
+++ b/libblkid/src/superblocks/exfat.c
@@ -115,12 +115,14 @@
 
 	sb = blkid_probe_get_sb(pr, mag, struct exfat_super_block);
 	if (!sb)
-		return -1;
+		return errno ? -errno : BLKID_PROBE_NONE;
 
 	label = find_label(pr, sb);
 	if (label)
 		blkid_probe_set_utf8label(pr, label->name,
 				min(label->length * 2, 30), BLKID_ENC_UTF16LE);
+	else if (errno)
+		return -errno;
 
 	blkid_probe_sprintf_uuid(pr, sb->volume_serial, 4,
 			"%02hhX%02hhX-%02hhX%02hhX",
@@ -130,7 +132,7 @@
 	blkid_probe_sprintf_version(pr, "%u.%u",
 			sb->version.major, sb->version.minor);
 
-	return 0;
+	return BLKID_PROBE_OK;
 }
 
 const struct blkid_idinfo exfat_idinfo =
diff --git a/libblkid/ext.c b/libblkid/src/superblocks/ext.c
similarity index 66%
rename from libblkid/ext.c
rename to libblkid/src/superblocks/ext.c
index eff96a0..5b1d179 100644
--- a/libblkid/ext.c
+++ b/libblkid/src/superblocks/ext.c
@@ -18,7 +18,6 @@
 #endif
 #include <time.h>
 
-#include "linux_version.h"
 #include "superblocks.h"
 
 struct ext2_super_block {
@@ -132,140 +131,11 @@
 #define EXT3_FEATURE_RO_COMPAT_UNSUPPORTED	~EXT3_FEATURE_RO_COMPAT_SUPP
 
 /*
- * Check to see if a filesystem is in /proc/filesystems.
- * Returns 1 if found, 0 if not
- */
-static int fs_proc_check(const char *fs_name)
-{
-	FILE	*f;
-	char	buf[80], *cp, *t;
-
-	f = fopen("/proc/filesystems", "r");
-	if (!f)
-		return 0;
-	while (!feof(f)) {
-		if (!fgets(buf, sizeof(buf), f))
-			break;
-		cp = buf;
-		if (!isspace(*cp)) {
-			while (*cp && !isspace(*cp))
-				cp++;
-		}
-		while (*cp && isspace(*cp))
-			cp++;
-		if ((t = strchr(cp, '\n')) != NULL)
-			*t = 0;
-		if ((t = strchr(cp, '\t')) != NULL)
-			*t = 0;
-		if ((t = strchr(cp, ' ')) != NULL)
-			*t = 0;
-		if (!strcmp(fs_name, cp)) {
-			fclose(f);
-			return 1;
-		}
-	}
-	fclose(f);
-	return (0);
-}
-
-/*
- * Check to see if a filesystem is available as a module
- * Returns 1 if found, 0 if not
- */
-static int check_for_modules(const char *fs_name)
-{
-#ifdef __linux__
-	struct utsname	uts;
-	FILE		*f;
-	char		buf[1024], *cp;
-	int		namesz;
-
-	if (uname(&uts))
-		return 0;
-	snprintf(buf, sizeof(buf), "/lib/modules/%s/modules.dep", uts.release);
-
-	f = fopen(buf, "r");
-	if (!f)
-		return 0;
-
-	namesz = strlen(fs_name);
-
-	while (!feof(f)) {
-		if (!fgets(buf, sizeof(buf), f))
-			break;
-		if ((cp = strchr(buf, ':')) != NULL)
-			*cp = 0;
-		else
-			continue;
-		if ((cp = strrchr(buf, '/')) == NULL)
-			continue;
-		cp++;
-
-		if (!strncmp(cp, fs_name, namesz) &&
-		    (!strcmp(cp + namesz, ".ko") ||
-		     !strcmp(cp + namesz, ".ko.gz"))) {
-			fclose(f);
-			return 1;
-		}
-	}
-	fclose(f);
-#endif /* __linux__ */
-	return 0;
-}
-
-/*
  * Starting in 2.6.29, ext4 can be used to support filesystems
  * without a journal.
  */
 #define EXT4_SUPPORTS_EXT2 KERNEL_VERSION(2, 6, 29)
 
-static int system_supports_ext2(void)
-{
-	static time_t	last_check = 0;
-	static int	ret = -1;
-	time_t		now = time(0);
-
-	if (ret != -1 || (now - last_check) < 5)
-		return ret;
-	last_check = now;
-	ret = (fs_proc_check("ext2") || check_for_modules("ext2"));
-	return ret;
-}
-
-static int system_supports_ext4(void)
-{
-	static time_t	last_check = 0;
-	static int	ret = -1;
-	time_t		now = time(0);
-
-	if (ret != -1 || (now - last_check) < 5)
-		return ret;
-	last_check = now;
-	ret = (fs_proc_check("ext4") || check_for_modules("ext4"));
-	return ret;
-}
-
-static int system_supports_ext4dev(void)
-{
-	static time_t	last_check = 0;
-	static int	ret = -1;
-	time_t		now = time(0);
-
-	if (ret != -1 || (now - last_check) < 5)
-		return ret;
-	last_check = now;
-	ret = (fs_proc_check("ext4dev") || check_for_modules("ext4dev"));
-	return ret;
-}
-
-static int system_supports_ext4_ext2(void)
-{
-#ifdef __linux__
-	return get_linux_version() >= EXT4_SUPPORTS_EXT2;
-#else
-	return 0;
-#endif
-}
 /*
  * reads superblock and returns:
  *	fc = feature_compat
@@ -295,7 +165,7 @@
 {
 	struct blkid_chain *chn = blkid_probe_get_chain(pr);
 
-	DBG(DEBUG_PROBE, printf("ext2_sb.compat = %08X:%08X:%08X\n",
+	DBG(PROBE, ul_debug("ext2_sb.compat = %08X:%08X:%08X",
 		   le32_to_cpu(es->s_feature_compat),
 		   le32_to_cpu(es->s_feature_incompat),
 		   le32_to_cpu(es->s_feature_ro_compat)));
@@ -328,11 +198,13 @@
 
 	es = ext_get_super(pr, NULL, &fi, NULL);
 	if (!es)
-		return -BLKID_ERR_PARAM;
+		return errno ? -errno : 1;
 	if (!(fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV))
-		return -BLKID_ERR_PARAM;
+		return 1;
 
 	ext_get_info(pr, 2, es);
+	blkid_probe_set_uuid_as(pr, es->s_uuid, "LOGUUID");
+
 	return 0;
 }
 
@@ -344,25 +216,16 @@
 
 	es = ext_get_super(pr, &fc, &fi, &frc);
 	if (!es)
-		return -BLKID_ERR_PARAM;
+		return errno ? -errno : 1;
 
 	/* Distinguish between ext3 and ext2 */
 	if (fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL)
-		return -BLKID_ERR_PARAM;
+		return 1;
 
 	/* Any features which ext2 doesn't understand */
 	if ((frc & EXT2_FEATURE_RO_COMPAT_UNSUPPORTED) ||
 	    (fi  & EXT2_FEATURE_INCOMPAT_UNSUPPORTED))
-		return -BLKID_ERR_PARAM;
-
-	/*
-	 * If ext2 is not present, but ext4 or ext4dev are, then
-	 * disclaim we are ext2
-	 */
-	if (!system_supports_ext2() &&
-	    (system_supports_ext4() || system_supports_ext4dev()) &&
-	    system_supports_ext4_ext2())
-		return -BLKID_ERR_PARAM;
+		return 1;
 
 	ext_get_info(pr, 2, es);
 	return 0;
@@ -376,16 +239,16 @@
 
 	es = ext_get_super(pr, &fc, &fi, &frc);
 	if (!es)
-		return -BLKID_ERR_PARAM;
+		return errno ? -errno : 1;
 
 	/* ext3 requires journal */
 	if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL))
-		return -BLKID_ERR_PARAM;
+		return 1;
 
 	/* Any features which ext3 doesn't understand */
 	if ((frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) ||
 	    (fi  & EXT3_FEATURE_INCOMPAT_UNSUPPORTED))
-		return -BLKID_ERR_PARAM;
+		return 1;
 
 	ext_get_info(pr, 3, es);
 	return 0;
@@ -400,40 +263,15 @@
 
 	es = ext_get_super(pr, &fc, &fi, &frc);
 	if (!es)
-		return -BLKID_ERR_PARAM;
+		return errno ? -errno : 1;
 
 	/* Distinguish from jbd */
 	if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
-		return -BLKID_ERR_PARAM;
+		return 1;
 
-	/*
-	 * If the filesystem does not have a journal and ext2 and ext4
-	 * is not present, then force this to be detected as an
-	 * ext4dev filesystem.
-	 */
-	if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
-	    !system_supports_ext2() && !system_supports_ext4() &&
-	    system_supports_ext4dev() &&
-	    system_supports_ext4_ext2())
-		goto force_ext4dev;
+	if (!(le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS))
+		return 1;
 
-	/*
-	 * If the filesystem is marked as OK for use by in-development
-	 * filesystem code, but ext4dev is not supported, and ext4 is,
-	 * then don't call ourselves ext4dev, since we should be
-	 * detected as ext4 in that case.
-	 *
-	 * If the filesystem is marked as in use by production
-	 * filesystem, then it can only be used by ext4 and NOT by
-	 * ext4dev, so always disclaim we are ext4dev in that case.
-	 */
-	if (le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) {
-		if (!system_supports_ext4dev() && system_supports_ext4())
-			return -BLKID_ERR_PARAM;
-	} else
-		return -BLKID_ERR_PARAM;
-
-force_ext4dev:
 	ext_get_info(pr, 4, es);
 	return 0;
 }
@@ -446,28 +284,17 @@
 
 	es = ext_get_super(pr, &fc, &fi, &frc);
 	if (!es)
-		return -1;
+		return errno ? -errno : 1;
 
 	/* Distinguish from jbd */
 	if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
-		return -BLKID_ERR_PARAM;
-
-	/*
-	 * If the filesystem does not have a journal and ext2 is not
-	 * present, then force this to be detected as an ext2
-	 * filesystem.
-	 */
-	if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
-	    !system_supports_ext2() && system_supports_ext4() &&
-	    system_supports_ext4_ext2())
-		goto force_ext4;
+		return 1;
 
 	/* Ext4 has at least one feature which ext3 doesn't understand */
 	if (!(frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) &&
 	    !(fi  & EXT3_FEATURE_INCOMPAT_UNSUPPORTED))
-		return -BLKID_ERR_PARAM;
+		return 1;
 
-force_ext4:
 	/*
 	 * If the filesystem is a OK for use by in-development
 	 * filesystem code, and ext4dev is supported or ext4 is not
@@ -478,10 +305,8 @@
 	 * filesystem, then it can only be used by ext4 and NOT by
 	 * ext4dev.
 	 */
-	if (le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) {
-		if (system_supports_ext4dev() || !system_supports_ext4())
-			return -BLKID_ERR_PARAM;
-	}
+	if (le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS)
+		return 1;
 
 	ext_get_info(pr, 4, es);
 	return 0;
diff --git a/libblkid/f2fs.c b/libblkid/src/superblocks/f2fs.c
similarity index 98%
rename from libblkid/f2fs.c
rename to libblkid/src/superblocks/f2fs.c
index 1543a7a..2bf0f5e 100644
--- a/libblkid/f2fs.c
+++ b/libblkid/src/superblocks/f2fs.c
@@ -62,7 +62,7 @@
 
 	sb = blkid_probe_get_sb(pr, mag, struct f2fs_super_block);
 	if (!sb)
-		return -1;
+		return errno ? -errno : 1;
 
 	major = le16_to_cpu(sb->major_ver);
 	minor = le16_to_cpu(sb->minor_ver);
diff --git a/libblkid/gfs.c b/libblkid/src/superblocks/gfs.c
similarity index 97%
rename from libblkid/gfs.c
rename to libblkid/src/superblocks/gfs.c
index b2c0163..1b26558 100644
--- a/libblkid/gfs.c
+++ b/libblkid/src/superblocks/gfs.c
@@ -64,7 +64,7 @@
 
 	sbd = blkid_probe_get_sb(pr, mag, struct gfs2_sb);
 	if (!sbd)
-		return -1;
+		return errno ? -errno : 1;
 
 	if (be32_to_cpu(sbd->sb_fs_format) == GFS_FORMAT_FS &&
 	    be32_to_cpu(sbd->sb_multihost_format) == GFS_FORMAT_MULTI)
@@ -78,7 +78,7 @@
 		return 0;
 	}
 
-	return -1;
+	return 1;
 }
 
 static int probe_gfs2(blkid_probe pr, const struct blkid_idmag *mag)
@@ -87,7 +87,7 @@
 
 	sbd = blkid_probe_get_sb(pr, mag, struct gfs2_sb);
 	if (!sbd)
-		return -1;
+		return errno ? -errno : 1;
 
 	if (be32_to_cpu(sbd->sb_fs_format) == GFS2_FORMAT_FS &&
 	    be32_to_cpu(sbd->sb_multihost_format) == GFS2_FORMAT_MULTI)
@@ -100,7 +100,7 @@
 		blkid_probe_set_version(pr, "1");
 		return 0;
 	}
-	return -1;
+	return 1;
 }
 
 const struct blkid_idinfo gfs_idinfo =
diff --git a/libblkid/hfs.c b/libblkid/src/superblocks/hfs.c
similarity index 97%
rename from libblkid/hfs.c
rename to libblkid/src/superblocks/hfs.c
index 6d960e9..fe57241 100644
--- a/libblkid/hfs.c
+++ b/libblkid/src/superblocks/hfs.c
@@ -154,7 +154,7 @@
 
 	hfs = blkid_probe_get_sb(pr, mag, struct hfs_mdb);
 	if (!hfs)
-		return -1;
+		return errno ? -errno : 1;
 
 	if ((memcmp(hfs->embed_sig, "H+", 2) == 0) ||
 	    (memcmp(hfs->embed_sig, "HX", 2) == 0))
@@ -193,7 +193,7 @@
 
 	sbd = blkid_probe_get_sb(pr, mag, struct hfs_mdb);
 	if (!sbd)
-		return -1;
+		return errno ? -errno : 1;
 
 	/* Check for a HFS+ volume embedded in a HFS volume */
 	if (memcmp(sbd->signature, "BD", 2) == 0) {
@@ -218,7 +218,7 @@
 				struct hfsplus_vol_header);
 
 	if (!hfsplus)
-		return -1;
+		return errno ? -errno : 1;
 
 	if ((memcmp(hfsplus->signature, "H+", 2) != 0) &&
 	    (memcmp(hfsplus->signature, "HX", 2) != 0))
@@ -228,7 +228,7 @@
 
 	blocksize = be32_to_cpu(hfsplus->blocksize);
 	if (blocksize < HFSPLUS_SECTOR_SIZE)
-		return -1;
+		return 1;
 
 	memcpy(extents, hfsplus->cat_file.extents, sizeof(extents));
 	cat_block = be32_to_cpu(extents[0].start_block);
@@ -236,7 +236,7 @@
 	buf = blkid_probe_get_buffer(pr,
 			off + ((blkid_loff_t) cat_block * blocksize), 0x2000);
 	if (!buf)
-		return 0;
+		return errno ? -errno : 0;
 
 	bnode = (struct hfsplus_bheader_record *)
 		&buf[sizeof(struct hfsplus_bnode_descriptor)];
@@ -271,7 +271,7 @@
 				(blkid_loff_t) off + leaf_off,
 				leaf_node_size);
 	if (!buf)
-		return 0;
+		return errno ? -errno : 0;
 
 	descr = (struct hfsplus_bnode_descriptor *) buf;
 	record_count = be16_to_cpu(descr->num_recs);
diff --git a/libblkid/highpoint_raid.c b/libblkid/src/superblocks/highpoint_raid.c
similarity index 95%
rename from libblkid/highpoint_raid.c
rename to libblkid/src/superblocks/highpoint_raid.c
index 0b41344..ad3b538 100644
--- a/libblkid/highpoint_raid.c
+++ b/libblkid/src/superblocks/highpoint_raid.c
@@ -30,9 +30,9 @@
 	uint32_t magic;
 
 	if (pr->size < 0x10000)
-		return -1;
+		return 1;
 	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
-		return -1;
+		return 1;
 
 	off = ((pr->size / 0x200) - 11) * 0x200;
 	hpt = (struct hpt45x_metadata *)
@@ -40,13 +40,13 @@
 					off,
 					sizeof(struct hpt45x_metadata));
 	if (!hpt)
-		return -1;
+		return errno ? -errno : 1;
 	magic = le32_to_cpu(hpt->magic);
 	if (magic != HPT45X_MAGIC_OK && magic != HPT45X_MAGIC_BAD)
-		return -1;
+		return 1;
 	if (blkid_probe_set_magic(pr, off, sizeof(hpt->magic),
 				(unsigned char *) &hpt->magic))
-		return -1;
+		return 1;
 	return 0;
 }
 
@@ -54,7 +54,7 @@
 		const struct blkid_idmag *mag __attribute__((__unused__)))
 {
 	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
-		return -1;
+		return 1;
 	return 0;
 }
 
diff --git a/libblkid/hpfs.c b/libblkid/src/superblocks/hpfs.c
similarity index 95%
rename from libblkid/hpfs.c
rename to libblkid/src/superblocks/hpfs.c
index f9b851a..0565d37 100644
--- a/libblkid/hpfs.c
+++ b/libblkid/src/superblocks/hpfs.c
@@ -68,7 +68,7 @@
 	/* super block */
 	hs = blkid_probe_get_sb(pr, mag, struct hpfs_super_block);
 	if (!hs)
-		return -1;
+		return errno ? -errno : 1;
 	version = hs->version;
 
 	/* spare super block */
@@ -77,9 +77,9 @@
 				HPFS_SBSPARE_OFFSET,
 				sizeof(struct hpfs_spare_super));
 	if (!hss)
-		return -1;
+		return errno ? -errno : 1;
 	if (memcmp(hss->magic, "\x49\x18\x91\xf9", 4) != 0)
-		return -1;
+		return 1;
 
 	/* boot block (with UUID and LABEL) */
 	hbb = (struct hpfs_boot_block *)
@@ -87,7 +87,7 @@
 				0,
 				sizeof(struct hpfs_boot_block));
 	if (!hbb)
-		return -1;
+		return errno ? -errno : 1;
 	if (memcmp(hbb->magic, "\x55\xaa", 2) == 0 &&
 	    memcmp(hbb->sig_hpfs, "HPFS", 4) == 0 &&
 	    hbb->sig_28h == 0x28) {
diff --git a/libblkid/iso9660.c b/libblkid/src/superblocks/iso9660.c
similarity index 98%
rename from libblkid/iso9660.c
rename to libblkid/src/superblocks/iso9660.c
index 148587b..d099467 100644
--- a/libblkid/iso9660.c
+++ b/libblkid/src/superblocks/iso9660.c
@@ -100,7 +100,7 @@
 
 	iso = blkid_probe_get_sb(pr, mag, struct high_sierra_volume_descriptor);
 	if (!iso)
-		return -1;
+		return errno ? -errno : 1;
 
 	blkid_probe_set_version(pr, "High Sierra");
 	blkid_probe_set_label(pr, iso->volume_id, sizeof(iso->volume_id));
@@ -178,7 +178,7 @@
 
 	iso = blkid_probe_get_sb(pr, mag, struct iso_volume_descriptor);
 	if (!iso)
-		return -1;
+		return errno ? -errno : 1;
 
 	memcpy(label, iso->volume_id, sizeof(label));
 
diff --git a/libblkid/iso9660.h b/libblkid/src/superblocks/iso9660.h
similarity index 100%
rename from libblkid/iso9660.h
rename to libblkid/src/superblocks/iso9660.h
diff --git a/libblkid/isw_raid.c b/libblkid/src/superblocks/isw_raid.c
similarity index 93%
rename from libblkid/isw_raid.c
rename to libblkid/src/superblocks/isw_raid.c
index 755c1b6..065c2b2 100644
--- a/libblkid/isw_raid.c
+++ b/libblkid/src/superblocks/isw_raid.c
@@ -33,9 +33,9 @@
 	struct isw_metadata *isw;
 
 	if (pr->size < 0x10000)
-		return -1;
+		return 1;
 	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
-		return -1;
+		return 1;
 
 	off = ((pr->size / 0x200) - 2) * 0x200;
 	isw = (struct isw_metadata *)
@@ -43,15 +43,16 @@
 					off,
 					sizeof(struct isw_metadata));
 	if (!isw)
-		return -1;
+		return errno ? -errno : 1;
+
 	if (memcmp(isw->sig, ISW_SIGNATURE, sizeof(ISW_SIGNATURE)-1) != 0)
-		return -1;
+		return 1;
 	if (blkid_probe_sprintf_version(pr, "%6s",
 			&isw->sig[sizeof(ISW_SIGNATURE)-1]) != 0)
-		return -1;
+		return 1;
 	if (blkid_probe_set_magic(pr, off, sizeof(isw->sig),
 				(unsigned char *) isw->sig))
-		return -1;
+		return 1;
 	return 0;
 }
 
diff --git a/libblkid/jfs.c b/libblkid/src/superblocks/jfs.c
similarity index 98%
rename from libblkid/jfs.c
rename to libblkid/src/superblocks/jfs.c
index 78c018c..ac684d8 100644
--- a/libblkid/jfs.c
+++ b/libblkid/src/superblocks/jfs.c
@@ -40,7 +40,7 @@
 
 	js = blkid_probe_get_sb(pr, mag, struct jfs_super_block);
 	if (!js)
-		return -1;
+		return errno ? -errno : 1;
 	if (le32_to_cpu(js->js_bsize) != (1U << le16_to_cpu(js->js_l2bsize)))
 		return 1;
 	if (le32_to_cpu(js->js_pbsize) != (1U << le16_to_cpu(js->js_l2pbsize)))
diff --git a/libblkid/jmicron_raid.c b/libblkid/src/superblocks/jmicron_raid.c
similarity index 93%
rename from libblkid/jmicron_raid.c
rename to libblkid/src/superblocks/jmicron_raid.c
index c708078..ca79867 100644
--- a/libblkid/jmicron_raid.c
+++ b/libblkid/src/superblocks/jmicron_raid.c
@@ -32,9 +32,9 @@
 	struct jm_metadata *jm;
 
 	if (pr->size < 0x10000)
-		return -1;
+		return 1;
 	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
-		return -1;
+		return 1;
 
 	off = ((pr->size / 0x200) - 1) * 0x200;
 	jm = (struct jm_metadata *)
@@ -42,15 +42,16 @@
 				off,
 				sizeof(struct jm_metadata));
 	if (!jm)
-		return -1;
+		return errno ? -errno : 1;
+
 	if (memcmp(jm->signature, JM_SIGNATURE, sizeof(JM_SIGNATURE) - 1) != 0)
-		return -1;
+		return 1;
 	if (blkid_probe_sprintf_version(pr, "%u.%u",
 				jm->major_version, jm->minor_version) != 0)
-		return -1;
+		return 1;
 	if (blkid_probe_set_magic(pr, off, sizeof(jm->signature),
 				(unsigned char *) jm->signature))
-		return -1;
+		return 1;
 	return 0;
 }
 
diff --git a/libblkid/linux_raid.c b/libblkid/src/superblocks/linux_raid.c
similarity index 92%
rename from libblkid/linux_raid.c
rename to libblkid/src/superblocks/linux_raid.c
index a3f9d67..cf29141 100644
--- a/libblkid/linux_raid.c
+++ b/libblkid/src/superblocks/linux_raid.c
@@ -110,13 +110,13 @@
 	uint64_t size;
 
 	if (pr->size < MD_RESERVED_BYTES)
-		return -1;
+		return 1;
 	mdp0 = (struct mdp0_super_block *)
 			blkid_probe_get_buffer(pr,
 				off,
 				sizeof(struct mdp0_super_block));
 	if (!mdp0)
-		return -1;
+		return errno ? -errno : 1;
 
 	memset(uuid.ints, 0, sizeof(uuid.ints));
 
@@ -173,12 +173,12 @@
 	}
 
 	if (blkid_probe_sprintf_version(pr, "%u.%u.%u", ma, mi, pa) != 0)
-		return -1;
+		return 1;
 	if (blkid_probe_set_uuid(pr, (unsigned char *) uuid.bytes) != 0)
-		return -1;
+		return 1;
 	if (blkid_probe_set_magic(pr, off, sizeof(mdp0->md_magic),
 				(unsigned char *) &mdp0->md_magic))
-		return -1;
+		return 1;
 	return 0;
 }
 
@@ -191,24 +191,24 @@
 				off,
 				sizeof(struct mdp1_super_block));
 	if (!mdp1)
-		return -1;
+		return errno ? -errno : 1;
 	if (le32_to_cpu(mdp1->magic) != MD_SB_MAGIC)
-		return -1;
+		return 1;
 	if (le32_to_cpu(mdp1->major_version) != 1U)
-		return -1;
+		return 1;
 	if (le64_to_cpu(mdp1->super_offset) != (uint64_t) off >> 9)
-		return -1;
+		return 1;
 	if (blkid_probe_set_uuid(pr, (unsigned char *) mdp1->set_uuid) != 0)
-		return -1;
+		return 1;
 	if (blkid_probe_set_uuid_as(pr,
 			(unsigned char *) mdp1->device_uuid, "UUID_SUB") != 0)
-		return -1;
+		return 1;
 	if (blkid_probe_set_label(pr, mdp1->set_name,
 				sizeof(mdp1->set_name)) != 0)
-		return -1;
+		return 1;
 	if (blkid_probe_set_magic(pr, off, sizeof(mdp1->magic),
 				(unsigned char *) &mdp1->magic))
-		return -1;
+		return 1;
 	return 0;
 }
 
@@ -216,35 +216,44 @@
 		const struct blkid_idmag *mag __attribute__((__unused__)))
 {
 	const char *ver = NULL;
+	int ret = BLKID_PROBE_NONE;
 
 	if (pr->size > MD_RESERVED_BYTES) {
 		/* version 0 at the end of the device */
 		uint64_t sboff = (pr->size & ~(MD_RESERVED_BYTES - 1))
-			         - MD_RESERVED_BYTES;
-		if (probe_raid0(pr, sboff) == 0)
-			return 0;
+			- MD_RESERVED_BYTES;
+		ret = probe_raid0(pr, sboff);
+		if (ret < 1)
+			return ret;	/* error */
 
 		/* version 1.0 at the end of the device */
 		sboff = (pr->size & ~(0x1000 - 1)) - 0x2000;
-		if (probe_raid1(pr, sboff) == 0)
+		ret = probe_raid1(pr, sboff);
+		if (ret < 0)
+			return ret;	/* error */
+		if (ret == 0)
 			ver = "1.0";
 	}
 
 	if (!ver) {
 		/* version 1.1 at the start of the device */
-		if (probe_raid1(pr, 0) == 0)
+		ret = probe_raid1(pr, 0);
+		if (ret == 0)
 			ver = "1.1";
 
 		/* version 1.2 at 4k offset from the start */
-		else if (probe_raid1(pr, 0x1000) == 0)
-			ver = "1.2";
+		else if (ret == BLKID_PROBE_NONE) {
+			ret = probe_raid1(pr, 0x1000);
+			if (ret == 0)
+				ver = "1.2";
+		}
 	}
 
 	if (ver) {
 		blkid_probe_set_version(pr, ver);
-		return 0;
+		return BLKID_PROBE_OK;
 	}
-	return -1;
+	return ret;
 }
 
 
diff --git a/libblkid/lsi_raid.c b/libblkid/src/superblocks/lsi_raid.c
similarity index 93%
rename from libblkid/lsi_raid.c
rename to libblkid/src/superblocks/lsi_raid.c
index 56721dd..697b0fe 100644
--- a/libblkid/lsi_raid.c
+++ b/libblkid/src/superblocks/lsi_raid.c
@@ -30,9 +30,9 @@
 	struct lsi_metadata *lsi;
 
 	if (pr->size < 0x10000)
-		return -1;
+		return 1;
 	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
-		return -1;
+		return 1;
 
 	off = ((pr->size / 0x200) - 1) * 0x200;
 	lsi = (struct lsi_metadata *)
@@ -40,13 +40,13 @@
 				off,
 				sizeof(struct lsi_metadata));
 	if (!lsi)
-		return -1;
+		return errno ? -errno : 1;
 
 	if (memcmp(lsi->sig, LSI_SIGNATURE, sizeof(LSI_SIGNATURE)-1) != 0)
-		return -1;
+		return 1;
 	if (blkid_probe_set_magic(pr, off, sizeof(lsi->sig),
 				(unsigned char *) lsi->sig))
-		return -1;
+		return 1;
 	return 0;
 }
 
diff --git a/libblkid/luks.c b/libblkid/src/superblocks/luks.c
similarity index 97%
rename from libblkid/luks.c
rename to libblkid/src/superblocks/luks.c
index f716e31..00696f2 100644
--- a/libblkid/luks.c
+++ b/libblkid/src/superblocks/luks.c
@@ -45,7 +45,7 @@
 
 	header = blkid_probe_get_sb(pr, mag, struct luks_phdr);
 	if (header == NULL)
-		return -1;
+		return errno ? -errno : 1;
 
 	blkid_probe_strncpy_uuid(pr, (unsigned char *) header->uuid,
 			sizeof(header->uuid));
diff --git a/libblkid/lvm2.c b/libblkid/src/superblocks/lvm.c
similarity index 94%
rename from libblkid/lvm2.c
rename to libblkid/src/superblocks/lvm.c
index 0afc773..3c6df74 100644
--- a/libblkid/lvm2.c
+++ b/libblkid/src/superblocks/lvm.c
@@ -82,7 +82,7 @@
 			mag->kboff << 10,
 			512 + sizeof(struct lvm2_pv_label_header));
 	if (!buf)
-		return -1;
+		return errno ? -errno : 1;
 
 	/* buf is at 0k or 1k offset; find label inside */
 	if (memcmp(buf, "LABELONE", 8) == 0) {
@@ -97,14 +97,12 @@
 	if (le64_to_cpu(label->sector_xl) != (unsigned) sector)
 		return 1;
 
-	if (lvm2_calc_crc(&label->offset_xl, LVM2_LABEL_SIZE -
-			((char *) &label->offset_xl - (char *) label)) !=
-			le32_to_cpu(label->crc_xl)) {
-		DBG(DEBUG_PROBE,
-		    printf("LVM2: label checksum incorrect at sector %d\n",
-			   sector));
+	if (!blkid_probe_verify_csum(
+		pr, lvm2_calc_crc(
+			&label->offset_xl, LVM2_LABEL_SIZE -
+			((char *) &label->offset_xl - (char *) label)),
+			le32_to_cpu(label->crc_xl)))
 		return 1;
-	}
 
 	format_lvm_uuid(uuid, (char *) label->pv_uuid);
 	blkid_probe_sprintf_uuid(pr, label->pv_uuid, sizeof(label->pv_uuid),
@@ -130,7 +128,7 @@
 
 	label = blkid_probe_get_sb(pr, mag, struct lvm1_pv_label_header);
 	if (!label)
-		return -1;
+		return errno ? -errno : 1;
 
 	version = le16_to_cpu(label->version);
 	if (version != 1 && version != 2)
@@ -165,7 +163,7 @@
 
 	sb = blkid_probe_get_sb(pr, mag, struct verity_sb);
 	if (sb == NULL)
-		return -1;
+		return errno ? -errno : 1;
 
 	version = le32_to_cpu(sb->version);
 	if (version != 1)
diff --git a/libblkid/src/superblocks/minix.c b/libblkid/src/superblocks/minix.c
new file mode 100644
index 0000000..9ea49fe
--- /dev/null
+++ b/libblkid/src/superblocks/minix.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 1999 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2001 by Andreas Dilger
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2008-2013 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+#include <string.h>
+#include "superblocks.h"
+#include "minix.h"
+
+#define minix_swab16(doit, num)	((uint16_t) (doit ? swab16(num) : num))
+#define minix_swab32(doit, num)	((uint32_t) (doit ? swab32(num) : num))
+
+static int get_minix_version(const unsigned char *data, int *other_endian)
+{
+	struct minix_super_block *sb = (struct minix_super_block *) data;
+	struct minix3_super_block *sb3 = (struct minix3_super_block *) data;
+	int version = 0;
+
+	*other_endian = 0;
+
+	switch (sb->s_magic) {
+	case MINIX_SUPER_MAGIC:
+	case MINIX_SUPER_MAGIC2:
+		version = 1;
+		break;
+	case MINIX2_SUPER_MAGIC:
+	case MINIX2_SUPER_MAGIC2:
+		version = 2;
+		break;
+	default:
+		if (sb3->s_magic == MINIX3_SUPER_MAGIC)
+			version = 3;
+		break;
+	}
+
+	if (!version) {
+		*other_endian = 1;
+
+		switch (swab16(sb->s_magic)) {
+		case MINIX_SUPER_MAGIC:
+		case MINIX_SUPER_MAGIC2:
+			version = 1;
+			break;
+		case MINIX2_SUPER_MAGIC:
+		case MINIX2_SUPER_MAGIC2:
+			version = 2;
+			break;
+		default:
+			if (sb3->s_magic == MINIX3_SUPER_MAGIC)
+				version = 3;
+			break;
+		}
+	}
+	if (!version)
+		return -1;
+
+	DBG(LOWPROBE, ul_debug("minix version %d detected [%s]", version,
+#if defined(WORDS_BIGENDIAN)
+	*other_endian ? "LE" : "BE"
+#else
+	*other_endian ? "BE" : "LE"
+#endif
+	));
+	return version;
+}
+
+static int probe_minix(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	unsigned char *ext;
+	const unsigned char *data;
+	int version = 0, swabme = 0;
+
+	data = blkid_probe_get_buffer(pr, 1024,
+			max(sizeof(struct minix_super_block),
+			    sizeof(struct minix3_super_block)));
+	if (!data)
+		return errno ? -errno : 1;
+	version = get_minix_version(data, &swabme);
+	if (version < 1)
+		return 1;
+
+	if (version <= 2) {
+		struct minix_super_block *sb = (struct minix_super_block *) data;
+		int zones, ninodes, imaps, zmaps, firstz;
+
+		if (sb->s_imap_blocks == 0 || sb->s_zmap_blocks == 0)
+			return 1;
+
+		zones = version == 2 ? minix_swab32(swabme, sb->s_zones) :
+				       minix_swab16(swabme, sb->s_nzones);
+		ninodes = minix_swab16(swabme, sb->s_ninodes);
+		imaps   = minix_swab16(swabme, sb->s_imap_blocks);
+		zmaps   = minix_swab16(swabme, sb->s_zmap_blocks);
+		firstz  = minix_swab16(swabme, sb->s_firstdatazone);
+
+		/* sanity checks to be sure that the FS is really minix */
+		if (imaps * MINIX_BLOCK_SIZE * 8 < ninodes + 1)
+			return 1;
+		if (zmaps * MINIX_BLOCK_SIZE * 8 < zones - firstz + 1)
+			return 1;
+
+	} else if (version == 3) {
+		struct minix3_super_block *sb = (struct minix3_super_block *) data;
+
+		if (sb->s_imap_blocks == 0 || sb->s_zmap_blocks == 0)
+			return 1;
+	}
+
+	/* unfortunately, some parts of ext3 is sometimes possible to
+	 * interpreted as minix superblock. So check for extN magic
+	 * string. (For extN magic string and offsets see ext.c.)
+	 */
+	ext = blkid_probe_get_buffer(pr, 0x400 + 0x38, 2);
+	if (!ext)
+		return errno ? -errno : 1;
+	else if (memcmp(ext, "\123\357", 2) == 0)
+		return 1;
+
+	blkid_probe_sprintf_version(pr, "%d", version);
+	return 0;
+}
+
+const struct blkid_idinfo minix_idinfo =
+{
+	.name		= "minix",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_minix,
+	.magics		=
+	{
+		/* version 1 - LE */
+		{ .magic = "\177\023", .len = 2, .kboff = 1, .sboff = 0x10 },
+		{ .magic = "\217\023", .len = 2, .kboff = 1, .sboff = 0x10 },
+
+		/* version 1 - BE */
+		{ .magic = "\023\177", .len = 2, .kboff = 1, .sboff = 0x10 },
+		{ .magic = "\023\217", .len = 2, .kboff = 1, .sboff = 0x10 },
+
+		/* version 2 - LE */
+		{ .magic = "\150\044", .len = 2, .kboff = 1, .sboff = 0x10 },
+		{ .magic = "\170\044", .len = 2, .kboff = 1, .sboff = 0x10 },
+
+		/* version 2 - BE */
+		{ .magic = "\044\150", .len = 2, .kboff = 1, .sboff = 0x10 },
+		{ .magic = "\044\170", .len = 2, .kboff = 1, .sboff = 0x10 },
+
+		/* version 3 - LE */
+		{ .magic = "\132\115", .len = 2, .kboff = 1, .sboff = 0x18 },
+
+		/* version 3 - BE */
+		{ .magic = "\115\132", .len = 2, .kboff = 1, .sboff = 0x18 },
+
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/netware.c b/libblkid/src/superblocks/netware.c
similarity index 98%
rename from libblkid/netware.c
rename to libblkid/src/superblocks/netware.c
index 7ef2162..af81cf5 100644
--- a/libblkid/netware.c
+++ b/libblkid/src/superblocks/netware.c
@@ -71,7 +71,7 @@
 
 	nw = blkid_probe_get_sb(pr, mag, struct netware_super_block);
 	if (!nw)
-		return -1;
+		return errno ? -errno : 1;
 
 	blkid_probe_set_uuid(pr, nw->SBH_PoolID);
 
diff --git a/libblkid/nilfs.c b/libblkid/src/superblocks/nilfs.c
similarity index 60%
rename from libblkid/nilfs.c
rename to libblkid/src/superblocks/nilfs.c
index 1f8f3a6..3f03901 100644
--- a/libblkid/nilfs.c
+++ b/libblkid/src/superblocks/nilfs.c
@@ -63,34 +63,59 @@
 	uint32_t	s_reserved[192];
 };
 
-/* nilfs2 magic string */
-#define NILFS_SB_MAGIC		"\x34\x34"
-/* nilfs2 super block offset */
-#define NILFS_SB_OFF		0x400
-/* nilfs2 super block offset in kB */
-#define NILFS_SB_KBOFF		(NILFS_SB_OFF >> 10)
-/* nilfs2 magic string offset within super block */
-#define NILFS_MAG_OFF		6
+#define NILFS_SB_MAGIC		0x3434
+#define NILFS_SB_OFFSET		0x400
 
-static int probe_nilfs2(blkid_probe pr, const struct blkid_idmag *mag)
+static int nilfs_valid_sb(blkid_probe pr, struct nilfs_super_block *sb)
 {
-	struct nilfs_super_block *sb;
 	static unsigned char sum[4];
 	const int sumoff = offsetof(struct nilfs_super_block, s_sum);
 	size_t bytes;
 	uint32_t crc;
 
-	sb = blkid_probe_get_sb(pr, mag, struct nilfs_super_block);
-	if (!sb)
-		return -1;
+	if (!sb || le16_to_cpu(sb->s_magic) != NILFS_SB_MAGIC)
+		return 0;
 
 	bytes = le16_to_cpu(sb->s_bytes);
 	crc = crc32(le32_to_cpu(sb->s_crc_seed), (unsigned char *)sb, sumoff);
 	crc = crc32(crc, sum, 4);
 	crc = crc32(crc, (unsigned char *)sb + sumoff + 4, bytes - sumoff - 4);
 
-	if (crc != le32_to_cpu(sb->s_sum))
-		return -1;
+	return blkid_probe_verify_csum(pr, crc, le32_to_cpu(sb->s_sum));
+}
+
+static int probe_nilfs2(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct nilfs_super_block *sb, *sbp, *sbb;
+	int valid[2], swp = 0;
+
+	/* primary */
+	sbp = (struct nilfs_super_block *) blkid_probe_get_buffer(
+			pr, NILFS_SB_OFFSET, sizeof(struct nilfs_super_block));
+	if (!sbp)
+		return errno ? -errno : 1;
+	/* backup */
+	sbb = (struct nilfs_super_block *) blkid_probe_get_buffer(
+			pr, ((pr->size / 0x200) - 8) * 0x200, sizeof(struct nilfs_super_block));
+	if (!sbb)
+		return errno ? -errno : 1;
+
+	/*
+	 * Compare two super blocks and set 1 in swp if the secondary
+	 * super block is valid and newer.  Otherwise, set 0 in swp.
+	 */
+	valid[0] = nilfs_valid_sb(pr, sbp);
+	valid[1] = nilfs_valid_sb(pr, sbb);
+	if (!valid[0] && !valid[1])
+		return 1;
+
+	swp = valid[1] && (!valid[0] ||
+			   le64_to_cpu(sbp->s_last_cno) >
+			   le64_to_cpu(sbb->s_last_cno));
+	sb = swp ? sbb : sbp;
+
+	DBG(LOWPROBE, ul_debug("nilfs2: primary=%d, backup=%d, swap=%d",
+				valid[0], valid[1], swp));
 
 	if (strlen(sb->s_volume_name))
 		blkid_probe_set_label(pr, (unsigned char *) sb->s_volume_name,
@@ -107,14 +132,7 @@
 	.name		= "nilfs2",
 	.usage		= BLKID_USAGE_FILESYSTEM,
 	.probefunc	= probe_nilfs2,
-	.magics		=
-	{
-		{
-			.magic = NILFS_SB_MAGIC,
-			.len = 2,
-			.kboff = NILFS_SB_KBOFF,
-			.sboff = NILFS_MAG_OFF
-		},
-		{ NULL }
-	}
+	/* default min.size is 128MiB, but 1MiB for "mkfs.nilfs2 -b 1024 -B 16" */
+	.minsz		= (1024 * 1024),
+	.magics		= BLKID_NONE_MAGIC
 };
diff --git a/libblkid/ntfs.c b/libblkid/src/superblocks/ntfs.c
similarity index 93%
rename from libblkid/ntfs.c
rename to libblkid/src/superblocks/ntfs.c
index 41c6b9c..8ff9ccd 100644
--- a/libblkid/ntfs.c
+++ b/libblkid/src/superblocks/ntfs.c
@@ -75,8 +75,8 @@
 #define NTFS_MAX_CLUSTER_SIZE	(64 * 1024)
 
 enum {
-	MFT_RECORD_ATTR_VOLUME_NAME		= cpu_to_le32(0x60),
-	MFT_RECORD_ATTR_END			= cpu_to_le32(0xffffffff)
+	MFT_RECORD_ATTR_VOLUME_NAME		= 0x60,
+	MFT_RECORD_ATTR_END			= 0xffffffff
 };
 
 static int probe_ntfs(blkid_probe pr, const struct blkid_idmag *mag)
@@ -91,7 +91,7 @@
 
 	ns = blkid_probe_get_sb(pr, mag, struct ntfs_super_block);
 	if (!ns)
-		return -1;
+		return errno ? -errno : 1;
 
 	/*
 	 * Check bios parameters block
@@ -149,16 +149,16 @@
 	off = le64_to_cpu(ns->mft_cluster_location) * sector_size *
 		sectors_per_cluster;
 
-	DBG(DEBUG_LOWPROBE, printf("NTFS: sector_size=%d, mft_record_size=%d, "
+	DBG(LOWPROBE, ul_debug("NTFS: sector_size=%d, mft_record_size=%d, "
 			"sectors_per_cluster=%d, nr_clusters=%ju "
-			"cluster_offset=%jd\n",
+			"cluster_offset=%jd",
 			(int) sector_size, mft_record_size,
 			sectors_per_cluster, nr_clusters,
 			off));
 
 	buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size);
 	if (!buf_mft)
-		return 1;
+		return errno ? -errno : 1;
 
 	if (memcmp(buf_mft, "FILE", 4))
 		return 1;
@@ -167,7 +167,7 @@
 
 	buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size);
 	if (!buf_mft)
-		return 1;
+		return errno ? -errno : 1;
 
 	if (memcmp(buf_mft, "FILE", 4))
 		return 1;
@@ -186,9 +186,9 @@
 		if (!attr_len)
 			break;
 
-		if (attr->type == MFT_RECORD_ATTR_END)
+		if (le32_to_cpu(attr->type) == MFT_RECORD_ATTR_END)
 			break;
-		if (attr->type == MFT_RECORD_ATTR_VOLUME_NAME) {
+		if (le32_to_cpu(attr->type) == MFT_RECORD_ATTR_VOLUME_NAME) {
 			unsigned int val_off = le16_to_cpu(attr->value_offset);
 			unsigned int val_len = le32_to_cpu(attr->value_len);
 			unsigned char *val = ((uint8_t *) attr) + val_off;
diff --git a/libblkid/nvidia_raid.c b/libblkid/src/superblocks/nvidia_raid.c
similarity index 93%
rename from libblkid/nvidia_raid.c
rename to libblkid/src/superblocks/nvidia_raid.c
index dd86cdc..5db8ec2 100644
--- a/libblkid/nvidia_raid.c
+++ b/libblkid/src/superblocks/nvidia_raid.c
@@ -32,9 +32,9 @@
 	struct nv_metadata *nv;
 
 	if (pr->size < 0x10000)
-		return -1;
+		return 1;
 	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
-		return -1;
+		return 1;
 
 	off = ((pr->size / 0x200) - 2) * 0x200;
 	nv = (struct nv_metadata *)
@@ -42,15 +42,15 @@
 				off,
 				sizeof(struct nv_metadata));
 	if (!nv)
-		return -1;
+		return errno ? -errno : 1;
 
 	if (memcmp(nv->vendor, NVIDIA_SIGNATURE, sizeof(NVIDIA_SIGNATURE)-1) != 0)
-		return -1;
+		return 1;
 	if (blkid_probe_sprintf_version(pr, "%u", le16_to_cpu(nv->version)) != 0)
-		return -1;
+		return 1;
 	if (blkid_probe_set_magic(pr, off, sizeof(nv->vendor),
 				(unsigned char *) nv->vendor))
-		return -1;
+		return 1;
 	return 0;
 }
 
diff --git a/libblkid/ocfs.c b/libblkid/src/superblocks/ocfs.c
similarity index 97%
rename from libblkid/ocfs.c
rename to libblkid/src/superblocks/ocfs.c
index 82170ac..3fe199d 100644
--- a/libblkid/ocfs.c
+++ b/libblkid/src/superblocks/ocfs.c
@@ -109,14 +109,14 @@
 	buf = blkid_probe_get_buffer(pr, mag->kboff << 10,
 			sizeof(struct ocfs_volume_header));
 	if (!buf)
-		return -1;
+		return errno ? -errno : 1;
 	memcpy(&ovh, buf, sizeof(ovh));
 
 	/* label */
 	buf = blkid_probe_get_buffer(pr, (mag->kboff << 10) + 512,
 			sizeof(struct ocfs_volume_label));
 	if (!buf)
-		return -1;
+		return errno ? -errno : 1;
 	memcpy(&ovl, buf, sizeof(ovl));
 
 	maj = ocfsmajor(ovh);
@@ -144,7 +144,7 @@
 
 	osb = blkid_probe_get_sb(pr, mag, struct ocfs2_super_block);
 	if (!osb)
-		return -1;
+		return errno ? -errno : 1;
 
 	blkid_probe_set_label(pr, (unsigned char *) osb->s_label, sizeof(osb->s_label));
 	blkid_probe_set_uuid(pr, osb->s_uuid);
@@ -162,7 +162,7 @@
 
 	dl = blkid_probe_get_sb(pr, mag, struct oracle_asm_disk_label);
 	if (!dl)
-		return -1;
+		return errno ? -errno : 1;
 
 	blkid_probe_set_label(pr, (unsigned char *) dl->dl_id, sizeof(dl->dl_id));
 	return 0;
diff --git a/libblkid/promise_raid.c b/libblkid/src/superblocks/promise_raid.c
similarity index 94%
rename from libblkid/promise_raid.c
rename to libblkid/src/superblocks/promise_raid.c
index 01e4e37..678460a 100644
--- a/libblkid/promise_raid.c
+++ b/libblkid/src/superblocks/promise_raid.c
@@ -33,9 +33,9 @@
 	};
 
 	if (pr->size < 0x40000)
-		return -1;
+		return 1;
 	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
-		return -1;
+		return 1;
 
 	for (i = 0; sectors[i] != 0; i++) {
 		uint64_t off;
@@ -47,18 +47,18 @@
 					off,
 					sizeof(struct promise_metadata));
 		if (!pdc)
-			return -1;
+			return errno ? -errno : 1;
 
 		if (memcmp(pdc->sig, PDC_SIGNATURE,
 				sizeof(PDC_SIGNATURE) - 1) == 0) {
 
 			if (blkid_probe_set_magic(pr, off, sizeof(pdc->sig),
 						(unsigned char *) pdc->sig))
-				return -1;
+				return 1;
 			return 0;
 		}
 	}
-	return -1;
+	return 1;
 }
 
 const struct blkid_idinfo pdcraid_idinfo = {
diff --git a/libblkid/src/superblocks/refs.c b/libblkid/src/superblocks/refs.c
new file mode 100644
index 0000000..ea81f20
--- /dev/null
+++ b/libblkid/src/superblocks/refs.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2013 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "superblocks.h"
+
+
+const struct blkid_idinfo refs_idinfo =
+{
+	.name		= "ReFS",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.magics		=
+	{
+		{ .magic = "\000\000\000ReFS\000", .len = 8 },
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/reiserfs.c b/libblkid/src/superblocks/reiserfs.c
similarity index 96%
rename from libblkid/reiserfs.c
rename to libblkid/src/superblocks/reiserfs.c
index 152571f..edbaaa9 100644
--- a/libblkid/reiserfs.c
+++ b/libblkid/src/superblocks/reiserfs.c
@@ -45,17 +45,17 @@
 
 	rs = blkid_probe_get_sb(pr, mag, struct reiserfs_super_block);
 	if (!rs)
-		return -1;
+		return errno ? -errno : 1;
 
 	blocksize = le16_to_cpu(rs->rs_blocksize);
 
 	/* The blocksize must be at least 512B */
 	if ((blocksize >> 9) == 0)
-		return -BLKID_ERR_PARAM;
+		return 1;
 
 	/* If the superblock is inside the journal, we have the wrong one */
 	if (mag->kboff / (blocksize >> 9) > le32_to_cpu(rs->rs_journal_block) / 2)
-		return -BLKID_ERR_BIG;
+		return 1;
 
 	/* LABEL/UUID are only valid for later versions of Reiserfs v3.6. */
 	if (mag->magic[6] == '2' || mag->magic[6] == '3') {
@@ -82,7 +82,7 @@
 
 	rs4 = blkid_probe_get_sb(pr, mag, struct reiser4_super_block);
 	if (!rs4)
-		return -1;
+		return errno ? -errno : 1;
 
 	if (*rs4->rs4_label)
 		blkid_probe_set_label(pr, rs4->rs4_label, sizeof(rs4->rs4_label));
diff --git a/libblkid/romfs.c b/libblkid/src/superblocks/romfs.c
similarity index 96%
rename from libblkid/romfs.c
rename to libblkid/src/superblocks/romfs.c
index 91ef996..8e63c10 100644
--- a/libblkid/romfs.c
+++ b/libblkid/src/superblocks/romfs.c
@@ -29,7 +29,7 @@
 
 	ros = blkid_probe_get_sb(pr, mag, struct romfs_super_block);
 	if (!ros)
-		return -1;
+		return errno ? -errno : 1;
 
 	if (strlen((char *) ros->ros_volume))
 		blkid_probe_set_label(pr, ros->ros_volume,
diff --git a/libblkid/silicon_raid.c b/libblkid/src/superblocks/silicon_raid.c
similarity index 88%
rename from libblkid/silicon_raid.c
rename to libblkid/src/superblocks/silicon_raid.c
index 496a3e7..edbefbc 100644
--- a/libblkid/silicon_raid.c
+++ b/libblkid/src/superblocks/silicon_raid.c
@@ -67,16 +67,18 @@
 
 #define SILICON_MAGIC		0x2F000000
 
-static int checksum(struct silicon_metadata *sil)
+static uint16_t silraid_checksum(struct silicon_metadata *sil)
 {
 	int sum = 0;
 	unsigned short count = offsetof(struct silicon_metadata, checksum1) / 2;
 	uint16_t *p = (uint16_t *) sil;
 
-	while (count--)
-		sum += *p++;
+	while (count--) {
+		uint16_t x = *p++;
+		sum += le16_to_cpu(x);
+	}
 
-	return (-sum & 0xFFFF) == le16_to_cpu(sil->checksum1);
+	return (-sum & 0xFFFF);
 }
 
 static int probe_silraid(blkid_probe pr,
@@ -86,9 +88,9 @@
 	struct silicon_metadata *sil;
 
 	if (pr->size < 0x10000)
-		return -1;
+		return 1;
 	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
-		return -1;
+		return 1;
 
 	off = ((pr->size / 0x200) - 1) * 0x200;
 
@@ -96,27 +98,25 @@
 			blkid_probe_get_buffer(pr, off,
 				sizeof(struct silicon_metadata));
 	if (!sil)
-		return -1;
+		return errno ? -errno : 1;
 
 	if (le32_to_cpu(sil->magic) != SILICON_MAGIC)
-		return -1;
+		return 1;
 	if (sil->disk_number >= 8)
-		return -1;
-	if (!checksum(sil)) {
-		DBG(DEBUG_LOWPROBE, printf("silicon raid: incorrect checksum\n"));
-		return -1;
-	}
+		return 1;
+	if (!blkid_probe_verify_csum(pr, silraid_checksum(sil), le16_to_cpu(sil->checksum1)))
+		return 1;
 
 	if (blkid_probe_sprintf_version(pr, "%u.%u",
 				le16_to_cpu(sil->major_ver),
 				le16_to_cpu(sil->minor_ver)) != 0)
-		return -1;
+		return 1;
 
 	if (blkid_probe_set_magic(pr,
 			off + offsetof(struct silicon_metadata, magic),
 			sizeof(sil->magic),
 			(unsigned char *) &sil->magic))
-		return -1;
+		return 1;
 	return 0;
 }
 
diff --git a/libblkid/src/superblocks/squashfs.c b/libblkid/src/superblocks/squashfs.c
new file mode 100644
index 0000000..8ed2838
--- /dev/null
+++ b/libblkid/src/superblocks/squashfs.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ *     Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "bitops.h"	/* swab16() */
+#include "superblocks.h"
+
+struct sqsh_super_block {
+	uint32_t	s_magic;
+	uint32_t	inodes;
+	uint32_t	bytes_used_2;
+	uint32_t	uid_start_2;
+	uint32_t	guid_start_2;
+	uint32_t	inode_table_start_2;
+	uint32_t	directory_table_start_2;
+	uint16_t	s_major;
+	uint16_t	s_minor;
+} __attribute__((packed));
+
+static int probe_squashfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct sqsh_super_block *sq;
+	uint16_t major;
+	uint16_t minor;
+
+	sq = blkid_probe_get_sb(pr, mag, struct sqsh_super_block);
+	if (!sq)
+		return errno ? -errno : 1;
+
+	major = le16_to_cpu(sq->s_major);
+	minor = le16_to_cpu(sq->s_minor);
+	if (major < 4)
+		return 1;
+
+	blkid_probe_sprintf_version(pr, "%u.%u", major, minor);
+
+	return 0;
+}
+
+static int probe_squashfs3(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct sqsh_super_block *sq;
+	uint16_t major;
+	uint16_t minor;
+
+	sq = blkid_probe_get_sb(pr, mag, struct sqsh_super_block);
+	if (!sq)
+		return errno ? -errno : 1;
+
+	if (strcmp(mag->magic, "sqsh") == 0) {
+		major = be16_to_cpu(sq->s_major);
+		minor = be16_to_cpu(sq->s_minor);
+	} else {
+		major = le16_to_cpu(sq->s_major);
+		minor = le16_to_cpu(sq->s_minor);
+	}
+
+	if (major > 3)
+		return 1;
+
+	blkid_probe_sprintf_version(pr, "%u.%u", major, minor);
+
+	return 0;
+}
+
+const struct blkid_idinfo squashfs_idinfo =
+{
+	.name		= "squashfs",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_squashfs,
+	.magics		=
+	{
+		{ .magic = "hsqs", .len = 4 },
+		{ NULL }
+	}
+};
+
+const struct blkid_idinfo squashfs3_idinfo =
+{
+	.name		= "squashfs3",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_squashfs3,
+	.magics		=
+	{
+		{ .magic = "sqsh", .len = 4 }, /* big endian */
+		{ .magic = "hsqs", .len = 4 }, /* little endian */
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/superblocks.c b/libblkid/src/superblocks/superblocks.c
similarity index 91%
rename from libblkid/superblocks.c
rename to libblkid/src/superblocks/superblocks.c
index 384d2ca..80bd6e5 100644
--- a/libblkid/superblocks.c
+++ b/libblkid/src/superblocks/superblocks.c
@@ -49,6 +49,8 @@
  *
  * @UUID_SUB: subvolume uuid (e.g. btrfs)
  *
+ * @LOGUUID: external log UUID (e.g. xfs)
+ *
  * @UUID_RAW: raw UUID from FS superblock
  *
  * @EXT_JOURNAL: external journal UUID
@@ -99,6 +101,7 @@
 	&adraid_idinfo,
 	&jmraid_idinfo,
 
+	&bcache_idinfo,
 	&drbd_idinfo,
 	&drbdproxy_datalog_idinfo,
 	&lvm2_idinfo,
@@ -113,6 +116,7 @@
 	&swsuspend_idinfo,
 	&swap_idinfo,
 	&xfs_idinfo,
+	&xfs_log_idinfo,
 	&ext4dev_idinfo,
 	&ext4_idinfo,
 	&ext3_idinfo,
@@ -131,6 +135,7 @@
 	&sysv_idinfo,
         &xenix_idinfo,
 	&ntfs_idinfo,
+	&refs_idinfo,
 	&cramfs_idinfo,
 	&romfs_idinfo,
 	&minix_idinfo,
@@ -141,6 +146,7 @@
 	&oracleasm_idinfo,
 	&vxfs_idinfo,
 	&squashfs_idinfo,
+	&squashfs3_idinfo,
 	&netware_idinfo,
 	&btrfs_idinfo,
 	&ubifs_idinfo,
@@ -279,7 +285,7 @@
 		} else if (flag & BLKID_FLTR_ONLYIN)
 			blkid_bmp_set_item(chn->fltr, i);
 	}
-	DBG(DEBUG_LOWPROBE, printf("a new probing usage-filter initialized\n"));
+	DBG(LOWPROBE, ul_debug("a new probing usage-filter initialized"));
 	return 0;
 }
 
@@ -330,20 +336,24 @@
 static int superblocks_probe(blkid_probe pr, struct blkid_chain *chn)
 {
 	size_t i;
+	int rc = BLKID_PROBE_NONE;
 
 	if (!pr || chn->idx < -1)
-		return -1;
+		return -EINVAL;
+
 	blkid_probe_chain_reset_vals(pr, chn);
 
-	DBG(DEBUG_LOWPROBE,
-		printf("--> starting probing loop [SUBLKS idx=%d]\n",
-		chn->idx));
+	if (pr->flags & BLKID_FL_NOSCAN_DEV)
+		return BLKID_PROBE_NONE;
 
 	if (pr->size <= 0 || (pr->size <= 1024 && !S_ISCHR(pr->mode)))
 		/* Ignore very very small block devices or regular files (e.g.
 		 * extended partitions). Note that size of the UBI char devices
 		 * is 1 byte */
-		goto nothing;
+		return BLKID_PROBE_NONE;
+
+	DBG(LOWPROBE, ul_debug("--> starting probing loop [SUBLKS idx=%d]",
+		chn->idx));
 
 	i = chn->idx < 0 ? 0 : chn->idx + 1U;
 
@@ -351,38 +361,50 @@
 		const struct blkid_idinfo *id;
 		const struct blkid_idmag *mag = NULL;
 		blkid_loff_t off = 0;
-		int rc = 0;
 
 		chn->idx = i;
 		id = idinfos[i];
 
 		if (chn->fltr && blkid_bmp_get_item(chn->fltr, i)) {
-			DBG(DEBUG_LOWPROBE, printf("filter out: %s\n", id->name));
+			DBG(LOWPROBE, ul_debug("filter out: %s", id->name));
+			rc = BLKID_PROBE_NONE;
 			continue;
 		}
 
-		if (id->minsz && id->minsz > pr->size)
+		if (id->minsz && id->minsz > pr->size) {
+			rc = BLKID_PROBE_NONE;
 			continue;	/* the device is too small */
+		}
 
 		/* don't probe for RAIDs, swap or journal on CD/DVDs */
 		if ((id->usage & (BLKID_USAGE_RAID | BLKID_USAGE_OTHER)) &&
-		    blkid_probe_is_cdrom(pr))
+		    blkid_probe_is_cdrom(pr)) {
+			rc = BLKID_PROBE_NONE;
 			continue;
+		}
 
 		/* don't probe for RAIDs on floppies */
-		if ((id->usage & BLKID_USAGE_RAID) && blkid_probe_is_tiny(pr))
+		if ((id->usage & BLKID_USAGE_RAID) && blkid_probe_is_tiny(pr)) {
+			rc = BLKID_PROBE_NONE;
 			continue;
+		}
 
-		DBG(DEBUG_LOWPROBE, printf("[%zd] %s:\n", i, id->name));
+		DBG(LOWPROBE, ul_debug("[%zd] %s:", i, id->name));
 
-		if (blkid_probe_get_idmag(pr, id, &off, &mag))
+		rc = blkid_probe_get_idmag(pr, id, &off, &mag);
+		if (rc < 0)
+			break;
+		if (rc != BLKID_PROBE_OK)
 			continue;
 
 		/* final check by probing function */
 		if (id->probefunc) {
-			DBG(DEBUG_LOWPROBE, printf("\tcall probefunc()\n"));
-			if (id->probefunc(pr, mag) != 0) {
+			DBG(LOWPROBE, ul_debug("\tcall probefunc()"));
+			rc = id->probefunc(pr, mag);
+			if (rc != BLKID_PROBE_OK) {
 				blkid_probe_chain_reset_vals(pr, chn);
+				if (rc < 0)
+					break;
 				continue;
 			}
 		}
@@ -401,21 +423,18 @@
 					(unsigned char *) mag->magic);
 		if (rc) {
 			blkid_probe_chain_reset_vals(pr, chn);
-			DBG(DEBUG_LOWPROBE, printf("failed to set result -- ingnore\n"));
+			DBG(LOWPROBE, ul_debug("failed to set result -- ignore"));
 			continue;
 		}
 
-		DBG(DEBUG_LOWPROBE,
-			printf("<-- leaving probing loop (type=%s) [SUBLKS idx=%d]\n",
+		DBG(LOWPROBE, ul_debug("<-- leaving probing loop (type=%s) [SUBLKS idx=%d]",
 			id->name, chn->idx));
-		return 0;
+		return BLKID_PROBE_OK;
 	}
 
-nothing:
-	DBG(DEBUG_LOWPROBE,
-		printf("<-- leaving probing loop (failed) [SUBLKS idx=%d]\n",
-		chn->idx));
-	return 1;
+	DBG(LOWPROBE, ul_debug("<-- leaving probing loop (failed=%d) [SUBLKS idx=%d]",
+			rc, chn->idx));
+	return rc;
 }
 
 /*
@@ -439,11 +458,13 @@
 	int intol = 0;
 	int rc;
 
+	if (pr->flags & BLKID_FL_NOSCAN_DEV)
+		return BLKID_PROBE_NONE;
+
 	while ((rc = superblocks_probe(pr, chn)) == 0) {
 
 		if (blkid_probe_is_tiny(pr) && !count)
-			/* floppy or so -- returns the first result. */
-			return 0;
+			return BLKID_PROBE_OK;	/* floppy or so -- returns the first result. */
 
 		count++;
 
@@ -466,14 +487,13 @@
 		return rc;		/* error */
 
 	if (count > 1 && intol) {
-		DBG(DEBUG_LOWPROBE,
-			printf("ERROR: superblocks chain: "
-			       "ambivalent result detected (%d filesystems)!\n",
+		DBG(LOWPROBE, ul_debug("ERROR: superblocks chain: "
+			       "ambivalent result detected (%d filesystems)!",
 			       count));
 		return -2;		/* error, ambivalent result (more FS) */
 	}
 	if (!count)
-		return 1;		/* nothing detected */
+		return BLKID_PROBE_NONE;
 
 	if (idx != -1) {
 		/* restore the first result */
@@ -490,7 +510,7 @@
 	if (chn->idx >= 0 && idinfos[chn->idx]->usage & BLKID_USAGE_RAID)
 		pr->prob_flags |= BLKID_PROBE_FL_IGNORE_PT;
 
-	return 0;
+	return BLKID_PROBE_OK;
 }
 
 int blkid_probe_set_version(blkid_probe pr, const char *version)
@@ -620,17 +640,6 @@
 	return 0;
 }
 
-/* like uuid_is_null() from libuuid, but works with arbitrary size of UUID */
-static int uuid_is_empty(const unsigned char *buf, size_t len)
-{
-	size_t i;
-
-	for (i = 0; i < len; i++)
-		if (buf[i])
-			return 0;
-	return 1;
-}
-
 int blkid_probe_sprintf_uuid(blkid_probe pr, unsigned char *uuid,
 				size_t len, const char *fmt, ...)
 {
@@ -641,7 +650,7 @@
 	if (len > BLKID_PROBVAL_BUFSIZ)
 		len = BLKID_PROBVAL_BUFSIZ;
 
-	if (uuid_is_empty(uuid, len))
+	if (blkid_uuid_is_empty(uuid, len))
 		return 0;
 
 	if ((chn->flags & BLKID_SUBLKS_UUIDRAW) &&
@@ -706,7 +715,7 @@
 	struct blkid_chain *chn = blkid_probe_get_chain(pr);
 	struct blkid_prval *v;
 
-	if (uuid_is_empty(uuid, 16))
+	if (blkid_uuid_is_empty(uuid, 16))
 		return 0;
 
 	if (!name) {
diff --git a/libblkid/superblocks.h b/libblkid/src/superblocks/superblocks.h
similarity index 95%
rename from libblkid/superblocks.h
rename to libblkid/src/superblocks/superblocks.h
index e45dc6a..3bbfb9c 100644
--- a/libblkid/superblocks.h
+++ b/libblkid/src/superblocks/superblocks.h
@@ -29,6 +29,7 @@
 extern const struct blkid_idinfo jbd_idinfo;
 extern const struct blkid_idinfo jfs_idinfo;
 extern const struct blkid_idinfo xfs_idinfo;
+extern const struct blkid_idinfo xfs_log_idinfo;
 extern const struct blkid_idinfo gfs_idinfo;
 extern const struct blkid_idinfo gfs2_idinfo;
 extern const struct blkid_idinfo romfs_idinfo;
@@ -40,6 +41,7 @@
 extern const struct blkid_idinfo hfs_idinfo;
 extern const struct blkid_idinfo hfsplus_idinfo;
 extern const struct blkid_idinfo ntfs_idinfo;
+extern const struct blkid_idinfo refs_idinfo;
 extern const struct blkid_idinfo iso9660_idinfo;
 extern const struct blkid_idinfo udf_idinfo;
 extern const struct blkid_idinfo vxfs_idinfo;
@@ -55,6 +57,7 @@
 extern const struct blkid_idinfo highpoint37x_idinfo;
 extern const struct blkid_idinfo highpoint45x_idinfo;
 extern const struct blkid_idinfo squashfs_idinfo;
+extern const struct blkid_idinfo squashfs3_idinfo;
 extern const struct blkid_idinfo netware_idinfo;
 extern const struct blkid_idinfo sysv_idinfo;
 extern const struct blkid_idinfo xenix_idinfo;
@@ -70,6 +73,7 @@
 extern const struct blkid_idinfo nilfs2_idinfo;
 extern const struct blkid_idinfo exfat_idinfo;
 extern const struct blkid_idinfo f2fs_idinfo;
+extern const struct blkid_idinfo bcache_idinfo;
 
 /*
  * superblock functions
diff --git a/libblkid/swap.c b/libblkid/src/superblocks/swap.c
similarity index 89%
rename from libblkid/swap.c
rename to libblkid/src/superblocks/swap.c
index 7ac119b..3f21391 100644
--- a/libblkid/swap.c
+++ b/libblkid/src/superblocks/swap.c
@@ -44,20 +44,27 @@
 	hdr = (struct swap_header_v1_2 *) blkid_probe_get_buffer(pr, 1024,
 				sizeof(struct swap_header_v1_2));
 	if (!hdr)
-		return -1;
+		return errno ? -errno : 1;
 
 	/* SWAPSPACE2 - check for wrong version or zeroed pagecount */
-	if (strcmp(version, "2") == 0 &&
-	    (hdr->version != 1 || hdr->lastpage == 0))
-		return -1;
+	if (strcmp(version, "1") == 0) {
+		if (hdr->version != 1 && swab32(hdr->version) != 1) {
+			DBG(LOWPROBE, ul_debug("incorrect swap version"));
+			return 1;
+		}
+		if (hdr->lastpage == 0) {
+			DBG(LOWPROBE, ul_debug("not set last swap page"));
+			return 1;
+		}
+	}
 
 	/* arbitrary sanity check.. is there any garbage down there? */
 	if (hdr->padding[32] == 0 && hdr->padding[33] == 0) {
 		if (hdr->volume[0] && blkid_probe_set_label(pr, hdr->volume,
 				sizeof(hdr->volume)) < 0)
-			return -1;
+			return 1;
 		if (blkid_probe_set_uuid(pr, hdr->uuid) < 0)
-			return -1;
+			return 1;
 	}
 
 	blkid_probe_set_version(pr, version);
@@ -69,31 +76,31 @@
 	unsigned char *buf;
 
 	if (!mag)
-		return -1;
+		return 1;
 
 	/* TuxOnIce keeps valid swap header at the end of the 1st page */
 	buf = blkid_probe_get_buffer(pr, 0, TOI_MAGIC_STRLEN);
 	if (!buf)
-		return -1;
+		return errno ? -errno : 1;
 
 	if (memcmp(buf, TOI_MAGIC_STRING, TOI_MAGIC_STRLEN) == 0)
 		return 1;	/* Ignore swap signature, it's TuxOnIce */
 
 	if (!memcmp(mag->magic, "SWAP-SPACE", mag->len)) {
 		/* swap v0 doesn't support LABEL or UUID */
-		blkid_probe_set_version(pr, "1");
+		blkid_probe_set_version(pr, "0");
 		return 0;
 
 	} else if (!memcmp(mag->magic, "SWAPSPACE2", mag->len))
-		return swap_set_info(pr, "2");
+		return swap_set_info(pr, "1");
 
-	return -1;
+	return 1;
 }
 
 static int probe_swsuspend(blkid_probe pr, const struct blkid_idmag *mag)
 {
 	if (!mag)
-		return -1;
+		return 1;
 	if (!memcmp(mag->magic, "S1SUSPEND", mag->len))
 		return swap_set_info(pr, "s1suspend");
 	if (!memcmp(mag->magic, "S2SUSPEND", mag->len))
@@ -105,7 +112,7 @@
 	if (!memcmp(mag->magic, "LINHIB0001", mag->len))
 		return swap_set_info(pr, "linhib0001");
 
-	return -1;	/* no signature detected */
+	return 1;	/* no signature detected */
 }
 
 const struct blkid_idinfo swap_idinfo =
diff --git a/libblkid/sysv.c b/libblkid/src/superblocks/sysv.c
similarity index 97%
rename from libblkid/sysv.c
rename to libblkid/src/superblocks/sysv.c
index 80b0cc5..4b34591 100644
--- a/libblkid/sysv.c
+++ b/libblkid/src/superblocks/sysv.c
@@ -80,7 +80,7 @@
 
 	sb = blkid_probe_get_sb(pr, mag, struct xenix_super_block);
 	if (!sb)
-		return -1;
+		return errno ? -errno : 1;
 	blkid_probe_set_label(pr, sb->s_fname, sizeof(sb->s_fname));
 	return 0;
 }
@@ -105,21 +105,21 @@
 					off,
 					sizeof(struct sysv_super_block));
 		if (!sb)
-			return -1;
+			return errno ? -errno : 1;
 
 		if (sb->s_magic == cpu_to_le32(0xfd187e20) ||
 		    sb->s_magic == cpu_to_be32(0xfd187e20)) {
 
 			if (blkid_probe_set_label(pr, sb->s_fname,
 						sizeof(sb->s_fname)))
-				return -1;
+				return 1;
 
 			if (blkid_probe_set_magic(pr,
 					off + offsetof(struct sysv_super_block,
 								s_magic),
 					sizeof(sb->s_magic),
 					(unsigned char *) &sb->s_magic))
-				return -1;
+				return 1;
 
 			return 0;
 		}
diff --git a/libblkid/ubifs.c b/libblkid/src/superblocks/ubifs.c
similarity index 96%
rename from libblkid/ubifs.c
rename to libblkid/src/superblocks/ubifs.c
index 2d69c2b..dc84260 100644
--- a/libblkid/ubifs.c
+++ b/libblkid/src/superblocks/ubifs.c
@@ -99,11 +99,12 @@
 
 	sb = blkid_probe_get_sb(pr, mag, struct ubifs_sb_node);
 	if (!sb)
-		return -1;
+		return errno ? -errno : 1;
 
 	blkid_probe_set_uuid(pr, sb->uuid);
 	blkid_probe_sprintf_version(pr, "w%dr%d",
-				    sb->fmt_version, sb->ro_compat_version);
+			le32_to_cpu(sb->fmt_version),
+			le32_to_cpu(sb->ro_compat_version));
 	return 0;
 }
 
diff --git a/libblkid/udf.c b/libblkid/src/superblocks/udf.c
similarity index 77%
rename from libblkid/udf.c
rename to libblkid/src/superblocks/udf.c
index 2cb471d..5cde3cc 100644
--- a/libblkid/udf.c
+++ b/libblkid/src/superblocks/udf.c
@@ -64,55 +64,70 @@
 	struct volume_descriptor *vd;
 	struct volume_structure_descriptor *vsd;
 	unsigned int bs;
+	unsigned int pbs[2];
 	unsigned int b;
 	unsigned int type;
 	unsigned int count;
 	unsigned int loc;
+	unsigned int i;
 
-	/* search Volume Sequence Descriptor (VSD) to get the logical
-	 * block size of the volume */
-	for (bs = 0x800; bs < 0x8000; bs += 0x800) {
+	/* The block size of a UDF filesystem is that of the underlying
+	 * storage; we check later on for the special case of image files,
+	 * which may have the 2048-byte block size of optical media. */
+	pbs[0] = blkid_probe_get_sectorsize(pr);
+	pbs[1] = 0x800;
+
+	/* check for a Volume Structure Descriptor (VSD); each is
+	 * 2048 bytes long */
+	for (b = 0; b < 0x8000; b += 0x800) {
 		vsd = (struct volume_structure_descriptor *)
 			blkid_probe_get_buffer(pr,
-					UDF_VSD_OFFSET + bs,
+					UDF_VSD_OFFSET + b,
 					sizeof(*vsd));
 		if (!vsd)
-			return 1;
+			return errno ? -errno : 1;
 		if (vsd->id[0] != '\0')
 			goto nsr;
 	}
-	return -1;
+	return 1;
 
 nsr:
 	/* search the list of VSDs for a NSR descriptor */
 	for (b = 0; b < 64; b++) {
 		vsd = (struct volume_structure_descriptor *)
 			blkid_probe_get_buffer(pr,
-					UDF_VSD_OFFSET + ((blkid_loff_t) b * bs),
+					UDF_VSD_OFFSET + ((blkid_loff_t) b * 0x800),
 					sizeof(*vsd));
 		if (!vsd)
-			return -1;
+			return errno ? -errno : 1;
 		if (vsd->id[0] == '\0')
-			return -1;
+			return 1;
 		if (memcmp(vsd->id, "NSR02", 5) == 0)
 			goto anchor;
 		if (memcmp(vsd->id, "NSR03", 5) == 0)
 			goto anchor;
 	}
-	return -1;
+	return 1;
 
 anchor:
-	/* read Anchor Volume Descriptor (AVDP) */
-	vd = (struct volume_descriptor *)
-		blkid_probe_get_buffer(pr, 256 * bs, sizeof(*vd));
-	if (!vd)
-		return -1;
+	/* read Anchor Volume Descriptor (AVDP), checking block size */
+	for (i = 0; i < 2; i++) {
+		vd = (struct volume_descriptor *)
+			blkid_probe_get_buffer(pr, 256 * pbs[i], sizeof(*vd));
+		if (!vd)
+			return errno ? -errno : 1;
 
-	type = le16_to_cpu(vd->tag.id);
-	if (type != 2) /* TAG_ID_AVDP */
-		return 0;
+		type = le16_to_cpu(vd->tag.id);
+		if (type == 2) /* TAG_ID_AVDP */
+			goto real_blksz;
+	}
+	return 0;
 
-	/* get desriptor list address and block count */
+real_blksz:
+	/* Use the actual block size from here on out */
+	bs = pbs[i];
+
+	/* get descriptor list address and block count */
 	count = le32_to_cpu(vd->type.anchor.length) / bs;
 	loc = le32_to_cpu(vd->type.anchor.location);
 
@@ -123,7 +138,7 @@
 					(blkid_loff_t) (loc + b) * bs,
 					sizeof(*vd));
 		if (!vd)
-			return -1;
+			return errno ? -errno : 1;
 	}
 
 	/* Try extract all possible ISO9660 information -- if there is
@@ -139,7 +154,8 @@
 			blkid_probe_get_buffer(pr,
 					(blkid_loff_t) (loc + b) * bs,
 					sizeof(*vd));
-
+		if (!vd)
+			return errno ? -errno : 1;
 		type = le16_to_cpu(vd->tag.id);
 		if (type == 0)
 			break;
diff --git a/libblkid/ufs.c b/libblkid/src/superblocks/ufs.c
similarity index 98%
rename from libblkid/ufs.c
rename to libblkid/src/superblocks/ufs.c
index 673a528..6ef2acd 100644
--- a/libblkid/ufs.c
+++ b/libblkid/src/superblocks/ufs.c
@@ -185,7 +185,7 @@
 					offsets[i] * 1024,
 					sizeof(struct ufs_super_block));
 		if (!ufs)
-			return -1;
+			return errno ? -errno : 1;
 
 		magBE = be32_to_cpu(ufs->fs_magic);
 		magLE = le32_to_cpu(ufs->fs_magic);
@@ -231,7 +231,7 @@
 				offsetof(struct ufs_super_block, fs_magic),
 			sizeof(ufs->fs_magic),
 			(unsigned char *) &ufs->fs_magic))
-		return -1;
+		return 1;
 
 	return 0;
 }
diff --git a/libblkid/vfat.c b/libblkid/src/superblocks/vfat.c
similarity index 95%
rename from libblkid/vfat.c
rename to libblkid/src/superblocks/vfat.c
index 2feb818..f38deac 100644
--- a/libblkid/vfat.c
+++ b/libblkid/src/superblocks/vfat.c
@@ -123,9 +123,8 @@
 	struct vfat_dir_entry *ent, *dir = NULL;
 	uint32_t i;
 
-	DBG(DEBUG_LOWPROBE,
-		printf("\tlook for label in root-dir "
-			"(entries: %d, offset: %jd)\n", entries, offset));
+	DBG(LOWPROBE, ul_debug("\tlook for label in root-dir "
+			"(entries: %d, offset: %jd)", entries, offset));
 
 	if (!blkid_probe_is_tiny(pr)) {
 		/* large disk, read whole root directory */
@@ -163,8 +162,7 @@
 
 		if ((ent->attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) ==
 		    FAT_ATTR_VOLUME_ID) {
-			DBG(DEBUG_LOWPROBE,
-				printf("\tfound fs LABEL at entry %d\n", i));
+			DBG(LOWPROBE, ul_debug("\tfound fs LABEL at entry %d", i));
 			return ent->name;
 		}
 	}
@@ -257,16 +255,20 @@
 	struct vfat_super_block *vs;
 	struct msdos_super_block *ms;
 	const struct blkid_idmag *mag = NULL;
+	int rc;
 
-	if (blkid_probe_get_idmag(pr, &vfat_idinfo, NULL, &mag) || !mag)
+	rc = blkid_probe_get_idmag(pr, &vfat_idinfo, NULL, &mag);
+	if (rc < 0)
+		return rc;	/* error */
+	if (rc != BLKID_PROBE_OK || !mag)
 		return 0;
 
 	ms = blkid_probe_get_sb(pr, mag, struct msdos_super_block);
 	if (!ms)
-		return 0;
+		return errno ? -errno : 0;
 	vs = blkid_probe_get_sb(pr, mag, struct vfat_super_block);
 	if (!vs)
-		return 0;
+		return errno ? -errno : 0;
 
 	return fat_valid_superblock(mag, ms, vs, NULL, NULL);
 }
@@ -285,10 +287,12 @@
 
 	ms = blkid_probe_get_sb(pr, mag, struct msdos_super_block);
 	if (!ms)
-		return 0;
+		return errno ? -errno : 1;
+
 	vs = blkid_probe_get_sb(pr, mag, struct vfat_super_block);
 	if (!vs)
-		return 0;
+		return errno ? -errno : 1;
+
 	if (!fat_valid_superblock(mag, ms, vs, &cluster_count, &fat_size))
 		return 1;
 
@@ -378,16 +382,16 @@
 					(blkid_loff_t) fsinfo_sect * sector_size,
 					sizeof(struct fat32_fsinfo));
 			if (buf == NULL)
-				return -1;
+				return errno ? -errno : 1;
 
 			fsinfo = (struct fat32_fsinfo *) buf;
 			if (memcmp(fsinfo->signature1, "\x52\x52\x61\x41", 4) != 0 &&
 			    memcmp(fsinfo->signature1, "\x52\x52\x64\x41", 4) != 0 &&
 			    memcmp(fsinfo->signature1, "\x00\x00\x00\x00", 4) != 0)
-				return -1;
+				return 1;
 			if (memcmp(fsinfo->signature2, "\x72\x72\x41\x61", 4) != 0 &&
 			    memcmp(fsinfo->signature2, "\x00\x00\x00\x00", 4) != 0)
-				return -1;
+				return 1;
 		}
 	}
 
diff --git a/libblkid/via_raid.c b/libblkid/src/superblocks/via_raid.c
similarity index 89%
rename from libblkid/via_raid.c
rename to libblkid/src/superblocks/via_raid.c
index eba7e4b..ee3ab65 100644
--- a/libblkid/via_raid.c
+++ b/libblkid/src/superblocks/via_raid.c
@@ -42,7 +42,7 @@
 	while (i--)
 		cs += ((uint8_t*) v)[i];
 
-	return cs == v->checksum;
+	return cs;
 }
 
 static int probe_viaraid(blkid_probe pr,
@@ -52,9 +52,9 @@
 	struct via_metadata *v;
 
 	if (pr->size < 0x10000)
-		return -1;
+		return 1;
 	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
-		return -1;
+		return 1;
 
 	off = ((pr->size / 0x200)-1) * 0x200;
 
@@ -63,19 +63,21 @@
 				off,
 				sizeof(struct via_metadata));
 	if (!v)
-		return -1;
+		return errno ? -errno : 1;
+
 	if (le16_to_cpu(v->signature) != VIA_SIGNATURE)
-		return -1;
+		return 1;
 	if (v->version_number > 2)
-		return -1;
-	if (!via_checksum(v))
-		return -1;
+		return 1;
+	if (!blkid_probe_verify_csum(pr, via_checksum(v), v->checksum))
+		return 1;
+
 	if (blkid_probe_sprintf_version(pr, "%u", v->version_number) != 0)
-		return -1;
+		return 1;
 	if (blkid_probe_set_magic(pr, off,
 				sizeof(v->signature),
 				(unsigned char *) &v->signature))
-		return -1;
+		return 1;
 	return 0;
 }
 
diff --git a/libblkid/vmfs.c b/libblkid/src/superblocks/vmfs.c
similarity index 97%
rename from libblkid/vmfs.c
rename to libblkid/src/superblocks/vmfs.c
index ead09a8..fac87ab 100644
--- a/libblkid/vmfs.c
+++ b/libblkid/src/superblocks/vmfs.c
@@ -28,7 +28,7 @@
 
 	header = blkid_probe_get_sb(pr, mag, struct vmfs_fs_info);
 	if (header == NULL)
-		return -1;
+		return errno ? -errno : 1;
 
 	blkid_probe_sprintf_uuid(pr, (unsigned char *) header->uuid, 16,
 		"%02x%02x%02x%02x-%02x%02x%02x%02x-"
@@ -53,7 +53,7 @@
 
 	header = blkid_probe_get_sb(pr, mag, struct vmfs_volume_info);
 	if (header == NULL)
-		return -1;
+		return errno ? -errno : 1;
 
 	blkid_probe_sprintf_value(pr, "UUID_SUB",
 		"%02x%02x%02x%02x-%02x%02x%02x%02x-"
diff --git a/libblkid/vxfs.c b/libblkid/src/superblocks/vxfs.c
similarity index 95%
rename from libblkid/vxfs.c
rename to libblkid/src/superblocks/vxfs.c
index fdab85a..19d284c 100644
--- a/libblkid/vxfs.c
+++ b/libblkid/src/superblocks/vxfs.c
@@ -20,7 +20,7 @@
 
 	vxs = blkid_probe_get_sb(pr, mag, struct vxfs_super_block);
 	if (!vxs)
-		return -1;
+		return errno ? -errno : 1;
 
 	blkid_probe_sprintf_version(pr, "%u", (unsigned int) vxs->vs_version);
 	return 0;
diff --git a/libblkid/src/superblocks/xfs.c b/libblkid/src/superblocks/xfs.c
new file mode 100644
index 0000000..a6c04a2
--- /dev/null
+++ b/libblkid/src/superblocks/xfs.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 1999 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2001 by Andreas Dilger
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ * Copyright (C) 2013 Eric Sandeen <sandeen@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+struct xfs_super_block {
+	uint32_t	sb_magicnum;	/* magic number == XFS_SB_MAGIC */
+	uint32_t	sb_blocksize;	/* logical block size, bytes */
+	uint64_t	sb_dblocks;	/* number of data blocks */
+	uint64_t	sb_rblocks;	/* number of realtime blocks */
+	uint64_t	sb_rextents;	/* number of realtime extents */
+	unsigned char	sb_uuid[16];	/* file system unique id */
+	uint64_t	sb_logstart;	/* starting block of log if internal */
+	uint64_t	sb_rootino;	/* root inode number */
+	uint64_t	sb_rbmino;	/* bitmap inode for realtime extents */
+	uint64_t	sb_rsumino;	/* summary inode for rt bitmap */
+	uint32_t	sb_rextsize;	/* realtime extent size, blocks */
+	uint32_t	sb_agblocks;	/* size of an allocation group */
+	uint32_t	sb_agcount;	/* number of allocation groups */
+	uint32_t	sb_rbmblocks;	/* number of rt bitmap blocks */
+	uint32_t	sb_logblocks;	/* number of log blocks */
+
+	uint16_t	sb_versionnum;	/* header version == XFS_SB_VERSION */
+	uint16_t	sb_sectsize;	/* volume sector size, bytes */
+	uint16_t	sb_inodesize;	/* inode size, bytes */
+	uint16_t	sb_inopblock;	/* inodes per block */
+	char		sb_fname[12];	/* file system name */
+	uint8_t		sb_blocklog;	/* log2 of sb_blocksize */
+	uint8_t		sb_sectlog;	/* log2 of sb_sectsize */
+	uint8_t		sb_inodelog;	/* log2 of sb_inodesize */
+	uint8_t		sb_inopblog;	/* log2 of sb_inopblock */
+	uint8_t		sb_agblklog;	/* log2 of sb_agblocks (rounded up) */
+	uint8_t		sb_rextslog;	/* log2 of sb_rextents */
+	uint8_t		sb_inprogress;	/* mkfs is in progress, don't mount */
+	uint8_t		sb_imax_pct;	/* max % of fs for inode space */
+					/* statistics */
+	uint64_t	sb_icount;	/* allocated inodes */
+	uint64_t	sb_ifree;	/* free inodes */
+	uint64_t	sb_fdblocks;	/* free data blocks */
+	uint64_t	sb_frextents;	/* free realtime extents */
+
+	/* this is not all... but enough for libblkid */
+
+} __attribute__((packed));
+
+#define XFS_MIN_BLOCKSIZE_LOG	9	/* i.e. 512 bytes */
+#define XFS_MAX_BLOCKSIZE_LOG	16	/* i.e. 65536 bytes */
+#define XFS_MIN_BLOCKSIZE	(1 << XFS_MIN_BLOCKSIZE_LOG)
+#define XFS_MAX_BLOCKSIZE	(1 << XFS_MAX_BLOCKSIZE_LOG)
+#define XFS_MIN_SECTORSIZE_LOG	9	/* i.e. 512 bytes */
+#define XFS_MAX_SECTORSIZE_LOG	15	/* i.e. 32768 bytes */
+#define XFS_MIN_SECTORSIZE	(1 << XFS_MIN_SECTORSIZE_LOG)
+#define XFS_MAX_SECTORSIZE	(1 << XFS_MAX_SECTORSIZE_LOG)
+
+#define	XFS_DINODE_MIN_LOG	8
+#define	XFS_DINODE_MAX_LOG	11
+#define	XFS_DINODE_MIN_SIZE	(1 << XFS_DINODE_MIN_LOG)
+#define	XFS_DINODE_MAX_SIZE	(1 << XFS_DINODE_MAX_LOG)
+
+#define	XFS_MAX_RTEXTSIZE	(1024 * 1024 * 1024)	/* 1GB */
+#define	XFS_DFL_RTEXTSIZE	(64 * 1024)	        /* 64kB */
+#define	XFS_MIN_RTEXTSIZE	(4 * 1024)		/* 4kB */
+
+#define XFS_MIN_AG_BLOCKS	64
+#define XFS_MAX_DBLOCKS(s) ((uint64_t)(s)->sb_agcount * (s)->sb_agblocks)
+#define XFS_MIN_DBLOCKS(s) ((uint64_t)((s)->sb_agcount - 1) *	\
+			 (s)->sb_agblocks + XFS_MIN_AG_BLOCKS)
+
+
+static void sb_from_disk(struct xfs_super_block *from,
+			 struct xfs_super_block *to)
+{
+
+	to->sb_magicnum = be32_to_cpu(from->sb_magicnum);
+	to->sb_blocksize = be32_to_cpu(from->sb_blocksize);
+	to->sb_dblocks = be64_to_cpu(from->sb_dblocks);
+	to->sb_rblocks = be64_to_cpu(from->sb_rblocks);
+	to->sb_rextents = be64_to_cpu(from->sb_rextents);
+	to->sb_logstart = be64_to_cpu(from->sb_logstart);
+	to->sb_rootino = be64_to_cpu(from->sb_rootino);
+	to->sb_rbmino = be64_to_cpu(from->sb_rbmino);
+	to->sb_rsumino = be64_to_cpu(from->sb_rsumino);
+	to->sb_rextsize = be32_to_cpu(from->sb_rextsize);
+	to->sb_agblocks = be32_to_cpu(from->sb_agblocks);
+	to->sb_agcount = be32_to_cpu(from->sb_agcount);
+	to->sb_rbmblocks = be32_to_cpu(from->sb_rbmblocks);
+	to->sb_logblocks = be32_to_cpu(from->sb_logblocks);
+	to->sb_versionnum = be16_to_cpu(from->sb_versionnum);
+	to->sb_sectsize = be16_to_cpu(from->sb_sectsize);
+	to->sb_inodesize = be16_to_cpu(from->sb_inodesize);
+	to->sb_inopblock = be16_to_cpu(from->sb_inopblock);
+	to->sb_blocklog = from->sb_blocklog;
+	to->sb_sectlog = from->sb_sectlog;
+	to->sb_inodelog = from->sb_inodelog;
+	to->sb_inopblog = from->sb_inopblog;
+	to->sb_agblklog = from->sb_agblklog;
+	to->sb_rextslog = from->sb_rextslog;
+	to->sb_inprogress = from->sb_inprogress;
+	to->sb_imax_pct = from->sb_imax_pct;
+	to->sb_icount = be64_to_cpu(from->sb_icount);
+	to->sb_ifree = be64_to_cpu(from->sb_ifree);
+	to->sb_fdblocks = be64_to_cpu(from->sb_fdblocks);
+	to->sb_frextents = be64_to_cpu(from->sb_frextents);
+}
+
+static int xfs_verify_sb(struct xfs_super_block *ondisk)
+{
+	struct xfs_super_block sb, *sbp = &sb;
+
+	/* beXX_to_cpu(), but don't convert UUID and fsname! */
+	sb_from_disk(ondisk, sbp);
+
+	/* sanity checks, we don't want to rely on magic string only */
+	if (sbp->sb_agcount <= 0					||
+	    sbp->sb_sectsize < XFS_MIN_SECTORSIZE			||
+	    sbp->sb_sectsize > XFS_MAX_SECTORSIZE			||
+	    sbp->sb_sectlog < XFS_MIN_SECTORSIZE_LOG			||
+	    sbp->sb_sectlog > XFS_MAX_SECTORSIZE_LOG			||
+	    sbp->sb_sectsize != (1 << sbp->sb_sectlog)			||
+	    sbp->sb_blocksize < XFS_MIN_BLOCKSIZE			||
+	    sbp->sb_blocksize > XFS_MAX_BLOCKSIZE			||
+	    sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG			||
+	    sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG			||
+	    sbp->sb_blocksize != (1 << sbp->sb_blocklog)		||
+	    sbp->sb_inodesize < XFS_DINODE_MIN_SIZE			||
+	    sbp->sb_inodesize > XFS_DINODE_MAX_SIZE			||
+	    sbp->sb_inodelog < XFS_DINODE_MIN_LOG			||
+	    sbp->sb_inodelog > XFS_DINODE_MAX_LOG			||
+	    sbp->sb_inodesize != (1 << sbp->sb_inodelog)		||
+	    (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog)	||
+	    (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE)	||
+	    (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE)	||
+	    (sbp->sb_imax_pct > 100 /* zero sb_imax_pct is valid */)	||
+	    sbp->sb_dblocks == 0					||
+	    sbp->sb_dblocks > XFS_MAX_DBLOCKS(sbp)			||
+	    sbp->sb_dblocks < XFS_MIN_DBLOCKS(sbp))
+		return 0;
+
+	/* TODO: version 5 has also checksum CRC32, maybe we can check it too */
+
+	return 1;
+}
+
+static int probe_xfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct xfs_super_block *xs;
+
+	xs = blkid_probe_get_sb(pr, mag, struct xfs_super_block);
+	if (!xs)
+		return errno ? -errno : 1;
+
+	if (!xfs_verify_sb(xs))
+		return 1;
+
+	if (strlen(xs->sb_fname))
+		blkid_probe_set_label(pr, (unsigned char *) xs->sb_fname,
+				sizeof(xs->sb_fname));
+	blkid_probe_set_uuid(pr, xs->sb_uuid);
+	return 0;
+}
+
+const struct blkid_idinfo xfs_idinfo =
+{
+	.name		= "xfs",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_xfs,
+	.magics		=
+	{
+		{ .magic = "XFSB", .len = 4 },
+		{ NULL }
+	}
+};
+
+struct xlog_rec_header {
+	uint32_t	h_magicno;
+	uint32_t	h_dummy1[1];
+	uint32_t	h_version;
+	uint32_t	h_len;
+	uint32_t	h_dummy2[71];
+	uint32_t	h_fmt;
+	unsigned char	h_uuid[16];
+} __attribute__((packed));
+
+#define XLOG_HEADER_MAGIC_NUM 0xFEEDbabe
+
+/*
+ * For very small filesystems, the minimum log size
+ * can be smaller, but that seems vanishingly unlikely
+ * when used with an external log (which is used for
+ * performance reasons; tiny conflicts with that goal).
+ */
+#define XFS_MIN_LOG_BYTES	(10 * 1024 * 1024)
+
+#define XLOG_FMT_LINUX_LE	1
+#define XLOG_FMT_LINUX_BE	2
+#define XLOG_FMT_IRIX_BE	3
+
+#define XLOG_VERSION_1		1
+#define XLOG_VERSION_2		2	/* Large IClogs, Log sunit */
+#define XLOG_VERSION_OKBITS	(XLOG_VERSION_1 | XLOG_VERSION_2)
+
+static int xlog_valid_rec_header(struct xlog_rec_header *rhead)
+{
+	uint32_t hlen;
+
+	if (rhead->h_magicno != cpu_to_be32(XLOG_HEADER_MAGIC_NUM))
+		return 0;
+
+	if (!rhead->h_version ||
+            (be32_to_cpu(rhead->h_version) & (~XLOG_VERSION_OKBITS)))
+		return 0;
+
+	/* LR body must have data or it wouldn't have been written */
+	hlen = be32_to_cpu(rhead->h_len);
+	if (hlen <= 0 || hlen > INT_MAX)
+		return 0;
+
+	if (rhead->h_fmt != cpu_to_be32(XLOG_FMT_LINUX_LE) &&
+	    rhead->h_fmt != cpu_to_be32(XLOG_FMT_LINUX_BE) &&
+	    rhead->h_fmt != cpu_to_be32(XLOG_FMT_IRIX_BE))
+		return 0;
+
+	return 1;
+}
+
+/* xlog record header will be in some sector in the first 256k */
+static int probe_xfs_log(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	int i;
+	struct xlog_rec_header *rhead;
+	unsigned char *buf;
+
+	buf = blkid_probe_get_buffer(pr, 0, 256*1024);
+	if (!buf)
+		return errno ? -errno : 1;
+
+	if (memcmp(buf, "XFSB", 4) == 0)
+		return 1;			/* this is regular XFS, ignore */
+
+	/* check the first 512 512-byte sectors */
+	for (i = 0; i < 512; i++) {
+		rhead = (struct xlog_rec_header *)&buf[i*512];
+
+		if (xlog_valid_rec_header(rhead)) {
+			blkid_probe_set_uuid_as(pr, rhead->h_uuid, "LOGUUID");
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+const struct blkid_idinfo xfs_log_idinfo =
+{
+	.name		= "xfs_external_log",
+	.usage		= BLKID_USAGE_OTHER,
+	.probefunc	= probe_xfs_log,
+	.magics		= BLKID_NONE_MAGIC,
+	.minsz		= XFS_MIN_LOG_BYTES,
+};
diff --git a/libblkid/zfs.c b/libblkid/src/superblocks/zfs.c
similarity index 92%
rename from libblkid/zfs.c
rename to libblkid/src/superblocks/zfs.c
index b96c5df..86da59d 100644
--- a/libblkid/zfs.c
+++ b/libblkid/src/superblocks/zfs.c
@@ -12,6 +12,7 @@
 #include <errno.h>
 #include <ctype.h>
 #include <inttypes.h>
+#include <limits.h>
 
 #include "superblocks.h"
 
@@ -64,7 +65,7 @@
 };
 
 #define nvdebug(fmt, ...)	do { } while(0)
-/*#define nvdebug(fmt, a...)	printf(fmt, ##a)*/
+/*#define nvdebug(fmt, a...)	fprintf(stderr, fmt, ##a)*/
 
 static void zfs_extract_guid_name(blkid_probe pr, loff_t offset)
 {
@@ -108,6 +109,8 @@
 
 			nvs->nvs_type = be32_to_cpu(nvs->nvs_type);
 			nvs->nvs_strlen = be32_to_cpu(nvs->nvs_strlen);
+			if (nvs->nvs_strlen > UINT_MAX - sizeof(*nvs))
+				break;
 			avail -= nvs->nvs_strlen + sizeof(*nvs);
 			nvdebug("nvstring: type %u string %*s\n", nvs->nvs_type,
 				nvs->nvs_strlen, nvs->nvs_string);
@@ -157,7 +160,7 @@
 }
 
 #define zdebug(fmt, ...)	do {} while(0)
-/*#define zdebug(fmt, a...)	printf(fmt, ##a)*/
+/*#define zdebug(fmt, a...)	fprintf(stderr, fmt, ##a)*/
 
 /* ZFS has 128x1kB host-endian root blocks, stored in 2 areas at the start
  * of the disk, and 2 areas at the end of the disk.  Check only some of them...
@@ -168,7 +171,7 @@
 	uint64_t swab_magic = swab64(UBERBLOCK_MAGIC);
 	struct zfs_uberblock *ub;
 	int swab_endian;
-	loff_t offset;
+	loff_t offset, ub_offset = 0;
 	int tried;
 	int found;
 
@@ -185,20 +188,24 @@
 			blkid_probe_get_buffer(pr, offset,
 					       sizeof(struct zfs_uberblock));
 		if (ub == NULL)
-			return -1;
+			return errno ? -errno : 1;
 
-		if (ub->ub_magic == UBERBLOCK_MAGIC)
+		if (ub->ub_magic == UBERBLOCK_MAGIC) {
+			ub_offset = offset;
 			found++;
+		}
 
-		if ((swab_endian = (ub->ub_magic == swab_magic)))
+		if ((swab_endian = (ub->ub_magic == swab_magic))) {
+			ub_offset = offset;
 			found++;
+		}
 
 		zdebug("probe_zfs: found %s-endian uberblock at %llu\n",
 		       swab_endian ? "big" : "little", offset >> 10);
 	}
 
 	if (found < 4)
-		return -1;
+		return 1;
 
 	/* If we found the 4th uberblock, then we will have exited from the
 	 * scanning loop immediately, and ub will be a valid uberblock. */
@@ -207,10 +214,10 @@
 
 	zfs_extract_guid_name(pr, offset);
 
-	if (blkid_probe_set_magic(pr, offset,
+	if (blkid_probe_set_magic(pr, ub_offset,
 				sizeof(ub->ub_magic),
 				(unsigned char *) &ub->ub_magic))
-		return -1;
+		return 1;
 
 	return 0;
 }
diff --git a/libblkid/sysfs.h b/libblkid/src/sysfs.h
similarity index 85%
copy from libblkid/sysfs.h
copy to libblkid/src/sysfs.h
index 739f9de..1de624a 100644
--- a/libblkid/sysfs.h
+++ b/libblkid/src/sysfs.h
@@ -58,6 +58,9 @@
 extern int sysfs_read_u64(struct sysfs_cxt *cxt, const char *attr, uint64_t *res);
 extern int sysfs_read_int(struct sysfs_cxt *cxt, const char *attr, int *res);
 
+extern int sysfs_write_string(struct sysfs_cxt *cxt, const char *attr, const char *str);
+extern int sysfs_write_u64(struct sysfs_cxt *cxt, const char *attr, uint64_t num);
+
 extern char *sysfs_get_devname(struct sysfs_cxt *cxt, char *buf, size_t bufsiz);
 
 extern char *sysfs_strdup(struct sysfs_cxt *cxt, const char *attr);
@@ -67,12 +70,19 @@
 extern dev_t sysfs_partno_to_devno(struct sysfs_cxt *cxt, int partno);
 extern char *sysfs_get_slave(struct sysfs_cxt *cxt);
 
+extern char *sysfs_get_devchain(struct sysfs_cxt *cxt, char *buf, size_t bufsz);
+extern int sysfs_next_subsystem(struct sysfs_cxt *cxt, char *devchain, char **subsys);
+extern int sysfs_is_hotpluggable(struct sysfs_cxt *cxt);
+
 extern int sysfs_is_partition_dirent(DIR *dir, struct dirent *d,
 			const char *parent_name);
 
 extern int sysfs_devno_to_wholedisk(dev_t dev, char *diskname,
             size_t len, dev_t *diskdevno);
 
+extern int sysfs_devno_is_lvm_private(dev_t devno);
+extern int sysfs_devno_is_wholedisk(dev_t devno);
+
 extern int sysfs_scsi_get_hctl(struct sysfs_cxt *cxt, int *h,
 			       int *c, int *t, int *l);
 extern char *sysfs_scsi_host_strdup_attribute(struct sysfs_cxt *cxt,
diff --git a/libblkid/tag.c b/libblkid/src/tag.c
similarity index 90%
rename from libblkid/tag.c
rename to libblkid/src/tag.c
index 9dbacef..6af8062 100644
--- a/libblkid/tag.c
+++ b/libblkid/src/tag.c
@@ -30,26 +30,24 @@
 	return tag;
 }
 
-#ifdef CONFIG_BLKID_DEBUG
 void blkid_debug_dump_tag(blkid_tag tag)
 {
 	if (!tag) {
-		printf("    tag: NULL\n");
+		fprintf(stderr, "    tag: NULL\n");
 		return;
 	}
 
-	printf("    tag: %s=\"%s\"\n", tag->bit_name, tag->bit_val);
+	fprintf(stderr, "    tag: %s=\"%s\"\n", tag->bit_name, tag->bit_val);
 }
-#endif
 
 void blkid_free_tag(blkid_tag tag)
 {
 	if (!tag)
 		return;
 
-	DBG(DEBUG_TAG, printf("    freeing tag %s=%s\n", tag->bit_name,
+	DBG(TAG, ul_debug("    freeing tag %s=%s", tag->bit_name,
 		   tag->bit_val ? tag->bit_val : "(NULL)"));
-	DBG(DEBUG_TAG, blkid_debug_dump_tag(tag));
+	DBG(TAG, blkid_debug_dump_tag(tag));
 
 	list_del(&tag->bit_tags);	/* list of tags for this device */
 	list_del(&tag->bit_names);	/* list of tags with this type */
@@ -81,7 +79,7 @@
 	return NULL;
 }
 
-extern int blkid_dev_has_tag(blkid_dev dev, const char *type,
+int blkid_dev_has_tag(blkid_dev dev, const char *type,
 			     const char *value)
 {
 	blkid_tag		tag;
@@ -109,8 +107,7 @@
 	list_for_each(p, &cache->bic_tags) {
 		tmp = list_entry(p, struct blkid_struct_tag, bit_tags);
 		if (!strcmp(tmp->bit_name, type)) {
-			DBG(DEBUG_TAG,
-			    printf("    found cache tag head %s\n", type));
+			DBG(TAG, ul_debug("    found cache tag head %s", type));
 			head = tmp;
 			break;
 		}
@@ -178,8 +175,7 @@
 				if (!head)
 					goto errout;
 
-				DBG(DEBUG_TAG,
-				    printf("    creating new cache tag head %s\n", name));
+				DBG(TAG, ul_debug("    creating new cache tag head %s", name));
 				head->bit_name = name ? strdup(name) : NULL;
 				if (!head->bit_name)
 					goto errout;
@@ -223,7 +219,7 @@
 {
 	char *name, *value, *cp;
 
-	DBG(DEBUG_TAG, printf("trying to parse '%s' as a tag\n", token));
+	DBG(TAG, ul_debug("trying to parse '%s' as a tag", token));
 
 	if (!token || !(cp = strchr(token, '=')))
 		return -1;
@@ -239,19 +235,23 @@
 			goto errout; /* missing closing quote */
 		*cp = '\0';
 	}
-	if (value && *value)
-		value = strdup(value);
-	if (!value)
-		goto errout;
+
+	if (ret_val) {
+		value = value && *value ? strdup(value) : NULL;
+		if (!value)
+			goto errout;
+		*ret_val = value;
+	}
 
 	if (ret_type)
 		*ret_type = name;
-	if (ret_val)
-		*ret_val = value;
+	else
+		free(name);
 
 	return 0;
 
 errout:
+	DBG(TAG, ul_debug("parse error: '%s'", token));
 	free(name);
 	return -1;
 }
@@ -279,10 +279,15 @@
 	struct list_head	*p;
 };
 
-extern blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev)
+blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev)
 {
 	blkid_tag_iterate	iter;
 
+	if (!dev) {
+		errno = EINVAL;
+		return NULL;
+	}
+
 	iter = malloc(sizeof(struct blkid_struct_tag_iterate));
 	if (iter) {
 		iter->magic = TAG_ITERATE_MAGIC;
@@ -295,7 +300,7 @@
 /*
  * Return 0 on success, -1 on error
  */
-extern int blkid_tag_next(blkid_tag_iterate iter,
+int blkid_tag_next(blkid_tag_iterate iter,
 			  const char **type, const char **value)
 {
 	blkid_tag tag;
@@ -314,7 +319,7 @@
 	return 0;
 }
 
-extern void blkid_tag_iterate_end(blkid_tag_iterate iter)
+void blkid_tag_iterate_end(blkid_tag_iterate iter)
 {
 	if (!iter || iter->magic != TAG_ITERATE_MAGIC)
 		return;
@@ -328,7 +333,7 @@
  * search specification, it returns the one with the highest priority
  * value.  This allows us to give preference to EVMS or LVM devices.
  */
-extern blkid_dev blkid_find_dev_with_tag(blkid_cache cache,
+blkid_dev blkid_find_dev_with_tag(blkid_cache cache,
 					 const char *type,
 					 const char *value)
 {
@@ -343,7 +348,7 @@
 
 	blkid_read_cache(cache);
 
-	DBG(DEBUG_TAG, printf("looking for %s=%s in cache\n", type, value));
+	DBG(TAG, ul_debug("looking for %s=%s in cache", type, value));
 
 try_again:
 	pri = -1;
diff --git a/libblkid/dm.c b/libblkid/src/topology/dm.c
similarity index 90%
rename from libblkid/dm.c
rename to libblkid/src/topology/dm.c
index 72ec9bd..e061632 100644
--- a/libblkid/dm.c
+++ b/libblkid/src/topology/dm.c
@@ -57,8 +57,7 @@
 	if (!cmd)
 		goto nothing;
 	if (pipe(dmpipe) < 0) {
-		DBG(DEBUG_LOWPROBE,
-			printf("Failed to open pipe: errno=%d", errno));
+		DBG(LOWPROBE, ul_debug("Failed to open pipe: errno=%d", errno));
 		goto nothing;
 	}
 
@@ -92,19 +91,17 @@
 
 		execv(dmargv[0], dmargv);
 
-		DBG(DEBUG_LOWPROBE,
-			printf("Failed to execute %s: errno=%d", cmd, errno));
+		DBG(LOWPROBE, ul_debug("Failed to execute %s: errno=%d", cmd, errno));
 		exit(1);
 	}
 	case -1:
-		DBG(DEBUG_LOWPROBE,
-			printf("Failed to forking: errno=%d", errno));
+		DBG(LOWPROBE, ul_debug("Failed to forking: errno=%d", errno));
 		goto nothing;
 	default:
 		break;
 	}
 
-	stream = fdopen(dmpipe[0], "r");
+	stream = fdopen(dmpipe[0], "r" UL_CLOEXECSTR);
 	if (!stream)
 		goto nothing;
 
diff --git a/libblkid/evms.c b/libblkid/src/topology/evms.c
similarity index 100%
rename from libblkid/evms.c
rename to libblkid/src/topology/evms.c
diff --git a/libblkid/ioctl.c b/libblkid/src/topology/ioctl.c
similarity index 100%
rename from libblkid/ioctl.c
rename to libblkid/src/topology/ioctl.c
diff --git a/libblkid/lvm1.c b/libblkid/src/topology/lvm.c
similarity index 90%
rename from libblkid/lvm1.c
rename to libblkid/src/topology/lvm.c
index 632c42b..bd079d4 100644
--- a/libblkid/lvm1.c
+++ b/libblkid/src/topology/lvm.c
@@ -67,8 +67,7 @@
 		goto nothing;
 
 	if (pipe(lvpipe) < 0) {
-		DBG(DEBUG_LOWPROBE,
-			printf("Failed to open pipe: errno=%d", errno));
+		DBG(LOWPROBE, ul_debug("Failed to open pipe: errno=%d", errno));
 		goto nothing;
 	}
 
@@ -95,19 +94,17 @@
 
 		execv(lvargv[0], lvargv);
 
-		DBG(DEBUG_LOWPROBE,
-			printf("Failed to execute %s: errno=%d", cmd, errno));
+		DBG(LOWPROBE, ul_debug("Failed to execute %s: errno=%d", cmd, errno));
 		exit(1);
 	}
 	case -1:
-		DBG(DEBUG_LOWPROBE,
-			printf("Failed to forking: errno=%d", errno));
+		DBG(LOWPROBE, ul_debug("Failed to forking: errno=%d", errno));
 		goto nothing;
 	default:
 		break;
 	}
 
-	stream = fdopen(lvpipe[0], "r");
+	stream = fdopen(lvpipe[0], "r" UL_CLOEXECSTR);
 	if (!stream)
 		goto nothing;
 
diff --git a/libblkid/md.c b/libblkid/src/topology/md.c
similarity index 100%
rename from libblkid/md.c
rename to libblkid/src/topology/md.c
diff --git a/libblkid/sysfs2.c b/libblkid/src/topology/sysfs.c
similarity index 100%
rename from libblkid/sysfs2.c
rename to libblkid/src/topology/sysfs.c
diff --git a/libblkid/topology.c b/libblkid/src/topology/topology.c
similarity index 94%
rename from libblkid/topology.c
rename to libblkid/src/topology/topology.c
index 9d4e7bd..93fa380 100644
--- a/libblkid/topology.c
+++ b/libblkid/src/topology/topology.c
@@ -150,10 +150,10 @@
 		return -1;
 
 	if (!S_ISBLK(pr->mode))
-		return -1;	/* nothing, works with block devices only */
+		return -EINVAL;	/* nothing, works with block devices only */
 
 	if (chn->binary) {
-		DBG(DEBUG_LOWPROBE, printf("initialize topology binary data\n"));
+		DBG(LOWPROBE, ul_debug("initialize topology binary data"));
 
 		if (chn->data)
 			/* reset binary data */
@@ -163,14 +163,13 @@
 			chn->data = calloc(1,
 					sizeof(struct blkid_struct_topology));
 			if (!chn->data)
-				return -1;
+				return -ENOMEM;
 		}
 	}
 
 	blkid_probe_chain_reset_vals(pr, chn);
 
-	DBG(DEBUG_LOWPROBE,
-		printf("--> starting probing loop [TOPOLOGY idx=%d]\n",
+	DBG(LOWPROBE, ul_debug("--> starting probing loop [TOPOLOGY idx=%d]",
 		chn->idx));
 
 	i = chn->idx < 0 ? 0 : chn->idx + 1U;
@@ -181,8 +180,7 @@
 		chn->idx = i;
 
 		if (id->probefunc) {
-			DBG(DEBUG_LOWPROBE, printf(
-				"%s: call probefunc()\n", id->name));
+			DBG(LOWPROBE, ul_debug("%s: call probefunc()", id->name));
 			if (id->probefunc(pr, NULL) != 0)
 				continue;
 		}
@@ -193,16 +191,14 @@
 		/* generic for all probing drivers */
 		topology_set_logical_sector_size(pr);
 
-		DBG(DEBUG_LOWPROBE,
-			printf("<-- leaving probing loop (type=%s) [TOPOLOGY idx=%d]\n",
+		DBG(LOWPROBE, ul_debug("<-- leaving probing loop (type=%s) [TOPOLOGY idx=%d]",
 			id->name, chn->idx));
-		return 0;
+		return BLKID_PROBE_OK;
 	}
 
-	DBG(DEBUG_LOWPROBE,
-		printf("<-- leaving probing loop (failed) [TOPOLOGY idx=%d]\n",
+	DBG(LOWPROBE, ul_debug("<-- leaving probing loop (failed) [TOPOLOGY idx=%d]",
 		chn->idx));
-	return 1;
+	return BLKID_PROBE_NONE;
 }
 
 static void topology_free(blkid_probe pr __attribute__((__unused__)),
diff --git a/libblkid/topology.h b/libblkid/src/topology/topology.h
similarity index 100%
rename from libblkid/topology.h
rename to libblkid/src/topology/topology.h
diff --git a/libblkid/verify.c b/libblkid/src/verify.c
similarity index 88%
rename from libblkid/verify.c
rename to libblkid/src/verify.c
index bd756e7..06f6d53 100644
--- a/libblkid/verify.c
+++ b/libblkid/src/verify.c
@@ -19,7 +19,9 @@
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
 #endif
+
 #include "blkidP.h"
+#include "sysfs.h"
 
 static void blkid_probe_to_tags(blkid_probe pr, blkid_dev dev)
 {
@@ -71,14 +73,13 @@
 	diff = now - dev->bid_time;
 
 	if (stat(dev->bid_name, &st) < 0) {
-		DBG(DEBUG_PROBE,
-		    printf("blkid_verify: error %m (%d) while "
-			   "trying to stat %s\n", errno,
+		DBG(PROBE, ul_debug("blkid_verify: error %m (%d) while "
+			   "trying to stat %s", errno,
 			   dev->bid_name));
 	open_err:
 		if ((errno == EPERM) || (errno == EACCES) || (errno == ENOENT)) {
 			/* We don't have read permission, just return cache data. */
-			DBG(DEBUG_PROBE, printf("returning unverified data for %s\n",
+			DBG(PROBE, ul_debug("returning unverified data for %s",
 						dev->bid_name));
 			return dev;
 		}
@@ -100,21 +101,23 @@
 		return dev;
 
 #ifndef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
-	DBG(DEBUG_PROBE,
-	    printf("need to revalidate %s (cache time %lu, stat time %lu,\n\t"
-		   "time since last check %lu)\n",
+	DBG(PROBE, ul_debug("need to revalidate %s (cache time %lu, stat time %lu,\t"
+		   "time since last check %lu)",
 		   dev->bid_name, (unsigned long)dev->bid_time,
 		   (unsigned long)st.st_mtime, (unsigned long)diff));
 #else
-	DBG(DEBUG_PROBE,
-	    printf("need to revalidate %s (cache time %lu.%lu, stat time %lu.%lu,\n\t"
-		   "time since last check %lu)\n",
+	DBG(PROBE, ul_debug("need to revalidate %s (cache time %lu.%lu, stat time %lu.%lu,\t"
+		   "time since last check %lu)",
 		   dev->bid_name,
 		   (unsigned long)dev->bid_time, (unsigned long)dev->bid_utime,
 		   (unsigned long)st.st_mtime, (unsigned long)st.st_mtim.tv_nsec / 1000,
 		   (unsigned long)diff));
 #endif
 
+	if (sysfs_devno_is_lvm_private(st.st_rdev)) {
+		blkid_free_dev(dev);
+		return NULL;
+	}
 	if (!cache->probe) {
 		cache->probe = blkid_new_probe();
 		if (!cache->probe) {
@@ -125,8 +128,8 @@
 
 	fd = open(dev->bid_name, O_RDONLY|O_CLOEXEC);
 	if (fd < 0) {
-		DBG(DEBUG_PROBE, printf("blkid_verify: error %m (%d) while "
-					"opening %s\n", errno,
+		DBG(PROBE, ul_debug("blkid_verify: error %m (%d) while "
+					"opening %s", errno,
 					dev->bid_name));
 		goto open_err;
 	}
@@ -177,7 +180,7 @@
 
 		blkid_probe_to_tags(cache->probe, dev);
 
-		DBG(DEBUG_PROBE, printf("%s: devno 0x%04llx, type %s\n",
+		DBG(PROBE, ul_debug("%s: devno 0x%04llx, type %s",
 			   dev->bid_name, (long long)st.st_rdev, dev->bid_type));
 	}
 
diff --git a/libblkid/version.c b/libblkid/src/version.c
similarity index 96%
rename from libblkid/version.c
rename to libblkid/src/version.c
index 9659b4c..9d129f7 100644
--- a/libblkid/version.c
+++ b/libblkid/src/version.c
@@ -16,8 +16,7 @@
 #include <stdio.h>
 #include <ctype.h>
 
-#include "blkid.h"
-#include "config.h"
+#include <blkid.h>
 
 /* LIBBLKID_* defined in the global config.h */
 static const char *lib_version = LIBBLKID_VERSION;	/* release version */
diff --git a/libblkid/widechar.h b/libblkid/src/widechar.h
similarity index 100%
rename from libblkid/widechar.h
rename to libblkid/src/widechar.h
diff --git a/libblkid/xalloc.h b/libblkid/src/xalloc.h
similarity index 71%
copy from libblkid/xalloc.h
copy to libblkid/src/xalloc.h
index 7b685e7..f012fb2 100644
--- a/libblkid/xalloc.h
+++ b/libblkid/src/xalloc.h
@@ -49,7 +49,7 @@
         return ret;
 }
 
-static inline char *xstrdup(const char *str)
+static inline char __attribute__((warn_unused_result)) *xstrdup(const char *str)
 {
         char *ret;
 
@@ -63,6 +63,21 @@
         return ret;
 }
 
+static inline char * __attribute__((warn_unused_result)) xstrndup(const char *str, size_t size)
+{
+        char *ret;
+
+        if (!str)
+                return NULL;
+
+        ret = strndup(str, size);
+
+        if (!ret)
+                err(XALLOC_EXIT_CODE, "cannot duplicate string");
+        return ret;
+}
+
+
 static inline int __attribute__ ((__format__(printf, 2, 3)))
     xasprintf(char **strp, const char *fmt, ...)
 {
@@ -76,16 +91,26 @@
 	return ret;
 }
 
+static inline int xvasprintf(char **strp, const char *fmt, va_list ap)
+{
+	int ret = vasprintf(&(*strp), fmt, ap);
+	if (ret < 0)
+		err(XALLOC_EXIT_CODE, "cannot allocate string");
+	return ret;
+}
 
-static inline char *xgethostname(void)
+
+static inline char * __attribute__((warn_unused_result)) xgethostname(void)
 {
 	char *name;
 	size_t sz = get_hostname_max() + 1;
 
 	name = xmalloc(sizeof(char) * sz);
-	if (gethostname(name, sz) != 0)
-		return NULL;
 
+	if (gethostname(name, sz) != 0) {
+		free(name);
+		return NULL;
+	}
 	name[sz - 1] = '\0';
 	return name;
 }
diff --git a/libblkid/strutils.h b/libblkid/strutils.h
deleted file mode 100644
index 00598cf..0000000
--- a/libblkid/strutils.h
+++ /dev/null
@@ -1,79 +0,0 @@
-#ifndef UTIL_LINUX_STRUTILS
-#define UTIL_LINUX_STRUTILS
-
-#include <inttypes.h>
-#include <string.h>
-#include <sys/types.h>
-
-/* default strtoxx_or_err() exit code */
-#ifndef STRTOXX_EXIT_CODE
-# define STRTOXX_EXIT_CODE EXIT_FAILURE
-#endif
-
-
-extern int strtosize(const char *str, uintmax_t *res);
-extern uintmax_t strtosize_or_err(const char *str, const char *errmesg);
-
-extern int16_t strtos16_or_err(const char *str, const char *errmesg);
-extern uint16_t strtou16_or_err(const char *str, const char *errmesg);
-
-extern int32_t strtos32_or_err(const char *str, const char *errmesg);
-extern uint32_t strtou32_or_err(const char *str, const char *errmesg);
-
-extern int64_t strtos64_or_err(const char *str, const char *errmesg);
-extern uint64_t strtou64_or_err(const char *str, const char *errmesg);
-
-extern double strtod_or_err(const char *str, const char *errmesg);
-
-extern long strtol_or_err(const char *str, const char *errmesg);
-extern unsigned long strtoul_or_err(const char *str, const char *errmesg);
-
-#ifndef HAVE_MEMPCPY
-extern void *mempcpy(void *restrict dest, const void *restrict src, size_t n);
-#endif
-#ifndef HAVE_STRNLEN
-extern size_t strnlen(const char *s, size_t maxlen);
-#endif
-#ifndef HAVE_STRNDUP
-extern char *strndup(const char *s, size_t n);
-#endif
-#ifndef HAVE_STRNCHR
-extern char *strnchr(const char *s, size_t maxlen, int c);
-#endif
-
-/* caller guarantees n > 0 */
-static inline void xstrncpy(char *dest, const char *src, size_t n)
-{
-	strncpy(dest, src, n-1);
-	dest[n-1] = 0;
-}
-
-extern void strmode(mode_t mode, char *str);
-
-/* Options for size_to_human_string() */
-enum
-{
-        SIZE_SUFFIX_1LETTER = 0,
-        SIZE_SUFFIX_3LETTER = 1,
-        SIZE_SUFFIX_SPACE   = 2
-};
-
-extern char *size_to_human_string(int options, uint64_t bytes);
-
-extern int string_to_idarray(const char *list, int ary[], size_t arysz,
-			   int (name2id)(const char *, size_t));
-extern int string_add_to_idarray(const char *list, int ary[],
-				 size_t arysz, int *ary_pos,
-				 int (name2id)(const char *, size_t));
-
-extern int string_to_bitarray(const char *list, char *ary,
-			    int (*name2bit)(const char *, size_t));
-
-extern int string_to_bitmask(const char *list,
-			     unsigned long *mask,
-			     long (*name2flag)(const char *, size_t));
-extern int parse_range(const char *str, int *lower, int *upper, int def);
-
-extern int streq_except_trailing_slash(const char *s1, const char *s2);
-
-#endif
diff --git a/libblkid/sun.c b/libblkid/sun.c
deleted file mode 100644
index f151f46..0000000
--- a/libblkid/sun.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * sun (solaris-sparc) partition parsing code
- *
- * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
- *
- * This file may be redistributed under the terms of the
- * GNU Lesser General Public License.
- */
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <stddef.h>
-
-#include "partitions.h"
-
-/* Supported VTOC setting */
-#define SUN_VTOC_SANITY		0x600DDEEE	/* magic number */
-#define SUN_VTOC_VERSION	1
-
-#define SUN_MAXPARTITIONS	8
-
-/* Partition IDs */
-#define SUN_TAG_WHOLEDISK          0x05
-
-struct sun_disklabel {
-	unsigned char info[128];   /* Informative text string */
-
-	struct sun_vtoc {
-		uint32_t version;     /* version */
-		char	 volume[8];   /* volume name */
-		uint16_t nparts;      /* num of partitions */
-
-		struct sun_info {     /* partition information */
-			uint16_t id;  /* tag */
-			uint16_t flags;
-		} __attribute__ ((packed)) infos[8];
-
-		uint16_t padding;      /* padding */
-		uint32_t bootinfo[3];  /* info needed by mboot */
-		uint32_t sanity;       /* magic number */
-		uint32_t reserved[10]; /* padding */
-		uint32_t timestamp[8]; /* partition timestamp */
-	} __attribute__ ((packed)) vtoc;
-
-	uint32_t write_reinstruct;     /* sectors to skip, writes */
-	uint32_t read_reinstruct;      /* sectors to skip, reads */
-	unsigned char spare[148];      /* padding */
-	uint16_t rspeed;               /* disk rotational speed */
-	uint16_t pcylcount;            /* physical cylinder count */
-	uint16_t sparecyl;             /* extra sects per cylinder */
-	uint16_t obs1;
-	uint16_t obs2;
-	uint16_t ilfact;               /* interleave factor */
-	uint16_t ncyl;                 /* data cylinder count */
-	uint16_t nacyl;                /* alt. cylinder count */
-	uint16_t ntrks;                /* tracks per cylinder   <---- */
-	uint16_t nsect;                /* sectors per track     <---- */
-	uint16_t obs3;
-	uint16_t obs4;
-
-	struct sun_partition {         /* partitions */
-		uint32_t start_cylinder;
-		uint32_t num_sectors;
-	} __attribute__ ((packed)) partitions[8];
-
-	uint16_t magic;                /* magic number */
-	uint16_t csum;                 /* label xor'd checksum */
-} __attribute__ ((packed));
-
-
-uint16_t count_checksum(struct sun_disklabel *label)
-{
-	uint16_t *ptr = ((uint16_t *) (label + 1)) - 1;
-	uint16_t sum;
-
-	for (sum = 0; ptr >= ((uint16_t *) label);)
-		sum ^= *ptr--;
-
-	return sum;
-}
-
-static int probe_sun_pt(blkid_probe pr,
-		const struct blkid_idmag *mag __attribute__((__unused__)))
-{
-	struct sun_disklabel *l;
-	struct sun_partition *p;
-	blkid_parttable tab = NULL;
-	blkid_partlist ls;
-	uint16_t nparts;
-	blkid_loff_t spc;
-	int i, use_vtoc;
-
-	l = (struct sun_disklabel *) blkid_probe_get_sector(pr, 0);
-	if (!l)
-		goto nothing;
-
-	if (count_checksum(l)) {
-		DBG(DEBUG_LOWPROBE, printf(
-			"detected corrupted sun disk label -- ignore\n"));
-		goto nothing;
-	}
-
-	if (blkid_partitions_need_typeonly(pr))
-		/* caller does not ask for details about partitions */
-		return 0;
-
-	ls = blkid_probe_get_partlist(pr);
-	if (!ls)
-		goto err;
-
-	tab = blkid_partlist_new_parttable(ls, "sun", 0);
-	if (!tab)
-		goto err;
-
-	/* sectors per cylinder (partition offset is in cylinders...) */
-	spc = be16_to_cpu(l->ntrks) * be16_to_cpu(l->nsect);
-
-	DBG(DEBUG_LOWPROBE,
-		printf("Sun VTOC sanity=%u version=%u nparts=%u\n",
-			be32_to_cpu(l->vtoc.sanity),
-			be32_to_cpu(l->vtoc.version),
-			be16_to_cpu(l->vtoc.nparts)));
-
-	/* Check to see if we can use the VTOC table */
-	use_vtoc = ((be32_to_cpu(l->vtoc.sanity) == SUN_VTOC_SANITY) &&
-		    (be32_to_cpu(l->vtoc.version) == SUN_VTOC_VERSION) &&
-		    (be16_to_cpu(l->vtoc.nparts) <= SUN_MAXPARTITIONS));
-
-	/* Use 8 partition entries if not specified in validated VTOC */
-	nparts = use_vtoc ? be16_to_cpu(l->vtoc.nparts) : SUN_MAXPARTITIONS;
-
-	/*
-	 * So that old Linux-Sun partitions continue to work,
-	 * alow the VTOC to be used under the additional condition ...
-	 */
-	use_vtoc = use_vtoc || !(l->vtoc.sanity || l->vtoc.version || l->vtoc.nparts);
-
-	for (i = 0, p = l->partitions; i < nparts; i++, p++) {
-
-		blkid_loff_t start, size;
-		uint16_t type = 0, flags = 0;
-		blkid_partition par;
-
-                start = be32_to_cpu(p->start_cylinder) * spc;
-		size = be32_to_cpu(p->num_sectors);
-		if (use_vtoc) {
-			type = be16_to_cpu(l->vtoc.infos[i].id);
-			flags = be16_to_cpu(l->vtoc.infos[i].flags);
-		}
-
-		if (type == SUN_TAG_WHOLEDISK || !size) {
-			blkid_partlist_increment_partno(ls);
-			continue;
-		}
-		par = blkid_partlist_add_partition(ls, tab, start, size);
-		if (!par)
-			goto err;
-
-		if (type)
-			blkid_partition_set_type(par, type);
-		if (flags)
-			blkid_partition_set_flags(par, flags);
-	}
-	return 0;
-
-nothing:
-	return 1;
-err:
-	return -1;
-}
-
-
-const struct blkid_idinfo sun_pt_idinfo =
-{
-	.name		= "sun",
-	.probefunc	= probe_sun_pt,
-	.magics		=
-	{
-		{
-		  .magic = "\xDA\xBE",		/* big-endian magic string */
-		  .len = 2,
-		  .sboff = offsetof(struct sun_disklabel, magic)
-		},
-		{ NULL }
-	}
-};
-
diff --git a/libblkid/swapheader.h b/libblkid/swapheader.h
deleted file mode 100644
index 42d521a..0000000
--- a/libblkid/swapheader.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef _SWAPHEADER_H
-#define _SWAPHEADER_H
-
-struct swap_header_v1 {
-        char         bootbits[1024];    /* Space for disklabel etc. */
-	unsigned int version;
-	unsigned int last_page;
-	unsigned int nr_badpages;
-	unsigned int padding[125];
-	unsigned int badpages[1];
-};
-
-
-#define SWAP_UUID_LENGTH 16
-#define SWAP_LABEL_LENGTH 16
-
-struct swap_header_v1_2 {
-	char	      bootbits[1024];    /* Space for disklabel etc. */
-	unsigned int  version;
-	unsigned int  last_page;
-	unsigned int  nr_badpages;
-	unsigned char uuid[SWAP_UUID_LENGTH];
-	char	      volume_name[SWAP_LABEL_LENGTH];
-	unsigned int  padding[117];
-	unsigned int  badpages[1];
-};
-
-#endif /* _SWAPHEADER_H */
diff --git a/libblkid/tt.c b/libblkid/tt.c
deleted file mode 100644
index cbe4e3b..0000000
--- a/libblkid/tt.c
+++ /dev/null
@@ -1,1005 +0,0 @@
-/*
- * TT - Table or Tree, features:
- * - column width could be defined as absolute or relative to the terminal width
- * - allows to truncate or wrap data in columns
- * - prints tree if parent->child relation is defined
- * - draws the tree by ASCII or UTF8 lines (depends on terminal setting)
- *
- * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
- *
- * This file may be redistributed under the terms of the
- * GNU Lesser General Public License.
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <termios.h>
-#include <ctype.h>
-
-#include "c.h"
-#include "nls.h"
-#include "widechar.h"
-#include "tt.h"
-#include "mbsalign.h"
-#include "ttyutils.h"
-
-struct tt_symbols {
-	const char *branch;
-	const char *vert;
-	const char *right;
-};
-
-static const struct tt_symbols ascii_tt_symbols = {
-	.branch = "|-",
-	.vert	= "| ",
-	.right	= "`-",
-};
-
-#ifdef HAVE_WIDECHAR
-#define UTF_V	"\342\224\202"	/* U+2502, Vertical line drawing char */
-#define UTF_VR	"\342\224\234"	/* U+251C, Vertical and right */
-#define UTF_H	"\342\224\200"	/* U+2500, Horizontal */
-#define UTF_UR	"\342\224\224"	/* U+2514, Up and right */
-
-static const struct tt_symbols utf8_tt_symbols = {
-	.branch = UTF_VR UTF_H,
-	.vert   = UTF_V " ",
-	.right	= UTF_UR UTF_H,
-};
-#endif /* !HAVE_WIDECHAR */
-
-#define is_last_column(_tb, _cl) \
-		list_entry_is_last(&(_cl)->cl_columns, &(_tb)->tb_columns)
-
-/*
- * Counts number of cells in multibyte string. For all control and
- * non-printable chars is the result width enlarged to store \x?? hex
- * sequence. See mbs_safe_encode().
- */
-static size_t mbs_safe_width(const char *s)
-{
-	mbstate_t st;
-	const char *p = s;
-	size_t width = 0;
-
-	memset(&st, 0, sizeof(st));
-
-	while (p && *p) {
-		if (iscntrl((unsigned char) *p)) {
-			width += 4;			/* *p encoded to \x?? */
-			p++;
-		}
-#ifdef HAVE_WIDECHAR
-		else {
-			wchar_t wc;
-			size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st);
-
-			if (len == 0)
-				break;
-
-			if (len == (size_t) -1 || len == (size_t) -2) {
-				len = 1;
-				width += (isprint((unsigned char) *p) ? 1 : 4);
-
-			} if (!iswprint(wc))
-				width += len * 4;	/* hex encode whole sequence */
-			else
-				width += wcwidth(wc);	/* number of cells */
-			p += len;
-		}
-#else
-		else if (!isprint((unsigned char) *p)) {
-			width += 4;			/* *p encoded to \x?? */
-			p++;
-		} else {
-			width++;
-			p++;
-		}
-#endif
-	}
-
-	return width;
-}
-
-/*
- * Returns allocated string where all control and non-printable chars are
- * replaced with \x?? hex sequence.
- */
-static char *mbs_safe_encode(const char *s, size_t *width)
-{
-	mbstate_t st;
-	const char *p = s;
-	char *res, *r;
-	size_t sz = s ? strlen(s) : 0;
-
-
-	if (!sz)
-		return NULL;
-
-	memset(&st, 0, sizeof(st));
-
-	res = malloc((sz * 4) + 1);
-	if (!res)
-		return NULL;
-
-	r = res;
-	*width = 0;
-
-	while (p && *p) {
-		if (iscntrl((unsigned char) *p)) {
-			sprintf(r, "\\x%02x", (unsigned char) *p);
-			r += 4;
-			*width += 4;
-			p++;
-		}
-#ifdef HAVE_WIDECHAR
-		else {
-			wchar_t wc;
-			size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st);
-
-			if (len == 0)
-				break;		/* end of string */
-
-			if (len == (size_t) -1 || len == (size_t) -2) {
-				len = 1;
-				/*
-				 * Not valid multibyte sequence -- maybe it's
-				 * printable char according to the current locales.
-				 */
-				if (!isprint((unsigned char) *p)) {
-					sprintf(r, "\\x%02x", (unsigned char) *p);
-					r += 4;
-					*width += 4;
-				} else {
-					width++;
-					*r++ = *p;
-				}
-			} else if (!iswprint(wc)) {
-				size_t i;
-				for (i = 0; i < len; i++) {
-					sprintf(r, "\\x%02x", (unsigned char) *p);
-					r += 4;
-					*width += 4;
-				}
-			} else {
-				memcpy(r, p, len);
-				r += len;
-				*width += wcwidth(wc);
-			}
-			p += len;
-		}
-#else
-		else if (!isprint((unsigned char) *p)) {
-			sprintf(r, "\\x%02x", (unsigned char) *p);
-			p++;
-			r += 4;
-			*width += 4;
-		} else {
-			*r++ = *p++;
-			*width++;
-		}
-#endif
-	}
-
-	*r = '\0';
-
-	return res;
-}
-
-/*
- * @flags: TT_FL_* flags (usually TT_FL_{ASCII,RAW})
- *
- * Returns: newly allocated table
- */
-struct tt *tt_new_table(int flags)
-{
-	struct tt *tb;
-
-	tb = calloc(1, sizeof(struct tt));
-	if (!tb)
-		return NULL;
-
-	tb->flags = flags;
-	INIT_LIST_HEAD(&tb->tb_lines);
-	INIT_LIST_HEAD(&tb->tb_columns);
-
-#if defined(HAVE_WIDECHAR)
-	if (!(flags & TT_FL_ASCII) && !strcmp(nl_langinfo(CODESET), "UTF-8"))
-		tb->symbols = &utf8_tt_symbols;
-	else
-#endif
-		tb->symbols = &ascii_tt_symbols;
-
-	tb->first_run = TRUE;
-	return tb;
-}
-
-void tt_remove_lines(struct tt *tb)
-{
-	if (!tb)
-		return;
-
-	while (!list_empty(&tb->tb_lines)) {
-		struct tt_line *ln = list_entry(tb->tb_lines.next,
-						struct tt_line, ln_lines);
-		list_del(&ln->ln_lines);
-		free(ln->data);
-		free(ln);
-	}
-}
-
-void tt_free_table(struct tt *tb)
-{
-	if (!tb)
-		return;
-
-	tt_remove_lines(tb);
-
-	while (!list_empty(&tb->tb_columns)) {
-		struct tt_column *cl = list_entry(tb->tb_columns.next,
-						struct tt_column, cl_columns);
-		list_del(&cl->cl_columns);
-		free(cl);
-	}
-	free(tb);
-}
-
-
-/*
- * @tb: table
- * @name: column header
- * @whint: column width hint (absolute width: N > 1; relative width: N < 1)
- * @flags: usually TT_FL_{TREE,TRUNCATE}
- *
- * The column width is possible to define by three ways:
- *
- *  @whint = 0..1    : relative width, percent of terminal width
- *
- *  @whint = 1..N    : absolute width, empty colum will be truncated to
- *                     the column header width
- *
- *  @whint = 1..N
- *  @flags = TT_FL_STRICTWIDTH
- *                   : absolute width, empty colum won't be truncated
- *
- * The column is necessary to address (for example for tt_line_set_data()) by
- * sequential number. The first defined column has the colnum = 0. For example:
- *
- *	tt_define_column(tab, "FOO", 0.5, 0);		// colnum = 0
- *	tt_define_column(tab, "BAR", 0.5, 0);		// colnum = 1
- *      .
- *      .
- *	tt_line_set_data(line, 0, "foo-data");		// FOO column
- *	tt_line_set_data(line, 1, "bar-data");		// BAR column
- *
- * Returns: newly allocated column definition
- */
-struct tt_column *tt_define_column(struct tt *tb, const char *name,
-					double whint, int flags)
-{
-	struct tt_column *cl;
-
-	if (!tb)
-		return NULL;
-	cl = calloc(1, sizeof(*cl));
-	if (!cl)
-		return NULL;
-
-	cl->name = name;
-	cl->width_hint = whint;
-	cl->flags = flags;
-	cl->seqnum = tb->ncols++;
-
-	if (flags & TT_FL_TREE)
-		tb->flags |= TT_FL_TREE;
-
-	INIT_LIST_HEAD(&cl->cl_columns);
-	list_add_tail(&cl->cl_columns, &tb->tb_columns);
-	return cl;
-}
-
-/*
- * @tb: table
- * @parent: parental line or NULL
- *
- * Returns: newly allocate line
- */
-struct tt_line *tt_add_line(struct tt *tb, struct tt_line *parent)
-{
-	struct tt_line *ln = NULL;
-
-	if (!tb || !tb->ncols)
-		goto err;
-	ln = calloc(1, sizeof(*ln));
-	if (!ln)
-		goto err;
-	ln->data = calloc(tb->ncols, sizeof(char *));
-	if (!ln->data)
-		goto err;
-
-	ln->table = tb;
-	ln->parent = parent;
-	INIT_LIST_HEAD(&ln->ln_lines);
-	INIT_LIST_HEAD(&ln->ln_children);
-	INIT_LIST_HEAD(&ln->ln_branch);
-
-	list_add_tail(&ln->ln_lines, &tb->tb_lines);
-
-	if (parent)
-		list_add_tail(&ln->ln_children, &parent->ln_branch);
-	return ln;
-err:
-	free(ln);
-	return NULL;
-}
-
-/*
- * @tb: table
- * @colnum: number of column (0..N)
- *
- * Returns: pointer to column or NULL
- */
-struct tt_column *tt_get_column(struct tt *tb, size_t colnum)
-{
-	struct list_head *p;
-
-	list_for_each(p, &tb->tb_columns) {
-		struct tt_column *cl =
-				list_entry(p, struct tt_column, cl_columns);
-		if (cl->seqnum == colnum)
-			return cl;
-	}
-	return NULL;
-}
-
-/*
- * @ln: line
- * @colnum: number of column (0..N)
- * @data: printable data
- *
- * Stores data that will be printed to the table cell.
- */
-int tt_line_set_data(struct tt_line *ln, int colnum, const char *data)
-{
-	struct tt_column *cl;
-
-	if (!ln)
-		return -1;
-	cl = tt_get_column(ln->table, colnum);
-	if (!cl)
-		return -1;
-
-	if (ln->data[cl->seqnum]) {
-		size_t sz = strlen(ln->data[cl->seqnum]);;
-		ln->data_sz = ln->data_sz > sz ? ln->data_sz - sz : 0;
-	}
-
-	ln->data[cl->seqnum] = data;
-	if (data)
-		ln->data_sz += strlen(data);
-	return 0;
-}
-
-int tt_line_set_userdata(struct tt_line *ln, void *data)
-{
-	if (!ln)
-		return -1;
-	ln->userdata = data;
-	return 0;
-}
-
-static char *line_get_ascii_art(struct tt_line *ln, char *buf, size_t *bufsz)
-{
-	const char *art;
-	size_t len;
-
-	if (!ln->parent)
-		return buf;
-
-	buf = line_get_ascii_art(ln->parent, buf, bufsz);
-	if (!buf)
-		return NULL;
-
-	if (list_entry_is_last(&ln->ln_children, &ln->parent->ln_branch))
-		art = "  ";
-	else
-		art = ln->table->symbols->vert;
-
-	len = strlen(art);
-	if (*bufsz < len)
-		return NULL;	/* no space, internal error */
-
-	memcpy(buf, art, len);
-	*bufsz -= len;
-	return buf + len;
-}
-
-static char *line_get_data(struct tt_line *ln, struct tt_column *cl,
-				char *buf, size_t bufsz)
-{
-	const char *data = ln->data[cl->seqnum];
-	const struct tt_symbols *sym;
-	char *p = buf;
-
-	memset(buf, 0, bufsz);
-
-	if (!data)
-		return NULL;
-	if (!(cl->flags & TT_FL_TREE)) {
-		strncpy(buf, data, bufsz);
-		buf[bufsz - 1] = '\0';
-		return buf;
-	}
-
-	/*
-	 * Tree stuff
-	 */
-	if (ln->parent) {
-		p = line_get_ascii_art(ln->parent, buf, &bufsz);
-		if (!p)
-			return NULL;
-	}
-
-	sym = ln->table->symbols;
-
-	if (!ln->parent)
-		snprintf(p, bufsz, "%s", data);			/* root node */
-	else if (list_entry_is_last(&ln->ln_children, &ln->parent->ln_branch))
-		snprintf(p, bufsz, "%s%s", sym->right, data);	/* last chaild */
-	else
-		snprintf(p, bufsz, "%s%s", sym->branch, data);	/* any child */
-
-	return buf;
-}
-
-/*
- * This function counts column width.
- *
- * For the TT_FL_NOEXTREMES columns is possible to call this function two
- * times.  The first pass counts width and average width. If the column
- * contains too large fields (width greater than 2 * average) then the column
- * is marked as "extreme". In the second pass all extreme fields are ignored
- * and column width is counted from non-extreme fields only.
- */
-static void count_column_width(struct tt *tb, struct tt_column *cl,
-				 char *buf, size_t bufsz)
-{
-	struct list_head *lp;
-	int count = 0;
-	size_t sum = 0;
-
-	cl->width = 0;
-
-	list_for_each(lp, &tb->tb_lines) {
-		struct tt_line *ln = list_entry(lp, struct tt_line, ln_lines);
-		char *data = line_get_data(ln, cl, buf, bufsz);
-		size_t len = data ? mbs_safe_width(data) : 0;
-
-		if (len == (size_t) -1)		/* ignore broken multibyte strings */
-			len = 0;
-
-		if (len > cl->width_max)
-			cl->width_max = len;
-
-		if (cl->is_extreme && len > cl->width_avg * 2)
-			continue;
-		else if (cl->flags & TT_FL_NOEXTREMES) {
-			sum += len;
-			count++;
-		}
-		if (len > cl->width)
-			cl->width = len;
-	}
-
-	if (count && cl->width_avg == 0) {
-		cl->width_avg = sum / count;
-
-		if (cl->width_max > cl->width_avg * 2)
-			cl->is_extreme = 1;
-	}
-
-	/* check and set minimal column width */
-	if (cl->name)
-		cl->width_min = mbs_safe_width(cl->name);
-
-	/* enlarge to minimal width */
-	if (cl->width < cl->width_min && !(cl->flags & TT_FL_STRICTWIDTH))
-		cl->width = cl->width_min;
-
-	/* use relative size for large columns */
-	else if (cl->width_hint >= 1 && cl->width < (size_t) cl->width_hint &&
-		 cl->width_min < (size_t) cl->width_hint)
-
-		cl->width = (size_t) cl->width_hint;
-}
-
-/*
- * This is core of the tt_* voodo...
- */
-static void recount_widths(struct tt *tb, char *buf, size_t bufsz)
-{
-	struct list_head *p;
-	size_t width = 0;	/* output width */
-	int trunc_only;
-	int extremes = 0;
-
-	/* set basic columns width
-	 */
-	list_for_each(p, &tb->tb_columns) {
-		struct tt_column *cl =
-				list_entry(p, struct tt_column, cl_columns);
-
-		count_column_width(tb, cl, buf, bufsz);
-		width += cl->width + (is_last_column(tb, cl) ? 0 : 1);
-		extremes += cl->is_extreme;
-	}
-
-	if (!tb->is_term)
-		return;
-
-	/* reduce columns with extreme fields
-	 */
-	if (width > tb->termwidth && extremes) {
-		list_for_each(p, &tb->tb_columns) {
-			struct tt_column *cl = list_entry(p, struct tt_column, cl_columns);
-			size_t org_width;
-
-			if (!cl->is_extreme)
-				continue;
-
-			org_width = cl->width;
-			count_column_width(tb, cl, buf, bufsz);
-
-			if (org_width > cl->width)
-				width -= org_width - cl->width;
-			else
-				extremes--;	/* hmm... nothing reduced */
-		}
-	}
-
-	if (width < tb->termwidth) {
-		/* try to found extreme column which fits into available space
-		 */
-		if (extremes) {
-			/* enlarge the first extreme column */
-			list_for_each(p, &tb->tb_columns) {
-				struct tt_column *cl =
-					list_entry(p, struct tt_column, cl_columns);
-				size_t add;
-
-				if (!cl->is_extreme)
-					continue;
-
-				/* this column is tooo large, ignore?
-				if (cl->width_max - cl->width >
-						(tb->termwidth - width))
-					continue;
-				*/
-
-				add = tb->termwidth - width;
-				if (add && cl->width + add > cl->width_max)
-					add = cl->width_max - cl->width;
-
-				cl->width += add;
-				width += add;
-
-				if (width == tb->termwidth)
-					break;
-			}
-		}
-		if (width < tb->termwidth) {
-			/* enalarge the last column */
-			struct tt_column *cl = list_entry(
-				tb->tb_columns.prev, struct tt_column, cl_columns);
-
-			if (!(cl->flags & TT_FL_RIGHT) && tb->termwidth - width > 0) {
-				cl->width += tb->termwidth - width;
-				width = tb->termwidth;
-			}
-		}
-	}
-
-	/* bad, we have to reduce output width, this is done in two steps:
-	 * 1/ reduce columns with a relative width and with truncate flag
-	 * 2) reduce columns with a relative width without truncate flag
-	 */
-	trunc_only = 1;
-	while (width > tb->termwidth) {
-		size_t org = width;
-
-		list_for_each(p, &tb->tb_columns) {
-			struct tt_column *cl =
-				list_entry(p, struct tt_column, cl_columns);
-
-			if (width <= tb->termwidth)
-				break;
-			if (cl->width_hint > 1 && !(cl->flags & TT_FL_TRUNC))
-				continue;	/* never truncate columns with absolute sizes */
-			if (cl->flags & TT_FL_TREE)
-				continue;	/* never truncate the tree */
-			if (trunc_only && !(cl->flags & TT_FL_TRUNC))
-				continue;
-			if (cl->width == cl->width_min)
-				continue;
-
-			/* truncate column with relative sizes */
-			if (cl->width_hint < 1 && cl->width > 0 && width > 0 &&
-			    cl->width > cl->width_hint * tb->termwidth) {
-				cl->width--;
-				width--;
-			}
-			/* truncate column with absolute size */
-			if (cl->width_hint > 1 && cl->width > 0 && width > 0 &&
-			    !trunc_only) {
-				cl->width--;
-				width--;
-			}
-
-		}
-		if (org == width) {
-			if (trunc_only)
-				trunc_only = 0;
-			else
-				break;
-		}
-	}
-
-/*
-	fprintf(stderr, "terminal: %d, output: %d\n", tb->termwidth, width);
-
-	list_for_each(p, &tb->tb_columns) {
-		struct tt_column *cl =
-			list_entry(p, struct tt_column, cl_columns);
-
-		fprintf(stderr, "width: %s=%zd [hint=%d, avg=%zd, max=%zd, extreme=%s]\n",
-			cl->name, cl->width,
-			cl->width_hint > 1 ? (int) cl->width_hint :
-					     (int) (cl->width_hint * tb->termwidth),
-			cl->width_avg,
-			cl->width_max,
-			cl->is_extreme ? "yes" : "not");
-	}
-*/
-	return;
-}
-
-void tt_fputs_quoted(const char *data, FILE *out)
-{
-	const char *p;
-
-	fputc('"', out);
-	for (p = data; p && *p; p++) {
-		if ((unsigned char) *p == 0x22 ||		/* " */
-		    (unsigned char) *p == 0x5c ||		/* \ */
-		    !isprint((unsigned char) *p) ||
-		    iscntrl((unsigned char) *p)) {
-
-			fprintf(out, "\\x%02x", (unsigned char) *p);
-		} else
-			fputc(*p, out);
-	}
-	fputc('"', out);
-}
-
-void tt_fputs_nonblank(const char *data, FILE *out)
-{
-	const char *p;
-
-	for (p = data; p && *p; p++) {
-		if (isblank((unsigned char) *p) ||
-		    (unsigned char) *p == 0x5c ||		/* \ */
-		    !isprint((unsigned char) *p) ||
-		    iscntrl((unsigned char) *p)) {
-
-			fprintf(out, "\\x%02x", (unsigned char) *p);
-
-		} else
-			fputc(*p, out);
-	}
-}
-
-/*
- * Prints data, data maybe be printed in more formats (raw, NAME=xxx pairs) and
- * control and non-printable chars maybe encoded in \x?? hex encoding.
- */
-static void print_data(struct tt *tb, struct tt_column *cl, char *data)
-{
-	size_t len = 0, i, width;
-	char *buf;
-
-	if (!data)
-		data = "";
-
-	/* raw mode */
-	if (tb->flags & TT_FL_RAW) {
-		tt_fputs_nonblank(data, stdout);
-		if (!is_last_column(tb, cl))
-			fputc(' ', stdout);
-		return;
-	}
-
-	/* NAME=value mode */
-	if (tb->flags & TT_FL_EXPORT) {
-		fprintf(stdout, "%s=", cl->name);
-		tt_fputs_quoted(data, stdout);
-		if (!is_last_column(tb, cl))
-			fputc(' ', stdout);
-		return;
-	}
-
-	/* note that 'len' and 'width' are number of cells, not bytes */
-	buf = mbs_safe_encode(data, &len);
-	data = buf;
-	if (!data)
-		data = "";
-
-	if (!len || len == (size_t) -1) {
-		len = 0;
-		data = NULL;
-	}
-	width = cl->width;
-
-	if (is_last_column(tb, cl) && len < width)
-		width = len;
-
-	/* truncate data */
-	if (len > width && (cl->flags & TT_FL_TRUNC)) {
-		if (data)
-			len = mbs_truncate(data, &width);
-		if (!data || len == (size_t) -1) {
-			len = 0;
-			data = NULL;
-		}
-	}
-	if (data) {
-		if (!(tb->flags & TT_FL_RAW) && (cl->flags & TT_FL_RIGHT)) {
-			size_t xw = cl->width;
-			fprintf(stdout, "%*s", (int) xw, data);
-			if (len < xw)
-				len = xw;
-		}
-		else
-			fputs(data, stdout);
-	}
-	for (i = len; i < width; i++)
-		fputc(' ', stdout);		/* padding */
-
-	if (!is_last_column(tb, cl)) {
-		if (len > width && !(cl->flags & TT_FL_TRUNC)) {
-			fputc('\n', stdout);
-			for (i = 0; i <= (size_t) cl->seqnum; i++) {
-				struct tt_column *x = tt_get_column(tb, i);
-				printf("%*s ", -((int)x->width), " ");
-			}
-		} else
-			fputc(' ', stdout);	/* columns separator */
-	}
-
-	free(buf);
-}
-
-static void print_line(struct tt_line *ln, char *buf, size_t bufsz)
-{
-	struct list_head *p;
-
-	/* set width according to the size of data
-	 */
-	list_for_each(p, &ln->table->tb_columns) {
-		struct tt_column *cl =
-				list_entry(p, struct tt_column, cl_columns);
-
-		print_data(ln->table, cl, line_get_data(ln, cl, buf, bufsz));
-	}
-	fputc('\n', stdout);
-}
-
-static void print_header(struct tt *tb, char *buf, size_t bufsz)
-{
-	struct list_head *p;
-
-	if (!tb->first_run ||
-	    (tb->flags & TT_FL_NOHEADINGS) ||
-	    (tb->flags & TT_FL_EXPORT) ||
-	    list_empty(&tb->tb_lines))
-		return;
-
-	/* set width according to the size of data
-	 */
-	list_for_each(p, &tb->tb_columns) {
-		struct tt_column *cl =
-				list_entry(p, struct tt_column, cl_columns);
-
-		strncpy(buf, cl->name, bufsz);
-		buf[bufsz - 1] = '\0';
-		print_data(tb, cl, buf);
-	}
-	fputc('\n', stdout);
-}
-
-static void print_table(struct tt *tb, char *buf, size_t bufsz)
-{
-	struct list_head *p;
-
-	print_header(tb, buf, bufsz);
-
-	list_for_each(p, &tb->tb_lines) {
-		struct tt_line *ln = list_entry(p, struct tt_line, ln_lines);
-
-		print_line(ln, buf, bufsz);
-	}
-}
-
-static void print_tree_line(struct tt_line *ln, char *buf, size_t bufsz)
-{
-	struct list_head *p;
-
-	print_line(ln, buf, bufsz);
-
-	if (list_empty(&ln->ln_branch))
-		return;
-
-	/* print all children */
-	list_for_each(p, &ln->ln_branch) {
-		struct tt_line *chld =
-				list_entry(p, struct tt_line, ln_children);
-		print_tree_line(chld, buf, bufsz);
-	}
-}
-
-static void print_tree(struct tt *tb, char *buf, size_t bufsz)
-{
-	struct list_head *p;
-
-	print_header(tb, buf, bufsz);
-
-	list_for_each(p, &tb->tb_lines) {
-		struct tt_line *ln = list_entry(p, struct tt_line, ln_lines);
-
-		if (ln->parent)
-			continue;
-
-		print_tree_line(ln, buf, bufsz);
-	}
-}
-
-/*
- * @tb: table
- *
- * Prints the table to stdout
- */
-int tt_print_table(struct tt *tb)
-{
-	char *line;
-	size_t line_sz;
-	struct list_head *p;
-
-	if (!tb)
-		return -1;
-
-	if (tb->first_run) {
-		tb->is_term = isatty(STDOUT_FILENO);
-
-		if (tb->is_term && !tb->termwidth)
-			tb->termwidth = get_terminal_width();
-		if (tb->termwidth <= 0)
-			tb->termwidth = 80;
-	}
-
-	line_sz = tb->termwidth;
-
-	list_for_each(p, &tb->tb_lines) {
-		struct tt_line *ln = list_entry(p, struct tt_line, ln_lines);
-		if (ln->data_sz > line_sz)
-			line_sz = ln->data_sz;
-	}
-
-	line_sz++;			/* make a space for \0 */
-	line = malloc(line_sz);
-	if (!line)
-		return -1;
-
-	if (tb->first_run &&
-	    !((tb->flags & TT_FL_RAW) || (tb->flags & TT_FL_EXPORT)))
-		recount_widths(tb, line, line_sz);
-
-	if (tb->flags & TT_FL_TREE)
-		print_tree(tb, line, line_sz);
-	else
-		print_table(tb, line, line_sz);
-
-	free(line);
-
-	tb->first_run = FALSE;
-	return 0;
-}
-
-#ifdef TEST_PROGRAM
-#include <errno.h>
-
-enum { MYCOL_NAME, MYCOL_FOO, MYCOL_BAR, MYCOL_PATH };
-
-int main(int argc, char *argv[])
-{
-	struct tt *tb;
-	struct tt_line *ln, *pr, *root;
-	int flags = 0, notree = 0, i;
-
-	if (argc == 2 && !strcmp(argv[1], "--help")) {
-		printf("%s [--ascii | --raw | --list]\n",
-				program_invocation_short_name);
-		return EXIT_SUCCESS;
-	} else if (argc == 2 && !strcmp(argv[1], "--ascii")) {
-		flags |= TT_FL_ASCII;
-	} else if (argc == 2 && !strcmp(argv[1], "--raw")) {
-		flags |= TT_FL_RAW;
-		notree = 1;
-	} else if (argc == 2 && !strcmp(argv[1], "--export")) {
-		flags |= TT_FL_EXPORT;
-		notree = 1;
-	} else if (argc == 2 && !strcmp(argv[1], "--list"))
-		notree = 1;
-
-	setlocale(LC_ALL, "");
-	bindtextdomain(PACKAGE, LOCALEDIR);
-	textdomain(PACKAGE);
-
-	tb = tt_new_table(flags);
-	if (!tb)
-		err(EXIT_FAILURE, "table initialization failed");
-
-	tt_define_column(tb, "NAME", 0.3, notree ? 0 : TT_FL_TREE);
-	tt_define_column(tb, "FOO", 0.3, TT_FL_TRUNC);
-	tt_define_column(tb, "BAR", 0.3, 0);
-	tt_define_column(tb, "PATH", 0.3, 0);
-
-	for (i = 0; i < 2; i++) {
-		root = ln = tt_add_line(tb, NULL);
-		tt_line_set_data(ln, MYCOL_NAME, "AAA");
-		tt_line_set_data(ln, MYCOL_FOO, "a-foo-foo");
-		tt_line_set_data(ln, MYCOL_BAR, "barBar-A");
-		tt_line_set_data(ln, MYCOL_PATH, "/mnt/AAA");
-
-		pr = ln = tt_add_line(tb, ln);
-		tt_line_set_data(ln, MYCOL_NAME, "AAA.A");
-		tt_line_set_data(ln, MYCOL_FOO, "a.a-foo-foo");
-		tt_line_set_data(ln, MYCOL_BAR, "barBar-A.A");
-		tt_line_set_data(ln, MYCOL_PATH, "/mnt/AAA/A");
-
-		ln = tt_add_line(tb, pr);
-		tt_line_set_data(ln, MYCOL_NAME, "AAA.A.AAA");
-		tt_line_set_data(ln, MYCOL_FOO, "a.a.a-foo-foo");
-		tt_line_set_data(ln, MYCOL_BAR, "barBar-A.A.A");
-		tt_line_set_data(ln, MYCOL_PATH, "/mnt/AAA/A/AAA");
-
-		ln = tt_add_line(tb, root);
-		tt_line_set_data(ln, MYCOL_NAME, "AAA.B");
-		tt_line_set_data(ln, MYCOL_FOO, "a.b-foo-foo");
-		tt_line_set_data(ln, MYCOL_BAR, "barBar-A.B");
-		tt_line_set_data(ln, MYCOL_PATH, "/mnt/AAA/B");
-
-		ln = tt_add_line(tb, pr);
-		tt_line_set_data(ln, MYCOL_NAME, "AAA.A.BBB");
-		tt_line_set_data(ln, MYCOL_FOO, "a.a.b-foo-foo");
-		tt_line_set_data(ln, MYCOL_BAR, "barBar-A.A.BBB");
-		tt_line_set_data(ln, MYCOL_PATH, "/mnt/AAA/A/BBB");
-
-		ln = tt_add_line(tb, pr);
-		tt_line_set_data(ln, MYCOL_NAME, "AAA.A.CCC");
-		tt_line_set_data(ln, MYCOL_FOO, "a.a.c-foo-foo");
-		tt_line_set_data(ln, MYCOL_BAR, "barBar-A.A.CCC");
-		tt_line_set_data(ln, MYCOL_PATH, "/mnt/AAA/A/CCC");
-
-		ln = tt_add_line(tb, root);
-		tt_line_set_data(ln, MYCOL_NAME, "AAA.C");
-		tt_line_set_data(ln, MYCOL_FOO, "a.c-foo-foo");
-		tt_line_set_data(ln, MYCOL_BAR, "barBar-A.C");
-		tt_line_set_data(ln, MYCOL_PATH, "/mnt/AAA/C");
-	}
-
-	tt_print_table(tb);
-	tt_free_table(tb);
-
-	return EXIT_SUCCESS;
-}
-#endif
diff --git a/libblkid/tt.h b/libblkid/tt.h
deleted file mode 100644
index 603844f..0000000
--- a/libblkid/tt.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Prints table or tree. See lib/table.c for more details and example.
- *
- * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
- *
- * This file may be redistributed under the terms of the
- * GNU Lesser General Public License.
- */
-#ifndef UTIL_LINUX_TT_H
-#define UTIL_LINUX_TT_H
-
-#include "list.h"
-
-enum {
-	/*
-	 * Global flags
-	 */
-	TT_FL_RAW         = (1 << 1),
-	TT_FL_ASCII       = (1 << 2),
-	TT_FL_NOHEADINGS  = (1 << 3),
-	TT_FL_EXPORT      = (1 << 4),
-
-	/*
-	 * Column flags
-	 */
-	TT_FL_TRUNC       = (1 << 5),	/* truncate fields data if necessary */
-	TT_FL_TREE        = (1 << 6),	/* use tree "ascii art" */
-	TT_FL_RIGHT	  = (1 << 7),	/* align to the right */
-	TT_FL_STRICTWIDTH = (1 << 8),	/* don't reduce width if column is empty */
-	TT_FL_NOEXTREMES  = (1 << 9)    /* ignore extreme fields when count column width*/
-};
-
-struct tt {
-	size_t	ncols;		/* number of columns */
-	size_t	termwidth;	/* terminal width */
-	int	is_term;	/* is a tty? */
-	int	flags;
-	int	first_run;
-
-	struct list_head	tb_columns;
-	struct list_head	tb_lines;
-
-	const struct tt_symbols	*symbols;
-};
-
-struct tt_column {
-	const char *name;	/* header */
-	size_t	seqnum;
-
-	size_t	width;		/* real column width */
-	size_t	width_min;	/* minimal width (usually header width) */
-	size_t  width_max;	/* maximal width */
-	size_t  width_avg;	/* average width, used to detect extreme fields */
-	double	width_hint;	/* hint (N < 1 is in percent of termwidth) */
-
-	int	flags;
-	int	is_extreme;
-
-	struct list_head	cl_columns;
-};
-
-struct tt_line {
-	struct tt	*table;
-	char const	**data;
-	void		*userdata;
-	size_t		data_sz;		/* strlen of all data */
-
-	struct list_head	ln_lines;	/* table lines */
-
-	struct list_head	ln_branch;	/* begin of branch (head of ln_children) */
-	struct list_head	ln_children;
-
-	struct tt_line	*parent;
-};
-
-extern struct tt *tt_new_table(int flags);
-extern void tt_free_table(struct tt *tb);
-extern void tt_remove_lines(struct tt *tb);
-extern int tt_print_table(struct tt *tb);
-
-extern struct tt_column *tt_define_column(struct tt *tb, const char *name,
-						double whint, int flags);
-
-extern struct tt_column *tt_get_column(struct tt *tb, size_t colnum);
-
-extern struct tt_line *tt_add_line(struct tt *tb, struct tt_line *parent);
-
-extern int tt_line_set_data(struct tt_line *ln, int colnum, const char *data);
-extern int tt_line_set_userdata(struct tt_line *ln, void *data);
-
-extern void tt_fputs_quoted(const char *data, FILE *out);
-extern void tt_fputs_nonblank(const char *data, FILE *out);
-
-#endif /* UTIL_LINUX_TT_H */
diff --git a/libblkid/wholedisk.c b/libblkid/wholedisk.c
deleted file mode 100644
index 1dbb90c..0000000
--- a/libblkid/wholedisk.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * No copyright is claimed.  This code is in the public domain; do with
- * it what you wish.
- *
- * Written by Karel Zak <kzak@redhat.com>
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-
-#include "blkdev.h"
-#include "wholedisk.h"
-
-int is_whole_disk_fd(int fd, const char *name)
-{
-#ifdef HDIO_GETGEO
-	if (fd != -1) {
-		struct hd_geometry geometry;
-		int i = ioctl(fd, HDIO_GETGEO, &geometry);
-		if (i == 0)
-			return geometry.start == 0;
-	}
-#endif
-	/*
-	 * The "silly heuristic" is still sexy for us, because
-	 * for example Xen doesn't implement HDIO_GETGEO for virtual
-	 * block devices (/dev/xvda).
-	 *
-	 * -- kzak@redhat.com (23-Feb-2006)
-	 */
-	while (*name)
-		name++;
-	return !isdigit(name[-1]);
-}
-
-int is_whole_disk(const char *name)
-{
-	int fd = -1, res = 0;
-#ifdef HDIO_GETGEO
-	fd = open(name, O_RDONLY);
-	if (fd != -1)
-#endif
-		res = is_whole_disk_fd(fd, name);
-
-	if (fd != -1)
-		close(fd);
-	return res;
-}
-
-#ifdef TEST_PROGRAM
-int main(int argc, char **argv)
-{
-	if (argc < 2) {
-		fprintf(stderr, "usage: %s <device>\n", argv[0]);
-		exit(EXIT_FAILURE);
-	}
-
-	printf("%s: is%s whole disk\n", argv[1],
-			is_whole_disk(argv[1]) ? "" : " NOT");
-	exit(EXIT_SUCCESS);
-}
-#endif
diff --git a/libblkid/wholedisk.h b/libblkid/wholedisk.h
deleted file mode 100644
index 251479e..0000000
--- a/libblkid/wholedisk.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef WHOLEDISK_H
-#define WHOLEDISK_H
-
-extern int is_whole_disk(const char *name);
-extern int is_whole_disk_fd(int fd, const char *name);
-
-#endif /* WHOLEDISK_H */
-
diff --git a/libblkid/xfs.c b/libblkid/xfs.c
deleted file mode 100644
index 1399fe1..0000000
--- a/libblkid/xfs.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 1999 by Andries Brouwer
- * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
- * Copyright (C) 2001 by Andreas Dilger
- * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
- * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
- *
- * This file may be redistributed under the terms of the
- * GNU Lesser General Public License.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <ctype.h>
-#include <stdint.h>
-
-#include "superblocks.h"
-
-struct xfs_super_block {
-	unsigned char	xs_magic[4];
-	uint32_t	xs_blocksize;
-	uint64_t	xs_dblocks;
-	uint64_t	xs_rblocks;
-	uint32_t	xs_dummy1[2];
-	unsigned char	xs_uuid[16];
-	uint32_t	xs_dummy2[15];
-	char		xs_fname[12];
-	uint32_t	xs_dummy3[2];
-	uint64_t	xs_icount;
-	uint64_t	xs_ifree;
-	uint64_t	xs_fdblocks;
-} __attribute__((packed));
-
-static int probe_xfs(blkid_probe pr, const struct blkid_idmag *mag)
-{
-	struct xfs_super_block *xs;
-
-	xs = blkid_probe_get_sb(pr, mag, struct xfs_super_block);
-	if (!xs)
-		return -1;
-
-	if (strlen(xs->xs_fname))
-		blkid_probe_set_label(pr, (unsigned char *) xs->xs_fname,
-				sizeof(xs->xs_fname));
-	blkid_probe_set_uuid(pr, xs->xs_uuid);
-	return 0;
-}
-
-const struct blkid_idinfo xfs_idinfo =
-{
-	.name		= "xfs",
-	.usage		= BLKID_USAGE_FILESYSTEM,
-	.probefunc	= probe_xfs,
-	.magics		=
-	{
-		{ .magic = "XFSB", .len = 4 },
-		{ NULL }
-	}
-};
-
diff --git a/libblkid/xgetpass.c b/libblkid/xgetpass.c
deleted file mode 100644
index ba20894..0000000
--- a/libblkid/xgetpass.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * A function to read the passphrase either from the terminal or from
- * an open file descriptor.
- *
- * Public domain.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-
-#include "c.h"
-#include "xgetpass.h"
-
-char *xgetpass(int pfd, const char *prompt)
-{
-	char *pass = NULL;
-	int len = 0, i;
-
-        if (pfd < 0) /* terminal */
-		return getpass(prompt);
-
-	for (i=0; ; i++) {
-		if (i >= len-1) {
-			char *tmppass = pass;
-			len += 128;
-
-			pass = realloc(tmppass, len);
-			if (!pass) {
-				pass = tmppass; /* the old buffer hasn't changed */
-				break;
-			}
-		}
-		if (pass && (read(pfd, pass + i, 1) != 1 ||
-			     pass[i] == '\n' || pass[i] == 0))
-			break;
-	}
-
-	if (pass)
-		pass[i] = '\0';
-	return pass;
-}
-
diff --git a/libblkid/xgetpass.h b/libblkid/xgetpass.h
deleted file mode 100644
index b5a3c87..0000000
--- a/libblkid/xgetpass.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef UTIL_LINUX_XGETPASS_H
-#define UTIL_LINUX_XGETPASS_H
-
-extern char *xgetpass(int pfd, const char *prompt);
-
-#endif /* UTIL_LINUX_XGETPASS_H */
diff --git a/partition.cpp b/partition.cpp
index 9770a5f..8edf54a 100644
--- a/partition.cpp
+++ b/partition.cpp
@@ -31,7 +31,7 @@
 	#include "cutils/properties.h"
 #endif
 
-#include "libblkid/blkid.h"
+#include "libblkid/include/blkid.h"
 #include "variables.h"
 #include "twcommon.h"
 #include "partitions.hpp"
@@ -2070,6 +2070,7 @@
 		maxFileSize = 3.94 * constTB; //3.94 TB
 	else
 		maxFileSize = 100000000L;
+	LOGINFO("Get_Max_FileSize::maxFileSize: %\n", maxFileSize);
 	return maxFileSize - 1;
 }
 
diff --git a/prebuilt/Android.mk b/prebuilt/Android.mk
index d8ed87c..86db949 100644
--- a/prebuilt/Android.mk
+++ b/prebuilt/Android.mk
@@ -38,7 +38,6 @@
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libgccdemangle.so
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libutils.so
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libdl.so
-RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libext2_blkid.so
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libext2_com_err.so
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libext2_e2p.so
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libext2fs.so
@@ -57,6 +56,9 @@
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libminzip.so
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libmtdutils.so
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libtar.so
+RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libutil-linux.so
+RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libuuid.so
+RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libfdisk.so
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libblkid.so
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libmmcutils.so
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libbmlutils.so