File multipath-tools-suse-update of Package multipath-tools

 Makefile.inc                            |    1 -
 devmap_name/Makefile                    |    5 +-
 kpartx/Makefile                         |   16 +-
 kpartx/bsd.c                            |   39 +++-
 kpartx/devmapper.c                      |   32 +++-
 kpartx/devmapper.h                      |    1 +
 kpartx/dos.c                            |    7 +-
 kpartx/kpartx.c                         |  158 +++++++++---
 kpartx/kpartx.h                         |    4 +
 kpartx/kpartx.rules                     |   36 +++
 kpartx/kpartx_id                        |   93 +++++++
 kpartx/sun.c                            |  131 ++++++++++
 libcheckers/Makefile                    |    4 +-
 libmultipath/Makefile                   |    8 +-
 libmultipath/config.h                   |    1 +
 libmultipath/configure.c                |    4 +-
 libmultipath/discovery.c                |  422 ++++++++++++-------------------
 libmultipath/discovery.h                |    7 +-
 libmultipath/hwtable.c                  |   14 +-
 libmultipath/list.h                     |  289 +++++++++++++++++++++
 libmultipath/print.c                    |   47 ++--
 libmultipath/structs.h                  |   15 +-
 libmultipath/structs_vec.c              |    7 +-
 libmultipath/sysfs.c                    |  405 +++++++++++++++++++++++++++++
 libmultipath/sysfs.h                    |   20 ++
 libmultipath/uevent.c                   |   99 +++++---
 libmultipath/util.c                     |   52 ++++
 libmultipath/util.h                     |    4 +-
 multipath/Makefile                      |   12 +-
 multipath/main.c                        |   11 +-
 multipath/multipath.init.suse           |  104 ++++++++
 multipath/multipath.rules               |   19 +-
 multipathd/Makefile                     |    7 +-
 multipathd/cli_handlers.c               |   17 ++-
 multipathd/main.c                       |   92 +++----
 multipathd/main.h                       |    2 +-
 multipathd/multipathd.init.suse         |  155 +++++++++++
 path_priority/pp_alua/Makefile          |    3 +-
 path_priority/pp_balance_units/Makefile |    6 +-
 path_priority/pp_emc/Makefile           |    2 +-
 path_priority/pp_hds_modular/Makefile   |    2 +-
 path_priority/pp_netapp/Makefile        |    2 +-
 path_priority/pp_random/Makefile        |    2 +-
 path_priority/pp_tpc/Makefile           |    2 +-
 44 files changed, 1881 insertions(+), 478 deletions(-)

diff --git a/Makefile.inc b/Makefile.inc
index fe6cbdf..786565c 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -17,7 +17,6 @@ ifeq ($(strip $(BUILD)),klibc)
 	CC = klcc
 	klibcdir = /usr/lib/klibc
 	libdm    = $(klibcdir)/lib/libdevmapper.a
-	libsysfs = $(klibcdir)/lib/libsysfs.a
 endif
 
 prefix      = 
diff --git a/devmap_name/Makefile b/devmap_name/Makefile
index 8b0c678..57051d9 100644
--- a/devmap_name/Makefile
+++ b/devmap_name/Makefile
@@ -18,7 +18,7 @@ EXEC = devmap_name
 all: $(BUILD)
 
 prepare:
-	rm -f core *.o *.gz
+	rm -f core *.o
 
 glibc: prepare $(OBJS)
 	$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
@@ -34,7 +34,6 @@ install: $(EXEC) $(EXEC).8
 
 uninstall:
 	rm $(DESTDIR)$(bindir)/$(EXEC)
-	rm $(DESTDIR)$(mandir)/$(EXEC).8
 
 clean:
-	rm -f core *.o $(EXEC) *.gz
+	rm -f core *.o $(EXEC)
diff --git a/kpartx/Makefile b/kpartx/Makefile
index 522a6a0..a8ea2be 100644
--- a/kpartx/Makefile
+++ b/kpartx/Makefile
@@ -10,11 +10,11 @@ CFLAGS += -I. -D_LARGEFILE64_SOURCE
 
 ifeq ($(strip $(BUILD)),klibc)
 	OBJS = bsd.o dos.o kpartx.o solaris.o unixware.o gpt.o crc32.o \
-	       lopart.o xstrncpy.o devmapper.o dasd.o mac.o \
+	       lopart.o xstrncpy.o devmapper.o dasd.o mac.o sun.o \
 	       $(MULTIPATHLIB)-$(BUILD).a $(libdm)
 else
 	LDFLAGS = -ldevmapper
-	OBJS = bsd.o dos.o kpartx.o solaris.o unixware.o dasd.o \
+	OBJS = bsd.o dos.o kpartx.o solaris.o unixware.o dasd.o sun.o \
 	       gpt.o mac.o crc32.o lopart.o xstrncpy.o devmapper.o
 endif
 
@@ -23,7 +23,7 @@ EXEC = kpartx
 all: $(BUILD)
 
 prepare:
-	rm -f core *.o *.gz
+	rm -f core *.o
 
 glibc: prepare $(OBJS)
 	$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
@@ -34,15 +34,17 @@ klibc: prepare $(OBJS)
 $(MULTIPATHLIB)-$(BUILD).a:
 	make -C $(multipathdir) BUILD=$(BUILD)
 
-install: $(EXEC) $(EXEC).8
+install: $(EXEC) kpartx_id $(EXEC).8
 	install -d $(DESTDIR)$(bindir)
-	install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)
+	install -m 755 $(EXEC) $(DESTDIR)$(bindir)
+	install -m 755 kpartx_id $(DESTDIR)$(bindir)
 	install -d $(DESTDIR)$(mandir)
 	install -m 644 $(EXEC).8 $(DESTDIR)$(mandir)
+	install -d $(DESTDIR)/etc/udev/rules.d
+	install -m 644 kpartx.rules $(DESTDIR)/etc/udev/rules.d/70-kpartx.rules
 
 uninstall:
 	rm -f $(DESTDIR)$(bindir)/$(EXEC)
-	rm -f $(DESTDIR)$(mandir)/$(EXEC).8.gz
 
 clean:
-	rm -f core *.o $(EXEC) *.gz
+	rm -f core *.o $(EXEC)
diff --git a/kpartx/bsd.c b/kpartx/bsd.c
index 3ae2dc4..f87175e 100644
--- a/kpartx/bsd.c
+++ b/kpartx/bsd.c
@@ -10,7 +10,7 @@ struct bsd_disklabel {
 	short int	d_type;		/* drive type */
 	short int	d_subtype;	/* controller/d_type specific */
 	char	d_typename[16];		/* type name, e.g. "eagle" */
-	char	d_packname[16];		/* pack identifier */ 
+	char	d_packname[16];		/* pack identifier */
 	unsigned int	d_secsize;	/* # of bytes per sector */
 	unsigned int	d_nsectors;	/* # of data sectors per track */
 	unsigned int	d_ntracks;	/* # of tracks per cylinder */
@@ -50,12 +50,12 @@ int
 read_bsd_pt(int fd, struct slice all, struct slice *sp, int ns) {
 	struct bsd_disklabel *l;
 	struct bsd_partition *p;
-	unsigned int offset = all.start;
+	unsigned int offset = all.start, end;
 	int max_partitions;
 	char *bp;
-	int n = 0;
+	int n = 0, i, j;
 
-	bp = getblock(fd, offset+1); 	/* 1 sector suffices */
+	bp = getblock(fd, offset+1);    /* 1 sector suffices */
 	if (bp == NULL)
 		return -1;
 
@@ -79,5 +79,36 @@ read_bsd_pt(int fd, struct slice all, st
 			break;
 		}
 	}
+	/*
+	 * Convention has it that the bsd disklabel will always have
+	 * the 'c' partition spanning the entire disk.
+	 * So we have to check for contained slices.
+	 */
+	for(i = 0; i < n; i++) {
+		if (sp[i].size == 0)
+			continue;
+
+		end = sp[i].start + sp[i].size;
+		for(j = 0; j < n; j ++) {
+			if ( i == j )
+				continue;
+			if (sp[j].size == 0)
+				continue;
+
+			if (sp[i].start < sp[j].start) {
+				if (end > sp[j].start &&
+				    end < sp[j].start + sp[j].size) {
+					/* Invalid slice */
+					fprintf(stderr,
+						"bsd_disklabel: slice %d overlaps with %d\n", i , j);
+					sp[i].size = 0;
+				}
+			} else {
+				if (end <= sp[j].start + sp[j].size) {
+					sp[i].container = j + 1;
+				}
+			}
+		}
+	}
 	return n;
 }
diff --git a/kpartx/devmapper.c b/kpartx/devmapper.c
index 4b228ed..6e3e198 100644
--- a/kpartx/devmapper.c
+++ b/kpartx/devmapper.c
@@ -200,7 +200,8 @@ char *
 dm_mapuuid(int major, int minor)
 {
 	struct dm_task *dmt;
-	char *tmp, *uuid = NULL;
+	const char *tmp;
+	char *uuid = NULL;
 
 	if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
 		return NULL;
@@ -219,3 +220,32 @@ out:
 	dm_task_destroy(dmt);
 	return uuid;
 }
+
+int
+dm_devn (char * mapname, int *major, int *minor)
+{
+	int r = 1;
+	struct dm_task *dmt;
+	struct dm_info info;
+
+	if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
+		return 0;
+
+	if (!dm_task_set_name(dmt, mapname))
+		goto out;
+
+	if (!dm_task_run(dmt))
+		goto out;
+
+	if (!dm_task_get_info(dmt, &info))
+		goto out;
+
+	*major = info.major;
+	*minor = info.minor;
+
+	r = 0;
+out:
+	dm_task_destroy(dmt);
+	return r;
+}
+
diff --git a/kpartx/devmapper.h b/kpartx/devmapper.h
index e20e456..ccdbead 100644
--- a/kpartx/devmapper.h
+++ b/kpartx/devmapper.h
@@ -6,3 +6,4 @@ int dm_map_present (char *);
 char * dm_mapname(int major, int minor);
 dev_t dm_get_first_dep(char *devname);
 char * dm_mapuuid(int major, int minor);
+int dm_devn (char * mapname, int *major, int *minor);
diff --git a/kpartx/dos.c b/kpartx/dos.c
index a707423..1691105 100644
--- a/kpartx/dos.c
+++ b/kpartx/dos.c
@@ -16,7 +16,7 @@ is_extended(int type) {
 }
 
 static int
