diff -urN multipath-tools-0.1.5/ChangeLog multipath-tools-0.1.6/ChangeLog
--- multipath-tools-0.1.5/ChangeLog	2004-03-25 17:51:57.000000000 +0100
+++ multipath-tools-0.1.6/ChangeLog	2004-04-25 18:44:40.000000000 +0200
@@ -1,3 +1,7 @@
+2004-04-25 multipath-tools-0.1.6
+	* add the dmadm WIP tool (read MD superblocks and create
+	  corresponding devmaps when possible)
+	* plug fd leak in TUR path checker
 2004-03-25 multipath-tools-0.1.5
 	* kpartx to manage the nested bdevs as /dev/cciss/c0d0.
 	  parts are named sysfs style : cciss!c0d0p*
diff -urN multipath-tools-0.1.5/VERSION multipath-tools-0.1.6/VERSION
--- multipath-tools-0.1.5/VERSION	2004-02-19 19:38:35.000000000 +0100
+++ multipath-tools-0.1.6/VERSION	1970-01-01 01:00:00.000000000 +0100
@@ -1 +0,0 @@
-0.0.5
diff -urN multipath-tools-0.1.5/dmadm/Makefile multipath-tools-0.1.6/dmadm/Makefile
--- multipath-tools-0.1.5/dmadm/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ multipath-tools-0.1.6/dmadm/Makefile	2004-03-29 15:47:29.000000000 +0200
@@ -0,0 +1,46 @@
+EXEC        = dmadm
+
+prefix      =
+exec_prefix = ${prefix}
+bindir      = ${exec_prefix}/sbin
+udevdir     = ../../..
+klibcdir    = $(udevdir)/klibc
+sysfsdir    = $(udevdir)/libsysfs
+arch        = i386
+klibcarch   = $(klibcdir)/klibc/arch/$(arch)/include
+
+CC = gcc
+GCCINCDIR := ${shell $(CC) -print-search-dirs | sed -ne "s/install: \(.*\)/\1include/gp"}
+KERNEL_DIR = /lib/modules/${shell uname -r}/build
+CFLAGS = -pipe -g -O2 -Wall -Wunused -Wstrict-prototypes -nostdinc \
+	 -I$(klibcdir)/klibc/include -I$(klibcdir)/klibc/include/bits32 \
+	 -I$(GCCINCDIR) -I$(KERNEL_DIR)/include -I. -I$(klibcarch) -I$(sysfsdir)
+
+OBJS = util.o dmadm.o
+CRT0 = $(udevdir)/klibc/klibc/crt0.o
+LIB = $(udevdir)/klibc/klibc/libc.a
+LIBGCC := $(shell $(CC) -print-libgcc-file-name )
+
+SYSFSOBJS = $(sysfsdir)/dlist.o $(sysfsdir)/sysfs_bus.o \
+	    $(sysfsdir)/sysfs_class.o $(sysfsdir)/sysfs_device.o \
+	    $(sysfsdir)/sysfs_dir.o $(sysfsdir)/sysfs_driver.o \
+	    $(sysfsdir)/sysfs_utils.o
+
+DMOBJS = ../libdevmapper/libdm-common.o \
+	 ../libdevmapper/ioctl/libdevmapper.o
+
+$(EXEC): $(OBJS)
+	$(LD) -o $(EXEC) $(CRT0) $(OBJS) $(SYSFSOBJS) $(DMOBJS) $(LIB) $(LIBGCC)
+	strip $(EXEC)
+
+clean:
+	rm -f $(OBJS) *.o $(EXEC) *~
+
+install:
+	install -d $(DESTDIR)$(bindir)
+	install -m 755 $(EXEC) $(DESTDIR)$(bindir)/
+
+uninstall:
+	rm $(DESTDIR)$(bindir)/$(EXEC)
+
+$(OBJS): mdadm.h
diff -urN multipath-tools-0.1.5/dmadm/README multipath-tools-0.1.6/dmadm/README
--- multipath-tools-0.1.5/dmadm/README	1970-01-01 01:00:00.000000000 +0100
+++ multipath-tools-0.1.6/dmadm/README	2004-04-25 18:46:57.000000000 +0200
@@ -0,0 +1,6 @@
+dmadm is a WIP tool.
+It reads MD superblocks and creates corresponding devmaps when possible
+
+Comments and contributions welcome
+
+christophe.varoqui@free.fr
Binary files multipath-tools-0.1.5/dmadm/dmadm and multipath-tools-0.1.6/dmadm/dmadm differ
diff -urN multipath-tools-0.1.5/dmadm/dmadm.c multipath-tools-0.1.6/dmadm/dmadm.c
--- multipath-tools-0.1.5/dmadm/dmadm.c	1970-01-01 01:00:00.000000000 +0100
+++ multipath-tools-0.1.6/dmadm/dmadm.c	2004-04-01 17:45:31.000000000 +0200
@@ -0,0 +1,407 @@
+/*
+ * mdadm - manage Linux "md" devices aka RAID arrays.
+ *
+ * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
+ *
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *    Author: Neil Brown
+ *    Email: <neilb@cse.unsw.edu.au>
+ *    Paper: Neil Brown
+ *           School of Computer Science and Engineering
+ *           The University of New South Wales
+ *           Sydney, 2052
+ *           Australia
+ */
+
+#include	"mdadm.h"
+#include	"../libdevmapper/libdevmapper.h"
+#include	<endian.h>
+#include	<sysfs/libsysfs.h>
+#include	<dlist.h>
+
+#if ! defined(__BIG_ENDIAN) && ! defined(__LITTLE_ENDIAN)
+#error no endian defined
+#endif
+#include	"md_u.h"
+#include	"md_p.h"
+
+#define DEBUG 1
+#define LOG(x, y, z...) if (DEBUG >= x) fprintf (stderr, y, ##z)
+
+#define LINEAR	-1
+#define STRIPED	0
+#define RAID1	1
+
+struct device {
+	char devname[FILE_NAME_SIZE];
+	unsigned long long size;
+	mdp_super_t super;
+};
+
+static int
+blacklist (char * dev) {
+	int i;
+	static struct {
+		char * headstr;
+		int lengh;
+	} blist[] = {
+		{"md", 2},
+		{"dm", 2},
+		{"sr", 2},
+		{"scd", 3},
+		{"ram", 3},
+		{"raw", 3},
+		{NULL, 0},
+	};
+
+	for (i = 0; blist[i].lengh; i++) {
+		if (strncmp (dev, blist[i].headstr, blist[i].lengh) == 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+static struct device *
+sort_by_disknum (struct device * a, struct device * b)
+{
+	return (a->super.this_disk.number < b->super.this_disk.number ? a : b);
+}
+
+unsigned long long
+get_disk_size (char * sysfs_path, char * devname) {
+	unsigned long long size;
+	char attr_path[FILE_NAME_SIZE];
+	char buff[FILE_NAME_SIZE];
+
+	sprintf(attr_path, "%s/%s/size", sysfs_path, devname);
+
+	if (0 > sysfs_read_attribute_value(attr_path, buff,
+		FILE_NAME_SIZE * sizeof(char)))
+		return -1;
+	
+	size = atoi(buff);
+	return size;
+}
+
+static int
+linear_target (struct dlist * mddevs)
+{
+	char mapname[FILE_NAME_SIZE];
+	char params[DM_PARAMS_SIZE];
+	struct device * dev = NULL;
+	unsigned long long start = 0;
+	struct dm_task *dmt = NULL;
+
+	dlist_for_each_data (mddevs, dev, struct device) {
+		memset (&params, 0x0, DM_PARAMS_SIZE);
+
+		if (!start) {
+			/* do only on first iteration */
+			sprintf (mapname, "%x:%x:%x:%x",
+				 dev->super.set_uuid0,
+				 dev->super.set_uuid1,
+				 dev->super.set_uuid2,
+				 dev->super.set_uuid3);
+			
+			if (!(dmt = dm_task_create (DM_DEVICE_CREATE)))
+				return 1;
+
+			if (!dm_task_set_name (dmt, mapname))
+				goto out;
+		}
+
+		sprintf (params, " %i:%i 0",
+				 dev->super.this_disk.major,
+				 dev->super.this_disk.minor);
+
+		LOG (1, "%llu %llu linear %s\n", start,
+		     MD_NEW_SIZE_SECTORS(dev->size), params);
+
+		if (!dm_task_add_target (dmt, start,
+					 MD_NEW_SIZE_SECTORS(dev->size),
+					 "linear", params))
+			goto out;
+
+		start += MD_NEW_SIZE_SECTORS(dev->size);
+	}
+
+	if (!dm_task_run (dmt))
+		goto out;
+
+	out:
+	dm_task_destroy (dmt);
+	return 0;
+}
+
+static int
+striped_target (struct dlist * mddevs)
+{
+	char * p;
+	char params[DM_PARAMS_SIZE];
+	char mapname[FILE_NAME_SIZE];
+	struct device * dev = NULL;
+	unsigned long long size = 0;
+	struct dm_task *dmt = NULL;
+
+	p = &params[0];
+
+	dlist_for_each_data (mddevs, dev, struct device) {
+
+		if (!size) {
+			/* do only on first iteration */
+			sprintf (mapname, "%x:%x:%x:%x",
+				 dev->super.set_uuid0,
+				 dev->super.set_uuid1,
+				 dev->super.set_uuid2,
+				 dev->super.set_uuid3);
+
+			size = dev->super.size * 2;
+			p += sprintf (p, "%i", dev->super.nr_disks);
+			p += sprintf (p, " %i", dev->super.chunk_size / 1024);
+		}
+
+		p += sprintf (p, " %i:%i 0",
+				 dev->super.this_disk.major,
+				 dev->super.this_disk.minor);
+	}
+
+	LOG (1, "0 %llu striped %s\n", size, params);
+
+	if (!(dmt = dm_task_create (DM_DEVICE_CREATE)))
+		return 1;
+
+	if (!dm_task_set_name (dmt, mapname))
+		goto out;
+
+	if (!dm_task_add_target (dmt, 0, size, "striped", params))
+		goto out;
+
+	if (!dm_task_run (dmt))
+		goto out;
+
+	out:
+	dm_task_destroy (dmt);
+	return 0;
+}
+
+static int
+raid1_target (struct dlist * mddevs)
+{
+	char * p;
+	char params[DM_PARAMS_SIZE];
+	char mapname[FILE_NAME_SIZE];
+	struct device * dev = NULL;
+	unsigned long long size = 0;
+	struct dm_task *dmt = NULL;
+
+	p = &params[0];
+
+	dlist_for_each_data (mddevs, dev, struct device) {
+
+		if (!size) {
+			/* do only on first iteration */
+			sprintf (mapname, "%x:%x:%x:%x",
+				 dev->super.set_uuid0,
+				 dev->super.set_uuid1,
+				 dev->super.set_uuid2,
+				 dev->super.set_uuid3);
+
+			size = dev->super.size * 2;
+			p += sprintf (p, "core 1 1024 %i", dev->super.nr_disks);
+		}
+
+		p += sprintf (p, " %i:%i 0",
+				 dev->super.this_disk.major,
+				 dev->super.this_disk.minor);
+	}
+
+	LOG (1, "0 %llu mirror %s\n", size, params);
+
+	if (!(dmt = dm_task_create (DM_DEVICE_CREATE)))
+		return 1;
+
+	if (!dm_task_set_name (dmt, mapname))
+		goto out;
+
+	if (!dm_task_add_target (dmt, 0, size, "mirror", params))
+		goto out;
+
+	if (!dm_task_run (dmt))
+		goto out;
+
+	out:
+	dm_task_destroy (dmt);
+	return 0;
+}
+
+int main (int argc, char **argv)
+{
+	struct sysfs_directory * sdir;
+	struct sysfs_directory * devp;
+	char sysfs_path[FILE_NAME_SIZE];
+	char devname[FILE_NAME_SIZE];
+	struct device * dev = NULL;
+	struct device * refdev = NULL;
+	struct dlist * devlist = NULL;
+	struct dlist * mddevs = NULL;
+	int fd, err;
+	int level;
+
+	/*
+	 * store every block device listed in sysfs in a dlist
+	 * if it has a MD superblock
+	 */
+	if (sysfs_get_mnt_path (sysfs_path, FILE_NAME_SIZE)) {
+		LOG (0, "need sysfs\n");
+		exit (1);
+	}
+
+	sprintf (devname, "%s/block", sysfs_path);
+	strncpy (sysfs_path, devname, FILE_NAME_SIZE);
+	sdir = sysfs_open_directory (sysfs_path);
+	sysfs_read_directory (sdir);
+
+	dlist_for_each_data (sdir->subdirs, devp, struct sysfs_directory) {
+
+		if (blacklist (devp->name))
+			continue;
+
+		LOG (2, "%s\n", devp->name);
+		sprintf (devname, "/dev/%s", devp->name);
+		fd = open(devname, O_RDONLY);
+
+		if (fd < 0) {
+			LOG (0, "Can't open %s\n", devname);
+			close (fd);
+			continue;
+		}
+		
+		dev = malloc (sizeof (struct device));
+
+		if (dev == NULL) {
+			LOG (0, "can't allocate memory for device\n");
+			exit (1);
+		}
+			
+		err = load_super(fd, &dev->super);
+		close (fd);
+
+		switch(err) {
+		case 1:
+			LOG (2, "cannot find device size for %s: %s\n",
+				devname, strerror(errno));
+			free (dev);
+			continue;
+		case 2:
+			LOG (2, "%s is too small for md\n",
+				devname);
+			free (dev);
+			continue;
+		case 3:
+			LOG (2, "Cannot seek to superblock on %s: %s\n",
+				devname, strerror(errno));
+			free (dev);
+			continue;
+		case 4:
+			LOG (2, "Cannot read superblock on %s\n",
+				devname);
+			free (dev);
+			continue;
+		case 5:
+			LOG (2, "No super block found on %s "
+				"(Expected magic %08x, got %08x)\n",
+				devname, MD_SB_MAGIC, dev->super.md_magic);
+			free (dev);
+			continue;
+		case 6:
+			LOG (2, "Cannot interpret superblock on %s - "
+				"version is %d\n",
+				devname, dev->super.major_version);
+			free (dev);
+			continue;
+		}
+
+		/* here we got a valid raid member, store */
+		LOG (1, "%s is part of a raid array\n", devname);
+
+		if (devlist == NULL) {
+			LOG (2, "First super detected : create dlist\n");
+			devlist = dlist_new (sizeof (struct device));
+		}
+
+		strcpy (dev->devname, devname);
+		dev->size = get_disk_size (sysfs_path, devp->name);
+		dlist_push (devlist, dev);
+	}
+
+	sysfs_close_directory (sdir);
+
+	/*
+	 * coalesce by MD UUID
+	 */
+	dlist_start (devlist);
+	while (dlist_next (devlist)) {
+		refdev = dlist_pop (devlist);
+		mddevs = dlist_new (sizeof (struct device));
+		dlist_push (mddevs, refdev);
+		level = refdev->super.level;
+		
+		LOG (1, "raid found : %d:%d",
+		     refdev->super.this_disk.major,
+		     refdev->super.this_disk.minor);
+
+		dlist_for_each_data (devlist, dev, struct device) {
+			if (0 == compare_super (&refdev->super, &dev->super)) {
+				LOG (1, " %d:%d",
+				     dev->super.this_disk.major,
+				     dev->super.this_disk.minor);
+				dlist_insert_sorted (mddevs, dev,
+						     (void *)sort_by_disknum);
+				dlist_pop (devlist);
+				continue;
+			}
+		}
+
+		LOG (1, "\n");
+
+		/*
+		 * here we have an array in mddevs.
+		 * do sanity checks and create devmap
+		 */
+		switch (level) {
+		case LINEAR:
+			linear_target (mddevs);
+			break;
+			
+		case STRIPED:
+			striped_target (mddevs);
+			break;
+
+		case RAID1:
+			raid1_target (mddevs);
+			break;
+
+		default:
+			LOG (1, "unsupported raid level : skip\n");
+		}
+
+		dlist_destroy (mddevs);
+	}
+	
+	return 0;
+}
Binary files multipath-tools-0.1.5/dmadm/dmadm.o and multipath-tools-0.1.6/dmadm/dmadm.o differ
diff -urN multipath-tools-0.1.5/dmadm/md_p.h multipath-tools-0.1.6/dmadm/md_p.h
--- multipath-tools-0.1.5/dmadm/md_p.h	1970-01-01 01:00:00.000000000 +0100
+++ multipath-tools-0.1.6/dmadm/md_p.h	2004-03-29 09:20:52.000000000 +0200
@@ -0,0 +1,176 @@
+/*
+   md_p.h : physical layout of Linux RAID devices
+          Copyright (C) 1996-98 Ingo Molnar, Gadi Oxman
+	  
+   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.
+   
+   You should have received a copy of the GNU General Public License
+   (for example /usr/src/linux/COPYING); if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+*/
+
+#ifndef _MD_P_H
+#define _MD_P_H
+
+/*
+ * RAID superblock.
+ *
+ * The RAID superblock maintains some statistics on each RAID configuration.
+ * Each real device in the RAID set contains it near the end of the device.
+ * Some of the ideas are copied from the ext2fs implementation.
+ *
+ * We currently use 4096 bytes as follows:
+ *
+ *	word offset	function
+ *
+ *	   0  -    31	Constant generic RAID device information.
+ *        32  -    63   Generic state information.
+ *	  64  -   127	Personality specific information.
+ *	 128  -   511	12 32-words descriptors of the disks in the raid set.
+ *	 512  -   911	Reserved.
+ *	 912  -  1023	Disk specific descriptor.
+ */
+
+/*
+ * If x is the real device size in bytes, we return an apparent size of:
+ *
+ *	y = (x & ~(MD_RESERVED_BYTES - 1)) - MD_RESERVED_BYTES
+ *
+ * and place the 4kB superblock at offset y.
+ */
+#define MD_RESERVED_BYTES		(64 * 1024)
+#define MD_RESERVED_SECTORS		(MD_RESERVED_BYTES / 512)
+#define MD_RESERVED_BLOCKS		(MD_RESERVED_BYTES / BLOCK_SIZE)
+
+#define MD_NEW_SIZE_SECTORS(x)		((x & ~(MD_RESERVED_SECTORS - 1)) - MD_RESERVED_SECTORS)
+#define MD_NEW_SIZE_BLOCKS(x)		((x & ~(MD_RESERVED_BLOCKS - 1)) - MD_RESERVED_BLOCKS)
+
+#define MD_SB_BYTES			4096
+#define MD_SB_WORDS			(MD_SB_BYTES / 4)
+#define MD_SB_BLOCKS			(MD_SB_BYTES / BLOCK_SIZE)
+#define MD_SB_SECTORS			(MD_SB_BYTES / 512)
+
+/*
+ * The following are counted in 32-bit words
+ */
+#define	MD_SB_GENERIC_OFFSET		0
+#define MD_SB_PERSONALITY_OFFSET	64
+#define MD_SB_DISKS_OFFSET		128
+#define MD_SB_DESCRIPTOR_OFFSET		992
+
+#define MD_SB_GENERIC_CONSTANT_WORDS	32
+#define MD_SB_GENERIC_STATE_WORDS	32
+#define MD_SB_GENERIC_WORDS		(MD_SB_GENERIC_CONSTANT_WORDS + MD_SB_GENERIC_STATE_WORDS)
+#define MD_SB_PERSONALITY_WORDS		64
+#define MD_SB_DESCRIPTOR_WORDS		32
+#define MD_SB_DISKS			27
+#define MD_SB_DISKS_WORDS		(MD_SB_DISKS*MD_SB_DESCRIPTOR_WORDS)
+#define MD_SB_RESERVED_WORDS		(1024 - MD_SB_GENERIC_WORDS - MD_SB_PERSONALITY_WORDS - MD_SB_DISKS_WORDS - MD_SB_DESCRIPTOR_WORDS)
+#define MD_SB_EQUAL_WORDS		(MD_SB_GENERIC_WORDS + MD_SB_PERSONALITY_WORDS + MD_SB_DISKS_WORDS)
+
+/*
+ * Device "operational" state bits
+ */
+#define MD_DISK_FAULTY		0 /* disk is faulty / operational */
+#define MD_DISK_ACTIVE		1 /* disk is running or spare disk */
+#define MD_DISK_SYNC		2 /* disk is in sync with the raid set */
+#define MD_DISK_REMOVED		3 /* disk is in sync with the raid set */
+
+typedef struct mdp_device_descriptor_s {
+	__u32 number;		/* 0 Device number in the entire set	      */
+	__u32 major;		/* 1 Device major number		      */
+	__u32 minor;		/* 2 Device minor number		      */
+	__u32 raid_disk;	/* 3 The role of the device in the raid set   */
+	__u32 state;		/* 4 Operational state			      */
+	__u32 reserved[MD_SB_DESCRIPTOR_WORDS - 5];
+} mdp_disk_t;
+
+#define MD_SB_MAGIC		0xa92b4efc
+
+/*
+ * Superblock state bits
+ */
+#define MD_SB_CLEAN		0
+#define MD_SB_ERRORS		1
+
+typedef struct mdp_superblock_s {
+	/*
+	 * Constant generic information
+	 */
+	__u32 md_magic;		/*  0 MD identifier 			      */
+	__u32 major_version;	/*  1 major version to which the set conforms */
+	__u32 minor_version;	/*  2 minor version ...			      */
+	__u32 patch_version;	/*  3 patchlevel version ...		      */
+	__u32 gvalid_words;	/*  4 Number of used words in this section    */
+	__u32 set_uuid0;	/*  5 Raid set identifier		      */
+	__u32 ctime;		/*  6 Creation time			      */
+	__u32 level;		/*  7 Raid personality			      */
+	__u32 size;		/*  8 Apparent size of each individual disk   */
+	__u32 nr_disks;		/*  9 total disks in the raid set	      */
+	__u32 raid_disks;	/* 10 disks in a fully functional raid set    */
+	__u32 md_minor;		/* 11 preferred MD minor device number	      */
+	__u32 not_persistent;	/* 12 does it have a persistent superblock    */
+	__u32 set_uuid1;	/* 13 Raid set identifier #2		      */
+	__u32 set_uuid2;	/* 14 Raid set identifier #3		      */
+	__u32 set_uuid3;	/* 15 Raid set identifier #4		      */
+	__u32 gstate_creserved[MD_SB_GENERIC_CONSTANT_WORDS - 16];
+
+	/*
+	 * Generic state information
+	 */
+	__u32 utime;		/*  0 Superblock update time		      */
+	__u32 state;		/*  1 State bits (clean, ...)		      */
+	__u32 active_disks;	/*  2 Number of currently active disks	      */
+	__u32 working_disks;	/*  3 Number of working disks		      */
+	__u32 failed_disks;	/*  4 Number of failed disks		      */
+	__u32 spare_disks;	/*  5 Number of spare disks		      */
+	__u32 sb_csum;		/*  6 checksum of the whole superblock        */
+#if  __BYTE_ORDER ==  __BIG_ENDIAN
+	__u32 events_hi;	/*  7 high-order of superblock update count   */
+	__u32 events_lo;	/*  8 low-order of superblock update count    */
+#else
+	__u32 events_lo;	/*  7 low-order of superblock update count    */
+	__u32 events_hi;	/*  8 high-order of superblock update count   */
+#endif
+	__u32 gstate_sreserved[MD_SB_GENERIC_STATE_WORDS - 9];
+
+	/*
+	 * Personality information
+	 */
+	__u32 layout;		/*  0 the array's physical layout	      */
+	__u32 chunk_size;	/*  1 chunk size in bytes		      */
+	__u32 root_pv;		/*  2 LV root PV */
+	__u32 root_block;	/*  3 LV root block */
+	__u32 pstate_reserved[MD_SB_PERSONALITY_WORDS - 4];
+
+	/*
+	 * Disks information
+	 */
+	mdp_disk_t disks[MD_SB_DISKS];
+
+	/*
+	 * Reserved
+	 */
+	__u32 reserved[MD_SB_RESERVED_WORDS];
+
+	/*
+	 * Active descriptor
+	 */
+	mdp_disk_t this_disk;
+
+} mdp_super_t;
+
+#ifdef __TINYC__
+typedef unsigned long long __u64;
+#endif
+
+static inline __u64 md_event(mdp_super_t *sb) {
+	__u64 ev = sb->events_hi;
+	return (ev<<32)| sb->events_lo;
+}
+
+#endif 
+
diff -urN multipath-tools-0.1.5/dmadm/md_u.h multipath-tools-0.1.6/dmadm/md_u.h
--- multipath-tools-0.1.5/dmadm/md_u.h	1970-01-01 01:00:00.000000000 +0100
+++ multipath-tools-0.1.6/dmadm/md_u.h	2004-03-29 09:33:01.000000000 +0200
@@ -0,0 +1,116 @@
+/*
+   md_u.h : user <=> kernel API between Linux raidtools and RAID drivers
+          Copyright (C) 1998 Ingo Molnar
+	  
+   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.
+   
+   You should have received a copy of the GNU General Public License
+   (for example /usr/src/linux/COPYING); if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+*/
+
+#ifndef _MD_U_H
+#define _MD_U_H
+
+/* ioctls */
+
+/* status */
+#define RAID_VERSION		_IOR (MD_MAJOR, 0x10, mdu_version_t)
+#define GET_ARRAY_INFO		_IOR (MD_MAJOR, 0x11, mdu_array_info_t)
+#define GET_DISK_INFO		_IOR (MD_MAJOR, 0x12, mdu_disk_info_t)
+#define PRINT_RAID_DEBUG	_IO (MD_MAJOR, 0x13)
+#define RAID_AUTORUN		_IO (MD_MAJOR, 0x14)
+
+/* configuration */
+#define CLEAR_ARRAY		_IO (MD_MAJOR, 0x20)
+#define ADD_NEW_DISK		_IOW (MD_MAJOR, 0x21, mdu_disk_info_t)
+#define HOT_REMOVE_DISK		_IO (MD_MAJOR, 0x22)
+#define SET_ARRAY_INFO		_IOW (MD_MAJOR, 0x23, mdu_array_info_t)
+#define SET_DISK_INFO		_IO (MD_MAJOR, 0x24)
+#define WRITE_RAID_INFO		_IO (MD_MAJOR, 0x25)
+#define UNPROTECT_ARRAY		_IO (MD_MAJOR, 0x26)
+#define PROTECT_ARRAY		_IO (MD_MAJOR, 0x27)
+#define HOT_ADD_DISK		_IO (MD_MAJOR, 0x28)
+#define SET_DISK_FAULTY		_IO (MD_MAJOR, 0x29)
+
+/* usage */
+#define RUN_ARRAY		_IOW (MD_MAJOR, 0x30, mdu_param_t)
+#define START_ARRAY		_IO (MD_MAJOR, 0x31)
+#define STOP_ARRAY		_IO (MD_MAJOR, 0x32)
+#define STOP_ARRAY_RO		_IO (MD_MAJOR, 0x33)
+#define RESTART_ARRAY_RW	_IO (MD_MAJOR, 0x34)
+
+typedef struct mdu_version_s {
+	int major;
+	int minor;
+	int patchlevel;
+} mdu_version_t;
+
+typedef struct mdu_array_info_s {
+	/*
+	 * Generic constant information
+	 */
+	int major_version;
+	int minor_version;
+	int patch_version;
+	int ctime;
+	int level;
+	int size;
+	int nr_disks;
+	int raid_disks;
+	int md_minor;
+	int not_persistent;
+
+	/*
+	 * Generic state information
+	 */
+	int utime;		/*  0 Superblock update time		      */
+	int state;		/*  1 State bits (clean, ...)		      */
+	int active_disks;	/*  2 Number of currently active disks	      */
+	int working_disks;	/*  3 Number of working disks		      */
+	int failed_disks;	/*  4 Number of failed disks		      */
+	int spare_disks;	/*  5 Number of spare disks		      */
+
+	/*
+	 * Personality information
+	 */
+	int layout;		/*  0 the array's physical layout	      */
+	int chunk_size;	/*  1 chunk size in bytes		      */
+
+} mdu_array_info_t;
+
+typedef struct mdu_disk_info_s {
+	/*
+	 * configuration/status of one particular disk
+	 */
+	int number;
+	int major;
+	int minor;
+	int raid_disk;
+	int state;
+
+} mdu_disk_info_t;
+
+typedef struct mdu_start_info_s {
+	/*
+	 * configuration/status of one particular disk
+	 */
+	int major;
+	int minor;
+	int raid_disk;
+	int state;
+
+} mdu_start_info_t;
+
+typedef struct mdu_param_s
+{
+	int			personality;	/* 1,2,3,4 */
+	int			chunk_size;	/* in bytes */
+	int			max_fault;	/* unused for now */
+} mdu_param_t;
+
+#endif 
+
diff -urN multipath-tools-0.1.5/dmadm/mdadm.h multipath-tools-0.1.6/dmadm/mdadm.h
--- multipath-tools-0.1.5/dmadm/mdadm.h	1970-01-01 01:00:00.000000000 +0100
+++ multipath-tools-0.1.6/dmadm/mdadm.h	2004-03-29 18:12:33.000000000 +0200
@@ -0,0 +1,221 @@
+/*
+ * mdadm - manage Linux "md" devices aka RAID arrays.
+ *
+ * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
+ *
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *    Author: Neil Brown
+ *    Email: <neilb@cse.unsw.edu.au>
+ *    Paper: Neil Brown
+ *           School of Computer Science and Engineering
+ *           The University of New South Wales
+ *           Sydney, 2052
+ *           Australia
+ */
+
+#define	__USE_LARGEFILE64
+#define	MD_MAJOR 9
+#define FILE_NAME_SIZE 255
+#define DM_PARAMS_SIZE 2048
+
+#include	<unistd.h>
+#include	<sys/types.h>
+#include	<sys/stat.h>
+#include	<stdlib.h>
+#include	<time.h>
+#include	<fcntl.h>
+#include	<stdio.h>
+#include	<errno.h>
+#include	<string.h>
+#include	<linux/kdev_t.h>
+#include	<sys/mount.h>
+#include	<asm/types.h>
+#include	<sys/ioctl.h>
+
+#ifndef BLKGETSIZE
+#define BLKGETSIZE _IO(0x12,96) /* return device size /512 (long *arg) */
+#endif
+
+#ifndef BLKSSZGET
+#define BLKSSZGET _IO(0x12,104) /* get block device sector size */
+#endif
+
+#ifndef BLKFLSBUF
+#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */
+#endif
+
+#ifndef BLKGETSIZE64
+#define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (u64 *arg) */
+#endif
+
+#include	"md_u.h"
+#include	"md_p.h"
+
+//extern __off64_t lseek64 __P ((int __fd, __off64_t __offset, int __whence));
+#define lseek64 llseek
+
+#define Name	"dmadm"
+
+enum mode {
+	ASSEMBLE=1,
+	BUILD,
+	CREATE,
+	MANAGE,
+	MISC,
+	MONITOR,
+};
+
+extern char short_options[];
+extern struct option long_options[];
+extern char Version[], Usage[], Help[], OptionHelp[],
+	Help_create[], Help_build[], Help_assemble[],
+	Help_manage[], Help_misc[], Help_monitor[], Help_config[];
+
+/* structures read from config file */
+/* List of mddevice names and identifiers
+ * Identifiers can be:
+ *    uuid=128-hex-uuid
+ *    super-minor=decimal-minor-number-from-superblock
+ *    devices=comma,separated,list,of,device,names,with,wildcards
+ *
+ * If multiple fields are present, the intersection of all matching
+ * devices is considered
+ */
+#define UnSet (0xfffe)
+typedef struct mddev_ident_s {
+	char *devname;
+	
+	int uuid_set;
+	__u32 uuid[4];
+
+	unsigned int super_minor;
+
+	char *devices;		/* comma separated list of device
+				 * names with wild cards
+				 */
+	int level;
+	unsigned int raid_disks;
+	unsigned int spare_disks;
+	char *spare_group;
+	struct mddev_ident_s *next;
+} *mddev_ident_t;
+
+/* List of device names - wildcards expanded */
+typedef struct mddev_dev_s {
+	char *devname;
+	char disposition;	/* 'a' for add, 'r' for remove, 'f' for fail.
+				 * Not set for names read from .config
+				 */
+	struct mddev_dev_s *next;
+} *mddev_dev_t;
+
+typedef struct mapping {
+	char *name;
+	int num;
+} mapping_t;
+
+
+struct mdstat_ent {
+	char		*dev;
+	int		devnum;
+	int		active;
+	char		*level;
+	char		*pattern; /* U or up, _ for down */
+	int		percent; /* -1 if no resync */
+	struct mdstat_ent *next;
+};
+
+extern struct mdstat_ent *mdstat_read(void);
+extern void free_mdstat(struct mdstat_ent *ms);
+
+#ifndef Sendmail
+#define Sendmail "/usr/lib/sendmail -t"
+#endif
+
+extern char *map_num(mapping_t *map, int num);
+extern int map_name(mapping_t *map, char *name);
+extern mapping_t r5layout[], pers[], modes[];
+
+extern char *map_dev(int major, int minor);
+
+
+extern int Manage_ro(char *devname, int fd, int readonly);
+extern int Manage_runstop(char *devname, int fd, int runstop);
+extern int Manage_subdevs(char *devname, int fd,
+			  mddev_dev_t devlist);
+
+
+extern int Assemble(char *mddev, int mdfd,
+		    mddev_ident_t ident,
+		    char *conffile,
+		    mddev_dev_t devlist,
+		    int readonly, int runstop,
+		    char *update,
+		    int verbose, int force);
+
+extern int Build(char *mddev, int mdfd, int chunk, int level,
+		 int raiddisks,
+		 mddev_dev_t devlist);
+
+
+extern int Create(char *mddev, int mdfd,
+		  int chunk, int level, int layout, unsigned long size, int raiddisks, int sparedisks,
+		  int subdevs, mddev_dev_t devlist,
+		  int runstop, int verbose, int force);
+
+extern int Detail(char *dev, int brief, int test);
+extern int Query(char *dev);
+extern int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust);
+extern int Monitor(mddev_dev_t devlist,
+		   char *mailaddr, char *alert_cmd,
+		   int period, int daemonise, int scan, int oneshot,
+		   char *config, int test);
+
+extern int Kill(char *dev, int force);
+
+extern int md_get_version(int fd);
+extern int get_linux_version(void);
+extern int parse_uuid(char *str, int uuid[4]);
+extern int check_ext2(int fd, char *name);
+extern int check_reiser(int fd, char *name);
+extern int check_raid(int fd, char *name);
+
+extern mddev_ident_t conf_get_ident(char *conffile, char *dev);
+extern mddev_dev_t conf_get_devs(char *conffile);
+extern char *conf_get_mailaddr(char *conffile);
+extern char *conf_get_program(char *conffile);
+extern char *conf_line(FILE *file);
+extern char *conf_word(FILE *file, int allow_key);
+extern void free_line(char *line);
+extern int match_oneof(char *devices, char *devname);
+extern int load_super(int fd, mdp_super_t *super);
+extern void uuid_from_super(int uuid[4], mdp_super_t *super);
+extern int same_uuid(int a[4], int b[4]);
+extern int compare_super(mdp_super_t *first, mdp_super_t *second);
+extern unsigned long calc_sb_csum(mdp_super_t *super);
+extern int store_super(int fd, mdp_super_t *super);
+extern int enough(int level, int raid_disks, int avail_disks);
+extern int ask(char *mesg);
+
+
+extern char *human_size(long long bytes);
+char *human_size_brief(long long bytes);
+
+extern void put_md_name(char *name);
+extern char *get_md_name(int dev);
+
+extern char DefaultConfFile[];
diff -urN multipath-tools-0.1.5/dmadm/util.c multipath-tools-0.1.6/dmadm/util.c
--- multipath-tools-0.1.5/dmadm/util.c	1970-01-01 01:00:00.000000000 +0100
+++ multipath-tools-0.1.6/dmadm/util.c	2004-03-29 10:29:01.000000000 +0200
@@ -0,0 +1,437 @@
+/*
+ * mdadm - manage Linux "md" devices aka RAID arrays.
+ *
+ * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
+ *
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *    Author: Neil Brown
+ *    Email: <neilb@cse.unsw.edu.au>
+ *    Paper: Neil Brown
+ *           School of Computer Science and Engineering
+ *           The University of New South Wales
+ *           Sydney, 2052
+ *           Australia
+ */
+
+#include	"mdadm.h"
+#include	"md_p.h"
+#include	<sys/utsname.h>
+#include	<ctype.h>
+
+/*
+ * Parse a 128 bit uuid in 4 integers
+ * format is 32 hexx nibbles with options :.<space> separator
+ * If not exactly 32 hex digits are found, return 0
+ * else return 1
+ */
+int parse_uuid(char *str, int uuid[4])
+{
+    int hit = 0; /* number of Hex digIT */
+    int i;
+    char c;
+    for (i=0; i<4; i++) uuid[i]=0;
+
+    while ((c= *str++)) {
+	int n;
+	if (c>='0' && c<='9')
+	    n = c-'0';
+	else if (c>='a' && c <= 'f')
+	    n = 10 + c - 'a';
+	else if (c>='A' && c <= 'F')
+	    n = 10 + c - 'A';
+	else if (strchr(":. -", c))
+	    continue;
+	else return 0;
+
+	if (hit<32) {
+	    uuid[hit/8] <<= 4;
+	    uuid[hit/8] += n;
+	}
+	hit++;
+    }
+    if (hit == 32)
+	return 1;
+    return 0;
+    
+}
+
+
+/*
+ * Get the md version number.
+ * We use the RAID_VERSION ioctl if it is supported
+ * If not, but we have a block device with major '9', we assume
+ * 0.36.0
+ *
+ * Return version number as 24 but number - assume version parts
+ * always < 255
+ */
+
+int md_get_version(int fd)
+{
+    struct stat stb;
+    mdu_version_t vers;
+
+    if (fstat(fd, &stb)<0)
+	return -1;
+    if ((S_IFMT&stb.st_mode) != S_IFBLK)
+	return -1;
+
+    if (ioctl(fd, RAID_VERSION, &vers) == 0)
+	return  (vers.major*10000) + (vers.minor*100) + vers.patchlevel;
+    if (errno == EACCES)
+	    return -1;
+    if (MAJOR(stb.st_rdev) == MD_MAJOR)
+	return (3600);
+    return -1;
+}
+
+    
+int get_linux_version()
+{
+	struct utsname name;
+	char *cp;
+	int a,b,c;
+	if (uname(&name) <0)
+		return -1;
+
+	cp = name.release;
+	a = strtoul(cp, &cp, 10);
+	if (*cp != '.') return -1;
+	b = strtoul(cp+1, &cp, 10);
+	if (*cp != '.') return -1;
+	c = strtoul(cp+1, NULL, 10);
+
+	return (a*1000000)+(b*1000)+c;
+}
+
+int enough(int level, int raid_disks, int avail_disks)
+{
+	switch (level) {
+	case -4:
+		return avail_disks>= 1;
+	case -1:
+	case 0:
+		return avail_disks == raid_disks;
+	case 1:
+		return avail_disks >= 1;
+	case 4:
+	case 5:
+		return avail_disks >= raid_disks-1;
+	case 6:
+		return avail_disks >= raid_disks-2;
+	default:
+		return 0;
+	}
+}
+
+int same_uuid(int a[4], int b[4])
+{
+    if (a[0]==b[0] &&
+	a[1]==b[1] &&
+	a[2]==b[2] &&
+	a[3]==b[3])
+	return 1;
+    return 0;
+}
+
+void uuid_from_super(int uuid[4], mdp_super_t *super)
+{
+    uuid[0] = super->set_uuid0;
+    if (super->minor_version >= 90) {
+	uuid[1] = super->set_uuid1;
+	uuid[2] = super->set_uuid2;
+	uuid[3] = super->set_uuid3;
+    } else {
+	uuid[1] = 0;
+	uuid[2] = 0;
+	uuid[3] = 0;
+    }
+}
+
+int compare_super(mdp_super_t *first, mdp_super_t *second)
+{
+    /*
+     * return:
+     *  0 same, or first was empty, and second was copied
+     *  1 second had wrong number
+     *  2 wrong uuid
+     *  3 wrong other info
+     */
+    int uuid1[4], uuid2[4];
+    if (second->md_magic != MD_SB_MAGIC)
+	return 1;
+    if (first-> md_magic != MD_SB_MAGIC) {
+	memcpy(first, second, sizeof(*first));
+	return 0;
+    }
+
+    uuid_from_super(uuid1, first);
+    uuid_from_super(uuid2, second);
+    if (!same_uuid(uuid1, uuid2))
+	return 2;
+    if (first->major_version != second->major_version ||
+	first->minor_version != second->minor_version ||
+	first->patch_version != second->patch_version ||
+	first->gvalid_words  != second->gvalid_words  ||
+	first->ctime         != second->ctime         ||
+	first->level         != second->level         ||
+	first->size          != second->size          ||
+	first->raid_disks    != second->raid_disks    )
+	return 3;
+
+    return 0;
+}
+
+int load_super(int fd, mdp_super_t *super)
+{
+	/* try to read in the superblock
+	 *
+	 * return
+	 *   0 - success
+	 *   1 - no block size
+	 *   2 - too small
+	 *   3 - no seek
+	 *   4 - no read
+	 *   5 - no magic
+	 *   6 - wrong major version
+	 */
+	unsigned long size;
+	unsigned long long offset;
+    
+	if (ioctl(fd, BLKGETSIZE, &size))
+		return 1;
+
+	if (size < MD_RESERVED_SECTORS*2)
+		return 2;
+	
+	offset = MD_NEW_SIZE_SECTORS(size);
+
+	offset *= 512;
+
+	ioctl(fd, BLKFLSBUF, 0); /* make sure we read current data */
+
+	if (lseek64(fd, offset, 0)< 0LL)
+		return 3;
+
+	if (read(fd, super, sizeof(*super)) != sizeof(*super))
+		return 4;
+
+	if (super->md_magic != MD_SB_MAGIC)
+		return 5;
+
+	if (super->major_version != 0)
+		return 6;
+	return 0;
+}
+
+int store_super(int fd, mdp_super_t *super)
+{
+	long size;
+	long long offset;
+    
+	if (ioctl(fd, BLKGETSIZE, &size))
+		return 1;
+
+	if (size < MD_RESERVED_SECTORS*2)
+		return 2;
+	
+	offset = MD_NEW_SIZE_SECTORS(size);
+
+	offset *= 512;
+
+	if (lseek64(fd, offset, 0)< 0LL)
+		return 3;
+
+	if (write(fd, super, sizeof(*super)) != sizeof(*super))
+		return 4;
+
+	return 0;
+}
+    
+
+
+int check_raid(int fd, char *name)
+{
+	mdp_super_t super;
+	time_t crtime;
+	if (load_super(fd, &super))
+		return 0;
+	/* Looks like a raid array .. */
+	fprintf(stderr, Name ": %s appears to be part of a raid array:\n",
+		name);
+	crtime = super.ctime;
+	return 1;
+}
+
+char *map_num(mapping_t *map, int num)
+{
+	while (map->name) {
+		if (map->num == num)
+			return map->name;
+		map++;
+	}
+	return NULL;
+}
+
+int map_name(mapping_t *map, char *name)
+{
+	while (map->name) {
+		if (strcmp(map->name, name)==0)
+			return map->num;
+		map++;
+	}
+	return UnSet;
+}
+
+unsigned long calc_sb_csum(mdp_super_t *super)
+{
+        unsigned int  oldcsum = super->sb_csum;
+	unsigned long long newcsum = 0;
+	unsigned long csum;
+	int i;
+	unsigned int *superc = (int*) super;
+	super->sb_csum = 0;
+
+	for(i=0; i<MD_SB_BYTES/4; i++)
+		newcsum+= superc[i];
+	csum = (newcsum& 0xffffffff) + (newcsum>>32);
+	super->sb_csum = oldcsum;
+	return csum;
+}
+
+char *human_size(long long bytes)
+{
+	static char buf[30];
+	
+
+	if (bytes < 5000*1024)
+		buf[0]=0;
+	else if (bytes < 2*1024LL*1024LL*1024LL)
+		sprintf(buf, " (%ld.%02ld MiB %ld.%02ld MB)",
+			(long)(bytes>>20),
+			(long)((bytes&0xfffff)+0x100000/200)/(0x100000/100),
+			(long)(bytes/1000/1000),
+			(long)(((bytes%1000000)+5000)/10000)
+			);
+	else
+		sprintf(buf, " (%ld.%02ld GiB %ld.%02ld GB)",
+			(long)(bytes>>30),
+			(long)(((bytes>>10)&0xfffff)+0x100000/200)/(0x100000/100),
+			(long)(bytes/1000LL/1000LL/1000LL),
+			(long)((((bytes/1000)%1000000)+5000)/10000)
+			);
+	return buf;
+}
+
+char *human_size_brief(long long bytes)
+{
+	static char buf[30];
+	
+
+	if (bytes < 5000*1024)
+		sprintf(buf, "%ld.%02ldKiB",
+			(long)(bytes>>10), (long)(((bytes&1023)*100+512)/1024)
+			);
+	else if (bytes < 2*1024LL*1024LL*1024LL)
+		sprintf(buf, "%ld.%02ldMiB",
+			(long)(bytes>>20),
+			(long)((bytes&0xfffff)+0x100000/200)/(0x100000/100)
+			);
+	else
+		sprintf(buf, "%ld.%02ldGiB",
+			(long)(bytes>>30),
+			(long)(((bytes>>10)&0xfffff)+0x100000/200)/(0x100000/100)
+			);
+	return buf;
+}
+
+static int mdp_major = -1;
+/*
+void get_mdp_major(void)
+{
+	FILE *fl = fopen("/proc/devices", "r");
+	char *w;
+	int have_block = 0;
+	int have_devices = 0;
+	int last_num = -1;
+	if (!fl)
+		return;
+	while ((w = conf_word(fl, 1))) {
+		if (have_block && strcmp(w, "devices:")==0)
+			have_devices = 1;
+		have_block =  (strcmp(w, "Block")==0);
+		if (isdigit(w[0]))
+			last_num = atoi(w);
+		if (have_devices && strcmp(w, "mdp")==0)
+			mdp_major = last_num;
+		free(w);
+	}
+	fclose(fl);
+}
+
+char *get_md_name(int dev)
+{
+*/
+	/* find /dev/md%d or /dev/md/%d or make a device /dev/.tmp.md%d */
+	/* if dev < 0, want /dev/md/d%d or find mdp in /proc/devices ... */
+/*
+	static char devname[50];
+	struct stat stb;
+	dev_t rdev;
+
+	if (dev < 0) {
+
+		if (mdp_major < 0) get_mdp_major();
+		if (mdp_major < 0) return NULL;
+		rdev = MKDEV(mdp_major, (-1-dev)<<6);
+		sprintf(devname, "/dev/md/d%d", -1-dev);
+		if (stat(devname, &stb) == 0
+		    && (S_IFMT&stb.st_mode) == S_IFBLK
+		    && (stb.st_rdev == rdev))
+			return devname;
+	} else {
+		rdev = MKDEV(MD_MAJOR, dev);
+		sprintf(devname, "/dev/md%d", dev);
+		if (stat(devname, &stb) == 0
+		    && (S_IFMT&stb.st_mode) == S_IFBLK
+		    && (stb.st_rdev == rdev))
+			return devname;
+
+		sprintf(devname, "/dev/md/%d", dev);
+		if (stat(devname, &stb) == 0
+		    && (S_IFMT&stb.st_mode) == S_IFBLK
+		    && (stb.st_rdev == rdev))
+			return devname;
+	}
+	sprintf(devname, "/dev/.tmp.md%d", dev);
+	if (mknod(devname, S_IFBLK | 0600, rdev) == -1)
+		return NULL;
+
+	if (stat(devname, &stb) == 0
+	    && (S_IFMT&stb.st_mode) == S_IFBLK
+	    && (stb.st_rdev == rdev))
+		return devname;
+	unlink(devname);
+	return NULL;
+}
+
+void put_md_name(char *name)
+{
+	if (strncmp(name, "/dev/.tmp.md", 12)==0)
+		unlink(name);
+}
+*/
Binary files multipath-tools-0.1.5/dmadm/util.o and multipath-tools-0.1.6/dmadm/util.o differ
diff -urN multipath-tools-0.1.5/multipathd/checkers.c multipath-tools-0.1.6/multipathd/checkers.c
--- multipath-tools-0.1.5/multipathd/checkers.c	2004-02-29 10:39:25.000000000 +0100
+++ multipath-tools-0.1.6/multipathd/checkers.c	2004-04-01 15:36:38.000000000 +0200
@@ -23,6 +23,10 @@
 	char buf;
 
 	fd = open (devnode, O_RDONLY);
+
+	if (fd <= 0)
+		return fd;
+
 	if (read (fd, &buf, 1) != 1)
 		r = 0;
 	else
@@ -52,11 +56,13 @@
         io_hdr.timeout = 20000;
         io_hdr.pack_id = 0;
         if (ioctl(fd, SG_IO, &io_hdr) < 0) {
-                close(fd);
+                close (fd);
                 return 0;
         }
         if (io_hdr.info & SG_INFO_OK_MASK) {
+		close (fd);
                 return 0;
         }
+        close (fd);
         return 1;
 }