-read_extended_partition(int fd, struct partition *ep,
+read_extended_partition(int fd, struct partition *ep, int en,
 			struct slice *sp, int ns)
 {
 	struct partition p;
@@ -53,6 +53,7 @@ read_extended_partition(int fd, struct p
 			if (n < ns) {
 				sp[n].start = here + le32_to_cpu(p.start_sect);
 				sp[n].size = le32_to_cpu(p.nr_sects);
+				sp[n].container = en + 1;
 				n++;
 			} else {
 				fprintf(stderr,
@@ -97,9 +98,7 @@ read_dos_pt(int fd, struct slice all, st
 			break;
 		}
 		if (is_extended(p.sys_type)) {
-			n += read_extended_partition(fd, &p, sp+n, ns-n);
-			/* hide the extended partition itself */
-			sp[i].size = 0;
+			n += read_extended_partition(fd, &p, i, sp+n, ns-n);
 		}
 	}
 	return n;
diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c
index b406b95..52dfe93 100644
--- a/kpartx/kpartx.c
+++ b/kpartx/kpartx.c
@@ -79,6 +79,7 @@ initpts(void)
 	addpts("unixware", read_unixware_pt);
 	addpts("dasd", read_dasd_pt);
 	addpts("mac", read_mac_pt);
+	addpts("sun", read_sun_pt);
 }
 
 static char short_opts[] = "ladgvnp:t:";
@@ -115,7 +116,6 @@ strip_slash (char * device)
 	char * p = device;
 
 	while (*(p++) != 0x0) {
-		
 		if (*p == '/')
 			*p = '!';
 	}
@@ -125,9 +125,9 @@ static int
 find_devname_offset (char * device)
 {
 	char *p, *q = NULL;
-	
+
 	p = device;
-	
+
 	while (*p++)
 		if (*p == '/')
 			q = p;
@@ -182,7 +182,7 @@ get_hotplug_device(void)
 
 int
 main(int argc, char **argv){
-        int fd, i, j, k, n, op, off, arg;
+	int fd, i, j, m, n, op, off, arg, c, d;
 	struct slice all;
 	struct pt *ptp;
 	enum action what = LIST;
@@ -205,7 +205,7 @@ main(int argc, char **argv){
 	type = device = diskdevice = NULL;
 	memset(&all, 0, sizeof(all));
 	memset(&partname, 0, sizeof(partname));
-	
+
 	/* Check whether hotplug mode. */
 	progname = strrchr(argv[0], '/');
 
@@ -264,7 +264,7 @@ main(int argc, char **argv){
 	}
 
 	if (dm_prereq(DM_TARGET, 0, 0, 0) && (what == ADD || what == DELETE)) {
-		fprintf(stderr, "device mapper prerequisites not met\n"); 
+		fprintf(stderr, "device mapper prerequisites not met\n");
 		exit(1);
 	}
 
@@ -291,7 +291,7 @@ main(int argc, char **argv){
 
 		if (!loopdev && what == DELETE)
 			exit (0);
-				
+
 		if (!loopdev) {
 			loopdev = find_unused_loop_device();
 
@@ -308,7 +308,7 @@ main(int argc, char **argv){
 		memset(delim, 0, DELIM_SIZE);
 		set_delimiter(device, delim);
 	}
-	
+
 	off = find_devname_offset(device);
 
 	if (!loopdev) {
@@ -320,7 +320,7 @@ main(int argc, char **argv){
 
 	if (!uuid)
 		uuid = device + off;
-		
+
 	if (!mapname)
 		mapname = device + off;
 
@@ -339,7 +339,7 @@ main(int argc, char **argv){
 
 		if (type && strcmp(type, ptp->type))
 			continue;
-		
+
 		/* here we get partitions */
 		n = ptp->fn(fd, all, slices, SIZE(slices));
 
@@ -353,30 +353,50 @@ main(int argc, char **argv){
 		else
 			continue;
 
-		/*
-		 * test for overlap, as in the case of an extended partition
-		 * zero their size to avoid mapping
-		 */
-		for (j=0; j<n; j++) {
-			for (k=j+1; k<n; k++) {
-				if (slices[k].start > slices[j].start &&
-				    slices[k].start < slices[j].start +
-				    slices[j].size)
-					slices[j].size = 0;
-			}
-		}
-
 		switch(what) {
 		case LIST:
-			for (j = 0; j < n; j++) {
+			for (j = 0, c = 0, m = 0; j < n; j++) {
 				if (slices[j].size == 0)
 					continue;
+				if (slices[j].container > 0) {
+					c++;
+					continue;
+				}
+
+				slices[j].minor = m++;
 
 				printf("%s%s%d : 0 %lu %s %lu\n",
-					mapname, delim, j+1,
-					(unsigned long) slices[j].size, device,
-				        (unsigned long) slices[j].start);
+				       mapname, delim, j+1,
+				       (unsigned long) slices[j].size, device,
+				       (unsigned long) slices[j].start);
 			}
+			/* Loop to resolve contained slices */
+			d = c;
+			while (c) {
+				for (j = 0; j < n; j++) {
+					unsigned long start;
+					int k = slices[j].container - 1;
+
+					if (slices[j].size == 0)
+						continue;
+					if (slices[j].minor > 0)
+						continue;
+					if (slices[j].container == 0)
+						continue;
+					slices[j].minor = m++;
+
+					start = slices[j].start - slices[k].start;
+					printf("%s%s%d : 0 %lu /dev/dm-%d %lu\n",
+					       mapname, delim, j+1,
+					       (unsigned long) slices[j].size,
+					       slices[k].minor, start);
+					c--;
+				}
+				/* Terminate loop if nothing more to resolve */
+				if (d == c)
+					break;
+			}
+
 			break;
 
 		case DELETE:
@@ -401,7 +421,7 @@ main(int argc, char **argv){
 			if (S_ISREG (buf.st_mode)) {
 				if (del_loop(device)) {
 					if (verbose)
-				    		printf("can't del loop : %s\n",
+						printf("can't del loop : %s\n",
 							device);
 					exit(1);
 				}
@@ -410,17 +430,23 @@ main(int argc, char **argv){
 			break;
 
 		case ADD:
-			for (j=0; j<n; j++) {
+			for (j=0, c = 0; j<n; j++) {
 				if (slices[j].size == 0)
 					continue;
 
+				/* Skip all contained slices */
+				if (slices[j].container > 0) {
+					c++;
+					continue;
+				}
+
 				if (safe_sprintf(partname, "%s%s%d",
 					     mapname, delim, j+1)) {
 					fprintf(stderr, "partname too small\n");
 					exit(1);
 				}
 				strip_slash(partname);
-				
+
 				if (safe_sprintf(params, "%s %lu", device,
 					     (unsigned long)slices[j].start)) {
 					fprintf(stderr, "params too small\n");
@@ -437,10 +463,74 @@ main(int argc, char **argv){
 					dm_simplecmd(DM_DEVICE_RESUME,
 							partname);
 
+				dm_devn(partname, &slices[j].major,
+					&slices[j].minor);
+
 				if (verbose)
-					printf("add map %s : 0 %lu %s %s\n",
-						partname, slices[j].size,
-						DM_TARGET, params);
+					printf("add map %s (%d:%d): 0 %lu %s %s\n",
+					       partname, slices[j].major,
+					       slices[j].minor, slices[j].size,
+					       DM_TARGET, params);
+			}
+			/* Loop to resolve contained slices */
+			d = c;
+			while (c) {
+				for (j = 0; j < n; j++) {
+					int k = slices[j].container - 1;
+
+					if (slices[j].size == 0)
+						continue;
+
+					/* Skip all existing slices */
+					if (slices[j].minor > 0)
+						continue;
+
+					/* Skip all simple slices */
+					if (k < 0)
+						continue;
+
+					/* Check container slice */
+					if (slices[k].size == 0)
+						fprintf(stderr, "Invalid slice %d\n",
+							k);
+
+					if (safe_sprintf(partname, "%s%s%d",
+							 mapname, delim, j+1)) {
+						fprintf(stderr, "partname too small\n");
+						exit(1);
+					}
+					strip_slash(partname);
+
+					if (safe_sprintf(params, "%d:%d %lu",
+							 slices[k].major,
+							 slices[k].minor,
+							 (unsigned long)slices[j].start)) {
+						fprintf(stderr, "params too small\n");
+						exit(1);
+					}
+
+					op = (dm_map_present(partname) ?
+					      DM_DEVICE_RELOAD : DM_DEVICE_CREATE);
+
+					dm_addmap(op, partname, DM_TARGET, params,
+						  slices[j].size, uuid, j+1);
+
+					if (op == DM_DEVICE_RELOAD)
+						dm_simplecmd(DM_DEVICE_RESUME,
+							     partname);
+
+					dm_devn(partname, &slices[j].major,
+						&slices[j].minor);
+
+					if (verbose)
+						printf("add map %s : 0 %lu %s %s\n",
+						       partname, slices[j].size,
+						       DM_TARGET, params);
+					c--;
+				}
+				/* Terminate loop */
+				if (d == c)
+					break;
 			}
 			break;
 
@@ -516,7 +606,7 @@ getblock (int fd, unsigned int secnr) {
 	bp->next = blockhead;
 	blockhead = bp;
 	bp->block = (char *) xmalloc(READ_SIZE);
-	
+
 	if (read(fd, bp->block, READ_SIZE) != READ_SIZE) {
 		fprintf(stderr, "read error, sector %d\n", secnr);
 		bp->block = NULL;
diff --git a/kpartx/kpartx.h b/kpartx/kpartx.h
index 6a715de..9b3aeca 100644
--- a/kpartx/kpartx.h
+++ b/kpartx/kpartx.h
@@ -22,6 +22,9 @@
 struct slice {
 	unsigned long start;
 	unsigned long size;
+	int container;
+	int major;
+	int minor;
 };
 
 typedef int (ptreader)(int fd, struct slice all, struct slice *sp, int ns);
@@ -33,6 +36,7 @@ extern ptreader read_unixware_pt;
 extern ptreader read_gpt_pt;
 extern ptreader read_dasd_pt;
 extern ptreader read_mac_pt;
+extern ptreader read_sun_pt;
 
 char *getblock(int fd, unsigned int secnr);
 
diff --git a/kpartx/kpartx.rules b/kpartx/kpartx.rules
new file mode 100644
index 0000000..8666d45
--- /dev/null
+++ b/kpartx/kpartx.rules
@@ -0,0 +1,36 @@
+#
+# persistent links for device-mapper devices
+# only hardware-backed device-mapper devices (ie multipath, dmraid,
+# and kpartx) have meaningful persistent device names
+#
+
+KERNEL!="dm-*", GOTO="multipath_end"
+ACTION=="remove", GOTO="multipath_end"
+
+ENV{DM_TABLE_STATE}!="LIVE", GOTO="multipath_end"
+
+ENV{DM_UUID}=="?*", IMPORT{program}=="/sbin/kpartx_id %M %m $env{DM_UUID}"
+
+OPTIONS="link_priority=50"
+
+# Create persistent links for multipath tables
+ENV{DM_UUID}=="mpath-*", \
+	SYMLINK+="disk/by-id/$env{DM_TYPE}-$env{DM_NAME}"
+
+# Create persistent links for dmraid tables
+ENV{DM_UUID}=="mpath-*", \
+        SYMLINK+="disk/by-id/$env{DM_TYPE}-$env{DM_NAME}"
+
+# Create persistent links for partitions
+ENV{DM_PART}=="?*", \
+        SYMLINK+="disk/by-id/$env{DM_TYPE}-$env{DM_NAME}-part$env{DM_PART}"
+
+# Create dm tables for partitions
+ENV{DM_STATE}=="ACTIVE", ENV{DM_UUID}=="mpath-*", \
+        RUN+="/sbin/kpartx -a -p -part /dev/$kernel"
+ENV{DM_STATE}=="ACTIVE", ENV{DM_UUID}=="dmraid-*", \
+        RUN+="/sbin/kpartx -a -p -part /dev/$kernel"
+
+LABEL="multipath_end"
+
+
diff --git a/kpartx/kpartx_id b/kpartx/kpartx_id
new file mode 100644
index 0000000..e876b98
--- /dev/null
+++ b/kpartx/kpartx_id
@@ -0,0 +1,93 @@
+#!/bin/bash
+#
+# kpartx_id
+#
+# Generates ID information for device-mapper tables.
+#
+# Copyright (C) 2006 SUSE Linux Products GmbH
+# Author:
+#       Hannes Reinecke <hare@suse.de>
+#
+#
+#       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 version 2 of the License.
+#
+# This script generates ID information used to generate persistent symlinks.
+# It relies on the UUID strings generated by the various programs; the name
+# of the tables are of no consequence.
+#
+# Please note that dmraid does not provide the UUIDs (yet); a patch has been
+# sent upstream but has not been accepted yet.
+#
+
+DMSETUP=/sbin/dmsetup
+
+MAJOR=$1
+MINOR=$2
+UUID=$3
+
+if [ -z "$MAJOR" -o -z "$MINOR" ]; then
+    echo "usage: $0 major minor"
+    exit 1;
+fi
+
+# Device-mapper not installed; not an error
+if [ ! -x $DMSETUP ] ; then
+    exit 0
+fi
+
+
+# Table UUIDs are always '<type>-<uuid>'.
+dmuuid=${UUID#*-}
+dmtbl=${UUID%%-*}
+dmpart=${dmtbl#part}
+# kpartx types are 'part<num>'
+if [ "$dmpart" == "$dmtbl" ] ; then
+    dmpart=
+else
+    dmtbl=part
+fi
+
+# Set the name of the table. We're only interested in dmraid,
+# multipath, and kpartx tables; everything else is ignored.
+if [ "$dmtbl" == "part" ] ; then
+    # The name of the kpartx table is the name of the parent table
+    dmname=$($DMSETUP info  -c --noheadings -o name -u $dmuuid)
+    echo "DM_NAME=$dmname"
+    # We need the dependencies of the parent table to figure out
+    # the type if the parent is a multipath table
+    case "$dmuuid" in
+	mpath-*)
+	    dmdeps=$($DMSETUP deps -u $dmuuid)
+	    ;;
+    esac
+elif [ "$dmtbl" == "mpath" ] ; then
+    dmname=$tblname
+    # We need the dependencies of the table to figure out the type
+    dmdeps=$($DMSETUP deps -u $UUID)
+elif [ "$dmtbl" == "dmraid" ] ; then
+    dmname=$tblname
+fi
+
+[ -n "$dmpart" ] && echo "DM_PART=$dmpart"
+
+# Figure out the type of the map. For non-multipath maps it's
+# always 'raid'.
+if [ -n "$dmdeps" ] ; then
+    case "$dmdeps" in
+	*\(94,*)
+            echo "DM_TYPE=dasd"
+	    ;;
+	*\(9*)
+            echo "DM_TYPE=raid"
+	    ;;
+	*)
+            echo "DM_TYPE=scsi"
+	    ;;
+    esac
+else
+    echo "DM_TYPE=raid"
+fi
+
+exit 0
diff --git a/kpartx/sun.c b/kpartx/sun.c
new file mode 100644
index 0000000..3d88b21
--- /dev/null
+++ b/kpartx/sun.c
@@ -0,0 +1,131 @@
+/*
+ * Lifted from util-linux' partx sun.c
+ *
+ * Copyrights of the original file apply
+ * Copyright (c) 2007 Hannes Reinecke
+ */
+#include "kpartx.h"
+#include "byteorder.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <time.h>		/* time_t */
+
+#define SUN_DISK_MAGIC		0xDABE	/* Disk magic number */
+#define SUN_DISK_MAXPARTITIONS	8
+
+struct __attribute__ ((packed)) sun_raw_part {
+	u_int32_t	start_cylinder; /* where the part starts... */
+	u_int32_t	num_sectors;	/* ...and it's length */
+};
+
+struct __attribute__ ((packed)) sun_part_info {
+	u_int8_t	spare1;
+	u_int8_t	id;		/* Partition type */
+	u_int8_t	spare2;
+	u_int8_t	flags;		/* Partition flags */
+};
+
+struct __attribute__ ((packed)) sun_disk_label {
+	char		info[128];	/* Informative text string */
+	u_int8_t	spare0[14];
+	struct sun_part_info infos[SUN_DISK_MAXPARTITIONS];
+	u_int8_t	spare1[246];	/* Boot information etc. */
+	u_int16_t	rspeed;		/* Disk rotational speed */
+	u_int16_t	pcylcount;	/* Physical cylinder count */
+	u_int16_t	sparecyl;	/* extra sects per cylinder */
+	u_int8_t	spare2[4];	/* More magic... */
+	u_int16_t	ilfact;		/* Interleave factor */
+	u_int16_t	ncyl;		/* Data cylinder count */
+	u_int16_t	nacyl;		/* Alt. cylinder count */
+	u_int16_t	ntrks;		/* Tracks per cylinder */
+	u_int16_t	nsect;		/* Sectors per track */
+	u_int8_t	spare3[4];	/* Even more magic... */
+	struct sun_raw_part partitions[SUN_DISK_MAXPARTITIONS];
+	u_int16_t	magic;		/* Magic number */
+	u_int16_t	csum;		/* Label xor'd checksum */
+};
+
+/* Checksum Verification */
+static int
+sun_verify_checksum (struct sun_disk_label *label)
+{
+	u_int16_t *ush = ((u_int16_t *)(label + 1)) - 1;
+	u_int16_t csum = 0;
+
+	while (ush >= (u_int16_t *)label)
+		csum ^= *ush--;
+
+	return !csum;
+}
+
+int
+read_sun_pt(int fd, struct slice all, struct slice *sp, int ns) {
+	struct sun_disk_label *l;
+	struct sun_raw_part *s;
+	unsigned int offset = all.start, end;
+	int i, j, n;
+	char *bp;
+
+	bp = getblock(fd, offset);
+	if (bp == NULL)
+		return -1;
+
+	l = (struct sun_disk_label *) bp;
+	if(be16_to_cpu(l->magic) != SUN_DISK_MAGIC)
+		return -1;
+
+	if (!sun_verify_checksum(l)) {
+		fprintf(stderr, "Corrupted Sun disk label\n");
+		return -1;
+	}
+
+	for(i=0, n=0; i<SUN_DISK_MAXPARTITIONS; i++) {
+		s = &l->partitions[i];
+
+		if (s->num_sectors == 0)
+			continue;
+		if (n < ns) {
+			sp[n].start = offset +
+				be32_to_cpu(s->start_cylinder) * be16_to_cpu(l->nsect) * be16_to_cpu(l->ntrks);
+			sp[n].size = be32_to_cpu(s->num_sectors);
+			n++;
+		} else {
+			fprintf(stderr,
+				"sun_disklabel: too many slices\n");
+			break;
+		}
+	}
+	/*
+	 * Convention has it that the SUN disklabel will always have
+	 * the 'c' partition spanning the entire disk.
+	 * So we have to check for contained slices.
+	 */
+	for(i = 0; i < SUN_DISK_MAXPARTITIONS; i++) {
+		if (sp[i].size == 0)
+			continue;
+
+		end = sp[i].start + sp[i].size;
+		for(j = 0; j < SUN_DISK_MAXPARTITIONS; j ++) {
+			if ( i == j )
+				continue;
+			if (sp[j].size == 0)
+				continue;
+
+			if (sp[i].start < sp[j].start) {
+				if (end > sp[j].start &&
+				    end < sp[j].start + sp[j].size) {
+					/* Invalid slice */
+					fprintf(stderr,
+						"sun_disklabel: slice %d overlaps with %d\n", i , j);
+					sp[i].size = 0;
+				}
+			} else {
+				if (end <= sp[j].start + sp[j].size) {
+					sp[i].container = j + 1;
+				}
+			}
+		}
+	}
+	return n;
+}
+
diff --git a/libcheckers/Makefile b/libcheckers/Makefile
index 6340a68..bdd423f 100644
--- a/libcheckers/Makefile
+++ b/libcheckers/Makefile
@@ -11,7 +11,7 @@ OBJS = libsg.o checkers.o readsector0.o
 all: $(BUILD)
 
 prepare:
-	@file *-$(BUILD).a >/dev/null 2>&1 || rm -f core *.o *.gz
+	@file *-$(BUILD).a >/dev/null 2>&1 || rm -f core *.o
 
 klibc: prepare $(OBJS)
 	ar rs libcheckers-klibc.a *.o
@@ -24,4 +24,4 @@ install:
 uninstall:
 
 clean:
-	rm -f core *.a *.o *.gz
+	rm -f core *.a *.o
diff --git a/libmultipath/Makefile b/libmultipath/Makefile
index ef561a8..3ab059a 100644
--- a/libmultipath/Makefile
+++ b/libmultipath/Makefile
@@ -13,7 +13,7 @@ OBJS = memory.o parser.o vector.o devmap
        structs.o discovery.o propsel.o dict.o \
        pgpolicies.o debug.o regex.o defaults.o uevent.o \
        switchgroup.o uxsock.o print.o alias.o log_pthread.o \
-       log.o configure.o structs_vec.o
+       log.o configure.o structs_vec.o sysfs.o
 
 PREVBUILD = $(shell nm debug.o 2> /dev/null|grep log_safe)
 
@@ -25,7 +25,7 @@ else
 	CLEAN = $(shell if [ ! "x$(PREVBUILD)" = "x" ]; then echo clean; fi)
 endif
 
-LIBDM_API_FLUSH = $(shell objdump -T /lib/libdevmapper.so.* | grep -c dm_task_no_flush)
+LIBDM_API_FLUSH = $(shell /sbin/ldconfig -p | grep devmapper.so.1 | cut -d ' ' -f 4 | xargs objdump -T | grep -c dm_task_no_flush)
 
 ifeq ($(strip $(LIBDM_API_FLUSH)),1)
 	CFLAGS += -DLIBDM_API_FLUSH
@@ -34,7 +34,7 @@ endif
 all: $(BUILD)
 
 prepare: $(CLEAN)
-	@file *-$(BUILD).a >/dev/null 2>&1 || rm -f core *.o *.gz
+	@file *-$(BUILD).a >/dev/null 2>&1 || rm -f core *.o
 	@rm -f *-$(BUILD).a
 
 klibc: $(OBJS)
@@ -48,4 +48,4 @@ install:
 uninstall:
 
 clean:
-	rm -f core *.a *.o *.gz
+	rm -f core *.a *.o
diff --git a/libmultipath/config.h b/libmultipath/config.h
index 7caa11d..a25b3ad 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -66,6 +66,7 @@ struct config {
 	int pg_timeout;
 
 	char * dev;
+	char * sysfs_dir;
 	char * udev_dir;
 	char * selector;
 	char * getuid;
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
index a5bad4c..3cd6041 100644
--- a/libmultipath/configure.c
+++ b/libmultipath/configure.c
@@ -325,8 +325,10 @@ domap (struct multipath * mpp)
 			return DOMAP_RETRY;
 		}
 
-		if (dm_map_present(mpp->alias))
+		if (dm_map_present(mpp->alias)) {
+			condlog(3, "%s: map already present", mpp->alias);
 			break;
+		}
 
 		r = dm_addmap(DM_DEVICE_CREATE, mpp->alias, DEFAULT_TARGET,
 			      mpp->params, mpp->size, mpp->wwid);
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index a196583..52e0621 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -8,9 +8,8 @@
 #include <fcntl.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
+#include <dirent.h>
 #include <errno.h>
-#include <sysfs/dlist.h>
-#include <sysfs/libsysfs.h>
 
 #include <checkers.h>
 
@@ -24,6 +23,7 @@
 #include "debug.h"
 #include "propsel.h"
 #include "sg_include.h"
+#include "sysfs.h"
 #include "discovery.h"
 
 struct path *
@@ -87,127 +87,117 @@ path_discover (vector pathvec, struct co
 int
 path_discovery (vector pathvec, struct config * conf, int flag)
 {
-	struct dlist * ls;
-	struct sysfs_class * class;
-	struct sysfs_class_device * dev;
-	int r = 1;
-
-	if (!(class = sysfs_open_class("block")))
+	DIR *blkdir;
+	struct dirent *blkdev;
+	struct stat statbuf;
+	char devpath[PATH_MAX];
+	char *devptr;
+	int r = 0;
+
+	if (!(blkdir = opendir("/sys/block")))
 		return 1;
 
-	if (!(ls = sysfs_get_class_devices(class)))
-		goto out;
+	strcpy(devpath,"/sys/block");
+	while ((blkdev = readdir(blkdir)) != NULL) {
+		if ((strcmp(blkdev->d_name,".") == 0) ||
+		    (strcmp(blkdev->d_name,"..") == 0))
+			continue;
 
-	r = 0;
+		devptr = devpath + 10;
+		*devptr = '\0';
+		strcat(devptr,"/");
+		strcat(devptr,blkdev->d_name);
+		if (stat(devpath, &statbuf) < 0)
+			continue;
 
-	dlist_for_each_data(ls, dev, struct sysfs_class_device)
-		r += path_discover(pathvec, conf, dev->name, flag);
+		if (S_ISDIR(statbuf.st_mode) == 0)
+			continue;
 
-out:
-	sysfs_close_class(class);
-	return r;
-}
+		condlog(4, "Discover device %s", devpath);
 
-/*
- * the daemon can race udev upon path add,
- * not multipath(8), ran by udev
- */
-#if DAEMON
-#define WAIT_MAX_SECONDS 60
-#define WAIT_LOOP_PER_SECOND 5
-
-static int
-wait_for_file (char * filename)
-{
-	int loop;
-	struct stat stats;
-	
-	loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND;
-	
-	while (--loop) {
-		if (stat(filename, &stats) == 0)
-			return 0;
-
-		if (errno != ENOENT)
-			return 1;
-
-		usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
+		r += path_discover(pathvec, conf, blkdev->d_name, flag);
 	}
-	return 1;
-}
-#else
-static int
-wait_for_file (char * filename)
-{
-	return 0;
+	closedir(blkdir);
+	condlog(4, "Discovery status %d", r);
+	return r;
 }
-#endif
 
-#define declare_sysfs_get_str(fname, fmt) \
+#define declare_sysfs_get_str(fname) \
 extern int \
-sysfs_get_##fname (char * sysfs_path, char * dev, char * buff, int len) \
+sysfs_get_##fname (struct sysfs_device * dev, char * buff, size_t len) \
 { \
-	struct sysfs_attribute * attr; \
-	char attr_path[SYSFS_PATH_SIZE]; \
+	char *attr; \
 \
-	if (safe_sprintf(attr_path, fmt, sysfs_path, dev)) \
+	attr = sysfs_attr_get_value(dev->devpath, #fname); \
+	if (!attr) \
 		return 1; \
 \
-	if (wait_for_file(attr_path)) \
-		return 1; \
-\
-	if (!(attr = sysfs_open_attribute(attr_path))) \
-		return 1; \
-\
-	if (0 > sysfs_read_attribute(attr)) \
-		goto out; \
-\
-	if (attr->len < 2 || attr->len - 1 > len) \
-		goto out; \
-\
-	strncpy(buff, attr->value, attr->len - 1); \
-	strchop(buff); \
-	sysfs_close_attribute(attr); \
+	if (strlcpy(buff, attr, len) != strlen(attr)) \
+		return 2; \
 	return 0; \
-out: \
-	sysfs_close_attribute(attr); \
-	return 1; \
 }
 
-declare_sysfs_get_str(devtype, "%s/block/%s/device/devtype");
-declare_sysfs_get_str(cutype, "%s/block/%s/device/cutype");
-declare_sysfs_get_str(vendor, "%s/block/%s/device/vendor");
-declare_sysfs_get_str(model, "%s/block/%s/device/model");
-declare_sysfs_get_str(rev, "%s/block/%s/device/rev");
-declare_sysfs_get_str(dev, "%s/block/%s/dev");
+declare_sysfs_get_str(devtype);
+declare_sysfs_get_str(cutype);
+declare_sysfs_get_str(vendor);
+declare_sysfs_get_str(model);
+declare_sysfs_get_str(rev);
 
 int
-sysfs_get_size (char * sysfs_path, char * dev, unsigned long long * size)
+sysfs_get_dev (struct sysfs_device * dev, char * buff, size_t len)
 {
-	struct sysfs_attribute * attr;
-	char attr_path[SYSFS_PATH_SIZE];
-	int r;
+	char *attr;
 
-	if (safe_sprintf(attr_path, "%s/block/%s/size", sysfs_path, dev))
+	attr = sysfs_attr_get_value(dev->devpath, "dev");
+	if (!attr) {
+		condlog(3, "%s: no 'dev' attribute in sysfs", dev->kernel);
 		return 1;
+	}
+	if (strlcpy(buff, attr, len) != strlen(attr)) {
+		condlog(3, "%s: overflow in 'dev' attribute", dev->kernel);
+		return 2;
+	}
+	return 0;
+}
 
-	attr = sysfs_open_attribute(attr_path);
+int
+sysfs_get_size (struct sysfs_device * dev, unsigned long long * size)
+{
+	char *attr;
+	int r;
 
+	attr = sysfs_attr_get_value(dev->devpath, "size");
 	if (!attr)
 		return 1;
 
-	if (0 > sysfs_read_attribute(attr))
-		goto out;
-
-	r = sscanf(attr->value, "%llu\n", size);
-	sysfs_close_attribute(attr);
+	r = sscanf(attr, "%llu\n", size);
 
 	if (r != 1)
 		return 1;
 
 	return 0;
-out:
-	sysfs_close_attribute(attr);
+}
+	
+int
+sysfs_get_fc_nodename (struct sysfs_device * dev, char * node,
+		       unsigned int host, unsigned int channel,
+		       unsigned int target)
+{
+	char attr_path[SYSFS_PATH_SIZE], *attr;
+
+	if (safe_sprintf(attr_path, 
+			 "/class/fc_transport/target%i:%i:%i",
+			 host, channel, target)) {
+		condlog(0, "attr_path too small");
+		return 1;
+	}
+
+	attr = sysfs_attr_get_value(attr_path, "node_name");
+	if (attr) {
+		strlcpy(node, attr, strlen(attr));
+		return 0;
+	}
+
 	return 1;
 }
 	
@@ -224,68 +214,52 @@ opennode (char * dev, int mode)
 		return -1;
 	}
 
-	if (wait_for_file(devpath)) {
-		condlog(3, "failed to open %s", devpath);
-		return -1;
-	}
-
 	return open(devpath, mode);
 }
 
 extern int
 devt2devname (char *devname, char *devt)
 {
-	struct dlist * ls;
-	char attr_path[FILE_NAME_SIZE];
+	FILE *fd;
+	unsigned int tmpmaj, tmpmin, major, minor;
+	char dev[FILE_NAME_SIZE];
 	char block_path[FILE_NAME_SIZE];
-	struct sysfs_attribute * attr = NULL;
-	struct sysfs_class * class;
-	struct sysfs_class_device * dev;
+	struct stat statbuf;
 
-	if(safe_sprintf(block_path, "%s/block", sysfs_path)) {
-		condlog(0, "block_path too small");
+	if (sscanf(devt, "%u:%u", &major, &minor) != 2) {
+		condlog(0, "Invalid device number %s", devt);
 		return 1;
 	}
-	if (!(class = sysfs_open_class("block")))
-		return 1;
 
-	if (!(ls = sysfs_get_class_devices(class)))
-		goto err;
+	if ((fd = fopen("/proc/partitions", "r")) < 0) {
+		condlog(0, "Cannot open /proc/partitions");
+		return 1;
+	}
+	
+	while (!feof(fd)) {
+		if (fscanf(fd," %u %u %*d %s",&tmpmaj, &tmpmin, dev) != 3)
+			continue;
 
-	dlist_for_each_data(ls, dev, struct sysfs_class_device) {
-		if(safe_sprintf(attr_path, "%s/%s/dev",
-				block_path, dev->name)) {
-			condlog(0, "attr_path too small");
-			goto err;
-		}
-		if (!(attr = sysfs_open_attribute(attr_path)))
-			goto err;
-
-		if (sysfs_read_attribute(attr))
-			goto err1;
-
-		/* discard newline */
-		if (attr->len > 1) attr->len--;
-
-		if (strlen(devt) == attr->len &&
-		    strncmp(attr->value, devt, attr->len) == 0) {
-			if(safe_sprintf(attr_path, "%s/%s",
-					block_path, dev->name)) {
-				condlog(0, "attr_path too small");
-				goto err1;
-			}
-			sysfs_get_name_from_path(attr_path, devname,
-						 FILE_NAME_SIZE);
-			sysfs_close_attribute(attr);
-			sysfs_close_class(class);
-			return 0;
+		if ((major == tmpmaj) && (minor == tmpmin)) {
+			sprintf(block_path, "/sys/block/%s", dev);
+			break;
 		}
 	}
-err1:
-	sysfs_close_attribute(attr);
-err:
-	sysfs_close_class(class);
-	return 1;
+	fclose(fd);
+
+	if (strncpy(block_path,"/sys/block", 10))
+		return 1;
+
+	if (stat(block_path, &statbuf) < 0) {
+		condlog(0, "No sysfs entry for %s\n", block_path);
+		return 1;
+	}
+
+	if (S_ISDIR(statbuf.st_mode) == 0) {
+		condlog(0, "sysfs entry %s is not a directory\n", block_path);
+		return 1;
+	}
+	return 0;
 }
 
 static int
@@ -363,79 +337,21 @@ get_serial (char * str, int maxlen, int
 }
 
 static int
-sysfs_get_bus (char * sysfs_path, struct path * pp)
-{
-	struct sysfs_device *sdev;
-	char attr_path[FILE_NAME_SIZE];
-	char attr_buff[FILE_NAME_SIZE];
-
-	pp->bus = SYSFS_BUS_UNDEF;
-
-	/*
-	 * This is ugly : we should be able to do a simple
-	 * get_link("%s/block/%s/device/bus", ...) but it just
-	 * won't work
-	 */
-	if(safe_sprintf(attr_path, "%s/block/%s/device",
-			sysfs_path, pp->dev)) {
-		condlog(0, "attr_path too small");
-		return 1;
-	}
-
-	if (0 > sysfs_get_link(attr_path, attr_buff, sizeof(attr_buff)))
-		return 1;
-
-#if DAEMON
-	int loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND;
-
-	while (loop--) {
-		sdev = sysfs_open_device_path(attr_buff);
-
-		if (strlen(sdev->bus))
-			break;
-
-		sysfs_close_device(sdev);
-		usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
-	}
-#else
-	sdev = sysfs_open_device_path(attr_buff);
-#endif
-
-	if (!strncmp(sdev->bus, "scsi", 4))
-		pp->bus = SYSFS_BUS_SCSI;
-	else if (!strncmp(sdev->bus, "ide", 3))
-		pp->bus = SYSFS_BUS_IDE;
-	else if (!strncmp(sdev->bus, "ccw", 3))
-		pp->bus = SYSFS_BUS_CCW;
-	else
-		return 1;
-
-	sysfs_close_device(sdev);
-
-	return 0;
-}
-
-static int
-scsi_sysfs_pathinfo (struct path * pp)
+scsi_sysfs_pathinfo (struct path * pp, struct sysfs_device * parent)
 {
 	char attr_path[FILE_NAME_SIZE];
-	char attr_buff[FILE_NAME_SIZE];
-	struct sysfs_attribute * attr;
 
-	if (sysfs_get_vendor(sysfs_path, pp->dev,
-			     pp->vendor_id, SCSI_VENDOR_SIZE))
+	if (sysfs_get_vendor(parent, pp->vendor_id, SCSI_VENDOR_SIZE))
 		return 1;
 
 	condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
 
-	if (sysfs_get_model(sysfs_path, pp->dev,
-			    pp->product_id, SCSI_PRODUCT_SIZE))
+	if (sysfs_get_model(parent, pp->product_id, SCSI_PRODUCT_SIZE))
 		return 1;
 
 	condlog(3, "%s: product = %s", pp->dev, pp->product_id);
 
-	if (sysfs_get_rev(sysfs_path, pp->dev,
-			  pp->rev, SCSI_REV_SIZE))
+	if (sysfs_get_rev(parent, pp->rev, SCSI_REV_SIZE))
 		return 1;
 
 	condlog(3, "%s: rev = %s", pp->dev, pp->rev);
@@ -448,15 +364,7 @@ scsi_sysfs_pathinfo (struct path * pp)
 	/*
 	 * host / bus / target / lun
 	 */
-	if(safe_sprintf(attr_path, "%s/block/%s/device",
-			sysfs_path, pp->dev)) {
-		condlog(0, "attr_path too small");
-		return 1;
-	}
-	if (0 > sysfs_get_link(attr_path, attr_buff, sizeof(attr_buff)))
-		return 1;
-	
-	basename(attr_buff, attr_path);
+	basename(parent->devpath, attr_path);
 
 	sscanf(attr_path, "%i:%i:%i:%i",
 			&pp->sg_id.host_no,
@@ -473,35 +381,19 @@ scsi_sysfs_pathinfo (struct path * pp)
 	/*
 	 * target node name
 	 */
-	if(safe_sprintf(attr_path,
-			"%s/class/fc_transport/target%i:%i:%i/node_name",
-			sysfs_path,
-			pp->sg_id.host_no,
-			pp->sg_id.channel,
-			pp->sg_id.scsi_id)) {
-		condlog(0, "attr_path too small");
-		return 1;
+	if(!sysfs_get_fc_nodename(parent, pp->tgt_node_name,
+				 pp->sg_id.host_no,
+				 pp->sg_id.channel,
+				 pp->sg_id.scsi_id)) {
+		condlog(3, "%s: tgt_node_name = %s",
+			pp->dev, pp->tgt_node_name);
 	}
-	if (!(attr = sysfs_open_attribute(attr_path)))
-		return 0;
-
-	if (sysfs_read_attribute(attr))
-		goto err;
-
-	if (attr->len > 0)
-		strncpy(pp->tgt_node_name, attr->value, attr->len - 1);
-
-	condlog(3, "%s: tgt_node_name = %s",
-		pp->dev, pp->tgt_node_name);
 
 	return 0;
-err:
-	sysfs_close_attribute(attr);
-	return 1;
 }
 
 static int
-ccw_sysfs_pathinfo (struct path * pp)
+ccw_sysfs_pathinfo (struct path * pp, struct sysfs_device * parent)
 {
 	char attr_path[FILE_NAME_SIZE];
 	char attr_buff[FILE_NAME_SIZE];
@@ -510,8 +402,7 @@ ccw_sysfs_pathinfo (struct path * pp)
 
 	condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
 
-	if (sysfs_get_devtype(sysfs_path, pp->dev,
-			      attr_buff, FILE_NAME_SIZE))
+	if (sysfs_get_devtype(parent, attr_buff, FILE_NAME_SIZE))
 		return 1;
 
 	if (!strncmp(attr_buff, "3370", 4)) {
@@ -531,16 +422,8 @@ ccw_sysfs_pathinfo (struct path * pp)
 
 	/*
 	 * host / bus / target / lun
-	 */
-	if(safe_sprintf(attr_path, "%s/block/%s/device",
-			sysfs_path, pp->dev)) {
-		condlog(0, "attr_path too small");
-		return 1;
-	}
-	if (0 > sysfs_get_link(attr_path, attr_buff, sizeof(attr_buff)))
-		return 1;
-	
-	basename(attr_buff, attr_path);
+	 */	
+	basename(parent->devpath, attr_path);
 	pp->sg_id.lun = 0;
 	sscanf(attr_path, "%i.%i.%x",
 			&pp->sg_id.host_no,
@@ -557,20 +440,20 @@ ccw_sysfs_pathinfo (struct path * pp)
 }
 
 static int
-common_sysfs_pathinfo (struct path * pp)
+common_sysfs_pathinfo (struct path * pp, struct sysfs_device *dev)
 {
-	if (sysfs_get_bus(sysfs_path, pp))
-		return 1;
-
-	condlog(3, "%s: bus = %i", pp->dev, pp->bus);
+	char *attr;
 
-	if (sysfs_get_dev(sysfs_path, pp->dev,
-			  pp->dev_t, BLK_DEV_SIZE))
+	attr = sysfs_attr_get_value(dev->devpath, "dev");
+	if (!attr) {
+		condlog(3, "%s: no 'dev' attribute in sysfs", pp->dev);
 		return 1;
+	}
+	strlcpy(pp->dev_t, attr, BLK_DEV_SIZE);
 
 	condlog(3, "%s: dev_t = %s", pp->dev, pp->dev_t);
 
-	if (sysfs_get_size(sysfs_path, pp->dev, &pp->size))
+	if (sysfs_get_size(dev, &pp->size))
 		return 1;
 
 	condlog(3, "%s: size = %llu", pp->dev, pp->size);
@@ -578,19 +461,46 @@ common_sysfs_pathinfo (struct path * pp)
 	return 0;
 }
 
+struct sysfs_device *sysfs_device_from_path(struct path *pp)
+{
+	char sysdev[FILE_NAME_SIZE];
+
+	strlcpy(sysdev,"/block/", FILE_NAME_SIZE);
+	strlcat(sysdev,pp->dev, FILE_NAME_SIZE);
+
+	return sysfs_device_get(sysdev);
+}
+
 extern int
 sysfs_pathinfo(struct path * pp)
 {
-	if (common_sysfs_pathinfo(pp))
+	struct sysfs_device *parent;
+
+	pp->sysdev = sysfs_device_from_path(pp);
+	if (!pp->sysdev) {
+		condlog(1, "%s: failed to get sysfs information", pp->dev);
 		return 1;
+	}
+	
+	parent = sysfs_device_get_parent(pp->sysdev);
+
+	if (common_sysfs_pathinfo(pp, pp->sysdev))
+		return 1;
+
+	condlog(3, "%s: subsystem = %s", pp->dev, parent->subsystem);
+
+	if (!strncmp(parent->subsystem, "scsi",4))
+		pp->bus = SYSFS_BUS_SCSI;
+	if (!strncmp(parent->subsystem, "ccw",3))
+		pp->bus = SYSFS_BUS_CCW;
 
 	if (pp->bus == SYSFS_BUS_UNDEF)
 		return 0;
 	else if (pp->bus == SYSFS_BUS_SCSI) {
-		if (scsi_sysfs_pathinfo(pp))
+		if (scsi_sysfs_pathinfo(pp, parent))
 			return 1;
 	} else if (pp->bus == SYSFS_BUS_CCW) {
-		if (ccw_sysfs_pathinfo(pp))
+		if (ccw_sysfs_pathinfo(pp, parent))
 			return 1;
 	}
 	return 0;
diff --git a/libmultipath/discovery.h b/libmultipath/discovery.h
index ab62a59..c7cf7e8 100644
--- a/libmultipath/discovery.h
+++ b/libmultipath/discovery.h
@@ -24,12 +24,7 @@
 #define SCSI_COMMAND_TERMINATED 0x22
 #define SG_ERR_DRIVER_SENSE     0x08
 
-int sysfs_get_vendor (char * sysfs_path, char * dev, char * buff, int len);
-int sysfs_get_model (char * sysfs_path, char * dev, char * buff, int len);
-int sysfs_get_rev (char * sysfs_path, char * dev, char * buff, int len);
-int sysfs_get_dev (char * sysfs_path, char * dev, char * buff, int len);
-
-int sysfs_get_size (char * sysfs_path, char * dev, unsigned long long *);
+int sysfs_get_dev (struct sysfs_device * dev, char * buff, size_t len);
 int path_discovery (vector pathvec, struct config * conf, int flag);
 
 void basename (char *, char *);
diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c
index d5b227f..27098b2 100644
--- a/libmultipath/hwtable.c
+++ b/libmultipath/hwtable.c
@@ -63,7 +63,7 @@ static struct hwentry default_hw[] = {
 		.vendor        = "DEC",
 		.product       = "HSG80",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = "mpath_prio_hp_sw /dev/%n",
+		.getprio       = "/sbin/mpath_prio_hp_sw /dev/%n",
 		.features      = "1 queue_if_no_path",
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
@@ -94,7 +94,7 @@ static struct hwentry default_hw[] = {
 		.vendor        = "(COMPAQ|HP)",
 		.product       = "(MSA|HSV)1.0.*",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = "mpath_prio_hp_sw /dev/%n",
+		.getprio       = "/sbin/mpath_prio_hp_sw /dev/%n",
 		.features      = "1 queue_if_no_path",
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
@@ -110,7 +110,7 @@ static struct hwentry default_hw[] = {
 		.vendor        = "HP",
 		.product       = "MSA VOLUME",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = "mpath_prio_alua /dev/%n",
+		.getprio       = "/sbin/mpath_prio_alua /dev/%n",
 		.features      = DEFAULT_FEATURES,
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
@@ -126,7 +126,7 @@ static struct hwentry default_hw[] = {
 		.vendor        = "(COMPAQ|HP)",
 		.product       = "(MSA|HSV)1.1.*",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = "mpath_prio_alua /dev/%n",
+		.getprio       = "/sbin/mpath_prio_alua /dev/%n",
 		.features      = DEFAULT_FEATURES,
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
@@ -142,7 +142,7 @@ static struct hwentry default_hw[] = {
 		.vendor        = "HP",
 		.product       = "HSV2.*",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = "mpath_prio_alua /dev/%n",
+		.getprio       = "/sbin/mpath_prio_alua /dev/%n",
 		.features      = DEFAULT_FEATURES,
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
@@ -406,7 +406,7 @@ static struct hwentry default_hw[] = {
 		.vendor        = "IBM",
 		.product       = "S/390 DASD ECKD",
 		.bl_product       = "S/390.*",
-		.getuid        = "dasdinfo -u -b %n",
+		.getuid        = "/sbin/dasdinfo -u -b %n",
 		.getprio       = NULL,
 		.features      = "1 queue_if_no_path",
 		.hwhandler     = DEFAULT_HWHANDLER,
@@ -521,7 +521,7 @@ static struct hwentry default_hw[] = {
 		.vendor        = "SGI",
 		.product       = "IS.*",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = "mpath_prio_tpc /dev/%n",
+		.getprio       = "/sbin/mpath_prio_tpc /dev/%n",
 		.features      = DEFAULT_FEATURES,
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
diff --git a/libmultipath/list.h b/libmultipath/list.h
new file mode 100644
index 0000000..8626630
--- /dev/null
+++ b/libmultipath/list.h
@@ -0,0 +1,289 @@
+/*
+ * Copied from the Linux kernel source tree, version 2.6.0-test1.
+ *
+ * Licensed under the GPL v2 as per the whole kernel source tree.
+ *
+ */
+
+#ifndef _LIST_H
+#define _LIST_H
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ *
+ * @ptr:	the pointer to the member.
+ * @type:	the type of the container struct this is embedded in.
+ * @member:	the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({			\
+	const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
+	(type *)( (char *)__mptr - offsetof(type,member) );})
+
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized list entries.
+ */
+#define LIST_POISON1  ((void *) 0x00100100)
+#define LIST_POISON2  ((void *) 0x00200200)
+
+/*
+ * 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!
+ */
+static inline void __list_add(struct list_head *new,
+			      struct list_head *prev,
+			      struct list_head *next)
+{
+	next->prev = new;
+	new->next = next;
+	new->prev = prev;
+	prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: 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.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: 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.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, 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!
+ */
+static 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.
+ * Note: list_empty on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	entry->next = LIST_POISON1;
+	entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	INIT_LIST_HEAD(entry); 
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+	__list_del(list->prev, list->next);
+	list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+				  struct list_head *head)
+{
+	__list_del(list->prev, list->next);
+	list_add_tail(list, head);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(struct list_head *head)
+{
+	return head->next == head;
+}
+
+static inline void __list_splice(struct list_head *list,
+				 struct list_head *head)
+{
+	struct list_head *first = list->next;
+	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_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+	if (!list_empty(list))
+		__list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+				    struct list_head *head)
+{
+	if (!list_empty(list)) {
+		__list_splice(list, head);
+		INIT_LIST_HEAD(list);
+	}
+}
+
+/**
+ * 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) \
+	container_of(ptr, type, member)
+
+/**
+ * list_for_each	-	iterate over 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	-	iterate over a list
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @head:	the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+	for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev	-	iterate over a list backwards
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @head:	the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+	for (pos = (head)->prev; pos != (head); pos = pos->prev)
+
+/**
+ * list_for_each_safe	-	iterate over a list safe against removal of list entry
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @n:		another &struct list_head to use as temporary storage
+ * @head:	the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+	for (pos = (head)->next, n = pos->next; pos != (head); \
+		pos = n, n = pos->next)
+
+/**
+ * list_for_each_entry	-	iterate over list of given type
+ * @pos:	the type * to use as a loop counter.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member)				\
+	for (pos = list_entry((head)->next, typeof(*pos), member);	\
+	     &pos->member != (head); 					\
+	     pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos:	the type * to use as a loop counter.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member)			\
+	for (pos = list_entry((head)->prev, typeof(*pos), member);	\
+	     &pos->member != (head); 					\
+	     pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos:	the type * to use as a loop counter.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member)			\
+	for (pos = list_entry((head)->next, typeof(*pos), member),	\
+		n = list_entry(pos->member.next, typeof(*pos), member);	\
+	     &pos->member != (head); 					\
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+#endif /* _LIST_H */
diff --git a/libmultipath/print.c b/libmultipath/print.c
index dc8af48..1d80e48 100644
--- a/libmultipath/print.c
+++ b/libmultipath/print.c
@@ -5,8 +5,8 @@
 #include <string.h>
 #include <libdevmapper.h>
 #include <stdarg.h>
-#include <sysfs/dlist.h>
-#include <sysfs/libsysfs.h>
+#include <sys/stat.h>
+#include <dirent.h>
 
 #include <checkers.h>
 
@@ -1096,35 +1096,46 @@ snprint_blacklist_except (char * buff, i
 extern int
 snprint_devices (char * buff, int len, struct vectors *vecs)
 {
-        struct dlist * ls;
-        struct sysfs_class * class;
-        struct sysfs_class_device * dev;
+	DIR *blkdir;
+	struct dirent *blkdev;
+	struct stat statbuf;
+	char devpath[PATH_MAX];
+	char *devptr;
 	int threshold = MAX_LINE_LEN;
 	int fwd = 0;
 	int r;
 
 	struct path * pp;
 
-        if (!(class = sysfs_open_class("block")))
-                return 0;
-
-        if (!(ls = sysfs_get_class_devices(class))) {
-                sysfs_close_class(class);
-                return 0;
-        }
+	if (!(blkdir = opendir("/sys/block")))
+		return 1;
 
 	if ((len - fwd - threshold) <= 0)
 		return len;
 	fwd += snprintf(buff + fwd, len - fwd, "available block devices:\n");
 
-        dlist_for_each_data(ls, dev, struct sysfs_class_device) {
+	strcpy(devpath,"/sys/block");
+	devptr = devpath + 10;
+	while ((blkdev = readdir(blkdir)) != NULL) {
+		if ((strcmp(blkdev->d_name,".") == 0) ||
+		    (strcmp(blkdev->d_name,"..") == 0))
+			continue;
+
+		strcat(devptr,blkdev->d_name);
+		if (stat(devptr, &statbuf) < 0)
+			continue;
+
+		if (S_ISDIR(statbuf.st_mode) == 0)
+			continue;
+
 		if ((len - fwd - threshold)  <= 0)
 			return len;
-		fwd += snprintf(buff + fwd, len - fwd, "    %s", dev->name);
-		pp = find_path_by_dev(vecs->pathvec, dev->name);
+
+		fwd += snprintf(buff + fwd, len - fwd, "    %s", devpath);
+		pp = find_path_by_dev(vecs->pathvec, devpath);
 		if (!pp) {
 			r = filter_devnode(conf->blist_devnode,
-					   conf->elist_devnode, dev->name);
+					   conf->elist_devnode, devpath);
 			if (r > 0)
 				fwd += snprintf(buff + fwd, len - fwd,
 						" (blacklisted)");
@@ -1133,8 +1144,8 @@ snprint_devices (char * buff, int len, s
 						" (whitelisted)");
 		}
 		fwd += snprintf(buff + fwd, len - fwd, "\n");
-        }
-        sysfs_close_class(class);
+	}
+	closedir(blkdir);
 
 	if (fwd > len)
 		return len;
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
index 46dcdee..75322aa 100644
--- a/libmultipath/structs.h
+++ b/libmultipath/structs.h
@@ -9,6 +9,9 @@
 #define FILE_NAME_SIZE		256
 #define CALLOUT_MAX_SIZE	128
 #define BLK_DEV_SIZE		33
+#define PATH_SIZE		512
+#define NAME_SIZE		128
+
 
 #define SCSI_VENDOR_SIZE	9
 #define SCSI_PRODUCT_SIZE	17
@@ -86,9 +89,19 @@ struct scsi_dev {
 	int host_no;
 };
 
+struct sysfs_device {
+	struct sysfs_device *parent;		/* parent device */
+	char devpath[PATH_SIZE];
+	char subsystem[NAME_SIZE];		/* $class, $bus, drivers, module */
+	char kernel[NAME_SIZE];			/* device instance name */
+	char kernel_number[NAME_SIZE];
+	char driver[NAME_SIZE];			/* device driver name */
+};
+
 struct path {
 	char dev[FILE_NAME_SIZE];
 	char dev_t[BLK_DEV_SIZE];
+	struct sysfs_device *sysdev;
 	struct scsi_idlun scsi_id;
 	struct sg_id sg_id;
 	char wwid[WWID_SIZE];
@@ -200,6 +213,6 @@ struct path * first_path (struct multipa
 int pathcountgr (struct pathgroup *, int);
 int pathcount (struct multipath *, int);
 
-char sysfs_path[FILE_NAME_SIZE];
+extern char sysfs_path[PATH_SIZE];
 
 #endif /* _STRUCTS_H */
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
index a4a996a..1cc6028 100644
--- a/libmultipath/structs_vec.c
+++ b/libmultipath/structs_vec.c
@@ -13,6 +13,7 @@
 #include "dmparser.h"
 #include "config.h"
 #include "propsel.h"
+#include "sysfs.h"
 #include "discovery.h"
 #include "waiter.h"
 
@@ -373,10 +374,10 @@ verify_paths(struct multipath * mpp, str
 		/*
 		 * see if path is in sysfs
 		 */
-		if (!pp->dev || sysfs_get_dev(sysfs_path,
-				  pp->dev, pp->dev_t, BLK_DEV_SIZE)) {
+		if (!pp->sysdev || sysfs_get_dev(pp->sysdev,
+						 pp->dev_t, BLK_DEV_SIZE)) {
 			condlog(0, "%s: failed to access path %s", mpp->alias,
-				pp->dev ? pp->dev : pp->dev_t);
+				pp->sysdev ? pp->sysdev->devpath : pp->dev_t);
 			count++;
 			vector_del_slot(mpp->paths, i);
 			i--;
diff --git a/libmultipath/sysfs.c b/libmultipath/sysfs.c
new file mode 100644
index 0000000..e24aa34
--- /dev/null
+++ b/libmultipath/sysfs.c
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2005-2006 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *	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 version 2 of the License.
+ * 
+ *	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 <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <string.h>
+
+#include "checkers.h"
+#include "vector.h"
+#include "structs.h"
+#include "sysfs.h"
+#include "list.h"
+#include "util.h"
+
+char sysfs_path[PATH_SIZE];
+
+/* attribute value cache */
+static LIST_HEAD(attr_list);
+struct sysfs_attr {
+	struct list_head node;
+	char path[PATH_SIZE];
+	char *value;			/* points to value_local if value is cached */
+	char value_local[NAME_SIZE];
+};
+
+int sysfs_init(char *path, size_t len)
+{
+	if (path) {
+		strlcpy(sysfs_path, path, len);
+		remove_trailing_chars(sysfs_path, '/');
+	} else
+		strlcpy(sysfs_path, "/sys", len);
+	dbg("sysfs_path='%s'", sysfs_path);
+
+	INIT_LIST_HEAD(&attr_list);
+	return 0;
+}
+
+void sysfs_cleanup(void)
+{
+	struct sysfs_attr *attr_loop;
+	struct sysfs_attr *attr_temp;
+
+	list_for_each_entry_safe(attr_loop, attr_temp, &attr_list, node) {
+		list_del(&attr_loop->node);
+		free(attr_loop);
+	}
+
+}
+
+void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath,
+			     const char *subsystem, const char *driver)
+{
+	char *pos;
+
+	strlcpy(dev->devpath, devpath, sizeof(dev->devpath));
+	if (subsystem != NULL)
+		strlcpy(dev->subsystem, subsystem, sizeof(dev->subsystem));
+	if (driver != NULL)
+		strlcpy(dev->driver, driver, sizeof(dev->driver));
+
+	/* set kernel name */
+	pos = strrchr(dev->devpath, '/');
+	if (pos == NULL)
+		return;
+	strlcpy(dev->kernel, &pos[1], sizeof(dev->kernel));
+	dbg("kernel='%s'", dev->kernel);
+
+	/* some devices have '!' in their name, change that to '/' */
+	pos = dev->kernel;
+	while (pos[0] != '\0') {
+		if (pos[0] == '!')
+			pos[0] = '/';
+		pos++;
+	}
+
+	/* get kernel number */
+	pos = &dev->kernel[strlen(dev->kernel)];
+	while (isdigit(pos[-1]))
+		pos--;
+	strlcpy(dev->kernel_number, pos, sizeof(dev->kernel_number));
+	dbg("kernel_number='%s'", dev->kernel_number);
+}
+
+int sysfs_resolve_link(char *devpath, size_t size)
+{
+	char link_path[PATH_SIZE];
+	char link_target[PATH_SIZE];
+	int len;
+	int i;
+	int back;
+
+	strlcpy(link_path, sysfs_path, sizeof(link_path));
+	strlcat(link_path, devpath, sizeof(link_path));
+	len = readlink(link_path, link_target, sizeof(link_target));
+	if (len <= 0)
+		return -1;
+	link_target[len] = '\0';
+	dbg("path link '%s' points to '%s'", devpath, link_target);
+
+	for (back = 0; strncmp(&link_target[back * 3], "../", 3) == 0; back++)
+		;
+	dbg("base '%s', tail '%s', back %i", devpath, &link_target[back * 3], back);
+	for (i = 0; i <= back; i++) {
+		char *pos = strrchr(devpath, '/');
+
+		if (pos == NULL)
+			return -1;
+		pos[0] = '\0';
+	}
+	dbg("after moving back '%s'", devpath);
+	strlcat(devpath, "/", size);
+	strlcat(devpath, &link_target[back * 3], size);
+	return 0;
+}
+
+struct sysfs_device *sysfs_device_get(const char *devpath)
+{
+	char path[PATH_SIZE];
+	char devpath_real[PATH_SIZE];
+	struct sysfs_device *dev;
+	struct stat statbuf;
+	char link_path[PATH_SIZE];
+	char link_target[PATH_SIZE];
+	int len;
+	char *pos;
+
+	dbg("open '%s'", devpath);
+	strlcpy(devpath_real, devpath, sizeof(devpath_real));
+	remove_trailing_chars(devpath_real, '/');
+
+	/* if we got a link, resolve it to the real device */
+	strlcpy(path, sysfs_path, sizeof(path));
+	strlcat(path, devpath_real, sizeof(path));
+	if (lstat(path, &statbuf) != 0) {
+		dbg("stat '%s' failed: %s", path, strerror(errno));
+		return NULL;
+	}
+	if (S_ISLNK(statbuf.st_mode)) {
+		if (sysfs_resolve_link(devpath_real, sizeof(devpath_real)) != 0)
+			return NULL;
+
+	}
+
+	/* it is a new device */
+	dbg("new device '%s'", devpath_real);
+	dev = malloc(sizeof(struct sysfs_device));
+	if (dev == NULL)
+		return NULL;
+	memset(dev, 0x00, sizeof(struct sysfs_device));
+
+	sysfs_device_set_values(dev, devpath_real, NULL, NULL);
+
+	/* get subsystem name */
+	strlcpy(link_path, sysfs_path, sizeof(link_path));
+	strlcat(link_path, dev->devpath, sizeof(link_path));
+	strlcat(link_path, "/subsystem", sizeof(link_path));
+	len = readlink(link_path, link_target, sizeof(link_target));
+	if (len > 0) {
+		/* get subsystem from "subsystem" link */
+		link_target[len] = '\0';
+		dbg("subsystem link '%s' points to '%s'", link_path, link_target);
+		pos = strrchr(link_target, '/');
+		if (pos != NULL)
+			strlcpy(dev->subsystem, &pos[1], sizeof(dev->subsystem));
+	} else if (strncmp(dev->devpath, "/class/", 7) == 0) {
+		/* get subsystem from class dir */
+		strlcpy(dev->subsystem, &dev->devpath[7], sizeof(dev->subsystem));
+		pos = strchr(dev->subsystem, '/');
+		if (pos != NULL)
+			pos[0] = '\0';
+		else
+			dev->subsystem[0] = '\0';
+	} else if (strncmp(dev->devpath, "/block/", 7) == 0) {
+		strlcpy(dev->subsystem, "block", sizeof(dev->subsystem));
+	} else if (strncmp(dev->devpath, "/devices/", 9) == 0) {
+		/* get subsystem from "bus" link */
+		strlcpy(link_path, sysfs_path, sizeof(link_path));
+		strlcat(link_path, dev->devpath, sizeof(link_path));
+		strlcat(link_path, "/bus", sizeof(link_path));
+		len = readlink(link_path, link_target, sizeof(link_target));
+		if (len > 0) {
+			link_target[len] = '\0';
+			dbg("bus link '%s' points to '%s'", link_path, link_target);
+			pos = strrchr(link_target, '/');
+			if (pos != NULL)
+				strlcpy(dev->subsystem, &pos[1], sizeof(dev->subsystem));
+		}
+	} else if (strstr(dev->devpath, "/drivers/") != NULL) {
+		strlcpy(dev->subsystem, "drivers", sizeof(dev->subsystem));
+	} else if (strncmp(dev->devpath, "/module/", 8) == 0) {
+		strlcpy(dev->subsystem, "module", sizeof(dev->subsystem));
+	}
+
+	/* get driver name */
+	strlcpy(link_path, sysfs_path, sizeof(link_path));
+	strlcat(link_path, dev->devpath, sizeof(link_path));
+	strlcat(link_path, "/driver", sizeof(link_path));
+	len = readlink(link_path, link_target, sizeof(link_target));
+	if (len > 0) {
+		link_target[len] = '\0';
+		dbg("driver link '%s' points to '%s'", link_path, link_target);
+		pos = strrchr(link_target, '/');
+		if (pos != NULL)
+			strlcpy(dev->driver, &pos[1], sizeof(dev->driver));
+	}
+
+	return dev;
+}
+
+struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev)
+{
+	char parent_devpath[PATH_SIZE];
+	char *pos;
+
+	dbg("open '%s'", dev->devpath);
+
+	/* look if we already know the parent */
+	if (dev->parent != NULL)
+		return dev->parent;
+
+	/* requesting a parent is only valid for devices */
+	if ((strncmp(dev->devpath, "/devices/", 9) != 0) &&
+	    (strncmp(dev->devpath, "/subsystem/", 11) != 0) &&
+	    (strncmp(dev->devpath, "/class/", 7) != 0) &&
+	    (strncmp(dev->devpath, "/block/", 7) != 0))
+		return NULL;
+
+	strlcpy(parent_devpath, dev->devpath, sizeof(parent_devpath));
+	dbg("'%s'", parent_devpath);
+
+	/* strip last element */
+	pos = strrchr(parent_devpath, '/');
+	if (pos == NULL || pos == parent_devpath)
+		return NULL;
+	pos[0] = '\0';
+
+	/* are we at the top level of /devices */
+	if (strcmp(parent_devpath, "/devices") == 0) {
+		dbg("/devices top level");
+		return NULL;
+	}
+
+	/* at the subsystems top level we want to follow the old-style "device" link */
+	if (strncmp(parent_devpath, "/subsystem", 10) == 0) {
+		pos = strrchr(parent_devpath, '/');
+		if (pos == &parent_devpath[10] || pos == parent_devpath || strcmp(pos, "/devices") == 0) {
+			dbg("/subsystem top level, look for device link");
+			goto device_link;
+		}
+	}
+	if (strncmp(parent_devpath, "/class", 6) == 0) {
+		pos = strrchr(parent_devpath, '/');
+		if (pos == &parent_devpath[6] || pos == parent_devpath) {
+			dbg("/class top level, look for device link");
+			goto device_link;
+		}
+	}
+	if (strcmp(parent_devpath, "/block") == 0) {
+		dbg("/block top level, look for device link");
+		goto device_link;
+	}
+
+	/* get parent and remember it */
+	dev->parent = sysfs_device_get(parent_devpath);
+	return dev->parent;
+
+device_link:
+	strlcpy(parent_devpath, dev->devpath, sizeof(parent_devpath));
+	strlcat(parent_devpath, "/device", sizeof(parent_devpath));
+	if (sysfs_resolve_link(parent_devpath, sizeof(parent_devpath)) != 0)
+		return NULL;
+
+	/* get parent and remember it */
+	dev->parent = sysfs_device_get(parent_devpath);
+	return dev->parent;
+}
+
+struct sysfs_device *sysfs_device_get_parent_with_subsystem(struct sysfs_device *dev, const char *subsystem)
+{
+	struct sysfs_device *dev_parent;
+
+	dev_parent = sysfs_device_get_parent(dev);
+	while (dev_parent != NULL) {
+		if (strcmp(dev_parent->subsystem, subsystem) == 0)
+			return dev_parent;
+		dev_parent = sysfs_device_get_parent(dev_parent);
+	}
+	return NULL;
+}
+
+char *sysfs_attr_get_value(const char *devpath, const char *attr_name)
+{
+	char path_full[PATH_SIZE];
+	const char *path;
+	char value[NAME_SIZE];
+	struct sysfs_attr *attr_loop;
+	struct sysfs_attr *attr;
+	struct stat statbuf;
+	int fd;
+	ssize_t size;
+	size_t sysfs_len;
+
+	dbg("open '%s'/'%s'", devpath, attr_name);
+	sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full));
+	path = &path_full[sysfs_len];
+	strlcat(path_full, devpath, sizeof(path_full));
+	strlcat(path_full, "/", sizeof(path_full));
+	strlcat(path_full, attr_name, sizeof(path_full));
+
+	/* look for attribute in cache */
+	list_for_each_entry(attr_loop, &attr_list, node) {
+		if (strcmp(attr_loop->path, path) == 0) {
+			dbg("found in cache '%s'", attr_loop->path);
+			return attr_loop->value;
+		}
+	}
+
+	/* store attribute in cache (also negatives are kept in cache) */
+	dbg("new uncached attribute '%s'", path_full);
+	attr = malloc(sizeof(struct sysfs_attr));
+	if (attr == NULL)
+		return NULL;
+	memset(attr, 0x00, sizeof(struct sysfs_attr));
+	strlcpy(attr->path, path, sizeof(attr->path));
+	dbg("add to cache '%s'", path_full);
+	list_add(&attr->node, &attr_list);
+
+	if (lstat(path_full, &statbuf) != 0) {
+		dbg("stat '%s' failed: %s", path_full, strerror(errno));
+		goto out;
+	}
+
+	if (S_ISLNK(statbuf.st_mode)) {
+		/* links return the last element of the target path */
+		char link_target[PATH_SIZE];
+		int len;
+		const char *pos;
+
+		len = readlink(path_full, link_target, sizeof(link_target));
+		if (len > 0) {
+			link_target[len] = '\0';
+			pos = strrchr(link_target, '/');
+			if (pos != NULL) {
+				dbg("cache '%s' with link value '%s'", path_full, value);
+				strlcpy(attr->value_local, &pos[1], sizeof(attr->value_local));
+				attr->value = attr->value_local;
+			}
+		}
+		goto out;
+	}
+
+	/* skip directories */
+	if (S_ISDIR(statbuf.st_mode))
+		goto out;
+
+	/* skip non-readable files */
+	if ((statbuf.st_mode & S_IRUSR) == 0)
+		goto out;
+
+	/* read attribute value */
+	fd = open(path_full, O_RDONLY);
+	if (fd < 0) {
+		dbg("attribute '%s' does not exist", path_full);
+		goto out;
+	}
+	size = read(fd, value, sizeof(value));
+	close(fd);
+	if (size < 0)
+		goto out;
+	if (size == sizeof(value))
+		goto out;
+
+	/* got a valid value, store and return it */
+	value[size] = '\0';
+	remove_trailing_chars(value, '\n');
+	dbg("cache '%s' with attribute value '%s'", path_full, value);
+	strlcpy(attr->value_local, value, sizeof(attr->value_local));
+	attr->value = attr->value_local;
+
+out:
+	return attr->value;
+}
diff --git a/libmultipath/sysfs.h b/libmultipath/sysfs.h
new file mode 100644
index 0000000..4ac30db
--- /dev/null
+++ b/libmultipath/sysfs.h
@@ -0,0 +1,20 @@
+/*
+ * sysfs.h
+ */
+
+#ifndef _LIBMULTIPATH_SYSFS_H
+#define _LIBMULTIPATH_SYSFS_H
+
+#define dbg(format, arg...) do {} while (0)
+
+int sysfs_init(char *path, size_t len);
+void sysfs_cleanup(void);
+void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath,
+			     const char *subsystem, const char *driver);
+struct sysfs_device *sysfs_device_get(const char *devpath);
+struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev);
+struct sysfs_device *sysfs_device_get_parent_with_subsystem(struct sysfs_device *dev, const char *subsystem);
+char *sysfs_attr_get_value(const char *devpath, const char *attr_name);
+int sysfs_resolve_link(char *path, size_t size);
+
+#endif
diff --git a/libmultipath/uevent.c b/libmultipath/uevent.c
index 6482698..a4028d8 100644
--- a/libmultipath/uevent.c
+++ b/libmultipath/uevent.c
@@ -26,12 +26,14 @@
 #include <unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <stddef.h>
 #include <string.h>
 #include <fcntl.h>
 #include <time.h>
 #include <sys/socket.h>
 #include <sys/user.h>
-#include <asm/types.h>
+#include <sys/un.h>
+#include <linux/types.h>
 #include <linux/netlink.h>
 #include <pthread.h>
 #include <sys/mman.h>
@@ -105,6 +107,8 @@ int uevent_listen(int (*uev_trigger)(str
 {
 	int sock;
 	struct sockaddr_nl snl;
+	struct sockaddr_un sun;
+	socklen_t addrlen;
 	int retval;
 	int rcvbufsz = 128*1024;
 	int rcvsz = 0;
@@ -131,43 +135,72 @@ int uevent_listen(int (*uev_trigger)(str
 	pthread_attr_setstacksize(&attr, 64 * 1024);
 	pthread_create(&uevq_thr, &attr, uevq_thread, NULL);
 
-	memset(&snl, 0x00, sizeof(struct sockaddr_nl));
-	snl.nl_family = AF_NETLINK;
-	snl.nl_pid = getpid();
-	snl.nl_groups = 0xffffffff;
-
-	sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
-	if (sock == -1) {
-		condlog(0, "error getting socket, exit");
-		return 1;
-	}
-
 	/*
-	 * try to avoid dropping uevents, even so, this is not a guarantee,
-	 * but it does help to change the netlink uevent socket's
-	 * receive buffer threshold from the default value of 106,496 to
-	 * the maximum value of 262,142.
+	 * First check whether we have a udev socket
 	 */
-	retval = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvbufsz,
-			    sizeof(rcvbufsz));
+	memset(&sun, 0x00, sizeof(struct sockaddr_un));
+	sun.sun_family = AF_LOCAL;
+	strcpy(&sun.sun_path[1], "/org/kernel/dm/multipath_event");
+	addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(sun.sun_path+1) + 1;
+
+	sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
+	if (sock >= 0) {
+		const int feature_on = 1;
+
+		condlog(3, "reading events from udev socket.");
+
+		/* the bind takes care of ensuring only one copy running */
+		retval = bind(sock, (struct sockaddr *) &sun, addrlen);
+		if (retval < 0) {
+			condlog(0, "bind failed, exit");
+			goto exit;
+		}
 
-	if (retval < 0) {
-		condlog(0, "error setting receive buffer size for socket, exit");
-		exit(1);
-	}
-	retval = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvsz, prcvszsz);
+		/* enable receiving of the sender credentials */
+		setsockopt(sock, SOL_SOCKET, SO_PASSCRED, 
+			   &feature_on, sizeof(feature_on));
+
+	} else {
+		/* Fallback to read kernel netlink events */
+		memset(&snl, 0x00, sizeof(struct sockaddr_nl));
+		snl.nl_family = AF_NETLINK;
+		snl.nl_pid = getpid();
+		snl.nl_groups = 0xffffffff;
+
+		sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
+		if (sock == -1) {
+			condlog(0, "error getting socket, exit");
+			return 1;
+		}
 
-	if (retval < 0) {
-		condlog(0, "error setting receive buffer size for socket, exit");
-		exit(1);
-	}
-	condlog(3, "receive buffer size for socket is %u.", rcvsz);
+		condlog(3, "reading events from kernel.");
 
-	retval = bind(sock, (struct sockaddr *) &snl,
-		      sizeof(struct sockaddr_nl));
-	if (retval < 0) {
-		condlog(0, "bind failed, exit");
-		goto exit;
+		/*
+		 * try to avoid dropping uevents, even so, this is not a guarantee,
+		 * but it does help to change the netlink uevent socket's
+		 * receive buffer threshold from the default value of 106,496 to
+		 * the maximum value of 262,142.
+		 */
+		retval = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvbufsz,
+				    sizeof(rcvbufsz));
+
+		if (retval < 0) {
+			condlog(0, "error setting receive buffer size for socket, exit");
+			exit(1);
+		}
+		retval = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvsz, prcvszsz);
+		if (retval < 0) {
+			condlog(0, "error setting receive buffer size for socket, exit");
+			exit(1);
+		}
+		condlog(3, "receive buffer size for socket is %u.", rcvsz);
+
+		retval = bind(sock, (struct sockaddr *) &snl,
+			      sizeof(struct sockaddr_nl));
+		if (retval < 0) {
+			condlog(0, "bind failed, exit");
+			goto exit;
+		}
 	}
 
 	while (1) {
diff --git a/libmultipath/util.c b/libmultipath/util.c
index 911ec55..eaf2266 100644
--- a/libmultipath/util.c
+++ b/libmultipath/util.c
@@ -103,3 +103,55 @@ get_word (char * sentence, char ** word)
 	return skip + len;
 }
 
+size_t strlcpy(char *dst, const char *src, size_t size)
+{
+	size_t bytes = 0;
+	char *q = dst;
+	const char *p = src;
+	char ch;
+
+	while ((ch = *p++)) {
+		if (bytes+1 < size)
+			*q++ = ch;
+		bytes++;
+	}
+
+	/* If size == 0 there is no space for a final null... */
+	if (size)
+		*q = '\0';
+	return bytes;
+}
+
+size_t strlcat(char *dst, const char *src, size_t size)
+{
+	size_t bytes = 0;
+	char *q = dst;
+	const char *p = src;
+	char ch;
+
+	while (bytes < size && *q) {
+		q++;
+		bytes++;
+	}
+	if (bytes == size)
+		return (bytes + strlen(src));
+
+	while ((ch = *p++)) {
+		if (bytes+1 < size)
+		*q++ = ch;
+		bytes++;
+	}
+
+	*q = '\0';
+	return bytes;
+}
+
+void remove_trailing_chars(char *path, char c)
+{
+	size_t len;
+
+	len = strlen(path);
+	while (len > 0 && path[len-1] == c)
+		path[--len] = '\0';
+}
+
diff --git a/libmultipath/util.h b/libmultipath/util.h
index e86bae2..d0df8aa 100644
--- a/libmultipath/util.h
+++ b/libmultipath/util.h
@@ -6,7 +6,9 @@ void strchop(char *);
 void basename (char * src, char * dst);
 int filepresent (char * run);
 int get_word (char * sentence, char ** word);
-
+size_t strlcpy(char *dst, const char *src, size_t size);
+size_t strlcat(char *dst, const char *src, size_t size);
+void remove_trailing_chars(char *path, char c);
 
 #define safe_sprintf(var, format, args...)	\
 	snprintf(var, sizeof(var), format, ##args) >= sizeof(var)
diff --git a/multipath/Makefile b/multipath/Makefile
index 947d481..3f32c41 100644
--- a/multipath/Makefile
+++ b/multipath/Makefile
@@ -12,7 +12,7 @@ CFLAGS += -I$(multipathdir) -I$(checkers
 ifeq ($(strip $(BUILD)),klibc)
 	OBJS += $(libdm) $(libsysfs)
 else
-	LDFLAGS += -ldevmapper -lsysfs
+	LDFLAGS += -ldevmapper
 endif
 
 EXEC = multipath
@@ -21,7 +21,7 @@ all: $(BUILD)
 
 prepare:
 	make -C $(multipathdir) prepare
-	rm -f core *.o *.gz
+	rm -f core *.o
 
 glibc: prepare $(OBJS)
 	$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
@@ -37,17 +37,17 @@ $(MULTIPATHLIB)-$(BUILD).a:
 
 install:
 	install -d $(DESTDIR)$(bindir)
-	install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/
+	install -m 755 $(EXEC) $(DESTDIR)$(bindir)/
 	install -d $(DESTDIR)/etc/udev/rules.d
-	install -m 644 multipath.rules $(DESTDIR)/etc/udev/rules.d/
+	install -m 644 multipath.rules $(DESTDIR)/etc/udev/rules.d/71-multipath.rules
 	install -d $(DESTDIR)$(mandir)
 	install -m 644 $(EXEC).8 $(DESTDIR)$(mandir)
+	install -d $(DESTDIR)$(man5dir)
 	install -m 644 multipath.conf.5 $(DESTDIR)$(man5dir)
 
 uninstall:
 	rm $(DESTDIR)/etc/udev/rules.d/multipath.rules
 	rm $(DESTDIR)$(bindir)/$(EXEC)
-	rm $(DESTDIR)$(mandir)/$(EXEC).8
 
 clean:
-	rm -f core *.o $(EXEC) *.gz
+	rm -f core *.o $(EXEC)
diff --git a/multipath/main.c b/multipath/main.c
index c3d0dac..e2d7f41 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -25,7 +25,6 @@
 #include <stdio.h>
 #include <unistd.h>
 #include <ctype.h>
-#include <sysfs/libsysfs.h>
 
 #include <checkers.h>
 #include <vector.h>
@@ -37,6 +36,7 @@
 #include <structs.h>
 #include <structs_vec.h>
 #include <dmparser.h>
+#include <sysfs.h>
 #include <config.h>
 #include <blacklist.h>
 #include <discovery.h>
@@ -373,13 +373,13 @@ main (int argc, char *argv[])
 	if (dm_prereq(DEFAULT_TARGET))
 		exit(1);
 
-	if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) {
-		condlog(0, "multipath tools need sysfs mounted");
-		exit(1);
-	}
 	if (load_config(DEFAULT_CONFIGFILE))
 		exit(1);
 
+	if (sysfs_init(conf->sysfs_dir, FILE_NAME_SIZE)) {
+		condlog(0, "multipath tools need sysfs mounted");
+		exit(1);
+	}
 	while ((arg = getopt(argc, argv, ":dhl::FfM:v:p:b:t")) != EOF ) {
 		switch(arg) {
 		case 1: printf("optarg : %s\n",optarg);
@@ -472,6 +472,7 @@ main (int argc, char *argv[])
 		condlog(3, "restart multipath configuration process");
 	
 out:
+	sysfs_cleanup();
 	free_config(conf);
 	dm_lib_release();
 	dm_lib_exit();
diff --git a/multipath/multipath.init.suse b/multipath/multipath.init.suse
new file mode 100755
index 0000000..34a128c
--- /dev/null
+++ b/multipath/multipath.init.suse
@@ -0,0 +1,104 @@
+#! /bin/sh
+# Copyright (c) 2005 SuSE GmbH Nuernberg, Germany.
+#
+# Author: Hannes Reinecke <feedback@suse.de>
+#
+# init.d/boot.multipath
+#
+### BEGIN INIT INFO
+# Provides:          boot.multipath
+# Required-Start:    boot.device-mapper boot.udev
+# Required-Stop:
+# Default-Start:     B
+# Default-Stop:
+# Description:       Create multipath device targets
+### END INIT INFO
+
+PATH=/bin:/usr/bin:/sbin:/usr/sbin
+PROGRAM=/sbin/multipath
+
+# Set the maximum number of open files
+MAX_OPEN_FDS=4096
+
+test -x $PROGRAM || exit 5
+
+# Shell functions sourced from /etc/rc.status:
+#      rc_check         check and set local and overall rc status
+#      rc_status        check and set local and overall rc status
+#      rc_status -v     ditto but be verbose in local rc status
+#      rc_status -v -r  ditto and clear the local rc status
+#      rc_failed        set local and overall rc status to failed
+#      rc_reset         clear local rc status (overall remains)
+#      rc_exit          exit appropriate to overall rc status
+. /etc/rc.status
+
+# First reset status of this service
+rc_reset
+
+# Return values acc. to LSB for all commands but status:
+# 0 - success
+# 1 - misc error
+# 2 - invalid or excess args
+# 3 - unimplemented feature (e.g. reload)
+# 4 - insufficient privilege
+# 5 - program not installed
+# 6 - program not configured
+# 7 - program is not running
+# 
+# Note that starting an already running service, stopping
+# or restarting a not-running service as well as the restart
+# with force-reload (in case signalling is not supported) are
+# considered a success.
+
+case "$1" in
+    start)
+	echo -n "Creating multipath targets"
+	# Check whether multipath daemon is already running
+	if /sbin/multipathd -k"list paths" > /dev/null 2>&1 ; then
+	    echo -n " (multipathd running)"
+	    rc_status -v
+	    rc_exit
+	fi
+
+	# Load prerequisite module
+	modprobe dm-multipath
+	
+	# Be a chicken and flush all existing maps
+	$PROGRAM -F
+
+	# Clear /dev/disk/by-name/ prior to start-up; multipath will
+	# recreate them.
+	rm -f /dev/disk/by-name/* 2>&1 >/dev/null
+
+	# Set the maximum number of open files
+	if [ -n "$MAX_OPEN_FDS" ] ; then
+	    ulimit -n $MAX_OPEN_FDS
+	fi
+
+	# Start the program directly as checkproc doesn't work here
+	$PROGRAM -v 0
+
+	# Create all partitions which might have been missing
+	/sbin/dmsetup ls --target multipath --exec "/sbin/kpartx -a -p -part"
+
+	# Remember status and be verbose
+	rc_status -v
+	sleep 1
+	;;
+    stop)
+	# Remove all partition mappings
+	if dmsetup ls | grep -q -- -part; then
+	    /sbin/dmsetup ls --target multipath --exec "/sbin/kpartx -d -p -part"
+	fi
+
+	# And remove the multipath mappings themselves
+	for map in $(/sbin/dmsetup ls --target multipath | cut -f 1); do
+	    /sbin/dmsetup remove $map
+	done
+	;;
+    *)
+	echo "Usage: $0 {start|stop}"
+	exit 1
+	;;
+esac
+rc_exit
diff --git a/multipath/multipath.rules b/multipath/multipath.rules
index 10751ce..9d3579f 100644
--- a/multipath/multipath.rules
+++ b/multipath/multipath.rules
@@ -1,18 +1,7 @@
 #
-# multipath and multipath partitions nodes are created in /dev/mapper/
-# this file should be installed in /etc/udev/rules.d
+# udev rules for multipathing.
+# The persistent symlinks are created with the kpartx rules
 #
-# !! udev must not discard DM events !!
-# !! check the other installed rules !!
-#
-
-# lookup the devmap name
-#ACTION=="add", SUBSYSTEM=="block", KERNEL=="dm-*", \
-#	PROGRAM="/sbin/devmap_name %M %m"
-ACTION=="add", SUBSYSTEM=="block", KERNEL=="dm-*", \
-	PROGRAM="/sbin/dmsetup -j %M -m %m --noopencount --noheadings -c -o name info"
-
-# take care of devmap partitioning
-ACTION=="add", SUBSYSTEM=="block", KERNEL=="dm-*", \
-	RUN+="/sbin/kpartx -a /dev/mapper/%c"
 
+# socket for uevents
+RUN+="socket:/org/kernel/dm/multipath_event"
diff --git a/multipathd/Makefile b/multipathd/Makefile
index da351dc..bbab8da 100644
--- a/multipathd/Makefile
+++ b/multipathd/Makefile
@@ -7,7 +7,7 @@ include ../Makefile.inc
 # basic flags setting
 #
 CFLAGS += -DDAEMON -I$(multipathdir) -I$(checkersdir)
-LDFLAGS = -lpthread -ldevmapper -lsysfs -lreadline -lncurses
+LDFLAGS = -lpthread -ldevmapper -lreadline -lncurses
 
 #
 # debuging stuff
@@ -44,7 +44,7 @@ $(MULTIPATHLIB)-glibc.a:
 
 install:
 	install -d $(DESTDIR)$(bindir)
-	install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)
+	install -m 755 $(EXEC) $(DESTDIR)$(bindir)
 	install -d $(DESTDIR)$(rcdir)
 	install -d $(DESTDIR)$(mandir)
 	install -m 644 $(EXEC).8 $(DESTDIR)$(mandir)
@@ -52,9 +52,8 @@ install:
 uninstall:
 	rm -f $(DESTDIR)$(bindir)/$(EXEC)
 	rm -f $(DESTDIR)$(rcdir)/$(EXEC)
-	rm -f $(DESTDIR)$(mandir)/$(EXEC).8
 
 clean:
 	$(MAKE) -C $(multipathdir) prepare DAEMON=1
-	rm -f core *.o $(EXEC) *.gz
+	rm -f core *.o $(EXEC)
 
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
index 4938e84..7bae02a 100644
--- a/multipathd/cli_handlers.c
+++ b/multipathd/cli_handlers.c
@@ -13,6 +13,7 @@
 #include <blacklist.h>
 #include <debug.h>
 #include <print.h>
+#include <sysfs.h>
 
 #include "main.h"
 #include "cli.h"
@@ -312,6 +313,9 @@ cli_add_map (void * v, char ** reply, in
 {
 	struct vectors * vecs = (struct vectors *)data;
 	char * param = get_keyparam(v, MAP);
+	int minor;
+	char dev_path[PATH_SIZE];
+	struct sysfs_device *sysdev;
 
 	condlog(2, "%s: add map (operator)", param);
 
@@ -321,7 +325,18 @@ cli_add_map (void * v, char ** reply, in
 		condlog(2, "%s: map blacklisted", param);
 		return 0;
 	}
-	return ev_add_map(param, vecs);
+	minor = dm_get_minor(param);
+	if (minor < 0) {
+		condlog(2, "%s: not a device mapper table", param);
+		return 0;
+	}
+	sprintf(dev_path,"/block/dm-%d", minor);
+	sysdev = sysfs_device_get(dev_path);
+	if (!sysdev) {
+		condlog(2, "%s: not found in sysfs", param);
+		return 0;
+	}
+	return ev_add_map(sysdev, vecs);
 }
 
 int
diff --git a/multipathd/main.c b/multipathd/main.c
index 94b0b95..a173da3 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -14,12 +14,6 @@
 #include <errno.h>
 
 /*
- * libsysfs
- */
-#include <sysfs/libsysfs.h>
-#include <sysfs/dlist.h>
-
-/*
  * libcheckers
  */
 #include <checkers.h>
@@ -40,6 +34,7 @@
 #include <structs_vec.h>
 #include <dmparser.h>
 #include <devmapper.h>
+#include <sysfs.h>
 #include <dict.h>
 #include <discovery.h>
 #include <debug.h>
@@ -208,31 +203,29 @@ flush_map(struct multipath * mpp, struct
 }
 
 static int
-uev_add_map (char * devname, struct vectors * vecs)
+uev_add_map (struct sysfs_device * dev, struct vectors * vecs)
 {
-	condlog(2, "%s: add map (uevent)", devname);
-	return ev_add_map(devname, vecs);
+	condlog(2, "%s: add map (uevent)", dev->kernel);
+	return ev_add_map(dev, vecs);
 }
 
 int
-ev_add_map (char * devname, struct vectors * vecs)
+ev_add_map (struct sysfs_device * dev, struct vectors * vecs)
 {
-	int major, minor;
-	char dev_t[BLK_DEV_SIZE];
 	char * alias;
+	char *dev_t;
+	int major, minor;
 	char * refwwid;
 	struct multipath * mpp;
 	int map_present;
 	int r = 1;
 
-	/* libsysfs seems to forget to terminate the string... */
-	memset(dev_t, 0, BLK_DEV_SIZE);
-	if (sscanf(devname, "dm-%d", &minor) == 1 &&
-	    !sysfs_get_dev(sysfs_path, devname, dev_t, BLK_DEV_SIZE) &&
-	    sscanf(dev_t, "%d:%d", &major, &minor) == 2)
-		alias = dm_mapname(major, minor);
-	else
-		alias = STRDUP(devname);
+	dev_t = sysfs_attr_get_value(dev->devpath, "dev");
+
+	if (!dev_t || sscanf(dev_t, "%d:%d", &major, &minor) != 2)
+		return 1;
+
+	alias = dm_mapname(major, minor);
 		
 	if (!alias)
 		return 1;
@@ -241,7 +234,6 @@ ev_add_map (char * devname, struct vecto
 
 	if (map_present && dm_type(alias, DEFAULT_TARGET) <= 0) {
 		condlog(4, "%s: not a multipath map", alias);
-		FREE(alias);
 		return 0;
 	}
 
@@ -254,8 +246,7 @@ ev_add_map (char * devname, struct vecto
 		 * of uev_add_path
 		 */
 		condlog(0, "%s: devmap already registered",
-			devname);
-		FREE(alias);
+			dev->kernel);
 		return 0;
 	}
 
@@ -265,10 +256,10 @@ ev_add_map (char * devname, struct vecto
 	if (map_present && (mpp = add_map_without_path(vecs, minor, alias,
 					start_waiter_thread))) {
 		sync_map_state(mpp);
-		condlog(3, "%s: devmap %s added", alias, devname);
+		condlog(3, "%s: devmap %s added", alias, dev->kernel);
 		return 0;
 	}
-	refwwid = get_refwwid(devname, DEV_DEVMAP, vecs->pathvec);
+	refwwid = get_refwwid(dev->kernel, DEV_DEVMAP, vecs->pathvec);
 
 	if (refwwid) {
 		r = coalesce_paths(vecs, NULL, refwwid);
@@ -276,20 +267,19 @@ ev_add_map (char * devname, struct vecto
 	}
 	
 	if (!r)
-		condlog(3, "%s: devmap %s added", alias, devname);
+		condlog(3, "%s: devmap %s added", alias, dev->kernel);
 	else
-		condlog(0, "%s: uev_add_map %s failed", alias, devname);
+		condlog(0, "%s: uev_add_map %s failed", alias, dev->kernel);
 
 	FREE(refwwid);
-	FREE(alias);
 	return r;
 }
 
 static int
-uev_remove_map (char * devname, struct vectors * vecs)
+uev_remove_map (struct sysfs_device * dev, struct vectors * vecs)
 {
-	condlog(2, "%s: remove map (uevent)", devname);
-	return ev_remove_map(devname, vecs);
+	condlog(2, "%s: remove map (uevent)", dev->kernel);
+	return ev_remove_map(dev->kernel, vecs);
 }
 
 int
@@ -310,13 +300,13 @@ ev_remove_map (char * devname, struct ve
 }
 
 static int
-uev_umount_map (char * devname, struct vectors * vecs)
+uev_umount_map (struct sysfs_device * dev, struct vectors * vecs)
 {
 	struct multipath * mpp;
 
-	condlog(2, "%s: umount map (uevent)", devname);
+	condlog(2, "%s: umount map (uevent)", dev->kernel);
 
-	mpp = find_mp_by_str(vecs->mpvec, devname);
+	mpp = find_mp_by_str(vecs->mpvec, dev->kernel);
 
 	if (!mpp)
 		return 0;
@@ -331,10 +321,10 @@ uev_umount_map (char * devname, struct v
 }
 	
 static int
-uev_add_path (char * devname, struct vectors * vecs)
+uev_add_path (struct sysfs_device * dev, struct vectors * vecs)
 {
-	condlog(2, "%s: add path (uevent)", devname);
-	return (ev_add_path(devname, vecs) != 1)? 0 : 1;
+	condlog(2, "%s: add path (uevent)", dev->kernel);
+	return (ev_add_path(dev->kernel, vecs) != 1)? 0 : 1;
 }
 
 
@@ -450,10 +440,10 @@ out:
 }
 
 static int
-uev_remove_path (char * devname, struct vectors * vecs)
+uev_remove_path (struct sysfs_device * dev, struct vectors * vecs)
 {
-	condlog(2, "%s: remove path (uevent)", devname);
-	return ev_remove_path(devname, vecs);
+	condlog(2, "%s: remove path (uevent)", dev->kernel);
+	return ev_remove_path(dev->kernel, vecs);
 }
 
 int
@@ -636,7 +626,7 @@ int
 uev_trigger (struct uevent * uev, void * trigger_data)
 {
 	int r = 0;
-	char devname[32];
+	struct sysfs_device *sysdev;
 	struct vectors * vecs;
 
 	vecs = (struct vectors *)trigger_data;
@@ -644,7 +634,7 @@ uev_trigger (struct uevent * uev, void *
 	if (uev_discard(uev->devpath))
 		return 0;
 
-	basename(uev->devpath, devname);
+	sysdev = sysfs_device_get(uev->devpath);
 	lock(vecs->lock);
 
 	/*
@@ -652,17 +642,17 @@ uev_trigger (struct uevent * uev, void *
 	 * Add events are ignored here as the tables
 	 * are not fully initialised then.
 	 */
-	if (!strncmp(devname, "dm-", 3)) {
+	if (!strncmp(sysdev->kernel, "dm-", 3)) {
 		if (!strncmp(uev->action, "change", 6)) {
-			r = uev_add_map(devname, vecs);
+			r = uev_add_map(sysdev, vecs);
 			goto out;
 		}
 		if (!strncmp(uev->action, "remove", 6)) {
-			r = uev_remove_map(devname, vecs);
+			r = uev_remove_map(sysdev, vecs);
 			goto out;
 		}
 		if (!strncmp(uev->action, "umount", 6)) {
-			r = uev_umount_map(devname, vecs);
+			r = uev_umount_map(sysdev, vecs);
 			goto out;
 		}
 		goto out;
@@ -672,15 +662,15 @@ uev_trigger (struct uevent * uev, void *
 	 * path add/remove event
 	 */
 	if (filter_devnode(conf->blist_devnode, conf->elist_devnode,
-		 	   devname) > 0)
+		 	   sysdev->kernel) > 0)
 		goto out;
 
 	if (!strncmp(uev->action, "add", 3)) {
-		r = uev_add_path(devname, vecs);
+		r = uev_add_path(sysdev, vecs);
 		goto out;
 	}
 	if (!strncmp(uev->action, "remove", 6)) {
-		r = uev_remove_path(devname, vecs);
+		r = uev_remove_path(sysdev, vecs);
 		goto out;
 	}
 
@@ -1278,7 +1268,7 @@ child (void * param)
 	if (!vecs)
 		exit(1);
 
-	if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) {
+	if (sysfs_init(conf->sysfs_dir, FILE_NAME_SIZE)) {
 		condlog(0, "can not find sysfs mount point");
 		exit(1);
 	}
@@ -1315,6 +1305,8 @@ child (void * param)
 	pthread_cancel(uevent_thr);
 	pthread_cancel(uxlsnr_thr);
 
+	sysfs_cleanup();
+
 	free_keys(keys);
 	keys = NULL;
 	free_handlers(handlers);
diff --git a/multipathd/main.h b/multipathd/main.h
index d0cce3a..1a6dc55 100644
--- a/multipathd/main.h
+++ b/multipathd/main.h
@@ -7,7 +7,7 @@
 int reconfigure (struct vectors *);
 int ev_add_path (char *, struct vectors *);
 int ev_remove_path (char *, struct vectors *);
-int ev_add_map (char *, struct vectors *);
+int ev_add_map (struct sysfs_device *, struct vectors *);
 int ev_remove_map (char *, struct vectors *);
 
 #endif /* MAIN_H */
diff --git a/multipathd/multipathd.init.suse b/multipathd/multipathd.init.suse
new file mode 100755
index 0000000..a297956
--- /dev/null
+++ b/multipathd/multipathd.init.suse
@@ -0,0 +1,155 @@
+#! /bin/sh
+# Copyright (c) 1995-2001 SuSE GmbH Nuernberg, Germany.
+#
+# Author: Thorsten Kukuk <feedback@suse.de>
+#
+# init.d/routed
+#
+#   and symbolic its link
+#
+# /usr/sbin/rcrouted
+#
+### BEGIN INIT INFO
+# Provides:          multipathd
+# Required-Start:    $syslog
+# Required-Stop:
+# Default-Start:     3 5
+# Default-Stop:	     0 1 2 4 6
+# Description:       Starts multipath daemon
+### END INIT INFO
+
+PATH=/bin:/usr/bin:/sbin:/usr/sbin
+DAEMON=/sbin/multipathd
+PIDFILE=/var/run/multipathd.pid
+
+# Set the maximum number of open files
+MAX_OPEN_FDS=4096
+
+test -x $DAEMON || exit 5
+
+# Shell functions sourced from /etc/rc.status:
+#      rc_check         check and set local and overall rc status
+#      rc_status        check and set local and overall rc status
+#      rc_status -v     ditto but be verbose in local rc status
+#      rc_status -v -r  ditto and clear the local rc status
+#      rc_failed        set local and overall rc status to failed
+#      rc_reset         clear local rc status (overall remains)
+#      rc_exit          exit appropriate to overall rc status
+. /etc/rc.status
+
+# First reset status of this service
+rc_reset
+
+# Return values acc. to LSB for all commands but status:
+# 0 - success
+# 1 - misc error
+# 2 - invalid or excess args
+# 3 - unimplemented feature (e.g. reload)
+# 4 - insufficient privilege
+# 5 - program not installed
+# 6 - program not configured
+# 7 - program is not running
+# 
+# Note that starting an already running service, stopping
+# or restarting a not-running service as well as the restart
+# with force-reload (in case signalling is not supported) are
+# considered a success.
+
+case "$1" in
+    start)
+	echo -n "Starting multipathd"
+
+	modprobe dm-multipath
+
+	# Set the maximum number of open files
+	if [ -n "$MAX_OPEN_FDS" ] ; then
+	    ulimit -n $MAX_OPEN_FDS
+	fi
+
+	if [ -f $PIDFILE ]; then
+		PID="$(cat $PIDFILE)"
+		PROCNAME="$(ps -o cmd --no-headers $PID)"
+	fi
+
+	if [ "$PROCNAME" != "$DAEMON" ]; then
+		$DAEMON
+	fi
+	
+	# Remember status and be verbose
+	rc_status -v
+	sleep 1
+	;;
+    stop)
+	echo -n "Shutting down multipathd"
+	# Because of the way how multipathd sets up its own namespace
+	# and chroots to it, killproc cannot be used with this process.
+	# So implement a cruder version:
+	if [ -f $PIDFILE ]; then
+		PID="$(cat $PIDFILE)"
+		PROCNAME="$(ps -o cmd --no-headers $PID)"
+	fi
+
+	if [ "$PROCNAME" == "$DAEMON" ]; then
+		kill -TERM $PID
+	fi
+
+	# Remember status and be verbose
+	rc_status -v
+	;;
+    try-restart)
+	## Stop the service and if this succeeds (i.e. the 
+	## service was running before), start it again.
+        $0 status >/dev/null &&  $0 restart
+
+	# Remember status and be quiet
+	rc_status
+	;;
+    restart|force-reload)
+	## Stop the service and regardless of whether it was
+	## running or not, start it again.
+	$0 stop
+	$0 start
+
+	# Remember status and be quiet
+	rc_status
+	;;
+    reload)
+	## Like force-reload, but if daemon does not support
+	## signalling, do nothing (!)
+
+	# If it does not support reload:
+	exit 3
+	;;
+    status)
+	echo -n "Checking for multipathd: "
+
+	# Status has a slightly different for the status command:
+	# 0 - service running
+	# 1 - service dead, but /var/run/  pid  file exists
+	# 2 - service dead, but /var/lock/ lock file exists
+	# 3 - service not running
+
+	if [ -f $PIDFILE ]; then
+		PID="$(cat $PIDFILE)"
+		PROCNAME="$(ps -o cmd --no-headers $PID)"
+		if [ "$PROCNAME" == "$DAEMON" ]; then
+			(exit 0)
+		else
+			(exit 1)
+		fi
+	else
+		(exit 3)
+	fi
+
+	rc_status -v
+	;;
+    probe)
+	## Optional: Probe for the necessity of a reload,
+	## give out the argument which is required for a reload.
+	;;
+    *)
+	echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|probe}"
+	exit 1
+	;;
+esac
+rc_exit
diff --git a/path_priority/pp_alua/Makefile b/path_priority/pp_alua/Makefile
index 6c58529..ce78455 100644
--- a/path_priority/pp_alua/Makefile
+++ b/path_priority/pp_alua/Makefile
@@ -41,10 +41,9 @@ install: $(EXEC) $(EXEC).8
 
 uninstall:
 	rm $(DESTDIR)$(bindir)/$(EXEC)
-	rm $(DESTDIR)$(mandir)/$(EXEC).8
 
 clean:	
-	rm -f *.o *.gz $(EXEC)
+	rm -f *.o $(EXEC)
 
 main.o:	main.c rtpg.h spc3.h
 
diff --git a/path_priority/pp_balance_units/Makefile b/path_priority/pp_balance_units/Makefile
index bed7fb0..b0fee28 100644
--- a/path_priority/pp_balance_units/Makefile
+++ b/path_priority/pp_balance_units/Makefile
@@ -22,7 +22,7 @@ EXEC = mpath_prio_balance_units
 all: $(BUILD)
 
 prepare:
-	rm -f core *.o *.gz
+	rm -f core *.o
 
 glibc: prepare $(OBJS)
 	$(CC) -o $(EXEC) $(OBJS) $(LDFLAGS)
@@ -35,10 +35,10 @@ $(MULTIPATHLIB)-$(BUILD).a:
 
 install:
 	install -d $(DESTDIR)$(bindir)
-	install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/
+	install -m 755 $(EXEC) $(DESTDIR)$(bindir)/
 
 uninstall:
 	rm $(DESTDIR)$(bindir)/$(EXEC)
 
 clean:
-	rm -f core *.o $(EXEC) *.gz
+	rm -f core *.o $(EXEC)
diff --git a/path_priority/pp_emc/Makefile b/path_priority/pp_emc/Makefile
index 651bdcd..8c6e922 100644
--- a/path_priority/pp_emc/Makefile
+++ b/path_priority/pp_emc/Makefile
@@ -14,7 +14,7 @@ klibc:	$(OBJS)
 	$(CC) -static -o $(EXEC) $(OBJS)
 
 install: $(EXEC)
-	install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
+	install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
 
 uninstall:
 	rm $(DESTDIR)$(bindir)/$(EXEC)
diff --git a/path_priority/pp_hds_modular/Makefile b/path_priority/pp_hds_modular/Makefile
index a0249a5..1c276e6 100644
--- a/path_priority/pp_hds_modular/Makefile
+++ b/path_priority/pp_hds_modular/Makefile
@@ -14,7 +14,7 @@ klibc:	$(OBJS)
 	$(CC) -static -o $(EXEC) $(OBJS)
 
 install: $(EXEC)
-	install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
+	install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
 
 uninstall:
 	rm $(DESTDIR)$(bindir)/$(EXEC)
diff --git a/path_priority/pp_netapp/Makefile b/path_priority/pp_netapp/Makefile
index 9e7d3a3..2d571b0 100644
--- a/path_priority/pp_netapp/Makefile
+++ b/path_priority/pp_netapp/Makefile
@@ -14,7 +14,7 @@ klibc:	$(OBJS)
 	$(CC) -static -o $(EXEC) $(OBJS)
 
 install: $(EXEC)
-	install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
+	install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
 
 uninstall:
 	rm $(DESTDIR)$(bindir)/$(EXEC)
diff --git a/path_priority/pp_random/Makefile b/path_priority/pp_random/Makefile
index 85f42a2..ca7974e 100644
--- a/path_priority/pp_random/Makefile
+++ b/path_priority/pp_random/Makefile
@@ -14,7 +14,7 @@ klibc:	$(OBJS)
 	$(CC) -static -o $(EXEC) $(OBJS)
 
 install: $(EXEC)
-	install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
+	install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
 
 uninstall:
 	rm $(DESTDIR)$(bindir)/$(EXEC)
diff --git a/path_priority/pp_tpc/Makefile b/path_priority/pp_tpc/Makefile
index 86841dd..624f76d 100644
--- a/path_priority/pp_tpc/Makefile
+++ b/path_priority/pp_tpc/Makefile
@@ -14,7 +14,7 @@ klibc:	$(OBJS)
 	$(CC) -static -o $(EXEC) $(OBJS)
 
 install: $(EXEC)
-	install -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
+	install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
 
 uninstall:
 	rm $(DESTDIR)$(bindir)/$(EXEC)
openSUSE Build Service is sponsored by