diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f8a9b2b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+SOURCES/util-linux-2.23.2.tar.xz
diff --git a/.util-linux.metadata b/.util-linux.metadata
new file mode 100644
index 0000000..0cacf1c
--- /dev/null
+++ b/.util-linux.metadata
@@ -0,0 +1 @@
+1c3023304dd66663fd314bee424d7cc829fff538 SOURCES/util-linux-2.23.2.tar.xz
diff --git a/README.md b/README.md
deleted file mode 100644
index 0e7897f..0000000
--- a/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
-The master branch has no content
- 
-Look at the c7 branch if you are working with CentOS-7, or the c4/c5/c6 branch for CentOS-4, 5 or 6
- 
-If you find this file in a distro specific branch, it means that no content has been checked in yet
diff --git a/SOURCES/0060-build-sys-add-CFLAGS-and-LDFLAGS-for-daemons-and-sha.patch b/SOURCES/0060-build-sys-add-CFLAGS-and-LDFLAGS-for-daemons-and-sha.patch
new file mode 100644
index 0000000..cc9d680
--- /dev/null
+++ b/SOURCES/0060-build-sys-add-CFLAGS-and-LDFLAGS-for-daemons-and-sha.patch
@@ -0,0 +1,166 @@
+From 097c66ef2dd4779e01d13ad4a5f9733334fa9d1a Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 27 Aug 2013 10:02:04 +0200
+Subject: [PATCH 60/84] build-sys: add CFLAGS and LDFLAGS for daemons and
+ shared libs
+
+This is necessary for paranoid security guys who believe that things
+like "-Wl,-z,relro" or "-Wl,-z,bind_now" is a way how to make the
+world a safer place...
+
+[rhel7: add also SOLIB_* to libfdisk]
+
+Upstream: http://github.com/karelzak/util-linux/commit/03d00d495f3b505d9cae967c629fb38aca301e01
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1092520
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ Documentation/howto-compilation.txt | 10 +++++-----
+ configure.ac                        | 10 ++++++++++
+ libblkid/src/Makemodule.am          |  2 ++
+ libfdisk/src/Makemodule.am          |  3 +++
+ libmount/src/Makemodule.am          |  2 ++
+ libuuid/src/Makemodule.am           |  7 ++++++-
+ misc-utils/Makemodule.am            |  3 ++-
+ 7 files changed, 30 insertions(+), 7 deletions(-)
+
+diff --git a/Documentation/howto-compilation.txt b/Documentation/howto-compilation.txt
+index bebe0d2..4b39246 100644
+--- a/Documentation/howto-compilation.txt
++++ b/Documentation/howto-compilation.txt
+@@ -27,12 +27,12 @@ Compiling
+ 	The SUID_* feature is currently supported for chfn, chsh,
+ 	newgrp, su, write, mount, and umount.
+ 
+-	Preferred compilation options for developers, when
+-	using gcc, are:
++	Use DAEMON_CFLAGS and DAEMON_LDFLAGS when you want to define
++	special compiler options for daemons; supported for uuidd.
+ 
+-	export CFLAGS="-Wmissing-parameter-type -Wsign-compare
+-	-Wtype-limits -Wuninitialized -Wunused-parameter
+-	-Wunused-but-set-parameter -fno-common"
++	Use SOLIB_CFLAGS and SOLIB_LDFLAGS when you want to define
++	special compiler options for shared libraries; supported for
++	libmount, libblkid and libuuid.
+ 
+ 	FIXME: add notes about klib and uClib.
+ 
+diff --git a/configure.ac b/configure.ac
+index f7c27cd..f3c7214 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1538,6 +1538,16 @@ AC_ARG_VAR([SUID_CFLAGS],
+ AC_ARG_VAR([SUID_LDFLAGS],
+ 	   [LDFLAGS used for binaries which are usually with the suid bit])
+ 
++AC_ARG_VAR([DAEMON_CFLAGS],
++	   [CFLAGS used for binaries which are usually executed as daemons])
++AC_ARG_VAR([DAEMON_LDFLAGS],
++	   [LDFLAGS used for binaries which are usually executed as daemons])
++
++AC_ARG_VAR([SOLIB_CFLAGS],
++	   [CFLAGS used for shared libraries])
++AC_ARG_VAR([SOLIB_LDFLAGS],
++	   [LDFLAGS used for shared libraries])
++
+ LIBS=""
+ 
+ 
+diff --git a/libblkid/src/Makemodule.am b/libblkid/src/Makemodule.am
+index 04d8621..1563976 100644
+--- a/libblkid/src/Makemodule.am
++++ b/libblkid/src/Makemodule.am
+@@ -113,6 +113,7 @@ libblkid_la_LIBADD = libcommon.la
+ 
+ 
+ libblkid_la_CFLAGS = \
++	$(SOLIB_CFLAGS) \
+ 	-I$(ul_libblkid_incdir) \
+ 	-I$(top_srcdir)/libblkid/src
+ 
+@@ -128,6 +129,7 @@ libblkid_la_DEPENDENCIES = \
+ 	libblkid/src/blkid.h.in
+ 
+ libblkid_la_LDFLAGS = \
++	$(SOLIB_LDFLAGS) \
+ 	-Wl,--version-script=$(top_srcdir)/libblkid/src/blkid.sym \
+ 	-version-info $(LIBBLKID_VERSION_INFO)
+ 
+diff --git a/libfdisk/src/Makemodule.am b/libfdisk/src/Makemodule.am
+index fbfb1b4..5c50001 100644
+--- a/libfdisk/src/Makemodule.am
++++ b/libfdisk/src/Makemodule.am
+@@ -25,6 +25,8 @@ nodist_libfdisk_la_SOURCES = libfdisk/src/fdiskP.h
+ libfdisk_la_LIBADD = libcommon.la
+ 
+ libfdisk_la_CFLAGS = \
++	$(AM_CFLAGS) \
++	$(SOLIB_CFLAGS) \
+ 	-I$(ul_libfdisk_incdir) \
+ 	-I$(top_srcdir)/libfdisk/src
+ 
+@@ -39,6 +41,7 @@ libfdisk_la_CFLAGS += -I$(ul_libuuid_incdir)
+ endif
+ 
+ libfdisk_la_DEPENDENCIES = $(libfdisk_la_LIBADD)
++libfdisk_la_LDFLAGS = $(SOLIB_LDFLAGS)
+ 
+ 
+ check_PROGRAMS += \
+diff --git a/libmount/src/Makemodule.am b/libmount/src/Makemodule.am
+index 494e02a..8ef07e5 100644
+--- a/libmount/src/Makemodule.am
++++ b/libmount/src/Makemodule.am
+@@ -33,6 +33,7 @@ nodist_libmount_la_SOURCES = libmount/src/mountP.h
+ libmount_la_LIBADD = libcommon.la libblkid.la $(SELINUX_LIBS)
+ 
+ libmount_la_CFLAGS = \
++	$(SOLIB_CFLAGS) \
+ 	-I$(ul_libblkid_incdir) \
+ 	-I$(ul_libmount_incdir) \
+ 	-I$(top_srcdir)/libmount/src
+@@ -43,6 +44,7 @@ libmount_la_DEPENDENCIES = \
+ 	libmount/src/libmount.h.in
+ 
+ libmount_la_LDFLAGS = \
++	$(SOLIB_LDFLAGS) \
+ 	-Wl,--version-script=$(top_srcdir)/libmount/src/libmount.sym \
+ 	-version-info $(LIBMOUNT_VERSION_INFO)
+ 
+diff --git a/libuuid/src/Makemodule.am b/libuuid/src/Makemodule.am
+index 73f1ba9..a20cb4c 100644
+--- a/libuuid/src/Makemodule.am
++++ b/libuuid/src/Makemodule.am
+@@ -29,9 +29,14 @@ libuuid_la_SOURCES = \
+ 
+ libuuid_la_DEPENDENCIES = libuuid/src/uuid.sym
+ libuuid_la_LIBADD       = $(SOCKET_LIBS)
+-libuuid_la_CFLAGS       = -I$(ul_libuuid_incdir) -Ilibuuid/src
++
++libuuid_la_CFLAGS = \
++	 $(SOLIB_CFLAGS) \
++	 -I$(ul_libuuid_incdir) \
++	 -Ilibuuid/src
+ 
+ libuuid_la_LDFLAGS = \
++	$(SOLIB_LDFLAGS) \
+ 	-Wl,--version-script=$(top_srcdir)/libuuid/src/uuid.sym \
+ 	-version-info $(LIBUUID_VERSION_INFO)
+ 
+diff --git a/misc-utils/Makemodule.am b/misc-utils/Makemodule.am
+index a615047..70a78f2 100644
+--- a/misc-utils/Makemodule.am
++++ b/misc-utils/Makemodule.am
+@@ -77,7 +77,8 @@ if BUILD_UUIDD
+ usrsbin_exec_PROGRAMS += uuidd
+ dist_man_MANS += misc-utils/uuidd.8
+ uuidd_LDADD = $(LDADD) libuuid.la
+-uuidd_CFLAGS = $(AM_CFLAGS) -I$(ul_libuuid_incdir)
++uuidd_CFLAGS = $(DAEMON_CFLAGS) $(AM_CFLAGS) -I$(ul_libuuid_incdir)
++uuidd_LDFLAGS = $(DAEMON_LDFLAGS) $(AM_LDFLAGS)
+ uuidd_SOURCES = misc-utils/uuidd.c
+ if USE_SOCKET_ACTIVATION
+ uuidd_SOURCES += misc-utils/sd-daemon.c misc-utils/sd-daemon.h
+-- 
+2.7.4
+
diff --git a/SOURCES/0061-libmount-be-more-restrictive-about-valid-tag-names.patch b/SOURCES/0061-libmount-be-more-restrictive-about-valid-tag-names.patch
new file mode 100644
index 0000000..7e5d394
--- /dev/null
+++ b/SOURCES/0061-libmount-be-more-restrictive-about-valid-tag-names.patch
@@ -0,0 +1,183 @@
+From f5ef29a5b5c51fe2039352dabcc4946fa2f55861 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 2 Jul 2013 10:46:10 +0200
+Subject: [PATCH 61/84] libmount: be more restrictive about valid tag names
+
+ # mount DUMMY=filename.img /mnt
+
+The 'DUMMY=filename.img' is a filename and should not be
+interpreted as tag name. The valid tag names are LABEL, UUID,
+PARTLABEL and PARTUUID only.
+
+Upstream: http://github.com/karelzak/util-linux/commit/2c6b25f01802808b142d450af3352605720899da
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1248003
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libmount/src/cache.c  | 29 ++++++++++++-----------------
+ libmount/src/fs.c     |  9 ++++++---
+ libmount/src/mountP.h |  2 ++
+ libmount/src/tab.c    | 20 ++++++++------------
+ libmount/src/utils.c  | 12 ++++++++++++
+ 5 files changed, 40 insertions(+), 32 deletions(-)
+
+diff --git a/libmount/src/cache.c b/libmount/src/cache.c
+index 7b65122..43a4daf 100644
+--- a/libmount/src/cache.c
++++ b/libmount/src/cache.c
+@@ -583,22 +583,18 @@ error:
+ char *mnt_resolve_spec(const char *spec, struct libmnt_cache *cache)
+ {
+ 	char *cn = NULL;
++	char *t = NULL, *v = NULL;
+ 
+ 	if (!spec)
+ 		return NULL;
+ 
+-	if (strchr(spec, '=')) {
+-		char *tag, *val;
+-
+-		if (!blkid_parse_tag_string(spec, &tag, &val)) {
+-			cn = mnt_resolve_tag(tag, val, cache);
+-
+-			free(tag);
+-			free(val);
+-		}
+-	} else
++	if (blkid_parse_tag_string(spec, &t, &v) == 0 && mnt_valid_tagname(t))
++		cn = mnt_resolve_tag(t, v, cache);
++	else
+ 		cn = mnt_resolve_path(spec, cache);
+ 
++	free(t);
++	free(v);
+ 	return cn;
+ }
+ 
+@@ -663,6 +659,7 @@ int test_read_tags(struct libmnt_test *ts, int argc, char *argv[])
+ 
+ 	while(fgets(line, sizeof(line), stdin)) {
+ 		size_t sz = strlen(line);
++		char *t = NULL, *v = NULL;
+ 
+ 		if (sz > 0 && line[sz - 1] == '\n')
+ 			line[sz - 1] = '\0';
+@@ -674,16 +671,14 @@ int test_read_tags(struct libmnt_test *ts, int argc, char *argv[])
+ 			if (mnt_cache_read_tags(cache, line) < 0)
+ 				fprintf(stderr, "%s: read tags failed\n", line);
+ 
+-		} else if (strchr(line, '=')) {
+-			char *tag, *val;
++		} else if (blkid_parse_tag_string(line, &t, &v) == 0) {
+ 			const char *cn = NULL;
+ 
+-			if (!blkid_parse_tag_string(line, &tag, &val)) {
+-				cn = cache_find_tag(cache, tag, val);
++			if (mnt_valid_tagname(t))
++				cn = cache_find_tag(cache, t, v);
++			free(t);
++			free(v);
+ 
+-				free(tag);
+-				free(val);
+-			}
+ 			if (cn)
+ 				printf("%s: %s\n", line, cn);
+ 			else
+diff --git a/libmount/src/fs.c b/libmount/src/fs.c
+index c95cdc7..75e3bbb 100644
+--- a/libmount/src/fs.c
++++ b/libmount/src/fs.c
+@@ -318,9 +318,12 @@ int __mnt_fs_set_source_ptr(struct libmnt_fs *fs, char *source)
+ 
+ 	assert(fs);
+ 
+-	if (source && *source != '/' && strchr(source, '=')) {
+-		if (blkid_parse_tag_string(source, &t, &v) != 0)
+-			return -1;
++	if (source && blkid_parse_tag_string(source, &t, &v) == 0 &&
++	    !mnt_valid_tagname(t)) {
++		/* parsable but unknown tag -- ignore */
++		free(t);
++		free(v);
++		t = v = NULL;
+ 	}
+ 
+ 	if (fs->source != source)
+diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h
+index e064a68..7b0848f 100644
+--- a/libmount/src/mountP.h
++++ b/libmount/src/mountP.h
+@@ -136,6 +136,8 @@ extern int startswith(const char *s, const char *sx)
+ 
+ extern char *stripoff_last_component(char *path);
+ 
++extern int mnt_valid_tagname(const char *tagname);
++
+ extern int is_file_empty(const char *name);
+ 
+ extern int mkdir_p(const char *path, mode_t mode);
+diff --git a/libmount/src/tab.c b/libmount/src/tab.c
+index e3524a8..1ba1eec 100644
+--- a/libmount/src/tab.c
++++ b/libmount/src/tab.c
+@@ -801,7 +801,8 @@ struct libmnt_fs *mnt_table_find_tag(struct libmnt_table *tb, const char *tag,
+ struct libmnt_fs *mnt_table_find_source(struct libmnt_table *tb,
+ 					const char *source, int direction)
+ {
+-	struct libmnt_fs *fs = NULL;
++	struct libmnt_fs *fs;
++	char *t = NULL, *v = NULL;
+ 
+ 	assert(tb);
+ 
+@@ -812,18 +813,13 @@ struct libmnt_fs *mnt_table_find_source(struct libmnt_table *tb,
+ 
+ 	DBG(TAB, mnt_debug_h(tb, "lookup SOURCE: '%s'", source));
+ 
+-	if (source && *source && strchr(source, '=')) {
+-		char *tag, *val;
+-
+-		if (blkid_parse_tag_string(source, &tag, &val) == 0) {
+-
+-			fs = mnt_table_find_tag(tb, tag, val, direction);
+-
+-			free(tag);
+-			free(val);
+-		}
+-	} else
++	if (blkid_parse_tag_string(source, &t, &v) || !mnt_valid_tagname(t))
+ 		fs = mnt_table_find_srcpath(tb, source, direction);
++	else
++		fs = mnt_table_find_tag(tb, t, v, direction);
++
++	free(t);
++	free(v);
+ 
+ 	return fs;
+ }
+diff --git a/libmount/src/utils.c b/libmount/src/utils.c
+index 6a444ad..9305bb8 100644
+--- a/libmount/src/utils.c
++++ b/libmount/src/utils.c
+@@ -65,6 +65,18 @@ int is_file_empty(const char *name)
+ 	return (stat(name, &st) != 0 || st.st_size == 0);
+ }
+ 
++int mnt_valid_tagname(const char *tagname)
++{
++	if (tagname && *tagname && (
++	    strcmp("UUID", tagname) == 0 ||
++	    strcmp("LABEL", tagname) == 0 ||
++	    strcmp("PARTUUID", tagname) == 0 ||
++	    strcmp("PARTLABEL", tagname) == 0))
++		return 1;
++
++	return 0;
++}
++
+ int mnt_parse_offset(const char *str, size_t len, uintmax_t *res)
+ {
+ 	char *p;
+-- 
+2.7.4
+
diff --git a/SOURCES/0062-mount-umount-swapon-fsck-lsblk-findmnt-ignore-malfor.patch b/SOURCES/0062-mount-umount-swapon-fsck-lsblk-findmnt-ignore-malfor.patch
new file mode 100644
index 0000000..5bfb445
--- /dev/null
+++ b/SOURCES/0062-mount-umount-swapon-fsck-lsblk-findmnt-ignore-malfor.patch
@@ -0,0 +1,172 @@
+From 28663e752e125da99f8636ea0227d168f1e0e6aa Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Thu, 15 Oct 2015 11:53:44 +0200
+Subject: [PATCH 62/84] mount, umount, swapon, fsck, lsblk, findmnt: ignore
+ malformed lines
+
+The libmount provides way how to deal with parsing errors in fstab --
+on error callback function is executed and according to the return
+libmount manipulate with the malformed line, possible are three
+states:
+
+  1/ fatal error; all file ignored              (callback rc < 0)
+  2/ recoverable error; malformed line ignored  (callback rc > 0)
+  3/ ignore the error                           (callback rc == 0)
+
+The 2/ is the default if no callback specified.
+
+Unfortunately our utils uses 3/. The correct way is to use 2/.
+
+Upstream: http://github.com/karelzak/util-linux/commit/1cd9d0d7463850ef6b16a78b8a55e56dbf9a8db1
+Upstream: http://github.com/karelzak/util-linux/commit/1bb02a2da9f1bf7d80b352d540b29371099ab570
+Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1271850
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ disk-utils/fsck.c         |  2 +-
+ libmount/src/tab_parse.c  |  2 +-
+ misc-utils/findmnt.c      |  2 +-
+ misc-utils/lsblk.c        | 11 +++++++++++
+ sys-utils/mount.c         |  2 +-
+ sys-utils/swapon-common.c | 11 +++++++++++
+ sys-utils/umount.c        |  2 +-
+ 7 files changed, 27 insertions(+), 5 deletions(-)
+
+diff --git a/disk-utils/fsck.c b/disk-utils/fsck.c
+index 6e3a2c0..3ef8e5b 100644
+--- a/disk-utils/fsck.c
++++ b/disk-utils/fsck.c
+@@ -421,7 +421,7 @@ static int parser_errcb(struct libmnt_table *tb __attribute__ ((__unused__)),
+ 			const char *filename, int line)
+ {
+ 	warnx(_("%s: parse error at line %d -- ignore"), filename, line);
+-	return 0;
++	return 1;
+ }
+ 
+ /*
+diff --git a/libmount/src/tab_parse.c b/libmount/src/tab_parse.c
+index e930fd8..987e671 100644
+--- a/libmount/src/tab_parse.c
++++ b/libmount/src/tab_parse.c
+@@ -540,7 +540,7 @@ int mnt_table_parse_stream(struct libmnt_table *tb, FILE *f, const char *filenam
+ 		}
+ 		if (rc) {
+ 			mnt_free_fs(fs);
+-			if (rc == 1)
++			if (rc > 0)
+ 				continue;	/* recoverable error */
+ 			if (feof(f))
+ 				break;
+diff --git a/misc-utils/findmnt.c b/misc-utils/findmnt.c
+index 615ba08..f16da91 100644
+--- a/misc-utils/findmnt.c
++++ b/misc-utils/findmnt.c
+@@ -752,7 +752,7 @@ static int parser_errcb(struct libmnt_table *tb __attribute__ ((__unused__)),
+ 			const char *filename, int line)
+ {
+ 	warnx(_("%s: parse error at line %d"), filename, line);
+-	return 0;
++	return 1;
+ }
+ 
+ static char **append_tabfile(char **files, int *nfiles, char *filename)
+diff --git a/misc-utils/lsblk.c b/misc-utils/lsblk.c
+index 9e12a90..cd28c1d 100644
+--- a/misc-utils/lsblk.c
++++ b/misc-utils/lsblk.c
+@@ -337,6 +337,15 @@ static char *get_device_path(struct blkdev_cxt *cxt)
+ 	return xstrdup(path);
+ }
+ 
++static int table_parser_errcb(struct libmnt_table *tb __attribute__((__unused__)),
++			const char *filename, int line)
++{
++	if (filename)
++		warnx(_("%s: parse error: ignore entry at line %d."),
++							filename, line);
++	return 1;
++}
++
+ static int is_active_swap(const char *filename)
+ {
+ 	if (!swaps) {
+@@ -346,6 +355,7 @@ static int is_active_swap(const char *filename)
+ 		if (!mntcache)
+ 			mntcache = mnt_new_cache();
+ 
++		mnt_table_set_parser_errcb(swaps, table_parser_errcb);
+ 		mnt_table_set_cache(swaps, mntcache);
+ 		mnt_table_parse_swaps(swaps, NULL);
+ 	}
+@@ -368,6 +378,7 @@ static char *get_device_mountpoint(struct blkdev_cxt *cxt)
+ 		if (!mntcache)
+ 			mntcache = mnt_new_cache();
+ 
++		mnt_table_set_parser_errcb(mtab, table_parser_errcb);
+ 		mnt_table_set_cache(mtab, mntcache);
+ 		mnt_table_parse_mtab(mtab, NULL);
+ 	}
+diff --git a/sys-utils/mount.c b/sys-utils/mount.c
+index 0998b01..f332070 100644
+--- a/sys-utils/mount.c
++++ b/sys-utils/mount.c
+@@ -101,7 +101,7 @@ static int table_parser_errcb(struct libmnt_table *tb __attribute__((__unused__)
+ 	if (filename)
+ 		warnx(_("%s: parse error: ignore entry at line %d."),
+ 							filename, line);
+-	return 0;
++	return 1;
+ }
+ 
+ /*
+diff --git a/sys-utils/swapon-common.c b/sys-utils/swapon-common.c
+index 5c95ef3..5f14ddb 100644
+--- a/sys-utils/swapon-common.c
++++ b/sys-utils/swapon-common.c
+@@ -11,12 +11,22 @@ static struct libmnt_table *swaps, *fstab;
+ 
+ struct libmnt_cache *mntcache;
+ 
++static int table_parser_errcb(struct libmnt_table *tb __attribute__((__unused__)),
++			const char *filename, int line)
++{
++	if (filename)
++		warnx(_("%s: parse error: ignore entry at line %d."),
++							filename, line);
++	return 1;
++}
++
+ struct libmnt_table *get_fstab(void)
+ {
+ 	if (!fstab) {
+ 		fstab = mnt_new_table();
+ 		if (!fstab)
+ 			return NULL;
++		mnt_table_set_parser_errcb(fstab, table_parser_errcb);
+ 		mnt_table_set_cache(fstab, mntcache);
+ 		if (mnt_table_parse_fstab(fstab, NULL) != 0)
+ 			return NULL;
+@@ -32,6 +42,7 @@ struct libmnt_table *get_swaps(void)
+ 		if (!swaps)
+ 			return NULL;
+ 		mnt_table_set_cache(swaps, mntcache);
++		mnt_table_set_parser_errcb(swaps, table_parser_errcb);
+ 		if (mnt_table_parse_swaps(swaps, NULL) != 0)
+ 			return NULL;
+ 	}
+diff --git a/sys-utils/umount.c b/sys-utils/umount.c
+index 1bd275f..9c47744 100644
+--- a/sys-utils/umount.c
++++ b/sys-utils/umount.c
+@@ -45,7 +45,7 @@ static int table_parser_errcb(struct libmnt_table *tb __attribute__((__unused__)
+ 	if (filename)
+ 		warnx(_("%s: parse error: ignore entry at line %d."),
+ 							filename, line);
+-	return 0;
++	return 1;
+ }
+ 
+ 
+-- 
+2.7.4
+
diff --git a/SOURCES/0063-login-mount-fix-__SC_GETPW_R_SIZE_MAX-usage.patch b/SOURCES/0063-login-mount-fix-__SC_GETPW_R_SIZE_MAX-usage.patch
new file mode 100644
index 0000000..73f80e0
--- /dev/null
+++ b/SOURCES/0063-login-mount-fix-__SC_GETPW_R_SIZE_MAX-usage.patch
@@ -0,0 +1,146 @@
+From 3d1333293ef48117060cd4e285e9c49a6d061e83 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 15 Dec 2015 12:25:56 +0100
+Subject: [PATCH 63/84] login, mount: fix __SC_GETPW_R_SIZE_MAX usage
+
+sysconf(_SC_GETPW_R_SIZE_MAX) returns initial suggested size for pwd
+buffer (see getpwnam_r man page or POSIX). This is not large enough in
+some cases.
+
+Yes, this sysconf option is misnamed (should be _SC_GETPW_R_SIZE_MIN).
+
+Upstream: http://github.com/karelzak/util-linux/commit/f7ac9e71b18fa7314151f2ab65ee0bdd2ea89c07
+Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1290689
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ include/c.h          |  7 +++++++
+ libmount/src/utils.c | 25 ++++++-------------------
+ login-utils/login.c  | 12 ++----------
+ 3 files changed, 15 insertions(+), 29 deletions(-)
+
+diff --git a/include/c.h b/include/c.h
+index a50e8a5..7b59ce8 100644
+--- a/include/c.h
++++ b/include/c.h
+@@ -300,4 +300,11 @@ static inline int usleep(useconds_t usec)
+ # define SEEK_HOLE	4
+ #endif
+ 
++/*
++ * Note that sysconf(_SC_GETPW_R_SIZE_MAX) returns *initial* suggested size for
++ * pwd buffer and in some cases it is not large enough. See POSIX and
++ * getpwnam_r man page for more details.
++ */
++#define UL_GETPW_BUFSIZ	(16 * 1024)
++
+ #endif /* UTIL_LINUX_C_H */
+diff --git a/libmount/src/utils.c b/libmount/src/utils.c
+index 9305bb8..7c6f5b1 100644
+--- a/libmount/src/utils.c
++++ b/libmount/src/utils.c
+@@ -538,16 +538,6 @@ int mnt_get_filesystems(char ***filesystems, const char *pattern)
+ 	return rc;
+ }
+ 
+-static size_t get_pw_record_size(void)
+-{
+-#ifdef _SC_GETPW_R_SIZE_MAX
+-	long sz = sysconf(_SC_GETPW_R_SIZE_MAX);
+-	if (sz > 0)
+-		return sz;
+-#endif
+-	return 16384;
+-}
+-
+ /*
+  * Returns allocated string with username or NULL.
+  */
+@@ -555,14 +545,13 @@ char *mnt_get_username(const uid_t uid)
+ {
+         struct passwd pwd;
+ 	struct passwd *res;
+-	size_t sz = get_pw_record_size();
+ 	char *buf, *username = NULL;
+ 
+-	buf = malloc(sz);
++	buf = malloc(UL_GETPW_BUFSIZ);
+ 	if (!buf)
+ 		return NULL;
+ 
+-	if (!getpwuid_r(uid, &pwd, buf, sz, &res) && res)
++	if (!getpwuid_r(uid, &pwd, buf, UL_GETPW_BUFSIZ, &res) && res)
+ 		username = strdup(pwd.pw_name);
+ 
+ 	free(buf);
+@@ -574,17 +563,16 @@ int mnt_get_uid(const char *username, uid_t *uid)
+ 	int rc = -1;
+         struct passwd pwd;
+ 	struct passwd *pw;
+-	size_t sz = get_pw_record_size();
+ 	char *buf;
+ 
+ 	if (!username || !uid)
+ 		return -EINVAL;
+ 
+-	buf = malloc(sz);
++	buf = malloc(UL_GETPW_BUFSIZ);
+ 	if (!buf)
+ 		return -ENOMEM;
+ 
+-	if (!getpwnam_r(username, &pwd, buf, sz, &pw) && pw) {
++	if (!getpwnam_r(username, &pwd, buf, UL_GETPW_BUFSIZ, &pw) && pw) {
+ 		*uid= pw->pw_uid;
+ 		rc = 0;
+ 	} else {
+@@ -602,17 +590,16 @@ int mnt_get_gid(const char *groupname, gid_t *gid)
+ 	int rc = -1;
+         struct group grp;
+ 	struct group *gr;
+-	size_t sz = get_pw_record_size();
+ 	char *buf;
+ 
+ 	if (!groupname || !gid)
+ 		return -EINVAL;
+ 
+-	buf = malloc(sz);
++	buf = malloc(UL_GETPW_BUFSIZ);
+ 	if (!buf)
+ 		return -ENOMEM;
+ 
+-	if (!getgrnam_r(groupname, &grp, buf, sz, &gr) && gr) {
++	if (!getgrnam_r(groupname, &grp, buf, UL_GETPW_BUFSIZ, &gr) && gr) {
+ 		*gid= gr->gr_gid;
+ 		rc = 0;
+ 	} else {
+diff --git a/login-utils/login.c b/login-utils/login.c
+index a59dd3a..e0e960f 100644
+--- a/login-utils/login.c
++++ b/login-utils/login.c
+@@ -671,22 +671,14 @@ static struct passwd *get_passwd_entry(const char *username,
+ 					 struct passwd *pwd)
+ {
+ 	struct passwd *res = NULL;
+-	size_t sz = 16384;
+ 	int x;
+ 
+ 	if (!pwdbuf || !username)
+ 		return NULL;
+ 
+-#ifdef _SC_GETPW_R_SIZE_MAX
+-	{
+-		long xsz = sysconf(_SC_GETPW_R_SIZE_MAX);
+-		if (xsz > 0)
+-			sz = (size_t) xsz;
+-	}
+-#endif
+-	*pwdbuf = xrealloc(*pwdbuf, sz);
++	*pwdbuf = xrealloc(*pwdbuf, UL_GETPW_BUFSIZ);
+ 
+-	x = getpwnam_r(username, pwd, *pwdbuf, sz, &res);
++	x = getpwnam_r(username, pwd, *pwdbuf, UL_GETPW_BUFSIZ, &res);
+ 	if (!res) {
+ 		errno = x;
+ 		return NULL;
+-- 
+2.7.4
+
diff --git a/SOURCES/0064-bash-completion-use-n-as-IFS-when-ask-for-filenames.patch b/SOURCES/0064-bash-completion-use-n-as-IFS-when-ask-for-filenames.patch
new file mode 100644
index 0000000..6e63208
--- /dev/null
+++ b/SOURCES/0064-bash-completion-use-n-as-IFS-when-ask-for-filenames.patch
@@ -0,0 +1,623 @@
+From 28907c1a50132c9a308b8d2c22bf4905041c446f Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Mon, 30 Sep 2013 15:49:00 +0200
+Subject: [PATCH 64/84] bash-completion: use '\n' as IFS when ask for filenames
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The bash completion for more(1) treats the space-separated pieces of
+filenames as different files.
+
+	$ touch foo\ bar
+	$ more foo<TAB>
+	bar foo
+
+Upstream: http://github.com/karelzak/util-linux/commit/ce3e6b15e2c4478b2df9a7016c168b16325abfb0
+Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1296366
+Reported-by: Ángel González <ingenit@zoho.com>
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ bash-completion/blkid        | 1 +
+ bash-completion/colcrt       | 1 +
+ bash-completion/column       | 1 +
+ bash-completion/cytune       | 1 +
+ bash-completion/dmesg        | 1 +
+ bash-completion/fallocate    | 1 +
+ bash-completion/findmnt      | 1 +
+ bash-completion/flock        | 1 +
+ bash-completion/fsck.cramfs  | 1 +
+ bash-completion/hexdump      | 1 +
+ bash-completion/hwclock      | 1 +
+ bash-completion/ionice       | 1 +
+ bash-completion/last         | 1 +
+ bash-completion/ldattach     | 1 +
+ bash-completion/logger       | 1 +
+ bash-completion/look         | 1 +
+ bash-completion/losetup      | 1 +
+ bash-completion/lscpu        | 1 +
+ bash-completion/lslocks      | 1 +
+ bash-completion/mcookie      | 1 +
+ bash-completion/mkfs.cramfs  | 1 +
+ bash-completion/mkswap       | 1 +
+ bash-completion/more         | 2 ++
+ bash-completion/mountpoint   | 1 +
+ bash-completion/namei        | 1 +
+ bash-completion/nsenter      | 1 +
+ bash-completion/pg           | 1 +
+ bash-completion/pivot_root   | 1 +
+ bash-completion/readprofile  | 1 +
+ bash-completion/rename       | 1 +
+ bash-completion/rev          | 1 +
+ bash-completion/script       | 1 +
+ bash-completion/scriptreplay | 1 +
+ bash-completion/setterm      | 1 +
+ bash-completion/sfdisk       | 1 +
+ bash-completion/su           | 1 +
+ bash-completion/swaplabel    | 1 +
+ bash-completion/tailf        | 1 +
+ bash-completion/tunelp       | 1 +
+ bash-completion/ul           | 1 +
+ bash-completion/utmpdump     | 1 +
+ bash-completion/uuidd        | 3 +++
+ bash-completion/wall         | 1 +
+ bash-completion/wdctl        | 1 +
+ bash-completion/whereis      | 1 +
+ 45 files changed, 48 insertions(+)
+
+diff --git a/bash-completion/blkid b/bash-completion/blkid
+index b439328..9f97dd9 100644
+--- a/bash-completion/blkid
++++ b/bash-completion/blkid
+@@ -6,6 +6,7 @@ _blkid_module()
+ 	prev="${COMP_WORDS[COMP_CWORD-1]}"
+ 	case $prev in
+ 		'-c')
++			local IFS=$'\n'
+ 			compopt -o filenames
+ 			COMPREPLY=( $(compgen -f -- $cur) )
+ 			return 0
+diff --git a/bash-completion/colcrt b/bash-completion/colcrt
+index f9e4c33..c66d7e6 100644
+--- a/bash-completion/colcrt
++++ b/bash-completion/colcrt
+@@ -19,6 +19,7 @@ _colcrt_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- $cur) )
+ 	return 0
+diff --git a/bash-completion/column b/bash-completion/column
+index f5cb86b..3af8e73 100644
+--- a/bash-completion/column
++++ b/bash-completion/column
+@@ -30,6 +30,7 @@ _column_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- $cur) )
+ 	return 0
+diff --git a/bash-completion/cytune b/bash-completion/cytune
+index 4f42838..f685c88 100644
+--- a/bash-completion/cytune
++++ b/bash-completion/cytune
+@@ -33,6 +33,7 @@ _cytune_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- ${cur:-"/dev/tty"}) )
+ 	return 0
+diff --git a/bash-completion/dmesg b/bash-completion/dmesg
+index 60ecc1a..eab41ba 100644
+--- a/bash-completion/dmesg
++++ b/bash-completion/dmesg
+@@ -6,6 +6,7 @@ _dmesg_module()
+ 	prev="${COMP_WORDS[COMP_CWORD-1]}"
+ 	case $prev in
+ 		'-F'|'--file')
++			local IFS=$'\n'
+ 			compopt -o filenames
+ 			COMPREPLY=( $(compgen -f -- $cur) )
+ 			return 0
+diff --git a/bash-completion/fallocate b/bash-completion/fallocate
+index 5007b60..2c6e4cb 100644
+--- a/bash-completion/fallocate
++++ b/bash-completion/fallocate
+@@ -20,6 +20,7 @@ _fallocate_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- $cur) )
+ 	return 0
+diff --git a/bash-completion/findmnt b/bash-completion/findmnt
+index 9386d8f..3ed331a 100644
+--- a/bash-completion/findmnt
++++ b/bash-completion/findmnt
+@@ -18,6 +18,7 @@ _findmnt_module()
+ 			return 0
+ 			;;
+ 		'-F'|'--tab-file')
++			local IFS=$'\n'
+ 			compopt -o filenames
+ 			COMPREPLY=( $(compgen -f -- $cur) )
+ 			return 0
+diff --git a/bash-completion/flock b/bash-completion/flock
+index 8cd60d3..8e7f8b8 100644
+--- a/bash-completion/flock
++++ b/bash-completion/flock
+@@ -38,6 +38,7 @@ _flock_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- ${cur:-"/"}) )
+ 	return 0
+diff --git a/bash-completion/fsck.cramfs b/bash-completion/fsck.cramfs
+index 84f6f31..acf6564 100644
+--- a/bash-completion/fsck.cramfs
++++ b/bash-completion/fsck.cramfs
+@@ -6,6 +6,7 @@ _fsck.cramfs_module()
+ 	prev="${COMP_WORDS[COMP_CWORD-1]}"
+ 	case $prev in
+ 		'-x'|'--destination')
++			local IFS=$'\n'
+ 			compopt -o filenames
+ 			COMPREPLY=( $(compgen -o dirnames -- ${cur:-"/"}) )
+ 			return 0
+diff --git a/bash-completion/hexdump b/bash-completion/hexdump
+index 0c91187..c17bcae 100644
+--- a/bash-completion/hexdump
++++ b/bash-completion/hexdump
+@@ -28,6 +28,7 @@ _hexdump_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- $cur) )
+ 	return 0
+diff --git a/bash-completion/hwclock b/bash-completion/hwclock
+index 0c4ebaf..de1ac20 100644
+--- a/bash-completion/hwclock
++++ b/bash-completion/hwclock
+@@ -6,6 +6,7 @@ _hwclock_module()
+ 	prev="${COMP_WORDS[COMP_CWORD-1]}"
+ 	case $prev in
+ 		'-f'|'--rtc'|'--adjfile')
++			local IFS=$'\n'
+ 			compopt -o filenames
+ 			COMPREPLY=( $(compgen -f -- $cur) )
+ 			return 0
+diff --git a/bash-completion/ionice b/bash-completion/ionice
+index 3a01c51..1b1c5fe 100644
+--- a/bash-completion/ionice
++++ b/bash-completion/ionice
+@@ -30,6 +30,7 @@ _ionice_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- $cur) )
+ 	return 0
+diff --git a/bash-completion/last b/bash-completion/last
+index 493051e..c93be3d 100644
+--- a/bash-completion/last
++++ b/bash-completion/last
+@@ -6,6 +6,7 @@ _last_module()
+ 	prev="${COMP_WORDS[COMP_CWORD-1]}"
+ 	case $prev in
+ 		'-f')
++			local IFS=$'\n'
+ 			compopt -o filenames
+ 			COMPREPLY=( $(compgen -f -- $cur) )
+ 			return 0
+diff --git a/bash-completion/ldattach b/bash-completion/ldattach
+index 830142d..0b9d260 100644
+--- a/bash-completion/ldattach
++++ b/bash-completion/ldattach
+@@ -42,6 +42,7 @@ _ldattach_module()
+ 			return 0
+ 			;;
+ 		/*)
++			local IFS=$'\n'
+ 			compopt -o filenames
+ 			COMPREPLY=( $(compgen -f -- $cur) )
+ 			return 0
+diff --git a/bash-completion/logger b/bash-completion/logger
+index f46be8a..963abc7 100644
+--- a/bash-completion/logger
++++ b/bash-completion/logger
+@@ -6,6 +6,7 @@ _logger_module()
+ 	prev="${COMP_WORDS[COMP_CWORD-1]}"
+ 	case $prev in
+ 		'-f'|'--file')
++			local IFS=$'\n'
+ 			compopt -o filenames
+ 			COMPREPLY=( $(compgen -f -- $cur) )
+ 			return 0
+diff --git a/bash-completion/look b/bash-completion/look
+index e8676ba..303a756 100644
+--- a/bash-completion/look
++++ b/bash-completion/look
+@@ -20,6 +20,7 @@ _look_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- $cur) )
+ 	return 0
+diff --git a/bash-completion/losetup b/bash-completion/losetup
+index 75240b8..874c549 100644
+--- a/bash-completion/losetup
++++ b/bash-completion/losetup
+@@ -60,6 +60,7 @@ _losetup_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- $cur) )
+ 	return 0
+diff --git a/bash-completion/lscpu b/bash-completion/lscpu
+index bce07c4..244b418 100644
+--- a/bash-completion/lscpu
++++ b/bash-completion/lscpu
+@@ -41,6 +41,7 @@ _lscpu_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- $cur) )
+ 	return 0
+diff --git a/bash-completion/lslocks b/bash-completion/lslocks
+index 337d07e..c9cff2c 100644
+--- a/bash-completion/lslocks
++++ b/bash-completion/lslocks
+@@ -38,6 +38,7 @@ _lslocks_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- $cur) )
+ 	return 0
+diff --git a/bash-completion/mcookie b/bash-completion/mcookie
+index eb3f54b..4345b6e 100644
+--- a/bash-completion/mcookie
++++ b/bash-completion/mcookie
+@@ -6,6 +6,7 @@ _mcookie_module()
+ 	prev="${COMP_WORDS[COMP_CWORD-1]}"
+ 	case $prev in
+ 		'-f'|'--file')
++			local IFS=$'\n'
+ 			compopt -o filenames
+ 			COMPREPLY=( $(compgen -f -- $cur) )
+ 			return 0
+diff --git a/bash-completion/mkfs.cramfs b/bash-completion/mkfs.cramfs
+index 38ab3b6..af74e12 100644
+--- a/bash-completion/mkfs.cramfs
++++ b/bash-completion/mkfs.cramfs
+@@ -36,6 +36,7 @@ _mkfs.cramfs_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- $cur) )
+ 	return 0
+diff --git a/bash-completion/mkswap b/bash-completion/mkswap
+index c411b30..b72efaf 100644
+--- a/bash-completion/mkswap
++++ b/bash-completion/mkswap
+@@ -28,6 +28,7 @@ _mkswap_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- $cur) )
+ 	return 0
+diff --git a/bash-completion/more b/bash-completion/more
+index 945c7b3..809cea2 100644
+--- a/bash-completion/more
++++ b/bash-completion/more
+@@ -21,6 +21,8 @@ _more_module()
+ 			return 0
+ 			;;
+ 	esac
++
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- $cur) )
+ 	return 0
+diff --git a/bash-completion/mountpoint b/bash-completion/mountpoint
+index 8fe27b8..f74efc9 100644
+--- a/bash-completion/mountpoint
++++ b/bash-completion/mountpoint
+@@ -20,6 +20,7 @@ _mountpoint_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- ${cur:-"/"}) )
+ 	return 0
+diff --git a/bash-completion/namei b/bash-completion/namei
+index 63fb37a..6402735 100644
+--- a/bash-completion/namei
++++ b/bash-completion/namei
+@@ -16,6 +16,7 @@ _namei_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- $cur) )
+ 	return 0
+diff --git a/bash-completion/nsenter b/bash-completion/nsenter
+index 2970b8d..268f378 100644
+--- a/bash-completion/nsenter
++++ b/bash-completion/nsenter
+@@ -40,6 +40,7 @@ _nsenter_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- $cur) )
+ 	return 0
+diff --git a/bash-completion/pg b/bash-completion/pg
+index 9b1bad9..8fce130 100644
+--- a/bash-completion/pg
++++ b/bash-completion/pg
+@@ -25,6 +25,7 @@ _pg_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- $cur) )
+ 	return 0
+diff --git a/bash-completion/pivot_root b/bash-completion/pivot_root
+index 961c883..95df4b4 100644
+--- a/bash-completion/pivot_root
++++ b/bash-completion/pivot_root
+@@ -11,6 +11,7 @@ _pivot_root_module()
+ 	esac
+ 	case $COMP_CWORD in
+ 		1|2)
++			local IFS=$'\n'
+ 			compopt -o filenames
+ 			COMPREPLY=( $(compgen -o dirnames -- ${cur:-"/"}) )
+ 			;;
+diff --git a/bash-completion/readprofile b/bash-completion/readprofile
+index a5f45f5..bd265a6 100644
+--- a/bash-completion/readprofile
++++ b/bash-completion/readprofile
+@@ -6,6 +6,7 @@ _readprofile_module()
+ 	prev="${COMP_WORDS[COMP_CWORD-1]}"
+ 	case $prev in
+ 		'-m'|'--mapfile'|'-p'|'--profile')
++			local IFS=$'\n'
+ 			compopt -o filenames
+ 			COMPREPLY=( $(compgen -f -- $cur) )
+ 			return 0
+diff --git a/bash-completion/rename b/bash-completion/rename
+index 3842c4d..81365a5 100644
+--- a/bash-completion/rename
++++ b/bash-completion/rename
+@@ -24,6 +24,7 @@ _rename_module()
+ 			COMPREPLY=( $(compgen -W "replacement" -- $cur) )
+ 			;;
+ 		*)
++			local IFS=$'\n'
+ 			compopt -o filenames
+ 			COMPREPLY=( $(compgen -f -- $cur) )
+ 			;;
+diff --git a/bash-completion/rev b/bash-completion/rev
+index 619c5c4..e5397d5 100644
+--- a/bash-completion/rev
++++ b/bash-completion/rev
+@@ -16,6 +16,7 @@ _rev_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- $cur) )
+ 	return 0
+diff --git a/bash-completion/script b/bash-completion/script
+index 329fc48..d7efd7e 100644
+--- a/bash-completion/script
++++ b/bash-completion/script
+@@ -32,6 +32,7 @@ _script_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- $cur) )
+ 	return 0
+diff --git a/bash-completion/scriptreplay b/bash-completion/scriptreplay
+index 2ad7b11..a4aa8a0 100644
+--- a/bash-completion/scriptreplay
++++ b/bash-completion/scriptreplay
+@@ -24,6 +24,7 @@ _scriptreplay_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- $cur) )
+ 	return 0
+diff --git a/bash-completion/setterm b/bash-completion/setterm
+index 7fa0a4e..a7ef6eb 100644
+--- a/bash-completion/setterm
++++ b/bash-completion/setterm
+@@ -45,6 +45,7 @@ _setterm_module()
+ 			return 0
+ 			;;
+ 		'-file')
++			local IFS=$'\n'
+ 			compopt -o filenames
+ 			COMPREPLY=( $(compgen -f -- $cur) )
+ 			return 0
+diff --git a/bash-completion/sfdisk b/bash-completion/sfdisk
+index 0226b04..609104c 100644
+--- a/bash-completion/sfdisk
++++ b/bash-completion/sfdisk
+@@ -14,6 +14,7 @@ _sfdisk_module()
+ 			return 0
+ 			;;
+ 		'-O'|'-I')
++			local IFS=$'\n'
+ 			compopt -o filenames
+ 			COMPREPLY=( $(compgen -f -- $cur) )
+ 			return 0
+diff --git a/bash-completion/su b/bash-completion/su
+index e739b56..dad1b5f 100644
+--- a/bash-completion/su
++++ b/bash-completion/su
+@@ -38,6 +38,7 @@ _su_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- $cur) )
+ 	return 0
+diff --git a/bash-completion/swaplabel b/bash-completion/swaplabel
+index 093169e..08aa9cd 100644
+--- a/bash-completion/swaplabel
++++ b/bash-completion/swaplabel
+@@ -24,6 +24,7 @@ _swaplabel_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- $cur) )
+ 	return 0
+diff --git a/bash-completion/tailf b/bash-completion/tailf
+index e3dd295..0d4c869 100644
+--- a/bash-completion/tailf
++++ b/bash-completion/tailf
+@@ -20,6 +20,7 @@ _tailf_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- $cur) )
+ 	return 0
+diff --git a/bash-completion/tunelp b/bash-completion/tunelp
+index 614b235..bd2cce2 100644
+--- a/bash-completion/tunelp
++++ b/bash-completion/tunelp
+@@ -44,6 +44,7 @@ _tunelp_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- ${cur:-"/dev/lp"}) )
+ 	return 0
+diff --git a/bash-completion/ul b/bash-completion/ul
+index c00e510..449cbe0 100644
+--- a/bash-completion/ul
++++ b/bash-completion/ul
+@@ -25,6 +25,7 @@ _ul_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- $cur) )
+ 	return 0
+diff --git a/bash-completion/utmpdump b/bash-completion/utmpdump
+index 3b868ce..7e4fd5a 100644
+--- a/bash-completion/utmpdump
++++ b/bash-completion/utmpdump
+@@ -16,6 +16,7 @@ _utmpdump_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- $cur) )
+ 	return 0
+diff --git a/bash-completion/uuidd b/bash-completion/uuidd
+index c45b067..c8f6697 100644
+--- a/bash-completion/uuidd
++++ b/bash-completion/uuidd
+@@ -6,16 +6,19 @@ _uuidd_module()
+ 	prev="${COMP_WORDS[COMP_CWORD-1]}"
+ 	case $prev in
+ 		'-p'|'--pid'|'-s'|'--socket')
++			local IFS=$'\n'
+ 			compopt -o filenames
+ 			COMPREPLY=( $(compgen -f -- $cur) )
+ 			return 0
+ 			;;
+ 		'-T'|'--timeout')
++			local IFS=$'\n'
+ 			compopt -o filenames
+ 			COMPREPLY=( $(compgen -W "timeout" -- $cur) )
+ 			return 0
+ 			;;
+ 		'-n'|'--uuids')
++			local IFS=$'\n'
+ 			compopt -o filenames
+ 			COMPREPLY=( $(compgen -W "number" -- $cur) )
+ 			return 0
+diff --git a/bash-completion/wall b/bash-completion/wall
+index 55d9658..e3145ff 100644
+--- a/bash-completion/wall
++++ b/bash-completion/wall
+@@ -20,6 +20,7 @@ _wall_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- $cur) )
+ 	return 0
+diff --git a/bash-completion/wdctl b/bash-completion/wdctl
+index 33b4e1f..4f16e76 100644
+--- a/bash-completion/wdctl
++++ b/bash-completion/wdctl
+@@ -56,6 +56,7 @@ _wdctl_module()
+ 			return 0
+ 			;;
+ 	esac
++	local IFS=$'\n'
+ 	compopt -o filenames
+ 	COMPREPLY=( $(compgen -f -- ${cur:-"/dev/"}) )
+ 	return 0
+diff --git a/bash-completion/whereis b/bash-completion/whereis
+index 2273a07..0dcbac3 100644
+--- a/bash-completion/whereis
++++ b/bash-completion/whereis
+@@ -6,6 +6,7 @@ _whereis_module()
+ 	prev="${COMP_WORDS[COMP_CWORD-1]}"
+ 	case $prev in
+ 		'-B'|'-M'|'-S')
++			local IFS=$'\n'
+ 			compopt -o filenames
+ 			COMPREPLY=( $(compgen -o dirnames -- ${cur:-"/"}) )
+ 			return 0
+-- 
+2.7.4
+
diff --git a/SOURCES/0065-hwclock-change-audit-message.patch b/SOURCES/0065-hwclock-change-audit-message.patch
new file mode 100644
index 0000000..a50d8e2
--- /dev/null
+++ b/SOURCES/0065-hwclock-change-audit-message.patch
@@ -0,0 +1,31 @@
+From 19b9d9197374c5811e32777ca70a32eef37a1fb0 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Thu, 7 Jan 2016 13:23:24 +0100
+Subject: [PATCH 65/84] hwclock: change audit message
+
+The preferred layout is name=value for audit messages.
+
+Upstream: http://github.com/karelzak/util-linux/commit/fbed7e09f826e7804e99522cc1dd3cf54c9cdb67
+Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1296521
+References: https://bugzilla.redhat.com/show_bug.cgi?id=1296278
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ sys-utils/hwclock.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/sys-utils/hwclock.c b/sys-utils/hwclock.c
+index c7789c8..ac9294b 100644
+--- a/sys-utils/hwclock.c
++++ b/sys-utils/hwclock.c
+@@ -1939,7 +1939,7 @@ void __attribute__((__noreturn__)) hwaudit_exit(int status)
+ {
+ 	if (hwaudit_on) {
+ 		audit_log_user_message(hwaudit_fd, AUDIT_USYS_CONFIG,
+-				       "changing system time", NULL, NULL, NULL,
++				       "op=change-system-time", NULL, NULL, NULL,
+ 				       status ? 0 : 1);
+ 		close(hwaudit_fd);
+ 	}
+-- 
+2.7.4
+
diff --git a/SOURCES/0066-su-clean-up-groups-initialization.patch b/SOURCES/0066-su-clean-up-groups-initialization.patch
new file mode 100644
index 0000000..ebd0225
--- /dev/null
+++ b/SOURCES/0066-su-clean-up-groups-initialization.patch
@@ -0,0 +1,186 @@
+From b2a41801904c4b281a717dde7f5e146cbd4500b3 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Mon, 15 Feb 2016 13:55:37 +0100
+Subject: [PATCH 66/84] su: clean up groups initialization
+
+This patch does not change any su/runuser behaviour, code changes:
+
+* don't use huge groups[NGROUPS_MAX]; the array has 256k, but we need
+  it only occasionally when -G/-g specified.
+
+* the current code uses groups[0] for -g and the rest for -G, this patch adds
+  'gid' to remember -g argument to avoid memmove()
+
+* add function add_supp_group() to simplify su_main()
+
+* add note about -G and -g relation to the man pages (undocumented now)
+
+Upstream: http://github.com/karelzak/util-linux/commit/c619d3d167115990e9228b27851e0cc2faa8f936
+Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1304426
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ login-utils/runuser.1   |  5 ++--
+ login-utils/su-common.c | 68 +++++++++++++++++++++++++++----------------------
+ login-utils/su.1        |  5 ++--
+ 3 files changed, 44 insertions(+), 34 deletions(-)
+
+diff --git a/login-utils/runuser.1 b/login-utils/runuser.1
+index 7201ff0..d82dbb0 100644
+--- a/login-utils/runuser.1
++++ b/login-utils/runuser.1
+@@ -75,8 +75,9 @@ shell.
+ \fB\-g\fR, \fB\-\-group\fR=\fIgroup\fR\fR
+ specify the primary group, this option is allowed for root user only
+ .TP
+-\fB\-G\fR, \fB\-\-supp-group\fR=\fIgroup\fR\fR
+-specify a supplemental group, this option is allowed for root user only
++.BR \-G , " \-\-supp\-group" = \fIgroup
++Specify a supplemental group.  This option is available to the root user only.  The first specified
++supplementary group is also used as a primary group if the option \fB\-\-group\fR is unspecified.
+ .TP
+ \fB\-\fR, \fB\-l\fR, \fB\-\-login\fR
+ Starts the shell as login shell with an environment similar to a real
+diff --git a/login-utils/su-common.c b/login-utils/su-common.c
+index dd87804..d53d690 100644
+--- a/login-utils/su-common.c
++++ b/login-utils/su-common.c
+@@ -535,7 +535,7 @@ modify_environment (const struct passwd *pw, const char *shell)
+ /* Become the user and group(s) specified by PW.  */
+ 
+ static void
+-init_groups (const struct passwd *pw, gid_t *groups, int num_groups)
++init_groups (const struct passwd *pw, gid_t *groups, size_t num_groups)
+ {
+   int retval;
+ 
+@@ -707,6 +707,28 @@ evaluate_uid(void)
+   return (uid_t) 0 == ruid && ruid == euid ? 0 : 1;
+ }
+ 
++static gid_t
++add_supp_group(const char *name, gid_t **groups, size_t *ngroups)
++{
++  struct group *gr;
++
++  if (*ngroups >= NGROUPS_MAX)
++    errx(EXIT_FAILURE,
++	P_("specifying more than %d supplemental group is not possible",
++	   "specifying more than %d supplemental groups is not possible",
++	     NGROUPS_MAX - 1), NGROUPS_MAX - 1);
++
++  gr = getgrnam(name);
++  if (!gr)
++    errx(EXIT_FAILURE, _("group %s does not exist"), name);
++
++  *groups = xrealloc(*groups, sizeof(gid_t) * (*ngroups + 1));
++  (*groups)[*ngroups] = gr->gr_gid;
++  (*ngroups)++;
++
++  return gr->gr_gid;
++}
++
+ int
+ su_main (int argc, char **argv, int mode)
+ {
+@@ -717,10 +739,12 @@ su_main (int argc, char **argv, int mode)
+   char *shell = NULL;
+   struct passwd *pw;
+   struct passwd pw_copy;
+-  struct group *gr;
+-  gid_t groups[NGROUPS_MAX];
+-  int num_supp_groups = 0;
+-  int use_gid = 0;
++
++  gid_t *groups = NULL;
++  size_t ngroups = 0;
++  bool use_supp = false;
++  bool use_gid = false;
++  gid_t gid = 0;
+ 
+   static const struct option longopts[] = {
+     {"command", required_argument, NULL, 'c'},
+@@ -765,23 +789,13 @@ su_main (int argc, char **argv, int mode)
+ 	  break;
+ 
+ 	case 'g':
+-	  gr = getgrnam(optarg);
+-	  if (!gr)
+-	    errx(EXIT_FAILURE, _("group %s does not exist"), optarg);
+-	  use_gid = 1;
+-	  groups[0] = gr->gr_gid;
++	  use_gid = true;
++	  gid = add_supp_group(optarg, &groups, &ngroups);
+ 	  break;
+ 
+ 	case 'G':
+-	  num_supp_groups++;
+-	  if (num_supp_groups >= NGROUPS_MAX)
+-	     errx(EXIT_FAILURE,
+-		  _("can't specify more than %d supplemental groups"),
+-		  NGROUPS_MAX - 1);
+-	  gr = getgrnam(optarg);
+-	  if (!gr)
+-	    errx(EXIT_FAILURE, _("group %s does not exist"), optarg);
+-	  groups[num_supp_groups] = gr->gr_gid;
++	  use_supp = true;
++	  add_supp_group(optarg, &groups, &ngroups);
+ 	  break;
+ 
+ 	case 'l':
+@@ -852,7 +866,7 @@ su_main (int argc, char **argv, int mode)
+     break;
+   }
+ 
+-  if ((num_supp_groups || use_gid) && restricted)
++  if ((use_supp || use_gid) && restricted)
+     errx(EXIT_FAILURE, _("only root can specify alternative groups"));
+ 
+   logindefs_load_defaults = load_config;
+@@ -878,16 +892,10 @@ su_main (int argc, char **argv, int mode)
+ 			  : DEFAULT_SHELL);
+   endpwent ();
+ 
+-  if (num_supp_groups && !use_gid)
+-  {
+-    pw->pw_gid = groups[1];
+-    memmove (groups, groups + 1, sizeof(gid_t) * num_supp_groups);
+-  }
+-  else if (use_gid)
+-  {
++  if (use_supp && !use_gid)
+     pw->pw_gid = groups[0];
+-    num_supp_groups++;
+-  }
++  else if (use_gid)
++    pw->pw_gid = gid;
+ 
+   authenticate (pw);
+ 
+@@ -912,7 +920,7 @@ su_main (int argc, char **argv, int mode)
+     shell = xstrdup (shell ? shell : pw->pw_shell);
+   }
+ 
+-  init_groups (pw, groups, num_supp_groups);
++  init_groups (pw, groups, ngroups);
+ 
+   if (!simulate_login || command)
+     suppress_pam_info = 1;		/* don't print PAM info messages */
+diff --git a/login-utils/su.1 b/login-utils/su.1
+index eab1a6f..1f69868 100644
+--- a/login-utils/su.1
++++ b/login-utils/su.1
+@@ -62,8 +62,9 @@ shell.
+ \fB\-g\fR, \fB\-\-group\fR=\fIgroup\fR\fR
+ specify the primary group, this option is allowed for root user only
+ .TP
+-\fB\-G\fR, \fB\-\-supp-group\fR=\fIgroup\fR\fR
+-specify a supplemental group, this option is allowed for root user only
++.BR \-G , " \-\-supp\-group" = \fIgroup
++Specify a supplemental group.  This option is available to the root user only.  The first specified
++supplementary group is also used as a primary group if the option \fB\-\-group\fR is unspecified.
+ .TP
+ \fB\-\fR, \fB\-l\fR, \fB\-\-login\fR
+ Starts the shell as login shell with an environment similar to a real
+-- 
+2.7.4
+
diff --git a/SOURCES/0067-lscpu-Fix-model-and-model-name-on-Power-Systems.patch b/SOURCES/0067-lscpu-Fix-model-and-model-name-on-Power-Systems.patch
new file mode 100644
index 0000000..9bf633c
--- /dev/null
+++ b/SOURCES/0067-lscpu-Fix-model-and-model-name-on-Power-Systems.patch
@@ -0,0 +1,83 @@
+From 246ab88515fca389c02602521fc765d3e597fd7a Mon Sep 17 00:00:00 2001
+From: Vasant Hegde <hegdevasant@linux.vnet.ibm.com>
+Date: Mon, 14 Mar 2016 20:18:07 +0530
+Subject: [PATCH 67/84] lscpu: Fix model and model name on Power Systems
+
+On Power System, lspcu presently displays system model number instead of
+processor model name. 'model' tag in cpuinfo contains system model name,
+not processor model. Instead it uses 'cpu' tag for processor model name.
+Also it uses 'revision' tag for processor model.
+
+Fix lspcu so that it displays processor model number. Also display processor
+model name.
+
+cpuinfo output on Power System:
+  ...
+  ...
+
+  processor	: 127
+  cpu		: POWER8E (raw), altivec supported
+  clock		: 4322.000000MHz
+  revision	: 2.1 (pvr 004b 0201)
+
+  timebase	: 512000000
+  platform	: PowerNV
+  model		: 8286-42A
+  machine	: PowerNV 8286-42A
+  firmware	: OPAL
+
+Output without this patch:
+  Architecture:          ppc64le
+  Byte Order:            Little Endian
+  CPU(s):                128
+  On-line CPU(s) list:   0-127
+  Thread(s) per core:    8
+  Core(s) per socket:    4
+  Socket(s):             4
+  NUMA node(s):          4
+  Model:                 8286-42A
+  ...
+  ...
+
+Output with this patch:
+  Architecture:          ppc64le
+  Byte Order:            Little Endian
+  CPU(s):                128
+  On-line CPU(s) list:   0-127
+  Thread(s) per core:    8
+  Core(s) per socket:    4
+  Socket(s):             4
+  NUMA node(s):          4
+  Model:                 2.1 (pvr 004b 0201)
+  Model name:            POWER8E (raw), altivec supported
+  ...
+  ...
+
+Upstream: http://github.com/karelzak/util-linux/commit/3ac03fe4d20558b55635a048d7f2fb0f5e85ee2a
+Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1326615
+Signed-off-by: Vasant Hegde <hegdevasant@linux.vnet.ibm.com>
+---
+ sys-utils/lscpu.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/sys-utils/lscpu.c b/sys-utils/lscpu.c
+index 4af8176..68b15af 100644
+--- a/sys-utils/lscpu.c
++++ b/sys-utils/lscpu.c
+@@ -355,8 +355,13 @@ read_basicinfo(struct lscpu_desc *desc, struct lscpu_modifier *mod)
+ 		else if (lookup(buf, "vendor_id", &desc->vendor)) ;
+ 		else if (lookup(buf, "family", &desc->family)) ;
+ 		else if (lookup(buf, "cpu family", &desc->family)) ;
++#if defined(__powerpc__) || defined(__powerpc64__)
++		else if (lookup(buf, "revision", &desc->model)) ;
++		else if (lookup(buf, "cpu", &desc->modelname)) ;
++#else
+ 		else if (lookup(buf, "model", &desc->model)) ;
+ 		else if (lookup(buf, "model name", &desc->modelname)) ;
++#endif
+ 		else if (lookup(buf, "stepping", &desc->stepping)) ;
+ 		else if (lookup(buf, "cpu MHz", &desc->mhz)) ;
+ 		else if (lookup(buf, "flags", &desc->flags)) ;		/* x86 */
+-- 
+2.7.4
+
diff --git a/SOURCES/0068-lscpu-use-cpu-and-revision-tag-if-available.patch b/SOURCES/0068-lscpu-use-cpu-and-revision-tag-if-available.patch
new file mode 100644
index 0000000..c1962e2
--- /dev/null
+++ b/SOURCES/0068-lscpu-use-cpu-and-revision-tag-if-available.patch
@@ -0,0 +1,105 @@
+From cd0d8ef86151d72a246d565844d4c0470feb6b20 Mon Sep 17 00:00:00 2001
+From: Ruediger Meier <ruediger.meier@ga-group.nl>
+Date: Wed, 16 Mar 2016 13:18:18 +0100
+Subject: [PATCH 68/84] lscpu: use cpu and revision tag if available
+
+Avoid ifdef which does not work with --sysroot. Our existing test
+dumps produce even better output now for ppc and sparc.
+
+The logic moved to the printing section.
+
+Upstream: http://github.com/karelzak/util-linux/commit/641350fe822e7f1ac10873dad9a364bdeaba8083
+Upstream: http://github.com/karelzak/util-linux/commit/86c4817e0ea02656ddb62fe27757a9fd4f13b2d3
+Upstream: http://github.com/karelzak/util-linux/commit/c95e3889725389e9d7e24d29c2a71b015959575f
+Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1326615
+CC: Vasant Hegde <hegdevasant@linux.vnet.ibm.com>
+Signed-off-by: Ruediger Meier <ruediger.meier@ga-group.nl>
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ sys-utils/lscpu.c                             | 17 ++++++++---------
+ tests/expected/lscpu/lscpu-ppc64-POWER7       |  3 ++-
+ tests/expected/lscpu/lscpu-ppc64-POWER7-64cpu |  3 ++-
+ 3 files changed, 12 insertions(+), 11 deletions(-)
+
+diff --git a/sys-utils/lscpu.c b/sys-utils/lscpu.c
+index 68b15af..7a00636 100644
+--- a/sys-utils/lscpu.c
++++ b/sys-utils/lscpu.c
+@@ -141,6 +141,8 @@ struct lscpu_desc {
+ 	char	*family;
+ 	char	*model;
+ 	char	*modelname;
++	char	*revision;  /* alternative for model (ppc) */
++	char	*cpu;       /* alternative for modelname (ppc, sparc) */
+ 	char	*virtflag;	/* virtualization flag (vmx, svm) */
+ 	char	*hypervisor;	/* hypervisor software */
+ 	int	hyper;		/* hypervisor vendor ID */
+@@ -355,13 +357,8 @@ read_basicinfo(struct lscpu_desc *desc, struct lscpu_modifier *mod)
+ 		else if (lookup(buf, "vendor_id", &desc->vendor)) ;
+ 		else if (lookup(buf, "family", &desc->family)) ;
+ 		else if (lookup(buf, "cpu family", &desc->family)) ;
+-#if defined(__powerpc__) || defined(__powerpc64__)
+-		else if (lookup(buf, "revision", &desc->model)) ;
+-		else if (lookup(buf, "cpu", &desc->modelname)) ;
+-#else
+ 		else if (lookup(buf, "model", &desc->model)) ;
+ 		else if (lookup(buf, "model name", &desc->modelname)) ;
+-#endif
+ 		else if (lookup(buf, "stepping", &desc->stepping)) ;
+ 		else if (lookup(buf, "cpu MHz", &desc->mhz)) ;
+ 		else if (lookup(buf, "flags", &desc->flags)) ;		/* x86 */
+@@ -369,6 +366,8 @@ read_basicinfo(struct lscpu_desc *desc, struct lscpu_modifier *mod)
+ 		else if (lookup(buf, "type", &desc->flags)) ;		/* sparc64 */
+ 		else if (lookup(buf, "bogomips", &desc->bogomips)) ;
+ 		else if (lookup(buf, "bogomips per cpu", &desc->bogomips)) ; /* s390 */
++		else if (lookup(buf, "cpu", &desc->cpu)) ;
++		else if (lookup(buf, "revision", &desc->revision)) ;
+ 		else
+ 			continue;
+ 	}
+@@ -1264,10 +1263,10 @@ print_summary(struct lscpu_desc *desc, struct lscpu_modifier *mod)
+ 		print_s(_("Vendor ID:"), desc->vendor);
+ 	if (desc->family)
+ 		print_s(_("CPU family:"), desc->family);
+-	if (desc->model)
+-		print_s(_("Model:"), desc->model);
+-	if (desc->modelname)
+-		print_s(_("Model name:"), desc->modelname);
++	if (desc->model || desc->revision)
++		print_s(_("Model:"), desc->revision ? desc->revision : desc->model);
++	if (desc->modelname || desc->cpu)
++		print_s(_("Model name:"), desc->cpu ? desc->cpu : desc->modelname);
+ 	if (desc->stepping)
+ 		print_s(_("Stepping:"), desc->stepping);
+ 	if (desc->mhz)
+diff --git a/tests/expected/lscpu/lscpu-ppc64-POWER7 b/tests/expected/lscpu/lscpu-ppc64-POWER7
+index 0d6c5ba..9a3c0c9 100644
+--- a/tests/expected/lscpu/lscpu-ppc64-POWER7
++++ b/tests/expected/lscpu/lscpu-ppc64-POWER7
+@@ -4,7 +4,8 @@ Thread(s) per core:    4
+ Core(s) per socket:    1
+ Socket(s):             4
+ NUMA node(s):          1
+-Model:                 IBM,8233-E8B
++Model:                 2.1 (pvr 003f 0201)
++Model name:            POWER7 (architected), altivec supported
+ L1d cache:             32K
+ L1i cache:             32K
+ NUMA node0 CPU(s):     0-15
+diff --git a/tests/expected/lscpu/lscpu-ppc64-POWER7-64cpu b/tests/expected/lscpu/lscpu-ppc64-POWER7-64cpu
+index 40e2736..d4ae6c1 100644
+--- a/tests/expected/lscpu/lscpu-ppc64-POWER7-64cpu
++++ b/tests/expected/lscpu/lscpu-ppc64-POWER7-64cpu
+@@ -4,7 +4,8 @@ Thread(s) per core:    4
+ Core(s) per socket:    1
+ Socket(s):             16
+ NUMA node(s):          2
+-Model:                 IBM,8231-E2B
++Model:                 2.1 (pvr 003f 0201)
++Model name:            POWER7 (architected), altivec supported
+ L1d cache:             32K
+ L1i cache:             32K
+ NUMA node0 CPU(s):     0-63
+-- 
+2.7.4
+
diff --git a/SOURCES/0069-findfs-add-ability-to-work-with-PART-UUID-LABEL-too.patch b/SOURCES/0069-findfs-add-ability-to-work-with-PART-UUID-LABEL-too.patch
new file mode 100644
index 0000000..48c3db4
--- /dev/null
+++ b/SOURCES/0069-findfs-add-ability-to-work-with-PART-UUID-LABEL-too.patch
@@ -0,0 +1,137 @@
+From 2555bd3bad9ea8e7ae40a727f59bb546d2aa2717 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Fri, 28 Mar 2014 10:36:05 +0100
+Subject: [PATCH 69/84] findfs: add ability to work with PART{UUID,LABEL}= too
+
+Upstream: http://github.com/karelzak/util-linux/commit/c48508c2faa356c48c26d7d0070a6f20ae4ba9a0
+Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1335671
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ misc-utils/findfs.8 | 51 +++++++++++++++++++++++++++++++++++++++------------
+ misc-utils/findfs.c | 17 +++++------------
+ 2 files changed, 44 insertions(+), 24 deletions(-)
+
+diff --git a/misc-utils/findfs.8 b/misc-utils/findfs.8
+index 8a6bca1..b92cd45 100644
+--- a/misc-utils/findfs.8
++++ b/misc-utils/findfs.8
+@@ -7,19 +7,45 @@
+ findfs \- find a filesystem by label or UUID
+ .SH SYNOPSIS
+ .B findfs
+-.BI LABEL= label
+-.sp
+-.B findfs
+-.BI UUID= uuid
++.BI NAME= value
+ .SH DESCRIPTION
+ .B findfs
+-will search the disks in the system looking for a filesystem which has
+-a label matching
+-.I label
+-or a UUID equal to
+-.IR uuid .
+-If the filesystem is found, the device name for the filesystem will
+-be printed on stdout.
++will search the block devices in the system looking for a filesystem or
++partition with specified tag. The currently supported tags are:
++.TP
++.B LABEL=<label>
++Specifies filesystem label.
++.TP
++.B UUID=<uuid>
++Specifies filesystem UUID.
++.TP
++.B PARTUUID=<uuid>
++Specifies partition UUID. This partition identifier is supported for example for
++GUID  Partition  Table (GPT) partition tables.
++.TP
++.B PARTLABEL=<label>
++Specifies partition label (name). The partition labels are supported for example for
++GUID Partition Table (GPT) or MAC partition tables.
++.PP
++If the filesystem or partition is found, the device name will be printed on
++stdout.
++
++The complete overview about filesystems and partitions you can get for example
++by
++.RS
++
++.br
++.BI "lsblk \-\-fs"
++.br
++
++.BI "partx --show <disk>"
++.br
++
++.BI blkid
++.br
++
++.RE
++
+ .PP
+ .SH AUTHOR
+ .B findfs
+@@ -30,7 +56,8 @@ the util-linux package by Karel Zak (kzak@redhat.com).
+ enables debug output.
+ .SH SEE ALSO
+ .BR blkid (8),
+-.BR fsck (8)
++.BR lsblk (8),
++.BR partx (8)
+ .SH AVAILABILITY
+ The findfs command is part of the util-linux package and is available from
+ ftp://ftp.kernel.org/pub/linux/utils/util-linux/.
+diff --git a/misc-utils/findfs.c b/misc-utils/findfs.c
+index bc4a843..29ca1cb 100644
+--- a/misc-utils/findfs.c
++++ b/misc-utils/findfs.c
+@@ -19,8 +19,7 @@ static void __attribute__((__noreturn__)) usage(int rc)
+ {
+ 	FILE *out = rc ? stderr : stdout;
+ 	fputs(USAGE_HEADER, out);
+-	fprintf(out, _(" %1$s [options] LABEL=<label>\n"
+-		       " %1$s [options] UUID=<uuid>\n"),
++	fprintf(out, _(" %s [options] {LABEL,UUID,PARTUUID,PARTLABEL}=<value>\n"),
+ 		program_invocation_short_name);
+ 	fputs(USAGE_OPTIONS, out);
+ 	fputs(USAGE_HELP, out);
+@@ -31,7 +30,7 @@ static void __attribute__((__noreturn__)) usage(int rc)
+ 
+ int main(int argc, char **argv)
+ {
+-	char	*dev, *tk, *vl;
++	char	*dev;
+ 
+ 	setlocale(LC_ALL, "");
+ 	bindtextdomain(PACKAGE, LOCALEDIR);
+@@ -43,23 +42,17 @@ int main(int argc, char **argv)
+ 		 * with version from e2fsprogs */
+ 		usage(2);
+ 
+-	if (!strncmp(argv[1], "LABEL=", 6)) {
+-		tk = "LABEL";
+-		vl = argv[1] + 6;
+-	} else if (!strncmp(argv[1], "UUID=", 5)) {
+-		tk = "UUID";
+-		vl = argv[1] + 5;
+-	} else if (strcmp(argv[1], "-V") == 0 ||
++	if (strcmp(argv[1], "-V") == 0 ||
+ 		   strcmp(argv[1], "--version") == 0) {
+ 		printf(UTIL_LINUX_VERSION);
+ 		return EXIT_SUCCESS;
+ 	} else if (strcmp(argv[1], "-h") == 0 ||
+ 		   strcmp(argv[1], "--help") == 0) {
+ 		usage(EXIT_SUCCESS);
+-	} else
++	} else if (argv[1][0] == '-')
+ 		usage(2);
+ 
+-	dev = blkid_evaluate_tag(tk, vl, NULL);
++	dev = blkid_evaluate_tag(argv[1], NULL, NULL);
+ 	if (!dev)
+ 		errx(EXIT_FAILURE, _("unable to resolve '%s'"),	argv[1]);
+ 
+-- 
+2.7.4
+
diff --git a/SOURCES/0070-libblkid-fix-memory-leak-in-blkid_parse_tag_string.patch b/SOURCES/0070-libblkid-fix-memory-leak-in-blkid_parse_tag_string.patch
new file mode 100644
index 0000000..4453744
--- /dev/null
+++ b/SOURCES/0070-libblkid-fix-memory-leak-in-blkid_parse_tag_string.patch
@@ -0,0 +1,44 @@
+From 8af4232ff50154588c75f25a951b5619f05d0421 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 19 Nov 2013 17:52:56 +0100
+Subject: [PATCH 70/84] libblkid: fix memory leak in blkid_parse_tag_string()
+
+Upstream: http://github.com/karelzak/util-linux/commit/c1178175e7adb35388a3e34495974d7f24f45d5d
+Upstream: http://github.com/karelzak/util-linux/commit/aab691cf8deb4a53782a0317b6f96c5d8b61f8e9
+Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1335671
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libblkid/src/tag.c | 14 +++++++++-----
+ 1 file changed, 9 insertions(+), 5 deletions(-)
+
+diff --git a/libblkid/src/tag.c b/libblkid/src/tag.c
+index 3a70950..3aede04 100644
+--- a/libblkid/src/tag.c
++++ b/libblkid/src/tag.c
+@@ -237,14 +237,18 @@ int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val)
+ 			goto errout; /* missing closing quote */
+ 		*cp = '\0';
+ 	}
+-	value = value && *value ? strdup(value) : NULL;
+-	if (!value)
+-		goto errout;
++
++	if (ret_val) {
++		value = *value ? strdup(value) : NULL;
++		if (!value)
++			goto errout;
++		*ret_val = value;
++	}
+ 
+ 	if (ret_type)
+ 		*ret_type = name;
+-	if (ret_val)
+-		*ret_val = value;
++	else
++		free(name);
+ 
+ 	return 0;
+ 
+-- 
+2.7.4
+
diff --git a/SOURCES/0071-findmnt-don-t-rely-on-st_dev-for-target.patch b/SOURCES/0071-findmnt-don-t-rely-on-st_dev-for-target.patch
new file mode 100644
index 0000000..7d1bc7f
--- /dev/null
+++ b/SOURCES/0071-findmnt-don-t-rely-on-st_dev-for-target.patch
@@ -0,0 +1,104 @@
+From 0f66811659aa8fd8b14ade8a80bfecd580962b2d Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 10 Mar 2015 12:51:44 +0100
+Subject: [PATCH 71/84] findmnt: don't rely on st_dev for --target
+
+The overlay filesystem does not provide usable st_dev (in traditional
+UNIX way). It's necessary to search in /proc/self/mountinfo to detect
+which path element is mountpoint.
+
+$ findmnt --target /mnt/merged/dir-a/foo
+TARGET      SOURCE  FSTYPE  OPTIONS
+/mnt/merged overlay overlay rw,relatime,lowerdir=/mnt/low,upperdir=/mnt/high/data,workdir=/mnt/high/work
+
+Upstream: http://github.com/karelzak/util-linux/commit/cd41b385a06dde70bb45c3143d3459157bda58f8
+Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=587393
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libmount/src/utils.c |  6 +++++-
+ misc-utils/findmnt.8 |  8 ++++++--
+ misc-utils/findmnt.c | 17 +++++++++++------
+ 3 files changed, 22 insertions(+), 9 deletions(-)
+
+diff --git a/libmount/src/utils.c b/libmount/src/utils.c
+index 7c6f5b1..5783d88 100644
+--- a/libmount/src/utils.c
++++ b/libmount/src/utils.c
+@@ -859,7 +859,11 @@ int mnt_open_uniq_filename(const char *filename, char **name)
+  * This function finds the mountpoint that a given path resides in. @path
+  * should be canonicalized. The returned pointer should be freed by the caller.
+  *
+- * Returns: allocated string with target of the mounted device or NULL on error
++ * WARNING: the function compares st_dev of the @path elements. This traditional
++ * way maybe be insufficient on filesystems like Linux "overlay". See also
++ * mnt_table_find_target().
++ *
++ * Returns: allocated string with the target of the mounted device or NULL on error
+  */
+ char *mnt_get_mountpoint(const char *path)
+ {
+diff --git a/misc-utils/findmnt.8 b/misc-utils/findmnt.8
+index 407636e..54739b7 100644
+--- a/misc-utils/findmnt.8
++++ b/misc-utils/findmnt.8
+@@ -179,8 +179,12 @@ Search in
+ .IR /etc/fstab .
+ The output is in the list format (see \fB--list\fR).
+ .TP
+-.BR \-T , " \-\-target \fIdir\fP"
+-Explicitly define the mount target (mountpoint directory).
++.BR \-T , " \-\-target \fIpath\fP"
++Explicitly define the mount target (mountpoint directory). If the \fIpath\fR
++is not a mountpoint file or directory than
++.B findmnt
++checks \fIpath\fR elements in reverse order for get the mountpoint (this feature is 
++supported only if search in kernel files and unsupported for \fB\-\-fstab\fP).
+ .TP
+ .BR \-t , " \-\-types \fIlist\fP"
+ Limit the set of printed filesystems.  More than one type may be
+diff --git a/misc-utils/findmnt.c b/misc-utils/findmnt.c
+index f16da91..fe899db 100644
+--- a/misc-utils/findmnt.c
++++ b/misc-utils/findmnt.c
+@@ -236,9 +236,12 @@ static void set_source_match(const char *data)
+ 		set_match(COL_SOURCE, data);
+ }
+ 
+-static void enable_extra_target_match(void)
++/* @tb has to be from kernel (so no fstab or so)! */
++static void enable_extra_target_match(struct libmnt_table *tb)
+ {
+-	char *cn = NULL, *mnt = NULL;
++	char *cn = NULL;
++	const char *tgt = NULL, *mnt = NULL;
++	struct libmnt_fs *fs;
+ 
+ 	/*
+ 	 * Check if match pattern is mountpoint, if not use the
+@@ -248,9 +251,11 @@ static void enable_extra_target_match(void)
+ 	if (!cn)
+ 		return;
+ 
+-	mnt = mnt_get_mountpoint(cn);
+-	if (!mnt || strcmp(mnt, cn) == 0)
+-		return;
++	fs = mnt_table_find_mountpoint(tb, tgt, MNT_ITER_BACKWARD);
++	if (fs)
++		mnt = mnt_fs_get_target(fs);
++	if (mnt && strcmp(mnt, tgt) != 0)
++		set_match(COL_TARGET, xstrdup(mnt));	/* replace the current setting */
+ 
+ 	/* replace the current setting with the real mountpoint */
+ 	set_match(COL_TARGET, mnt);
+@@ -1484,7 +1489,7 @@ int main(int argc, char *argv[])
+ 			 * try it again with extra functionality for target
+ 			 * match
+ 			 */
+-			enable_extra_target_match();
++			enable_extra_target_match(tb);
+ 			rc = add_matching_lines(tb, tt, direction);
+ 		}
+ 	}
+-- 
+2.7.4
+
diff --git a/SOURCES/0072-libmount-cleanup-fs-root-detection-code.patch b/SOURCES/0072-libmount-cleanup-fs-root-detection-code.patch
new file mode 100644
index 0000000..b0b881d
--- /dev/null
+++ b/SOURCES/0072-libmount-cleanup-fs-root-detection-code.patch
@@ -0,0 +1,201 @@
+From bb3483bf21b9cbe462caaa74fbc03d2eb7845d74 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 10 Mar 2015 13:35:56 +0100
+Subject: [PATCH 72/84] libmount: cleanup fs root detection code
+
+Upstream: http://github.com/karelzak/util-linux/commit/cc06a01ec551ed2bcd397a5097165b4434179b34
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=587393
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libmount/src/tab.c                            | 32 ++++++++++++++++++++-----
+ libmount/src/utils.c                          | 34 ---------------------------
+ tests/expected/libmount/utils-fs-root         |  1 -
+ tests/expected/libmount/utils-fs-root-subdir  |  1 -
+ tests/expected/libmount/utils-fs-root-subdir2 |  1 -
+ tests/ts/libmount/utils                       | 12 ----------
+ 6 files changed, 26 insertions(+), 55 deletions(-)
+ delete mode 100644 tests/expected/libmount/utils-fs-root
+ delete mode 100644 tests/expected/libmount/utils-fs-root-subdir
+ delete mode 100644 tests/expected/libmount/utils-fs-root-subdir2
+
+diff --git a/libmount/src/tab.c b/libmount/src/tab.c
+index 1ba1eec..10ee7ce 100644
+--- a/libmount/src/tab.c
++++ b/libmount/src/tab.c
+@@ -46,6 +46,8 @@
+ #include "mountP.h"
+ #include "strutils.h"
+ #include "loopdev.h"
++#include "fileutils.h"
++#include "canonicalize.h"
+ 
+ static int is_mountinfo(struct libmnt_table *tb);
+ 
+@@ -900,6 +902,20 @@ struct libmnt_fs *mnt_table_find_devno(struct libmnt_table *tb,
+ 	return NULL;
+ }
+ 
++static char *remove_mountpoint_from_path(const char *path, const char *mnt)
++{
++        char *res;
++	const char *p;
++	size_t sz;
++
++	sz = strlen(mnt);
++	p = sz > 1 ? path + sz : path;
++
++	res = *p ? strdup(p) : strdup("/");
++	DBG(UTILS, mnt_debug("%s fs-root is %s", path, res));
++	return res;
++}
++
+ /*
+  * tb: /proc/self/mountinfo
+  * fs: filesystem
+@@ -919,7 +935,8 @@ struct libmnt_fs *mnt_table_get_fs_root(struct libmnt_table *tb,
+ 					unsigned long mountflags,
+ 					char **fsroot)
+ {
+-	char *root = NULL, *mnt = NULL;
++	char *root = NULL;
++	const char *mnt = NULL;
+ 	const char *fstype;
+ 	struct libmnt_fs *src_fs = NULL;
+ 
+@@ -937,10 +954,15 @@ struct libmnt_fs *mnt_table_get_fs_root(struct libmnt_table *tb,
+ 		DBG(TAB, mnt_debug("fs-root for bind"));
+ 
+ 		src = xsrc = mnt_resolve_spec(mnt_fs_get_source(fs), tb->cache);
+-		if (src)
+-			mnt = mnt_get_mountpoint(src);
++		if (src) {
++			struct libmnt_fs *fs = mnt_table_find_mountpoint(tb,
++							src, MNT_ITER_BACKWARD);
++			if (fs)
++				mnt = mnt_fs_get_target(fs);
++		}
++
+ 		if (mnt)
+-			root = mnt_get_fs_root(src, mnt);
++			root = remove_mountpoint_from_path(src, mnt);
+ 
+ 		if (xsrc && !tb->cache) {
+ 			free(xsrc);
+@@ -1007,11 +1029,9 @@ dflt:
+ 
+ 	DBG(TAB, mnt_debug("FS root result: %s", root));
+ 
+-	free(mnt);
+ 	return src_fs;
+ err:
+ 	free(root);
+-	free(mnt);
+ 	return NULL;
+ }
+ 
+diff --git a/libmount/src/utils.c b/libmount/src/utils.c
+index 5783d88..2151ff9 100644
+--- a/libmount/src/utils.c
++++ b/libmount/src/utils.c
+@@ -908,28 +908,6 @@ err:
+ 	return NULL;
+ }
+ 
+-char *mnt_get_fs_root(const char *path, const char *mnt)
+-{
+-	char *m = (char *) mnt, *res;
+-	const char *p;
+-	size_t sz;
+-
+-	if (!m)
+-		m = mnt_get_mountpoint(path);
+-	if (!m)
+-		return NULL;
+-
+-	sz = strlen(m);
+-	p = sz > 1 ? path + sz : path;
+-
+-	if (m != mnt)
+-		free(m);
+-
+-	res = *p ? strdup(p) : strdup("/");
+-	DBG(UTILS, mnt_debug("%s fs-root is %s", path, res));
+-	return res;
+-}
+-
+ /*
+  * Search for @name kernel command parametr.
+  *
+@@ -1085,17 +1063,6 @@ int test_mountpoint(struct libmnt_test *ts, int argc, char *argv[])
+ 	return 0;
+ }
+ 
+-int test_fsroot(struct libmnt_test *ts, int argc, char *argv[])
+-{
+-	char *path = canonicalize_path(argv[1]),
+-	     *mnt = path ? mnt_get_fs_root(path, NULL) : NULL;
+-
+-	printf("%s: %s\n", argv[1], mnt ? : "unknown");
+-	free(mnt);
+-	free(path);
+-	return 0;
+-}
+-
+ int test_filesystems(struct libmnt_test *ts, int argc, char *argv[])
+ {
+ 	char **filesystems = NULL;
+@@ -1170,7 +1137,6 @@ int main(int argc, char *argv[])
+ 	{ "--starts-with",   test_startswith,      "<string> <prefix>" },
+ 	{ "--ends-with",     test_endswith,        "<string> <prefix>" },
+ 	{ "--mountpoint",    test_mountpoint,      "<path>" },
+-	{ "--fs-root",       test_fsroot,          "<path>" },
+ 	{ "--cd-parent",     test_chdir,           "<path>" },
+ 	{ "--kernel-cmdline",test_kernel_cmdline,  "<option> | <option>=" },
+ 	{ "--mkdir",         test_mkdir,           "<path>" },
+diff --git a/tests/expected/libmount/utils-fs-root b/tests/expected/libmount/utils-fs-root
+deleted file mode 100644
+index 7746b28..0000000
+--- a/tests/expected/libmount/utils-fs-root
++++ /dev/null
+@@ -1 +0,0 @@
+-/proc: /
+diff --git a/tests/expected/libmount/utils-fs-root-subdir b/tests/expected/libmount/utils-fs-root-subdir
+deleted file mode 100644
+index 09cdb8d..0000000
+--- a/tests/expected/libmount/utils-fs-root-subdir
++++ /dev/null
+@@ -1 +0,0 @@
+-/proc/sys/kernel: /sys/kernel
+diff --git a/tests/expected/libmount/utils-fs-root-subdir2 b/tests/expected/libmount/utils-fs-root-subdir2
+deleted file mode 100644
+index 2e8b89a..0000000
+--- a/tests/expected/libmount/utils-fs-root-subdir2
++++ /dev/null
+@@ -1 +0,0 @@
+-/etc: /etc
+diff --git a/tests/ts/libmount/utils b/tests/ts/libmount/utils
+index 6facaad..89ecf10 100755
+--- a/tests/ts/libmount/utils
++++ b/tests/ts/libmount/utils
+@@ -64,18 +64,6 @@ ts_init_subtest "mountpoint-root"
+ ts_valgrind $TESTPROG --mountpoint / &> $TS_OUTPUT
+ ts_finalize_subtest
+ 
+-ts_init_subtest "fs-root"
+-ts_valgrind $TESTPROG --fs-root /proc &> $TS_OUTPUT
+-ts_finalize_subtest
+-
+-ts_init_subtest "fs-root-subdir"
+-ts_valgrind $TESTPROG --fs-root /proc/sys/kernel &> $TS_OUTPUT
+-ts_finalize_subtest
+-
+-ts_init_subtest "fs-root-subdir2"
+-ts_valgrind $TESTPROG --fs-root /etc &> $TS_OUTPUT
+-ts_finalize_subtest
+-
+ ts_init_subtest "kernel-cmdline"
+ export LIBMOUNT_KERNEL_CMDLINE="$TS_SELF/files/kernel_cmdline"
+ ts_valgrind $TESTPROG --kernel-cmdline selinux= &>> $TS_OUTPUT
+-- 
+2.7.4
+
diff --git a/SOURCES/0073-libmount-mark-overlay-as-pseudo-FS.patch b/SOURCES/0073-libmount-mark-overlay-as-pseudo-FS.patch
new file mode 100644
index 0000000..db6ce86
--- /dev/null
+++ b/SOURCES/0073-libmount-mark-overlay-as-pseudo-FS.patch
@@ -0,0 +1,27 @@
+From 346b97a27e817a001c71d45400f17429bd82b364 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Wed, 11 Mar 2015 11:38:07 +0100
+Subject: [PATCH 73/84] libmount: mark overlay as pseudo-FS
+
+Upstream: http://github.com/karelzak/util-linux/commit/209fd7a74879d37cef3d5d1679bc9cad76b96c7a
+Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=587393
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libmount/src/utils.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/libmount/src/utils.c b/libmount/src/utils.c
+index 2151ff9..c13fb96 100644
+--- a/libmount/src/utils.c
++++ b/libmount/src/utils.c
+@@ -269,6 +269,7 @@ int mnt_fstype_is_pseudofs(const char *type)
+ 		"mqueue",
+ 		"nfsd",
+ 		"none",
++		"overlay",
+ 		"pipefs",
+ 		"proc",
+ 		"pstore",
+-- 
+2.7.4
+
diff --git a/SOURCES/0074-logger-be-more-precise-about-port-description.patch b/SOURCES/0074-logger-be-more-precise-about-port-description.patch
new file mode 100644
index 0000000..8ff9c46
--- /dev/null
+++ b/SOURCES/0074-logger-be-more-precise-about-port-description.patch
@@ -0,0 +1,41 @@
+From f4ffe3de3ba721892af52c7ed5787f4470393242 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 21 Jun 2016 13:35:33 +0200
+Subject: [PATCH 74/84] logger: be more precise about --port description
+
+Upstream: http://github.com/karelzak/util-linux/commit/1c7227598824b1d9140298e9fe5742cae4131130
+Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1344222
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ misc-utils/logger.1 | 1 +
+ misc-utils/logger.c | 2 +-
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/misc-utils/logger.1 b/misc-utils/logger.1
+index 5eb8d09..8c4faca 100644
+--- a/misc-utils/logger.1
++++ b/misc-utils/logger.1
+@@ -72,6 +72,7 @@ port defined in /etc/services, which is often
+ \fB\-P\fR, \fB\-\-port\fR \fIport\fR
+ Use the specified
+ .IR port .
++When this option is not specified, the port defaults to syslog for udp and to syslog-conn for tcp connections.
+ .TP
+ \fB\-i\fR, \fB\-\-id\fR
+ Log the process ID of the logger process with each line.
+diff --git a/misc-utils/logger.c b/misc-utils/logger.c
+index c83c0b8..a331869 100644
+--- a/misc-utils/logger.c
++++ b/misc-utils/logger.c
+@@ -222,7 +222,7 @@ static void __attribute__ ((__noreturn__)) usage(FILE *out)
+ 		" -f, --file <file>     log the contents of this file\n"
+ 		" -h, --help            display this help text and exit\n"), out);
+ 	fputs(_(" -n, --server <name>   write to this remote syslog server\n"
+-		" -P, --port <number>   use this UDP port\n"
++		" -P, --port <port>     use this port for UDP or TCP connection\n"
+ 		" -p, --priority <prio> mark given message with this priority\n"
+ 		" -s, --stderr          output message to standard error as well\n"), out);
+ 	fputs(_(" -t, --tag <tag>       mark every line with this tag\n"
+-- 
+2.7.4
+
diff --git a/SOURCES/0075-libfdisk-gpt-be-more-careful-with-64bit-constants.patch b/SOURCES/0075-libfdisk-gpt-be-more-careful-with-64bit-constants.patch
new file mode 100644
index 0000000..82190fa
--- /dev/null
+++ b/SOURCES/0075-libfdisk-gpt-be-more-careful-with-64bit-constants.patch
@@ -0,0 +1,182 @@
+From 428be59e33d0875cdf5bf602a75328fb3d7c58ad Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 21 Jun 2016 14:06:14 +0200
+Subject: [PATCH 75/84] libfdisk: (gpt) be more careful with 64bit constants
+
+It's probably more robust (and readable) to be explicit when we count
+with constant and 64bit numbers.
+
+Upstream: http://github.com/karelzak/util-linux/commit/0a7cdf80606cc0670ef7f740d37640b05932e0ce
+Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1344482
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libfdisk/src/gpt.c | 40 ++++++++++++++++++++--------------------
+ 1 file changed, 20 insertions(+), 20 deletions(-)
+
+diff --git a/libfdisk/src/gpt.c b/libfdisk/src/gpt.c
+index 482d453..d3bdc2d 100644
+--- a/libfdisk/src/gpt.c
++++ b/libfdisk/src/gpt.c
+@@ -53,7 +53,7 @@
+ #define GPT_MBR_PROTECTIVE  1
+ #define GPT_MBR_HYBRID      2
+ 
+-#define GPT_PRIMARY_PARTITION_TABLE_LBA 0x00000001
++#define GPT_PRIMARY_PARTITION_TABLE_LBA 0x00000001ULL
+ 
+ #define EFI_PMBR_OSTYPE     0xEE
+ #define MSDOS_MBR_SIGNATURE 0xAA55
+@@ -364,7 +364,7 @@ static int gpt_mknew_pmbr(struct fdisk_context *cxt)
+ 	pmbr->partition_record[0].end_track    = 0xFF;
+ 	pmbr->partition_record[0].starting_lba = cpu_to_le32(1);
+ 	pmbr->partition_record[0].size_in_lba  =
+-		cpu_to_le32(min((uint32_t) cxt->total_sectors - 1, 0xFFFFFFFF));
++		cpu_to_le32((uint32_t) min(cxt->total_sectors - 1ULL, 0xFFFFFFFFULL));
+ 
+ 	return 0;
+ }
+@@ -379,14 +379,14 @@ static void gpt_mknew_header_common(struct fdisk_context *cxt,
+ 	header->my_lba = cpu_to_le64(lba);
+ 
+ 	if (lba == GPT_PRIMARY_PARTITION_TABLE_LBA) { /* primary */
+-		header->alternative_lba = cpu_to_le64(cxt->total_sectors - 1);
+-		header->partition_entry_lba = cpu_to_le64(2);
++		header->alternative_lba = cpu_to_le64(cxt->total_sectors - 1ULL);
++		header->partition_entry_lba = cpu_to_le64(2ULL);
+ 	} else { /* backup */
+ 		uint64_t esz = le32_to_cpu(header->npartition_entries) * sizeof(struct gpt_entry);
+ 		uint64_t esects = (esz + cxt->sector_size - 1) / cxt->sector_size;
+ 
+ 		header->alternative_lba = cpu_to_le64(GPT_PRIMARY_PARTITION_TABLE_LBA);
+-		header->partition_entry_lba = cpu_to_le64(cxt->total_sectors - 1 - esects);
++		header->partition_entry_lba = cpu_to_le64(cxt->total_sectors - 1ULL - esects);
+ 	}
+ }
+ 
+@@ -451,8 +451,8 @@ static int gpt_mknew_header(struct fdisk_context *cxt,
+ 	header->npartition_entries     = cpu_to_le32(GPT_NPARTITIONS);
+ 	header->sizeof_partition_entry = cpu_to_le32(sizeof(struct gpt_entry));
+ 
+-	last = cxt->total_sectors - 2 - esz;
+-	first = esz + 2;
++	last = cxt->total_sectors - 2ULL - esz;
++	first = esz + 2ULL;
+ 
+ 	if (first < cxt->first_lba && cxt->first_lba < last)
+ 		/* Align according to topology */
+@@ -520,7 +520,7 @@ check_hybrid:
+ 	 */
+ 	if (ret == GPT_MBR_PROTECTIVE) {
+ 		if (le32_to_cpu(pmbr->partition_record[0].size_in_lba) !=
+-		    min((uint32_t) cxt->total_sectors - 1, 0xFFFFFFFF))
++		    (uint32_t) min(cxt->total_sectors - 1ULL, 0xFFFFFFFFULL))
+ 			ret = 0;
+ 	}
+ done:
+@@ -538,7 +538,7 @@ static uint64_t last_lba(struct fdisk_context *cxt)
+ 	}
+ 
+ 	if (S_ISBLK(s.st_mode))
+-		return cxt->total_sectors - 1;
++		return cxt->total_sectors - 1ULL;
+ 	else if (S_ISREG(s.st_mode)) {
+ 		uint64_t sectors = s.st_size >> cxt->sector_size;
+ 		return (sectors / cxt->sector_size) - 1ULL;
+@@ -554,7 +554,7 @@ static ssize_t read_lba(struct fdisk_context *cxt, uint64_t lba,
+ 
+ 	if (lseek(cxt->dev_fd, offset, SEEK_SET) == (off_t) -1)
+ 		return -1;
+-	return read(cxt->dev_fd, buffer, bytes) != bytes;
++	return read(cxt->dev_fd, buffer, bytes) != (ssize_t) bytes;
+ }
+ 
+ 
+@@ -908,7 +908,7 @@ static uint64_t find_first_available(struct gpt_header *header,
+ 			if (first < gpt_partition_start(&e[i]))
+ 				continue;
+ 			if (first <= gpt_partition_end(&e[i])) {
+-				first = gpt_partition_end(&e[i]) + 1;
++				first = gpt_partition_end(&e[i]) + 1ULL;
+ 				first_moved = 1;
+ 			}
+ 		}
+@@ -937,7 +937,7 @@ static uint64_t find_last_free(struct gpt_header *header,
+ 		uint64_t ps = gpt_partition_start(&e[i]);
+ 
+ 		if (nearest_start > ps && ps > start)
+-			nearest_start = ps - 1;
++			nearest_start = ps - 1ULL;
+ 	}
+ 
+ 	return nearest_start;
+@@ -960,7 +960,7 @@ static uint64_t find_last_free_sector(struct gpt_header *header,
+ 		for (i = 0; i < le32_to_cpu(header->npartition_entries); i++) {
+ 			if ((last >= gpt_partition_start(&e[i])) &&
+ 			    (last <= gpt_partition_end(&e[i]))) {
+-				last = gpt_partition_start(&e[i]) - 1;
++				last = gpt_partition_start(&e[i]) - 1ULL;
+ 				last_moved = 1;
+ 			}
+ 		}
+@@ -986,7 +986,7 @@ static uint64_t find_first_in_largest(struct gpt_header *header, struct gpt_entr
+ 		first_sect =  find_first_available(header, e, start);
+ 		if (first_sect != 0) {
+ 			last_sect = find_last_free(header, e, first_sect);
+-			segment_size = last_sect - first_sect + 1;
++			segment_size = last_sect - first_sect + 1ULL;
+ 
+ 			if (segment_size > selected_size) {
+ 				selected_size = segment_size;
+@@ -1026,7 +1026,7 @@ static uint64_t get_free_sectors(struct fdisk_context *cxt, struct gpt_header *h
+ 				largest_seg = segment_sz;
+ 			totfound += segment_sz;
+ 			num++;
+-			start = last_sect + 1;
++			start = last_sect + 1ULL;
+ 		}
+ 	} while (first_sect);
+ 
+@@ -1165,7 +1165,7 @@ void gpt_list_table(struct fdisk_context *cxt,
+ 			continue;
+ 
+ 		/* the partition has to inside usable range */
+-		if (start < fu || start + size - 1 > lu)
++		if (start < fu || start + size - 1ULL > lu)
+ 			continue;
+ 
+ 		name = encode_to_utf8((unsigned char *)gpt->ents[i].partition_name,
+@@ -1266,11 +1266,11 @@ static int gpt_write_pmbr(struct fdisk_context *cxt)
+ 	 * Set size_in_lba to the size of the disk minus one. If the size of the disk
+ 	 * is too large to be represented by a 32bit LBA (2Tb), set it to 0xFFFFFFFF.
+ 	 */
+-	if (cxt->total_sectors - 1 > 0xFFFFFFFFULL)
++	if (cxt->total_sectors - 1ULL > 0xFFFFFFFFULL)
+ 		pmbr->partition_record[0].size_in_lba = cpu_to_le32(0xFFFFFFFF);
+ 	else
+ 		pmbr->partition_record[0].size_in_lba =
+-			cpu_to_le32(cxt->total_sectors - 1UL);
++			cpu_to_le32((uint32_t) (cxt->total_sectors - 1ULL));
+ 
+ 	offset = GPT_PMBR_LBA * cxt->sector_size;
+ 	if (offset != lseek(cxt->dev_fd, offset, SEEK_SET))
+@@ -1308,7 +1308,7 @@ static int gpt_write_disklabel(struct fdisk_context *cxt)
+ 		goto err0;
+ 
+ 	/* check that the backup header is properly placed */
+-	if (le64_to_cpu(gpt->pheader->alternative_lba) < cxt->total_sectors - 1)
++	if (le64_to_cpu(gpt->pheader->alternative_lba) < cxt->total_sectors - 1ULL)
+ 		/* TODO: correct this (with user authorization) and write */
+ 		goto err0;
+ 
+@@ -1645,7 +1645,7 @@ static int gpt_add_partition(
+ 
+ 		user_l = fdisk_ask_number_get_result(ask);
+ 		if (fdisk_ask_number_is_relative(ask))
+-			user_l = fdisk_align_lba_in_range(cxt, user_l, user_f, dflt_l) - 1;
++			user_l = fdisk_align_lba_in_range(cxt, user_l, user_f, dflt_l) - 1ULL;
+ 		if (user_l > user_f && user_l <= disk_l)
+ 			break;
+ 	}
+-- 
+2.7.4
+
diff --git a/SOURCES/0076-lsns-backport-new-command.patch b/SOURCES/0076-lsns-backport-new-command.patch
new file mode 100644
index 0000000..090bd16
--- /dev/null
+++ b/SOURCES/0076-lsns-backport-new-command.patch
@@ -0,0 +1,1251 @@
+From 03f539c766780a083010636cc67f96fcb2bab30f Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Fri, 24 Jun 2016 12:16:24 +0200
+Subject: [PATCH 76/84] lsns: backport new command
+
+Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1332084
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ bash-completion/lsns    |  55 ++++
+ configure.ac            |   6 +
+ include/Makemodule.am   |   1 +
+ include/c.h             |   8 +
+ include/debug.h         |   2 +-
+ include/idcache.h       |  28 ++
+ include/procutils.h     |   2 +
+ lib/Makemodule.am       |   1 +
+ lib/idcache.c           | 117 ++++++++
+ lib/procutils.c         |  43 +++
+ sys-utils/Makemodule.am |   7 +
+ sys-utils/lsns.8        |  78 +++++
+ sys-utils/lsns.c        | 748 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 13 files changed, 1095 insertions(+), 1 deletion(-)
+ create mode 100644 bash-completion/lsns
+ create mode 100644 include/idcache.h
+ create mode 100644 lib/idcache.c
+ create mode 100644 sys-utils/lsns.8
+ create mode 100644 sys-utils/lsns.c
+
+diff --git a/bash-completion/lsns b/bash-completion/lsns
+new file mode 100644
+index 0000000..d02df3b
+--- /dev/null
++++ b/bash-completion/lsns
+@@ -0,0 +1,55 @@
++_lsns_module()
++{
++	local cur prev OPTS LSNS_COLS_ALL
++	COMPREPLY=()
++	cur="${COMP_WORDS[COMP_CWORD]}"
++	prev="${COMP_WORDS[COMP_CWORD-1]}"
++	LSNS_COLS_ALL="
++		NS TYPE PATH NPROCS PID PPID COMMAND UID USER
++	"
++	case $prev in
++		'-o'|'--output')
++			local prefix realcur LSNS_COLS
++			realcur="${cur##*,}"
++			prefix="${cur%$realcur}"
++			for WORD in $LSNS_COLS_ALL; do
++				if ! [[ $prefix == *"$WORD"* ]]; then
++					LSNS_COLS="$WORD $LSNS_COLS"
++				fi
++			done
++			compopt -o nospace
++			COMPREPLY=( $(compgen -P "$prefix" -W "$LSNS_COLS" -S ',' -- $realcur) )
++			return 0
++			;;
++		'-p'|'--task')
++			COMPREPLY=( $(compgen -W "$(cd /proc && echo [0-9]*)" -- $cur) )
++			return 0
++			;;
++		'-t'|'--type')
++			COMPREPLY=( $(compgen -W "mnt net ipc user pid uts" -- $cur) )
++			return 0
++			;;
++		'-h'|'--help'|'-V'|'--version')
++			return 0
++			;;
++	esac
++	case $cur in
++		-*)
++			COMPREPLY=( $(compgen -W "
++					--list
++					--noheadings
++					--output
++					--task
++					--raw
++					--notruncate
++					--type
++					--help
++					--version
++				" -- $cur) )
++			return 0
++			;;
++	esac
++	COMPREPLY=( $(compgen -W "mnt net pid uts ipc user" -- $cur ) )
++	return 0
++}
++complete -F _lsns_module lsns
+diff --git a/configure.ac b/configure.ac
+index f3c7214..5d9ea39 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1032,6 +1032,12 @@ UL_REQUIRES_BUILD([lslogins], [libsmartcols])
+ AM_CONDITIONAL([BUILD_LSLOGINS], [test "x$build_lslogins" = xyes])
+ 
+ 
++UL_BUILD_INIT([lsns], [check])
++UL_REQUIRES_LINUX([lsns])
++UL_REQUIRES_BUILD([lsns], [libsmartcols])
++AM_CONDITIONAL([BUILD_LSNS], [test "x$build_lsns" = xyes])
++
++
+ UL_BUILD_INIT([chcpu], [check])
+ UL_REQUIRES_LINUX([chcpu])
+ UL_REQUIRES_HAVE([chcpu], [cpu_set_t], [cpu_set_t type])
+diff --git a/include/Makemodule.am b/include/Makemodule.am
+index 7b53244..757f317 100644
+--- a/include/Makemodule.am
++++ b/include/Makemodule.am
+@@ -15,6 +15,7 @@ dist_noinst_HEADERS += \
+ 	include/exec_shell.h \
+ 	include/exitcodes.h \
+ 	include/fileutils.h \
++	include/idcache.h \
+ 	include/ismounted.h \
+ 	include/linux_reboot.h \
+ 	include/linux_version.h \
+diff --git a/include/c.h b/include/c.h
+index 7b59ce8..a2779a5 100644
+--- a/include/c.h
++++ b/include/c.h
+@@ -110,6 +110,14 @@
+ 	_max1 > _max2 ? _max1 : _max2; })
+ #endif
+ 
++#ifndef cmp_numbers
++# define cmp_numbers(x, y) __extension__ ({	\
++	__typeof__(x) _a = (x);			\
++	__typeof__(y) _b = (y);			\
++	(void) (&_a == &_b);			\
++	_a == _b ? 0 : _a > _b ? 1 : -1; })
++#endif
++
+ #ifndef offsetof
+ #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+ #endif
+diff --git a/include/debug.h b/include/debug.h
+index 25045aa..848e474 100644
+--- a/include/debug.h
++++ b/include/debug.h
+@@ -15,7 +15,7 @@ struct dbg_mask { char *mname; int val; };
+ 
+ #define UL_DEBUG_DEFINE_MASK(m) int m ## _debug_mask
+ #define UL_DEBUG_DECLARE_MASK(m) extern UL_DEBUG_DEFINE_MASK(m)
+-#define UL_DEBUG_DEFINE_MASKANEMS(m) static const struct dbg_mask m ## _masknames[]
++#define UL_DEBUG_DEFINE_MASKNAMES(m) static const struct dbg_mask m ## _masknames[]
+ 
+ /* p - flag prefix, m - flag postfix */
+ #define UL_DEBUG_DEFINE_FLAG(p, m) p ## m
+diff --git a/include/idcache.h b/include/idcache.h
+new file mode 100644
+index 0000000..912edd5
+--- /dev/null
++++ b/include/idcache.h
+@@ -0,0 +1,28 @@
++#ifndef UTIL_LINUX_IDCACHE_H
++#define UTIL_LINUX_IDCACHE_H
++
++#include <sys/types.h>
++#include <pwd.h>
++
++#define IDCACHE_FLAGS_NAMELEN	(1 << 1)
++
++struct identry {
++	unsigned long int	id;
++	char			*name;
++	struct identry		*next;
++};
++
++struct idcache {
++	struct identry	*ent;	/* first entry */
++	int		width;	/* name width */
++};
++
++
++extern struct idcache *new_idcache(void);
++extern void add_gid(struct idcache *cache, unsigned long int id);
++extern void add_uid(struct idcache *cache, unsigned long int id);
++
++extern void free_idcache(struct idcache *ic);
++extern struct identry *get_id(struct idcache *ic, unsigned long int id);
++
++#endif /* UTIL_LINUX_IDCACHE_H */
+diff --git a/include/procutils.h b/include/procutils.h
+index 14b766c..9f8dd76 100644
+--- a/include/procutils.h
++++ b/include/procutils.h
+@@ -28,5 +28,7 @@ extern void proc_processes_filter_by_name(struct proc_processes *ps, const char
+ extern void proc_processes_filter_by_uid(struct proc_processes *ps, uid_t uid);
+ extern int proc_next_pid(struct proc_processes *ps, pid_t *pid);
+ 
++extern char *proc_get_command(pid_t pid);
++extern char *proc_get_command_name(pid_t pid);
+ 
+ #endif /* UTIL_LINUX_PROCUTILS */
+diff --git a/lib/Makemodule.am b/lib/Makemodule.am
+index eed31f1..73280f9 100644
+--- a/lib/Makemodule.am
++++ b/lib/Makemodule.am
+@@ -8,6 +8,7 @@ libcommon_la_SOURCES = \
+ 	lib/colors.c \
+ 	lib/crc32.c \
+ 	lib/env.c \
++	lib/idcache.c \
+ 	lib/fileutils.c \
+ 	lib/ismounted.c \
+ 	lib/mangle.c \
+diff --git a/lib/idcache.c b/lib/idcache.c
+new file mode 100644
+index 0000000..3c358b8
+--- /dev/null
++++ b/lib/idcache.c
+@@ -0,0 +1,117 @@
++
++#include <wchar.h>
++#include <pwd.h>
++#include <grp.h>
++#include <sys/types.h>
++
++#include "c.h"
++#include "idcache.h"
++
++#ifndef LOGIN_NAME_MAX
++#define LOGIN_NAME_MAX 256
++#endif
++
++struct identry *get_id(struct idcache *ic, unsigned long int id)
++{
++	struct identry *ent;
++
++	if (!ic)
++		return NULL;
++
++	for (ent = ic->ent; ent; ent = ent->next) {
++		if (ent->id == id)
++			return ent;
++	}
++
++	return NULL;
++}
++
++struct idcache *new_idcache()
++{
++	return calloc(1, sizeof(struct idcache));
++}
++
++void free_idcache(struct idcache *ic)
++{
++	struct identry *ent = ic->ent;
++
++	while (ent) {
++		struct identry *next = ent->next;
++		free(ent->name);
++		free(ent);
++		ent = next;
++	}
++
++	free(ic);
++}
++
++static void add_id(struct idcache *ic, char *name, unsigned long int id)
++{
++	struct identry *ent, *x;
++	int w = 0;
++
++	ent = calloc(1, sizeof(struct identry));
++	if (!ent)
++		return;
++	ent->id = id;
++
++	if (name) {
++#ifdef HAVE_WIDECHAR
++		wchar_t wc[LOGIN_NAME_MAX + 1];
++
++		if (mbstowcs(wc, name, LOGIN_NAME_MAX) > 0) {
++			wc[LOGIN_NAME_MAX] = '\0';
++			w = wcswidth(wc, LOGIN_NAME_MAX);
++		}
++		else
++#endif
++			w = strlen(name);
++	}
++
++	/* note, we ignore names with non-printable widechars */
++	if (w > 0) {
++		ent->name = strdup(name);
++		if (!ent->name) {
++			free(ent);
++			return;
++		}
++	} else {
++		if (asprintf(&ent->name, "%lu", id) < 0) {
++			free(ent);
++			return;
++		}
++	}
++
++	for (x = ic->ent; x && x->next; x = x->next);
++
++	if (x)
++		x->next = ent;
++	else
++		ic->ent = ent;
++
++	if (w <= 0)
++		w = ent->name ? strlen(ent->name) : 0;
++	ic->width = ic->width < w ? w : ic->width;
++	return;
++}
++
++void add_uid(struct idcache *cache, unsigned long int id)
++{
++	struct identry *ent= get_id(cache, id);
++
++	if (!ent) {
++		struct passwd *pw = getpwuid((uid_t) id);
++		add_id(cache, pw ? pw->pw_name : NULL, id);
++	}
++}
++
++void add_gid(struct idcache *cache, unsigned long int id)
++{
++	struct identry *ent = get_id(cache, id);
++
++	if (!ent) {
++		struct group *gr = getgrgid((gid_t) id);
++		add_id(cache, gr ? gr->gr_name : NULL, id);
++	}
++}
++
+diff --git a/lib/procutils.c b/lib/procutils.c
+index d633261..8dfdec9 100644
+--- a/lib/procutils.c
++++ b/lib/procutils.c
+@@ -25,6 +25,7 @@
+ #include "procutils.h"
+ #include "at.h"
+ #include "c.h"
++#include "all-io.h"
+ 
+ /*
+  * @pid: process ID for which we want to obtain the threads group
+@@ -193,6 +194,48 @@ int proc_next_pid(struct proc_processes *ps, pid_t *pid)
+ 	return 0;
+ }
+ 
++/* returns process command path, use free() for result */
++static char *proc_file_strdup(pid_t pid, const char *name)
++{
++	char buf[BUFSIZ], *res = NULL;
++	ssize_t sz = 0;
++	size_t i;
++	int fd;
++
++	snprintf(buf, sizeof(buf), "/proc/%d/%s", (int) pid, name);
++	fd = open(buf, O_RDONLY);
++	if (fd < 0)
++		goto done;
++
++	sz = read_all(fd, buf, sizeof(buf));
++	if (sz <= 0)
++		goto done;
++
++	for (i = 0; i < (size_t) sz; i++) {
++
++		if (buf[i] == '\0')
++			buf[i] = ' ';
++	}
++	buf[sz - 1] = '\0';
++	res = strdup(buf);
++done:
++	if (fd >= 0)
++		close(fd);
++	return res;
++}
++
++/* returns process command path, use free() for result */
++char *proc_get_command(pid_t pid)
++{
++	return proc_file_strdup(pid, "cmdline");
++}
++
++/* returns process command name, use free() for result */
++char *proc_get_command_name(pid_t pid)
++{
++	return proc_file_strdup(pid, "comm");
++}
++
+ #ifdef TEST_PROGRAM
+ 
+ static int test_tasks(int argc, char *argv[])
+diff --git a/sys-utils/Makemodule.am b/sys-utils/Makemodule.am
+index c6c561c..9baf5a3 100644
+--- a/sys-utils/Makemodule.am
++++ b/sys-utils/Makemodule.am
+@@ -182,6 +182,13 @@ prlimit_SOURCES = sys-utils/prlimit.c
+ prlimit_LDADD = $(LDADD) libcommon.la
+ endif
+ 
++if BUILD_LSNS
++usrbin_exec_PROGRAMS += lsns
++dist_man_MANS += sys-utils/lsns.8
++lsns_SOURCES =	sys-utils/lsns.c
++lsns_LDADD = $(LDADD) libcommon.la libsmartcols.la
++lsns_CFLAGS = $(AM_CFLAGS) -I$(ul_libsmartcols_incdir)
++endif
+ 
+ if BUILD_MOUNT
+ #
+diff --git a/sys-utils/lsns.8 b/sys-utils/lsns.8
+new file mode 100644
+index 0000000..328df47
+--- /dev/null
++++ b/sys-utils/lsns.8
+@@ -0,0 +1,78 @@
++.\" Man page for the lsns command.
++.\" Copyright 2015 Karel Zak <kzak@redhat.com>
++.\" May be distributed under the GNU General Public License
++
++.TH LSNS 8 "December 2015" "util-linux" "System Administration"
++.SH NAME
++lsns \- list namespaces
++.SH SYNOPSIS
++.B lsns
++[options]
++.RI [ namespace ]
++
++.SH DESCRIPTION
++.B lsns
++lists information about all the currently accessible namespaces or about the
++given \fInamespace\fP.  The \fInamespace\fP identifier is an inode number.
++
++The default output is subject to change.  So whenever possible, you should
++avoid using default outputs in your scripts.  Always explicitly define expected
++columns by using the \fB\-\-output\fR option together with a columns list in
++environments where a stable output is required.
++
++Note that \fBlsns\fR reads information directly from the /proc filesystem and
++for non-root users it may return incomplete information.  The current /proc
++filesystem may be unshared and affected by a PID namespace
++(see \fBunshare \-\-mount\-proc\fP for more details).
++.B lsns
++is not able to see persistent namespaces without processes where the namespace
++instance is held by a bind mount to /proc/\fIpid\fR/ns/\fItype\fR.
++
++.SH OPTIONS
++.TP
++.BR \-l , " \-\-list"
++Use list output format.
++.TP
++.BR \-n , " \-\-noheadings"
++Do not print a header line.
++.TP
++.BR \-o , " \-\-output " \fIlist\fP
++Specify which output columns to print.  Use \fB\-\-help\fR
++to get a list of all supported columns.
++
++The default list of columns may be extended if \fIlist\fP is
++specified in the format \fB+\fIlist\fP (e.g. \fBlsns \-o +PATH\fP).
++.TP
++.BR \-p , " \-\-task " \fIpid\fP
++Display only the namespaces held by the process with this \fIpid\fR.
++.TP
++.BR \-r , " \-\-raw"
++Use the raw output format.
++.TP
++.BR \-t , " \-\-type " \fItype\fP
++Display the specified \fItype\fP of namespaces only.  The supported types are
++\fBmnt\fP, \fBnet\fP, \fBipc\fP, \fBuser\fP, \fBpid\fP and \fButs\fP.  This
++option may be given more than once.
++.TP
++.BR \-u , " \-\-notruncate"
++Do not truncate text in columns.
++.TP
++.BR \-V , " \-\-version"
++Display version information and exit.
++.TP
++.BR \-h , " \-\-help"
++Display help text and exit.
++
++.SH AUTHORS
++.nf
++Karel Zak <kzak@redhat.com>
++.fi
++
++.SH "SEE ALSO"
++.BR unshare (1),
++.BR nsenter (1),
++.BR clone (2)
++
++.SH AVAILABILITY
++The lsns command is part of the util-linux package and is available from
++ftp://ftp.kernel.org/pub/linux/utils/util-linux/.
+diff --git a/sys-utils/lsns.c b/sys-utils/lsns.c
+new file mode 100644
+index 0000000..5ee2981
+--- /dev/null
++++ b/sys-utils/lsns.c
+@@ -0,0 +1,748 @@
++/*
++ * lsns(8) - list system namespaces
++ *
++ * Copyright (C) 2015 Karel Zak <kzak@redhat.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it would be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software Foundation,
++ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#include <stdio.h>
++#include <string.h>
++#include <getopt.h>
++#include <stdlib.h>
++#include <assert.h>
++#include <dirent.h>
++#include <unistd.h>
++#include <sys/stat.h>
++#include <sys/types.h>
++#include <wchar.h>
++#include <libsmartcols.h>
++
++#include "pathnames.h"
++#include "nls.h"
++#include "xalloc.h"
++#include "c.h"
++#include "list.h"
++#include "closestream.h"
++#include "optutils.h"
++#include "procutils.h"
++#include "strutils.h"
++#include "namespace.h"
++#include "path.h"
++#include "idcache.h"
++
++#include "debug.h"
++
++UL_DEBUG_DEFINE_MASK(lsns);
++UL_DEBUG_DEFINE_MASKNAMES(lsns) = UL_DEBUG_EMPTY_MASKNAMES;
++
++#define LSNS_DEBUG_INIT		(1 << 1)
++#define LSNS_DEBUG_PROC		(1 << 2)
++#define LSNS_DEBUG_NS		(1 << 3)
++#define LSNS_DEBUG_ALL		0xFFFF
++
++#define DBG(m, x)       __UL_DBG(lsns, LSNS_DEBUG_, m, x)
++#define ON_DBG(m, x)    __UL_DBG_CALL(lsns, LSNS_DEBUG_, m, x)
++
++struct idcache *uid_cache = NULL;
++
++/* column IDs */
++enum {
++	COL_NS = 0,
++	COL_TYPE,
++	COL_PATH,
++	COL_NPROCS,
++	COL_PID,
++	COL_PPID,
++	COL_COMMAND,
++	COL_UID,
++	COL_USER
++};
++
++/* column names */
++struct colinfo {
++	const char *name; /* header */
++	double	   whint; /* width hint (N < 1 is in percent of termwidth) */
++	int	   flags; /* SCOLS_FL_* */
++	const char *help;
++};
++
++/* columns descriptions */
++static const struct colinfo infos[] = {
++	[COL_NS]      = { "NS",     10, SCOLS_FL_RIGHT, N_("namespace identifier (inode number)") },
++	[COL_TYPE]    = { "TYPE",    5, 0, N_("kind of namespace") },
++	[COL_PATH]    = { "PATH",    0, 0, N_("path to the namespace")},
++	[COL_NPROCS]  = { "NPROCS",  5, SCOLS_FL_RIGHT, N_("number of processes in the namespace") },
++	[COL_PID]     = { "PID",     5, SCOLS_FL_RIGHT, N_("lowest PID in the namespace") },
++	[COL_PPID]    = { "PPID",    5, SCOLS_FL_RIGHT, N_("PPID of the PID") },
++	[COL_COMMAND] = { "COMMAND", 0, SCOLS_FL_TRUNC, N_("command line of the PID")},
++	[COL_UID]     = { "UID",     0, SCOLS_FL_RIGHT, N_("UID of the PID")},
++	[COL_USER]    = { "USER",    0, 0, N_("username of the PID")}
++};
++
++static int columns[ARRAY_SIZE(infos) * 2];
++static size_t ncolumns;
++
++enum {
++	LSNS_ID_MNT = 0,
++	LSNS_ID_NET,
++	LSNS_ID_PID,
++	LSNS_ID_UTS,
++	LSNS_ID_IPC,
++	LSNS_ID_USER
++};
++
++static char *ns_names[] = {
++	[LSNS_ID_MNT] = "mnt",
++	[LSNS_ID_NET] = "net",
++	[LSNS_ID_PID] = "pid",
++	[LSNS_ID_UTS] = "uts",
++	[LSNS_ID_IPC] = "ipc",
++	[LSNS_ID_USER] = "user"
++};
++
++struct lsns_namespace {
++	ino_t id;
++	int type;			/* LSNS_* */
++	int nprocs;
++
++	struct lsns_process *proc;
++
++	struct list_head namespaces;	/* lsns->processes member */
++	struct list_head processes;	/* head of lsns_process *siblings */
++};
++
++struct lsns_process {
++	pid_t pid;		/* process PID */
++	pid_t ppid;		/* parent's PID */
++	pid_t tpid;		/* thread group */
++	char state;
++	uid_t uid;
++
++	ino_t            ns_ids[ARRAY_SIZE(ns_names)];
++	struct list_head ns_siblings[ARRAY_SIZE(ns_names)];
++
++	struct list_head processes;	/* list of processes */
++
++	struct libscols_line *outline;
++	struct lsns_process *parent;
++};
++
++struct lsns {
++	struct list_head processes;
++	struct list_head namespaces;
++
++	pid_t	fltr_pid;	/* filter out by PID */
++	ino_t	fltr_ns;	/* filter out by namespace */
++	int	fltr_types[ARRAY_SIZE(ns_names)];
++	int	fltr_ntypes;
++
++	unsigned int raw	: 1,
++		     tree	: 1,
++		     list	: 1,
++		     notrunc	: 1,
++		     no_headings: 1;
++};
++
++static void lsns_init_debug(void)
++{
++	__UL_INIT_DEBUG(lsns, LSNS_DEBUG_, 0, LSNS_DEBUG);
++}
++
++static int ns_name2type(const char *name)
++{
++	size_t i;
++
++	for (i = 0; i < ARRAY_SIZE(ns_names); i++) {
++		if (strcmp(ns_names[i], name) == 0)
++			return i;
++	}
++	return -1;
++}
++
++static int column_name_to_id(const char *name, size_t namesz)
++{
++	size_t i;
++
++	assert(name);
++
++	for (i = 0; i < ARRAY_SIZE(infos); i++) {
++		const char *cn = infos[i].name;
++
++		if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
++			return i;
++	}
++	warnx(_("unknown column: %s"), name);
++	return -1;
++}
++
++static inline int get_column_id(int num)
++{
++	assert(num >= 0);
++	assert((size_t) num < ncolumns);
++	assert(columns[num] < (int) ARRAY_SIZE(infos));
++
++	return columns[num];
++}
++
++static inline const struct colinfo *get_column_info(unsigned num)
++{
++	return &infos[ get_column_id(num) ];
++}
++
++static ino_t get_ns_ino(int dir, const char *nsname, ino_t *ino)
++{
++	struct stat st;
++	char path[16];
++
++	snprintf(path, sizeof(path), "ns/%s", nsname);
++
++	if (fstatat(dir, path, &st, 0) != 0)
++		return -errno;
++	*ino = st.st_ino;
++	return 0;
++}
++
++
++static int read_process(struct lsns *ls, pid_t pid)
++{
++	struct lsns_process *p = NULL;
++	char buf[BUFSIZ];
++	DIR *dir;
++	int rc = 0, fd;
++	FILE *f = NULL;
++	size_t i;
++	struct stat st;
++
++	DBG(PROC, ul_debug("reading %d", (int) pid));
++
++	snprintf(buf, sizeof(buf), "/proc/%d", pid);
++	dir = opendir(buf);
++	if (!dir)
++		return -errno;
++
++	p = xcalloc(1, sizeof(*p));
++	if (!p) {
++		rc = -ENOMEM;
++		goto done;
++	}
++
++	if (fstat(dirfd(dir), &st) == 0) {
++		p->uid = st.st_uid;
++		add_uid(uid_cache, st.st_uid);
++	}
++
++	fd = openat(dirfd(dir), "stat", O_RDONLY);
++	if (fd < 0) {
++		rc = -errno;
++		goto done;
++	}
++	if (!(f = fdopen(fd, "r"))) {
++		rc = -errno;
++		goto done;
++	}
++	rc = fscanf(f, "%d %*s %c %d*[^\n]", &p->pid, &p->state, &p->ppid);
++	if (rc != 3) {
++		rc = rc < 0 ? -errno : -EINVAL;
++		goto done;
++	}
++	rc = 0;
++
++	for (i = 0; i < ARRAY_SIZE(p->ns_ids); i++) {
++		INIT_LIST_HEAD(&p->ns_siblings[i]);
++
++		if (!ls->fltr_types[i])
++			continue;
++
++		rc = get_ns_ino(dirfd(dir), ns_names[i], &p->ns_ids[i]);
++		if (rc && rc != -EACCES)
++			goto done;
++		rc = 0;
++	}
++
++	INIT_LIST_HEAD(&p->processes);
++
++	DBG(PROC, ul_debugobj(p, "new pid=%d", p->pid));
++	list_add_tail(&p->processes, &ls->processes);
++done:
++	if (f)
++		fclose(f);
++	closedir(dir);
++	if (rc)
++		free(p);
++	return rc;
++}
++
++static int read_processes(struct lsns *ls)
++{
++	struct proc_processes *proc = NULL;
++	pid_t pid;
++	int rc = 0;
++
++	DBG(PROC, ul_debug("opening /proc"));
++
++	if (!(proc = proc_open_processes())) {
++		rc = -errno;
++		goto done;
++	}
++
++	while (proc_next_pid(proc, &pid) == 0) {
++		rc = read_process(ls, pid);
++		if (rc && rc != -EACCES && rc != -ENOENT)
++			break;
++		rc = 0;
++	}
++done:
++	DBG(PROC, ul_debug("closing /proc"));
++	proc_close_processes(proc);
++	return rc;
++}
++
++static struct lsns_namespace *get_namespace(struct lsns *ls, ino_t ino)
++{
++	struct list_head *p;
++
++	list_for_each(p, &ls->namespaces) {
++		struct lsns_namespace *ns = list_entry(p, struct lsns_namespace, namespaces);
++
++		if (ns->id == ino)
++			return ns;
++	}
++	return NULL;
++}
++
++static int namespace_has_process(struct lsns_namespace *ns, pid_t pid)
++{
++	struct list_head *p;
++
++	list_for_each(p, &ns->processes) {
++		struct lsns_process *proc = list_entry(p, struct lsns_process, ns_siblings[ns->type]);
++
++		if (proc->pid == pid)
++			return 1;
++	}
++	return 0;
++}
++
++static struct lsns_namespace *add_namespace(struct lsns *ls, int type, ino_t ino)
++{
++	struct lsns_namespace *ns = xcalloc(1, sizeof(*ns));
++
++	if (!ns)
++		return NULL;
++
++	DBG(NS, ul_debugobj(ns, "new %s[%ju]", ns_names[type], (uintmax_t)ino));
++
++	INIT_LIST_HEAD(&ns->processes);
++	INIT_LIST_HEAD(&ns->namespaces);
++
++	ns->type = type;
++	ns->id = ino;
++
++	list_add_tail(&ns->namespaces, &ls->namespaces);
++	return ns;
++}
++
++static int add_process_to_namespace(struct lsns *ls, struct lsns_namespace *ns, struct lsns_process *proc)
++{
++	struct list_head *p;
++
++	DBG(NS, ul_debugobj(ns, "add process [%p] pid=%d to %s[%ju]",
++		proc, proc->pid, ns_names[ns->type], (uintmax_t)ns->id));
++
++	list_for_each(p, &ls->processes) {
++		struct lsns_process *xproc = list_entry(p, struct lsns_process, processes);
++
++		if (xproc->pid == proc->ppid)		/* my parent */
++			proc->parent = xproc;
++		else if (xproc->ppid == proc->pid)	/* my child */
++			xproc->parent = proc;
++	}
++
++	list_add_tail(&proc->ns_siblings[ns->type], &ns->processes);
++	ns->nprocs++;
++
++	if (!ns->proc || ns->proc->pid > proc->pid)
++		ns->proc = proc;
++
++	return 0;
++}
++
++static int cmp_namespaces(struct list_head *a, struct list_head *b,
++			  __attribute__((__unused__)) void *data)
++{
++	struct lsns_namespace *xa = list_entry(a, struct lsns_namespace, namespaces),
++			      *xb = list_entry(b, struct lsns_namespace, namespaces);
++
++	return cmp_numbers(xa->id, xb->id);
++}
++
++static int read_namespaces(struct lsns *ls)
++{
++	struct list_head *p;
++
++	DBG(NS, ul_debug("reading namespace"));
++
++	list_for_each(p, &ls->processes) {
++		size_t i;
++		struct lsns_namespace *ns;
++		struct lsns_process *proc = list_entry(p, struct lsns_process, processes);
++
++		for (i = 0; i < ARRAY_SIZE(proc->ns_ids); i++) {
++			if (proc->ns_ids[i] == 0)
++				continue;
++			if (!(ns = get_namespace(ls, proc->ns_ids[i]))) {
++				ns = add_namespace(ls, i, proc->ns_ids[i]);
++				if (!ns)
++					return -ENOMEM;
++			}
++			add_process_to_namespace(ls, ns, proc);
++		}
++	}
++
++	list_sort(&ls->namespaces, cmp_namespaces, NULL);
++
++	return 0;
++}
++
++static void add_scols_line(struct lsns *ls, struct libscols_table *table,
++			   struct lsns_namespace *ns, struct lsns_process *proc)
++{
++	size_t i;
++	struct libscols_line *line;
++
++	assert(ns);
++	assert(table);
++
++	line = scols_table_new_line(table,
++			ls->tree && proc->parent ? proc->parent->outline : NULL);
++	if (!line) {
++		warn(_("failed to add line to output"));
++		return;
++	}
++
++	for (i = 0; i < ncolumns; i++) {
++		char *str = NULL;
++
++		switch (get_column_id(i)) {
++		case COL_NS:
++			xasprintf(&str, "%ju", (uintmax_t)ns->id);
++			break;
++		case COL_PID:
++			xasprintf(&str, "%d", (int) proc->pid);
++			break;
++		case COL_PPID:
++			xasprintf(&str, "%d", (int) proc->ppid);
++			break;
++		case COL_TYPE:
++			xasprintf(&str, "%s", ns_names[ns->type]);
++			break;
++		case COL_NPROCS:
++			xasprintf(&str, "%d", ns->nprocs);
++			break;
++		case COL_COMMAND:
++			str = proc_get_command(proc->pid);
++			if (!str)
++				str = proc_get_command_name(proc->pid);
++			break;
++		case COL_PATH:
++			xasprintf(&str, "/proc/%d/ns/%s", (int) proc->pid, ns_names[ns->type]);
++			break;
++		case COL_UID:
++			xasprintf(&str, "%d", (int) proc->uid);
++			break;
++		case COL_USER:
++			xasprintf(&str, "%s", get_id(uid_cache, proc->uid)->name);
++			break;
++		default:
++			break;
++		}
++
++		if (str)
++			scols_line_set_data(line, i, str);
++	}
++
++	proc->outline = line;
++}
++
++static struct libscols_table *init_scols_table(struct lsns *ls)
++{
++	struct libscols_table *tab;
++	size_t i;
++
++	tab = scols_new_table();
++	if (!tab) {
++		warn(_("failed to initialize output table"));
++		return NULL;
++	}
++
++	scols_table_enable_raw(tab, ls->raw);
++	scols_table_enable_noheadings(tab, ls->no_headings);
++
++	for (i = 0; i < ncolumns; i++) {
++		const struct colinfo *col = get_column_info(i);
++		int flags = col->flags;
++
++		if (ls->notrunc)
++		       flags &= ~SCOLS_FL_TRUNC;
++		if (ls->tree && get_column_id(i) == COL_COMMAND)
++			flags |= SCOLS_FL_TREE;
++
++		if (!scols_table_new_column(tab, col->name, col->whint, flags)) {
++			warnx(_("failed to initialize output column"));
++			goto err;
++		}
++	}
++
++	return tab;
++err:
++	scols_unref_table(tab);
++	return NULL;
++}
++
++static int show_namespaces(struct lsns *ls)
++{
++	struct libscols_table *tab;
++	struct list_head *p;
++	int rc = 0;
++
++	tab = init_scols_table(ls);
++	if (!tab)
++		return -ENOMEM;
++
++	list_for_each(p, &ls->namespaces) {
++		struct lsns_namespace *ns = list_entry(p, struct lsns_namespace, namespaces);
++
++		if (ls->fltr_pid != 0 && !namespace_has_process(ns, ls->fltr_pid))
++			continue;
++
++		add_scols_line(ls, tab, ns, ns->proc);
++	}
++
++	scols_print_table(tab);
++	scols_unref_table(tab);
++	return rc;
++}
++
++static void show_process(struct lsns *ls, struct libscols_table *tab,
++			 struct lsns_process *proc, struct lsns_namespace *ns)
++{
++	/*
++	 * create a tree from parent->child relation, but only if the parent is
++	 * within the same namespace
++	 */
++	if (ls->tree
++	    && proc->parent
++	    && !proc->parent->outline
++	    && proc->parent->ns_ids[ns->type] == proc->ns_ids[ns->type])
++		show_process(ls, tab, proc->parent, ns);
++
++	add_scols_line(ls, tab, ns, proc);
++}
++
++
++static int show_namespace_processes(struct lsns *ls, struct lsns_namespace *ns)
++{
++	struct libscols_table *tab;
++	struct list_head *p;
++
++	tab = init_scols_table(ls);
++	if (!tab)
++		return -ENOMEM;
++
++	list_for_each(p, &ns->processes) {
++		struct lsns_process *proc = list_entry(p, struct lsns_process, ns_siblings[ns->type]);
++
++		if (!proc->outline)
++			show_process(ls, tab, proc, ns);
++	}
++
++
++	scols_print_table(tab);
++	scols_unref_table(tab);
++	return 0;
++}
++
++static void __attribute__ ((__noreturn__)) usage(FILE * out)
++{
++	size_t i;
++
++	fputs(USAGE_HEADER, out);
++
++	fprintf(out,
++		_(" %s [options] [<namespace>]\n"), program_invocation_short_name);
++
++	fputs(USAGE_SEPARATOR, out);
++	fputs(_("List system namespaces.\n"), out);
++
++	fputs(USAGE_OPTIONS, out);
++	fputs(_(" -l, --list             use list format output\n"), out);
++	fputs(_(" -n, --noheadings       don't print headings\n"), out);
++	fputs(_(" -o, --output <list>    define which output columns to use\n"), out);
++	fputs(_(" -p, --task <pid>       print process namespaces\n"), out);
++	fputs(_(" -r, --raw              use the raw output format\n"), out);
++	fputs(_(" -u, --notruncate       don't truncate text in columns\n"), out);
++	fputs(_(" -t, --type <name>      namespace type (mnt, net, ipc, user, pid, uts)\n"), out);
++
++	fputs(USAGE_SEPARATOR, out);
++	fputs(USAGE_HELP, out);
++	fputs(USAGE_VERSION, out);
++
++	fputs(_("\nAvailable columns (for --output):\n"), out);
++
++	for (i = 0; i < ARRAY_SIZE(infos); i++)
++		fprintf(out, " %11s  %s\n", infos[i].name, _(infos[i].help));
++
++	fprintf(out, USAGE_MAN_TAIL("lsns(8)"));
++
++	exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
++}
++
++
++int main(int argc, char *argv[])
++{
++	struct lsns ls;
++	int c;
++	int r = 0;
++	char *outarg = NULL;
++	static const struct option long_opts[] = {
++		{ "task",       required_argument, NULL, 'p' },
++		{ "help",	no_argument,       NULL, 'h' },
++		{ "output",     required_argument, NULL, 'o' },
++		{ "notruncate", no_argument,       NULL, 'u' },
++		{ "version",    no_argument,       NULL, 'V' },
++		{ "noheadings", no_argument,       NULL, 'n' },
++		{ "list",       no_argument,       NULL, 'l' },
++		{ "raw",        no_argument,       NULL, 'r' },
++		{ "type",       required_argument, NULL, 't' },
++		{ NULL, 0, NULL, 0 }
++	};
++
++	static const ul_excl_t excl[] = {	/* rows and cols in ASCII order */
++		{ 'J','r' },
++		{ 0 }
++	};
++	int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
++
++	setlocale(LC_ALL, "");
++	bindtextdomain(PACKAGE, LOCALEDIR);
++	textdomain(PACKAGE);
++	atexit(close_stdout);
++
++	lsns_init_debug();
++	memset(&ls, 0, sizeof(ls));
++
++	INIT_LIST_HEAD(&ls.processes);
++	INIT_LIST_HEAD(&ls.namespaces);
++
++	while ((c = getopt_long(argc, argv,
++				"lp:o:nruhVt:", long_opts, NULL)) != -1) {
++
++		err_exclusive_options(c, long_opts, excl, excl_st);
++
++		switch(c) {
++		case 'l':
++			ls.list = 1;
++			break;
++		case 'o':
++			outarg = optarg;
++			break;
++		case 'V':
++			printf(UTIL_LINUX_VERSION);
++			return EXIT_SUCCESS;
++		case 'p':
++			ls.fltr_pid = strtos32_or_err(optarg, _("invalid PID argument"));
++			break;
++		case 'h':
++			usage(stdout);
++		case 'n':
++			ls.no_headings = 1;
++			break;
++		case 'r':
++			ls.raw = 1;
++			break;
++		case 'u':
++			ls.notrunc = 1;
++			break;
++		case 't':
++		{
++			int type = ns_name2type(optarg);
++			if (type < 0)
++				errx(EXIT_FAILURE, _("unknown namespace type: %s"), optarg);
++			ls.fltr_types[type] = 1;
++			ls.fltr_ntypes++;
++			break;
++		}
++		case '?':
++		default:
++			usage(stderr);
++		}
++	}
++
++	if (!ls.fltr_ntypes) {
++		size_t i;
++		for (i = 0; i < ARRAY_SIZE(ns_names); i++)
++			ls.fltr_types[i] = 1;
++	}
++
++	if (optind < argc) {
++		if (ls.fltr_pid)
++			errx(EXIT_FAILURE, _("--task is mutually exclusive with <namespace>"));
++		ls.fltr_ns = strtou64_or_err(argv[optind], _("invalid namespace argument"));
++		ls.tree = ls.list ? 0 : 1;
++
++		if (!ncolumns) {
++			columns[ncolumns++] = COL_PID;
++			columns[ncolumns++] = COL_PPID;
++			columns[ncolumns++] = COL_USER;
++			columns[ncolumns++] = COL_COMMAND;
++		}
++	}
++
++	if (!ncolumns) {
++		columns[ncolumns++] = COL_NS;
++		columns[ncolumns++] = COL_TYPE;
++		columns[ncolumns++] = COL_NPROCS;
++		columns[ncolumns++] = COL_PID;
++		columns[ncolumns++] = COL_USER;
++		columns[ncolumns++] = COL_COMMAND;
++	}
++
++	if (outarg && string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns),
++					(int *) &ncolumns, column_name_to_id) < 0)
++		return EXIT_FAILURE;
++
++	scols_init_debug(0);
++
++	uid_cache = new_idcache();
++	if (!uid_cache)
++		err(EXIT_FAILURE, _("failed to allocate UID cache"));
++
++	r = read_processes(&ls);
++	if (!r)
++		r = read_namespaces(&ls);
++	if (!r) {
++		if (ls.fltr_ns) {
++			struct lsns_namespace *ns = get_namespace(&ls, ls.fltr_ns);
++
++			if (!ns)
++				errx(EXIT_FAILURE, _("not found namespace: %ju"), (uintmax_t) ls.fltr_ns);
++			r = show_namespace_processes(&ls, ns);
++		} else
++			r = show_namespaces(&ls);
++	}
++
++	free_idcache(uid_cache);
++	return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
++}
+-- 
+2.7.4
+
diff --git a/SOURCES/0077-lib-strutils-make-strmode-more-generic.patch b/SOURCES/0077-lib-strutils-make-strmode-more-generic.patch
new file mode 100644
index 0000000..5534e62
--- /dev/null
+++ b/SOURCES/0077-lib-strutils-make-strmode-more-generic.patch
@@ -0,0 +1,76 @@
+From 7bf448fe38478b6e76824fa5bbd2d2d25a48f618 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 30 Jun 2015 12:41:13 +0200
+Subject: [PATCH 77/84] lib/strutils: make strmode() more generic
+
+Upstream: http://github.com/karelzak/util-linux/commit/7015df4936ca320a86d2916533a17499ac5e4fcf
+Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1153770
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ lib/strutils.c | 36 +++++++++++++++++++-----------------
+ 1 file changed, 19 insertions(+), 17 deletions(-)
+
+diff --git a/lib/strutils.c b/lib/strutils.c
+index c263b86..f9cdcbb 100644
+--- a/lib/strutils.c
++++ b/lib/strutils.c
+@@ -349,37 +349,39 @@ void strtotimeval_or_err(const char *str, struct timeval *tv, const char *errmes
+  */
+ void strmode(mode_t mode, char *str)
+ {
++	unsigned short i = 0;
++
+ 	if (S_ISDIR(mode))
+-		str[0] = 'd';
++		str[i++] = 'd';
+ 	else if (S_ISLNK(mode))
+-		str[0] = 'l';
++		str[i++] = 'l';
+ 	else if (S_ISCHR(mode))
+-		str[0] = 'c';
++		str[i++] = 'c';
+ 	else if (S_ISBLK(mode))
+-		str[0] = 'b';
++		str[i++] = 'b';
+ 	else if (S_ISSOCK(mode))
+-		str[0] = 's';
++		str[i++] = 's';
+ 	else if (S_ISFIFO(mode))
+-		str[0] = 'p';
++		str[i++] = 'p';
+ 	else if (S_ISREG(mode))
+-		str[0] = '-';
++		str[i++] = '-';
+ 
+-	str[1] = mode & S_IRUSR ? 'r' : '-';
+-	str[2] = mode & S_IWUSR ? 'w' : '-';
+-	str[3] = (mode & S_ISUID
++	str[i++] = mode & S_IRUSR ? 'r' : '-';
++	str[i++] = mode & S_IWUSR ? 'w' : '-';
++	str[i++] = (mode & S_ISUID
+ 		? (mode & S_IXUSR ? 's' : 'S')
+ 		: (mode & S_IXUSR ? 'x' : '-'));
+-	str[4] = mode & S_IRGRP ? 'r' : '-';
+-	str[5] = mode & S_IWGRP ? 'w' : '-';
+-	str[6] = (mode & S_ISGID
++	str[i++] = mode & S_IRGRP ? 'r' : '-';
++	str[i++] = mode & S_IWGRP ? 'w' : '-';
++	str[i++] = (mode & S_ISGID
+ 		? (mode & S_IXGRP ? 's' : 'S')
+ 		: (mode & S_IXGRP ? 'x' : '-'));
+-	str[7] = mode & S_IROTH ? 'r' : '-';
+-	str[8] = mode & S_IWOTH ? 'w' : '-';
+-	str[9] = (mode & S_ISVTX
++	str[i++] = mode & S_IROTH ? 'r' : '-';
++	str[i++] = mode & S_IWOTH ? 'w' : '-';
++	str[i++] = (mode & S_ISVTX
+ 		? (mode & S_IXOTH ? 't' : 'T')
+ 		: (mode & S_IXOTH ? 'x' : '-'));
+-	str[10] = '\0';
++	str[i] = '\0';
+ }
+ 
+ /*
+-- 
+2.7.4
+
diff --git a/SOURCES/0078-lsipc-backport-new-command.patch b/SOURCES/0078-lsipc-backport-new-command.patch
new file mode 100644
index 0000000..e87be77
--- /dev/null
+++ b/SOURCES/0078-lsipc-backport-new-command.patch
@@ -0,0 +1,2000 @@
+From 9f643efe377d2a39929f19cc09e8890afc74d9a4 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Fri, 24 Jun 2016 12:57:13 +0200
+Subject: [PATCH 78/84] lsipc: backport new command
+
+Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1153770
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ bash-completion/lsipc   |   64 +++
+ configure.ac            |    6 +
+ include/xalloc.h        |    7 +
+ sys-utils/Makemodule.am |   10 +
+ sys-utils/ipcs.c        |    2 +-
+ sys-utils/ipcutils.c    |  116 ++---
+ sys-utils/ipcutils.h    |   13 +-
+ sys-utils/lsipc.1       |  133 +++++
+ sys-utils/lsipc.c       | 1316 +++++++++++++++++++++++++++++++++++++++++++++++
+ tests/functions.sh      |   16 +-
+ tests/ts/ipcs/limits2   |    9 +-
+ 11 files changed, 1613 insertions(+), 79 deletions(-)
+ create mode 100644 bash-completion/lsipc
+ create mode 100644 sys-utils/lsipc.1
+ create mode 100644 sys-utils/lsipc.c
+
+diff --git a/bash-completion/lsipc b/bash-completion/lsipc
+new file mode 100644
+index 0000000..6a87393
+--- /dev/null
++++ b/bash-completion/lsipc
+@@ -0,0 +1,64 @@
++_lsipc_module()
++{
++	local cur prev OPTS ARG
++	COMPREPLY=()
++	cur="${COMP_WORDS[COMP_CWORD]}"
++	prev="${COMP_WORDS[COMP_CWORD-1]}"
++	case $prev in
++		'-i'|'--id')
++			COMPREPLY=( $(compgen -W "id" -- $cur) )
++			return 0
++			;;
++		'-h'|'--help'|'-V'|'--version')
++			return 0
++			;;
++		'-o'|'--output')
++			local prefix realcur OUTPUT_ALL OUTPUT
++			realcur="${cur##*,}"
++			prefix="${cur%$realcur}"
++			OUTPUT_ALL="GENERAL KEY ID OWNER PERMS CUID
++			CGID UID GID CHANGE MESSAGE USEDBYTES
++			MSGS SEND RECV LSPID LRPID SHARED BYTES
++			NATTCH STATUS ATTACH DETACH CPID LPID NSEMS
++			LASTOP"
++			for WORD in $OUTPUT_ALL; do
++				if ! [[ $prefix == *"$WORD"* ]]; then
++					OUTPUT="$WORD $OUTPUT"
++				fi
++			done
++			compopt -o nospace
++			COMPREPLY=( $(compgen -P "$prefix" -W "$OUTPUT" -S ',' -- $realcur) )
++			return 0
++			;;
++	esac
++	case $cur in
++		-*)
++			OPTS="--id
++				--help
++				--version
++				--shmems
++				--queues
++				--semaphores
++				--colon-separate
++				--creator
++				--export
++				--global
++				--newline
++				--noheadings
++				--notruncate
++				--output
++				--pid
++				--print0
++				--raw
++				--time
++				--time-format"
++			COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) )
++			return 0
++			;;
++	esac
++	local IFS=$'\n'
++	compopt -o filenames
++	COMPREPLY=( $(compgen -f -- $cur) )
++	return 0
++}
++complete -F _lsipc_module lsipc
+diff --git a/configure.ac b/configure.ac
+index 5d9ea39..fe0a011 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1038,6 +1038,12 @@ UL_REQUIRES_BUILD([lsns], [libsmartcols])
+ AM_CONDITIONAL([BUILD_LSNS], [test "x$build_lsns" = xyes])
+ 
+ 
++UL_BUILD_INIT([lsipc], [check])
++UL_REQUIRES_LINUX([lsipc])
++UL_REQUIRES_BUILD([lsipc], [libsmartcols])
++AM_CONDITIONAL([BUILD_LSIPC], [test "x$build_lsipc" = xyes])
++
++
+ UL_BUILD_INIT([chcpu], [check])
+ UL_REQUIRES_LINUX([chcpu])
+ UL_REQUIRES_HAVE([chcpu], [cpu_set_t], [cpu_set_t type])
+diff --git a/include/xalloc.h b/include/xalloc.h
+index 6342793..1a1799a 100644
+--- a/include/xalloc.h
++++ b/include/xalloc.h
+@@ -19,6 +19,13 @@
+ # define XALLOC_EXIT_CODE EXIT_FAILURE
+ #endif
+ 
++static inline void __err_oom(const char *file, unsigned int line)
++{
++	err(XALLOC_EXIT_CODE, "%s: %u: cannot allocate memory", file, line);
++}
++
++#define err_oom()	__err_oom(__FILE__, __LINE__)
++
+ static inline __ul_alloc_size(1)
+ void *xmalloc(const size_t size)
+ {
+diff --git a/sys-utils/Makemodule.am b/sys-utils/Makemodule.am
+index 9baf5a3..6badd17 100644
+--- a/sys-utils/Makemodule.am
++++ b/sys-utils/Makemodule.am
+@@ -22,6 +22,16 @@ ipcs_SOURCES =	sys-utils/ipcs.c \
+ ipcs_LDADD = $(LDADD) libcommon.la
+ 
+ 
++if BUILD_LSIPC
++usrbin_exec_PROGRAMS += lsipc
++dist_man_MANS += sys-utils/lsipc.1
++lsipc_SOURCES =	sys-utils/lsipc.c \
++		sys-utils/ipcutils.c \
++		sys-utils/ipcutils.h
++lsipc_LDADD = $(LDADD) libcommon.la libsmartcols.la
++lsipc_CFLAGS = $(AM_CFLAGS) -I$(ul_libsmartcols_incdir)
++endif
++
+ usrbin_exec_PROGRAMS += renice
+ dist_man_MANS += sys-utils/renice.1
+ renice_SOURCES = sys-utils/renice.c
+diff --git a/sys-utils/ipcs.c b/sys-utils/ipcs.c
+index 14f5f0b..1843cd5 100644
+--- a/sys-utils/ipcs.c
++++ b/sys-utils/ipcs.c
+@@ -201,7 +201,7 @@ static void do_shm (char format, int unit)
+ 			       _("max seg size"), lim.shmmax, "\n", 0);
+ 		ipc_print_size(unit == IPC_UNIT_DEFAULT ? IPC_UNIT_KB : unit,
+ 			       _("max total shared memory"),
+-			       lim.shmall * getpagesize(), "\n", 0);
++			       (uint64_t) lim.shmall * getpagesize(), "\n", 0);
+ 		ipc_print_size(unit == IPC_UNIT_DEFAULT ? IPC_UNIT_BYTES : unit,
+ 			       _("min seg size"), lim.shmmin, "\n", 0);
+ 		return;
+diff --git a/sys-utils/ipcutils.c b/sys-utils/ipcutils.c
+index 62d7428..51fce7b 100644
+--- a/sys-utils/ipcutils.c
++++ b/sys-utils/ipcutils.c
+@@ -1,4 +1,3 @@
+-
+ #include <inttypes.h>
+ 
+ #include "c.h"
+@@ -54,8 +53,8 @@ int ipc_sem_get_limits(struct ipc_limits *lim)
+ 
+ 	}
+ 
+-	if (rc == 4) {
+-		struct seminfo seminfo;
++	if (rc != 4) {
++		struct seminfo seminfo = { .semmni = 0 };
+ 		union semun arg = { .array = (ushort *) &seminfo };
+ 
+ 		if (semctl(0, 0, IPC_INFO, arg) < 0)
+@@ -82,12 +81,15 @@ int ipc_shm_get_limits(struct ipc_limits *lim)
+ 		lim->shmmni = path_read_u64(_PATH_PROC_IPC_SHMMNI);
+ 
+ 	} else {
+-		struct shminfo shminfo;
++		struct shminfo *shminfo;
++		struct shmid_ds shmbuf;
+ 
+-		if (shmctl(0, IPC_INFO, (struct shmid_ds *) &shminfo) < 0)
++		if (shmctl(0, IPC_INFO, &shmbuf) < 0)
+ 			return 1;
+-		lim->shmmni = shminfo.shmmni;
+-		lim->shmall = shminfo.shmall;
++		shminfo = (struct shminfo *) &shmbuf;
++		lim->shmmni = shminfo->shmmni;
++		lim->shmall = shminfo->shmall;
++		lim->shmmax = shminfo->shmmax;
+ 	}
+ 
+ 	return 0;
+@@ -97,20 +99,24 @@ int ipc_shm_get_info(int id, struct shm_data **shmds)
+ {
+ 	FILE *f;
+ 	int i = 0, maxid;
++	char buf[BUFSIZ];
+ 	struct shm_data *p;
+-	struct shm_info dummy;
++	struct shmid_ds dummy;
+ 
+ 	p = *shmds = xcalloc(1, sizeof(struct shm_data));
+ 	p->next = NULL;
+ 
+ 	f = path_fopen("r", 0, _PATH_PROC_SYSV_SHM);
+ 	if (!f)
+-		goto fallback;
++		goto shm_fallback;
+ 
+ 	while (fgetc(f) != '\n');		/* skip header */
+ 
+-	while (feof(f) == 0) {
+-		if (fscanf(f,
++	while (fgets(buf, sizeof(buf), f) != NULL) {
++		/* scan for the first 14-16 columns (e.g. Linux 2.6.32 has 14) */
++		p->shm_rss = 0xdead;
++		p->shm_swp = 0xdead;
++		if (sscanf(buf,
+ 			  "%d %d  %o %"SCNu64 " %u %u  "
+ 			  "%"SCNu64 " %u %u %u %u %"SCNi64 " %"SCNi64 " %"SCNi64
+ 			  " %"SCNu64 " %"SCNu64 "\n",
+@@ -129,8 +135,8 @@ int ipc_shm_get_info(int id, struct shm_data **shmds)
+ 			   &p->shm_dtim,
+ 			   &p->shm_ctim,
+ 			   &p->shm_rss,
+-			   &p->shm_swp) != 16)
+-			continue;
++			   &p->shm_swp) < 14)
++			continue; /* invalid line, skipped */
+ 
+ 		if (id > -1) {
+ 			/* ID specified */
+@@ -153,28 +159,20 @@ int ipc_shm_get_info(int id, struct shm_data **shmds)
+ 	return i;
+ 
+ 	/* Fallback; /proc or /sys file(s) missing. */
+-fallback:
+-	i = id < 0 ? 0 : id;
+-
+-	maxid = shmctl(0, SHM_INFO, (struct shmid_ds *) &dummy);
+-	if (maxid < 0)
+-		return 0;
++shm_fallback:
++	maxid = shmctl(0, SHM_INFO, &dummy);
+ 
+-	while (i <= maxid) {
++	for (int j = 0; j <= maxid; j++) {
+ 		int shmid;
+ 		struct shmid_ds shmseg;
+ 		struct ipc_perm *ipcp = &shmseg.shm_perm;
+ 
+-		shmid = shmctl(i, SHM_STAT, &shmseg);
+-		if (shmid < 0) {
+-			if (-1 < id) {
+-				free(*shmds);
+-				return 0;
+-			}
+-			i++;
++		shmid = shmctl(j, SHM_STAT, &shmseg);
++		if (shmid < 0 || (id > -1 && shmid != id)) {
+ 			continue;
+ 		}
+ 
++		i++;
+ 		p->shm_perm.key = ipcp->KEY;
+ 		p->shm_perm.id = shmid;
+ 		p->shm_perm.mode = ipcp->mode;
+@@ -196,11 +194,12 @@ fallback:
+ 			p->next = xcalloc(1, sizeof(struct shm_data));
+ 			p = p->next;
+ 			p->next = NULL;
+-			i++;
+ 		} else
+-			return 1;
++			break;
+ 	}
+ 
++	if (i == 0)
++		free(*shmds);
+ 	return i;
+ }
+ 
+@@ -299,30 +298,22 @@ int ipc_sem_get_info(int id, struct sem_data **semds)
+ 	return i;
+ 
+ 	/* Fallback; /proc or /sys file(s) missing. */
+- sem_fallback:
+-	i = id < 0 ? 0 : id;
+-
++sem_fallback:
+ 	arg.array = (ushort *) (void *)&dummy;
+ 	maxid = semctl(0, 0, SEM_INFO, arg);
+-	if (maxid < 0)
+-		return 0;
+ 
+-	while (i <= maxid) {
++	for (int j = 0; j <= maxid; j++) {
+ 		int semid;
+ 		struct semid_ds semseg;
+ 		struct ipc_perm *ipcp = &semseg.sem_perm;
+ 		arg.buf = (struct semid_ds *)&semseg;
+ 
+-		semid = semctl(i, 0, SEM_STAT, arg);
+-		if (semid < 0) {
+-			if (-1 < id) {
+-				free(*semds);
+-				return 0;
+-			}
+-			i++;
++		semid = semctl(j, 0, SEM_STAT, arg);
++		if (semid < 0 || (id > -1 && semid != id)) {
+ 			continue;
+ 		}
+ 
++		i++;
+ 		p->sem_perm.key = ipcp->KEY;
+ 		p->sem_perm.id = semid;
+ 		p->sem_perm.mode = ipcp->mode;
+@@ -341,10 +332,12 @@ int ipc_sem_get_info(int id, struct sem_data **semds)
+ 			i++;
+ 		} else {
+ 			get_sem_elements(p);
+-			return 1;
++			break;
+ 		}
+ 	}
+ 
++	if (i == 0)
++		free(*semds);
+ 	return i;
+ }
+ 
+@@ -398,10 +391,6 @@ int ipc_msg_get_info(int id, struct msg_data **msgds)
+ 		if (id > -1) {
+ 			/* ID specified */
+ 			if (id == p->msg_perm.id) {
+-				/*
+-				 * FIXME: q_qbytes are not in /proc
+-				 *
+-				 */
+ 				if (msgctl(id, IPC_STAT, &msgseg) != -1)
+ 					p->q_qbytes = msgseg.msg_qbytes;
+ 				i = 1;
+@@ -422,27 +411,19 @@ int ipc_msg_get_info(int id, struct msg_data **msgds)
+ 	return i;
+ 
+ 	/* Fallback; /proc or /sys file(s) missing. */
+- msg_fallback:
+-	i = id < 0 ? 0 : id;
+-
+-	maxid = msgctl(id, MSG_STAT, &dummy);
+-	if (maxid < 0)
+-		return 0;
++msg_fallback:
++	maxid = msgctl(0, MSG_INFO, &dummy);
+ 
+-	while (i <= maxid) {
++	for (int j = 0; j <= maxid; j++) {
+ 		int msgid;
+ 		struct ipc_perm *ipcp = &msgseg.msg_perm;
+ 
+-		msgid = msgctl(i, MSG_STAT, &msgseg);
+-		if (msgid < 0) {
+-			if (-1 < id) {
+-				free(*msgds);
+-				return 0;
+-			}
+-			i++;
++		msgid = msgctl(j, MSG_STAT, &msgseg);
++		if (msgid < 0 || (id > -1 && msgid != id)) {
+ 			continue;
+ 		}
+ 
++		i++;
+ 		p->msg_perm.key = ipcp->KEY;
+ 		p->msg_perm.id = msgid;
+ 		p->msg_perm.mode = ipcp->mode;
+@@ -463,11 +444,12 @@ int ipc_msg_get_info(int id, struct msg_data **msgds)
+ 			p->next = xcalloc(1, sizeof(struct msg_data));
+ 			p = p->next;
+ 			p->next = NULL;
+-			i++;
+ 		} else
+-			return 1;
++			break;
+ 	}
+ 
++	if (i == 0)
++		free(*msgds);
+ 	return i;
+ }
+ 
+@@ -508,10 +490,10 @@ void ipc_print_perms(FILE *f, struct ipc_stat *is)
+ 		fprintf(f, " %-10u\n", is->gid);
+ }
+ 
+-void ipc_print_size(int unit, char *msg, size_t size, const char *end,
++void ipc_print_size(int unit, char *msg, uint64_t size, const char *end,
+ 		    int width)
+ {
+-	char format[16];
++	char format[32];
+ 
+ 	if (!msg)
+ 		/* NULL */ ;
+@@ -527,11 +509,11 @@ void ipc_print_size(int unit, char *msg, size_t size, const char *end,
+ 	switch (unit) {
+ 	case IPC_UNIT_DEFAULT:
+ 	case IPC_UNIT_BYTES:
+-		sprintf(format, "%%%dzu", width);
++		sprintf(format, "%%%dju", width);
+ 		printf(format, size);
+ 		break;
+ 	case IPC_UNIT_KB:
+-		sprintf(format, "%%%dzu", width);
++		sprintf(format, "%%%dju", width);
+ 		printf(format, size / 1024);
+ 		break;
+ 	case IPC_UNIT_HUMAN:
+diff --git a/sys-utils/ipcutils.h b/sys-utils/ipcutils.h
+index d2e5972..444065a 100644
+--- a/sys-utils/ipcutils.h
++++ b/sys-utils/ipcutils.h
+@@ -12,6 +12,7 @@
+ #include <unistd.h>
+ #include <grp.h>
+ #include <pwd.h>
++#include <stdint.h>
+ 
+ /*
+  * SHM_DEST and SHM_LOCKED are defined in kernel headers, but inside
+@@ -34,11 +35,11 @@
+ # define SHM_INFO	14
+ struct shm_info {
+ 	int used_ids;
+-	ulong shm_tot;		/* total allocated shm */
+-	ulong shm_rss;		/* total resident shm */
+-	ulong shm_swp;		/* total swapped shm */
+-	ulong swap_attempts;
+-	ulong swap_successes;
++	unsigned long shm_tot;		/* total allocated shm */
++	unsigned long shm_rss;		/* total resident shm */
++	unsigned long shm_swp;		/* total swapped shm */
++	unsigned long swap_attempts;
++	unsigned long swap_successes;
+ };
+ #endif
+ 
+@@ -118,7 +119,7 @@ struct ipc_stat {
+ };
+ 
+ extern void ipc_print_perms(FILE *f, struct ipc_stat *is);
+-extern void ipc_print_size(int unit, char *msg, size_t size, const char *end, int width);
++extern void ipc_print_size(int unit, char *msg, uint64_t size, const char *end, int width);
+ 
+ /* See 'struct shmid_kernel' in kernel sources
+  */
+diff --git a/sys-utils/lsipc.1 b/sys-utils/lsipc.1
+new file mode 100644
+index 0000000..98449cb
+--- /dev/null
++++ b/sys-utils/lsipc.1
+@@ -0,0 +1,133 @@
++.\" Copyright 2015 Ondrej Oprala(ooprala@redhat.com)
++.\" May be distributed under the GNU General Public License
++.TH LSIPC "1" "November 2015" "util-linux" "User Commands"
++.SH NAME
++lsipc \- show information on IPC facilities currently employed in the system
++.SH SYNOPSIS
++.B lsipc
++[options]
++.SH DESCRIPTION
++.B lsipc
++shows information on the inter-process communication facilities
++for which the calling process has read access.
++.SH OPTIONS
++.TP
++\fB\-i\fR, \fB\-\-id\fR \fIid\fR
++Show full details on just the one resource element identified by
++.IR id .
++This option needs to be combined with one of the three resource options:
++.BR \-m ,
++.BR \-q " or"
++.BR \-s .
++It is possible to override the default output format for this option with the
++\fB\-\-list\fR, \fB\-\-raw\fR, \fB\-\-json\fR or \fB\-\-export\fR option.
++.TP
++\fB\-g\fR, \fB\-\-global\fR
++Show system-wide usage and limits of IPC resources.
++This option may be combined with one of the three resource options:
++.BR \-m ,
++.BR \-q " or"
++.BR \-s .
++The default is to show information about all resources.
++.TP
++\fB\-h\fR, \fB\-\-help\fR
++Display help text and exit.
++.TP
++\fB\-V\fR, \fB\-\-version\fR
++Display version information and exit.
++.SS "Resource options"
++.TP
++\fB\-m\fR, \fB\-\-shmems\fR
++Write information about active shared memory segments.
++.TP
++\fB\-q\fR, \fB\-\-queues\fR
++Write information about active message queues.
++.TP
++\fB\-s\fR, \fB\-\-semaphores\fR
++Write information about active semaphore sets.
++.SS "Output formatting"
++.TP
++\fB\-c\fR, \fB\-\-creator\fR
++Show creator and owner.
++.TP
++\fB\-e\fR, \fB\-\-export\fR
++Output data in the format of NAME=VALUE.
++.TP
++\fB\-l\fR, \fB\-\-list\fR
++Use the list output format.  This is the default, except when \fB\-\-id\fR
++is used.
++.TP
++\fB\-n\fR, \fB\-\-newline\fR
++Display each piece of information on a separate line.
++.TP
++\fB\-\-noheadings\fR
++Do not print a header line.
++.TP
++\fB\-\-notruncate\fR
++Don't truncate output.
++.TP
++\fB\-o\fR, \fB\-\-output \fIlist\fP
++Specify which output columns to print.  Use
++.B \-\-help
++to get a list of all supported columns.
++.TP
++\fB\-p\fR, \fB\-\-pid\fR
++Show PIDs of creator and last operator.
++.TP
++\fB\-r\fR, \fB\-\-raw\fR
++Raw output (no columnation).
++.TP
++\fB\-t\fR, \fB\-\-time\fR
++Write time information.  The time of the last control operation that changed
++the access permissions for all facilities, the time of the last
++.I msgsnd()
++and
++.I msgrcv()
++operations on message queues, the time of the last
++.I shmat()
++and
++.I shmdt()
++operations on shared memory, and the time of the last
++.I semop()
++operation on semaphores.
++.TP
++\fB\-\-time\-format\fR \fItype\fP
++Display dates in short, full or iso format.  The default is short, this time
++format is designed to be space efficient and human readable.
++
++.SH EXIT STATUS
++.TP
++0
++if OK,
++.TP
++1
++if incorrect arguments specified,
++.TP
++2
++if a serious error occurs.
++.SH SEE ALSO
++.BR ipcrm (1),
++.BR ipcmk (1),
++.BR msgrcv (2),
++.BR msgsnd (2),
++.BR semget (2),
++.BR semop (2),
++.BR shmat (2),
++.BR shmdt (2),
++.BR shmget (2)
++.SH HISTORY
++The \fBlsipc\fP utility is inspired by the \fBipcs\fP utility.
++.SH AUTHORS
++.MT ooprala@redhat.com
++Ondrej Oprala
++.ME
++.br
++.MT kzak@redhat.com
++Karel Zak
++.ME
++
++.SH AVAILABILITY
++The lsipc command is part of the util-linux package and is available from
++.UR ftp://\:ftp.kernel.org\:/pub\:/linux\:/utils\:/util-linux/
++Linux Kernel Archive
++.UE .
+diff --git a/sys-utils/lsipc.c b/sys-utils/lsipc.c
+new file mode 100644
+index 0000000..0be9d91
+--- /dev/null
++++ b/sys-utils/lsipc.c
+@@ -0,0 +1,1316 @@
++/*
++ * lsipc - List information about IPC instances employed in the system
++ *
++ * Copyright (C) 2015 Ondrej Oprala <ooprala@redhat.com>
++ * Copyright (C) 2015 Karel Zak <ooprala@redhat.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it would 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.
++ *
++ *
++ * lsipc is inspired by the ipcs utility. The aim is to create
++ * a utility unencumbered by a standard to provide more flexible
++ * means of controlling the output.
++ */
++
++#include <errno.h>
++#include <getopt.h>
++#include <sys/time.h>
++#include <unistd.h>
++
++#include <libsmartcols.h>
++
++#include "c.h"
++#include "nls.h"
++#include "closestream.h"
++#include "strutils.h"
++#include "optutils.h"
++#include "xalloc.h"
++#include "procutils.h"
++#include "ipcutils.h"
++
++/*
++ * time modes
++ * */
++enum {
++	TIME_INVALID = 0,
++	TIME_SHORT,
++	TIME_FULL,
++	TIME_ISO
++};
++
++/*
++ * IDs
++ */
++enum {
++	/* generic */
++	COLDESC_IDX_GEN_FIRST = 0,
++		COL_KEY = COLDESC_IDX_GEN_FIRST,
++		COL_ID,
++		COL_OWNER,
++		COL_PERMS,
++		COL_CUID,
++		COL_CUSER,
++		COL_CGID,
++		COL_CGROUP,
++		COL_UID,
++		COL_USER,
++		COL_GID,
++		COL_GROUP,
++		COL_CTIME,
++	COLDESC_IDX_GEN_LAST = COL_CTIME,
++
++	/* msgq-specific */
++	COLDESC_IDX_MSG_FIRST,
++		COL_USEDBYTES = COLDESC_IDX_MSG_FIRST,
++		COL_MSGS,
++		COL_SEND,
++		COL_RECV,
++		COL_LSPID,
++		COL_LRPID,
++	COLDESC_IDX_MSG_LAST = COL_LRPID,
++
++	/* shm-specific */
++	COLDESC_IDX_SHM_FIRST,
++		COL_SIZE = COLDESC_IDX_SHM_FIRST,
++		COL_NATTCH,
++		COL_STATUS,
++		COL_ATTACH,
++		COL_DETACH,
++		COL_COMMAND,
++		COL_CPID,
++		COL_LPID,
++	COLDESC_IDX_SHM_LAST = COL_LPID,
++
++	/* sem-specific */
++	COLDESC_IDX_SEM_FIRST,
++		COL_NSEMS = COLDESC_IDX_SEM_FIRST,
++		COL_OTIME,
++	COLDESC_IDX_SEM_LAST = COL_OTIME,
++
++	/* summary (--global) */
++	COLDESC_IDX_SUM_FIRST,
++		COL_RESOURCE = COLDESC_IDX_SUM_FIRST,
++		COL_DESC,
++		COL_LIMIT,
++		COL_USED,
++		COL_USEPERC,
++	COLDESC_IDX_SUM_LAST = COL_USEPERC
++};
++
++/* not all columns apply to all options, so we specify a legal range for each */
++static size_t LOWER, UPPER;
++
++/*
++ * output modes
++ */
++enum {
++	OUT_EXPORT = 1,
++	OUT_NEWLINE,
++	OUT_RAW,
++	OUT_PRETTY,
++	OUT_LIST
++};
++
++struct lsipc_control {
++	int outmode;
++	unsigned int noheadings : 1,		/* don't print header line */
++		     notrunc : 1,		/* don't truncate columns */
++		     bytes : 1,			/* SIZE in bytes */
++		     numperms : 1,		/* numeric permissions */
++		     time_mode : 2;
++};
++
++struct lsipc_coldesc {
++	const char *name;
++	const char *help;
++	const char *pretty_name;
++
++	double whint;	/* width hint */
++	long flag;
++};
++
++static const struct lsipc_coldesc coldescs[] =
++{
++	/* common */
++	[COL_KEY]	= { "KEY",	N_("Resource key"), N_("Key"), 1},
++	[COL_ID]	= { "ID",	N_("Resource ID"), N_("ID"), 1},
++	[COL_OWNER]	= { "OWNER",	N_("Owner's username or UID"), N_("Owner"), 1, SCOLS_FL_RIGHT},
++	[COL_PERMS]	= { "PERMS",	N_("Permissions"), N_("Permissions"), 1, SCOLS_FL_RIGHT},
++	[COL_CUID]	= { "CUID",	N_("Creator UID"), N_("Creator UID"), 1, SCOLS_FL_RIGHT},
++	[COL_CUSER]     = { "CUSER",    N_("Creator user"), N_("Creator user"), 1 },
++	[COL_CGID]	= { "CGID",	N_("Creator GID"), N_("Creator GID"), 1, SCOLS_FL_RIGHT},
++	[COL_CGROUP]    = { "CGROUP",   N_("Creator group"), N_("Creator group"), 1 },
++	[COL_UID]	= { "UID",	N_("User ID"), N_("UID"), 1, SCOLS_FL_RIGHT},
++	[COL_USER]	= { "USER",	N_("User name"), N_("User name"), 1},
++	[COL_GID]	= { "GID",	N_("Group ID"), N_("GID"), 1, SCOLS_FL_RIGHT},
++	[COL_GROUP]	= { "GROUP",	N_("Group name"), N_("Group name"), 1},
++	[COL_CTIME]	= { "CTIME",	N_("Time of the last change"), N_("Last change"), 1, SCOLS_FL_RIGHT},
++
++	/* msgq-specific */
++	[COL_USEDBYTES]	= { "USEDBYTES",N_("Bytes used"), N_("Bytes used"), 1, SCOLS_FL_RIGHT},
++	[COL_MSGS]	= { "MSGS",	N_("Number of messages"), N_("Messages"), 1},
++	[COL_SEND]	= { "SEND",	N_("Time of last msg sent"), N_("Msg sent"), 1, SCOLS_FL_RIGHT},
++	[COL_RECV]	= { "RECV",	N_("Time of last msg received"), N_("Msg received"), 1, SCOLS_FL_RIGHT},
++	[COL_LSPID]	= { "LSPID",	N_("PID of the last msg sender"), N_("Msg sender"), 1, SCOLS_FL_RIGHT},
++	[COL_LRPID]	= { "LRPID",	N_("PID of the last msg receiver"), N_("Msg receiver"), 1, SCOLS_FL_RIGHT},
++
++	/* shm-specific */
++	[COL_SIZE]	= { "SIZE",	N_("Segment size"), N_("Segment size"), 1, SCOLS_FL_RIGHT},
++	[COL_NATTCH]	= { "NATTCH",	N_("Number of attached processes"), N_("Attached processes"), 1, SCOLS_FL_RIGHT},
++	[COL_STATUS]	= { "STATUS",	N_("Status"), N_("Status"), 1, SCOLS_FL_NOEXTREMES},
++	[COL_ATTACH]	= { "ATTACH",	N_("Attach time"), N_("Attach time"), 1, SCOLS_FL_RIGHT},
++	[COL_DETACH]	= { "DETACH",	N_("Detach time"), N_("Detach time"), 1, SCOLS_FL_RIGHT},
++	[COL_COMMAND]	= { "COMMAND",  N_("Creator command line"), N_("Creator command"), 0, SCOLS_FL_TRUNC},
++	[COL_CPID]	= { "CPID",	N_("PID of the creator"), N_("Creator PID"), 1, SCOLS_FL_RIGHT},
++	[COL_LPID]	= { "LPID",	N_("PID of last user"), N_("Last user PID"), 1, SCOLS_FL_RIGHT},
++
++	/* sem-specific */
++	[COL_NSEMS]	= { "NSEMS",	N_("Number of semaphores"), N_("Semaphores"), 1, SCOLS_FL_RIGHT},
++	[COL_OTIME]	= { "OTIME",	N_("Time of the last operation"), N_("Last operation"), 1, SCOLS_FL_RIGHT},
++
++	/* cols for summarized information */
++	[COL_RESOURCE]  = { "RESOURCE", N_("Resource name"), N_("Resource"), 1 },
++	[COL_DESC]      = { "DESCRIPTION",N_("Resource description"), N_("Description"), 1 },
++	[COL_USED]      = { "USED",     N_("Currently used"), N_("Used"), 1, SCOLS_FL_RIGHT },
++	[COL_USEPERC]	= { "USE%",     N_("Currently use percentage"), N_("Use"), 1, SCOLS_FL_RIGHT },
++	[COL_LIMIT]     = { "LIMIT",    N_("System-wide limit"), N_("Limit"), 1, SCOLS_FL_RIGHT },
++};
++
++
++/* columns[] array specifies all currently wanted output column. The columns
++ * are defined by coldescs[] array and you can specify (on command line) each
++ * column twice. That's enough, dynamically allocated array of the columns is
++ * unnecessary overkill and over-engineering in this case */
++static int columns[ARRAY_SIZE(coldescs) * 2];
++static size_t ncolumns;
++
++static inline size_t err_columns_index(size_t arysz, size_t idx)
++{
++	if (idx >= arysz)
++		errx(EXIT_FAILURE, _("too many columns specified, "
++				     "the limit is %zu columns"),
++				arysz - 1);
++	return idx;
++}
++
++#define add_column(ary, n, id)	\
++		((ary)[ err_columns_index(ARRAY_SIZE(ary), (n)) ] = (id))
++
++static int column_name_to_id(const char *name, size_t namesz)
++{
++	size_t i;
++
++	for (i = 0; i < ARRAY_SIZE(coldescs); i++) {
++		const char *cn = coldescs[i].name;
++
++		if (!strncasecmp(name, cn, namesz) && !*(cn + namesz)) {
++			if (i > COL_CTIME) {
++				if (i >= LOWER && i <= UPPER)
++					return i;
++				else {
++					warnx(_("column %s does not apply to the specified IPC"), name);
++					return -1;
++				}
++			} else
++				return i;
++		}
++	}
++	warnx(_("unknown column: %s"), name);
++	return -1;
++}
++
++static char *get_username(struct passwd **pw, uid_t id)
++{
++	if (!*pw || (*pw)->pw_uid != id)
++		*pw = getpwuid(id);
++
++	return *pw ? xstrdup((*pw)->pw_name) : NULL;
++}
++
++static char *get_groupname(struct group **gr, gid_t id)
++{
++	if (!*gr || (*gr)->gr_gid != id)
++		*gr = getgrgid(id);
++
++	return *gr ? xstrdup((*gr)->gr_name) : NULL;
++}
++
++static int parse_time_mode(const char *optarg)
++{
++	struct lsipc_timefmt {
++		const char *name;
++		const int val;
++	};
++	static const struct lsipc_timefmt timefmts[] = {
++		{"iso", TIME_ISO},
++		{"full", TIME_FULL},
++		{"short", TIME_SHORT},
++	};
++	size_t i;
++
++	for (i = 0; i < ARRAY_SIZE(timefmts); i++) {
++		if (strcmp(timefmts[i].name, optarg) == 0)
++			return timefmts[i].val;
++	}
++	errx(EXIT_FAILURE, _("unknown time format: %s"), optarg);
++}
++
++static void __attribute__ ((__noreturn__)) usage(FILE * out)
++{
++	size_t i;
++
++	fputs(USAGE_HEADER, out);
++	fprintf(out, _(" %s [options]\n"), program_invocation_short_name);
++
++	fputs(USAGE_SEPARATOR, out);
++	fputs(_("Show information on IPC facilities.\n"), out);
++
++	fputs(USAGE_SEPARATOR, out);
++	fputs(_("Resource options:\n"), out);
++	fputs(_(" -m, --shmems      shared memory segments\n"), out);
++	fputs(_(" -q, --queues      message queues\n"), out);
++	fputs(_(" -s, --semaphores  semaphores\n"), out);
++	fputs(_(" -g, --global      info about system-wide usage (may be used with -m, -q and -s)\n"), out);
++	fputs(_(" -i, --id <id>     print details on resource identified by <id>\n"), out);
++
++	fputs(USAGE_OPTIONS, out);
++	fputs(_("     --noheadings         don't print headings\n"), out);
++	fputs(_("     --notruncate         don't truncate output\n"), out);
++	fputs(_("     --time-format=<type> display dates in short, full or iso format\n"), out);
++	fputs(_(" -b, --bytes              print SIZE in bytes rather than in human readable format\n"), out);
++	fputs(_(" -c, --creator            show creator and owner\n"), out);
++	fputs(_(" -e, --export             display in an export-able output format\n"), out);
++	fputs(_(" -n, --newline            display each piece of information on a new line\n"), out);
++	fputs(_(" -l, --list               force list output format (for example with --id)\n"), out);
++	fputs(_(" -o, --output[=<list>]    define the columns to output\n"), out);
++	fputs(_(" -P, --numeric-perms      print numeric permissions (PERMS column)\n"), out);
++	fputs(_(" -r, --raw                display in raw mode\n"), out);
++	fputs(_(" -t, --time               show attach, detach and change times\n"), out);
++
++	fputs(USAGE_SEPARATOR, out);
++	fputs(USAGE_HELP, out);
++	fputs(USAGE_VERSION, out);
++
++	fprintf(out, _("\nGeneric columns:\n"));
++	for (i = COLDESC_IDX_GEN_FIRST; i <= COLDESC_IDX_GEN_LAST; i++)
++		fprintf(out, " %14s  %s\n", coldescs[i].name, _(coldescs[i].help));
++
++	fprintf(out, _("\nShared-memory columns (--shmems):\n"));
++	for (i = COLDESC_IDX_SHM_FIRST; i <= COLDESC_IDX_SHM_LAST; i++)
++		fprintf(out, " %14s  %s\n", coldescs[i].name, _(coldescs[i].help));
++
++	fprintf(out, _("\nMessage-queue columns (--queues):\n"));
++	for (i = COLDESC_IDX_MSG_FIRST; i <= COLDESC_IDX_MSG_LAST; i++)
++		fprintf(out, " %14s  %s\n", coldescs[i].name, _(coldescs[i].help));
++
++	fprintf(out, _("\nSemaphore columns (--semaphores):\n"));
++	for (i = COLDESC_IDX_SEM_FIRST; i <= COLDESC_IDX_SEM_LAST; i++)
++		fprintf(out, " %14s  %s\n", coldescs[i].name, _(coldescs[i].help));
++
++	fprintf(out, _("\nSummary columns (--global):\n"));
++	for (i = COLDESC_IDX_SUM_FIRST; i <= COLDESC_IDX_SUM_LAST; i++)
++		fprintf(out, " %14s  %s\n", coldescs[i].name, _(coldescs[i].help));
++
++	fprintf(out, USAGE_MAN_TAIL("lsipc(1)"));
++	exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
++}
++
++static struct libscols_table *new_table(struct lsipc_control *ctl)
++{
++	struct libscols_table *table = scols_new_table();
++
++	if (!table)
++		errx(EXIT_FAILURE, _("failed to initialize output table"));
++	if (ctl->noheadings)
++		scols_table_enable_noheadings(table, 1);
++
++	switch(ctl->outmode) {
++	case OUT_NEWLINE:
++		scols_table_set_column_separator(table, "\n");
++		/* fallthrough */
++	case OUT_EXPORT:
++		scols_table_enable_export(table, 1);
++		break;
++	case OUT_RAW:
++		scols_table_enable_raw(table, 1);
++		break;
++	case OUT_PRETTY:
++		scols_table_enable_noheadings(table, 1);
++		break;
++	default:
++		break;
++	}
++	return table;
++}
++
++static struct libscols_table *setup_table(struct lsipc_control *ctl)
++{
++	struct libscols_table *table = new_table(ctl);
++	size_t n;
++
++	for (n = 0; n < ncolumns; n++) {
++		int flags = coldescs[columns[n]].flag;
++
++		if (ctl->notrunc)
++			flags &= ~SCOLS_FL_TRUNC;
++
++		if (!scols_table_new_column(table,
++				coldescs[columns[n]].name,
++				coldescs[columns[n]].whint,
++				flags))
++			goto fail;
++	}
++	return table;
++fail:
++	scols_unref_table(table);
++	return NULL;
++}
++
++static int print_pretty(struct libscols_table *table)
++{
++	struct libscols_iter *itr = scols_new_iter(SCOLS_ITER_FORWARD);
++	struct libscols_column *col;
++	struct libscols_cell *data;
++	struct libscols_line *ln;
++	const char *hstr, *dstr;
++	int n = 0;
++
++	ln = scols_table_get_line(table, 0);
++	while (!scols_table_next_column(table, itr, &col)) {
++
++		data = scols_line_get_cell(ln, n);
++
++		hstr = N_(coldescs[columns[n]].pretty_name);
++		dstr = scols_cell_get_data(data);
++
++		if (dstr)
++			printf("%s:%*c%-36s\n", hstr, 35 - (int)strlen(hstr), ' ', dstr);
++		++n;
++	}
++
++	/* this is used to pretty-print detailed info about a semaphore array */
++	if (ln) {
++		struct libscols_table *subtab = scols_line_get_userdata(ln);
++		if (subtab) {
++			printf(_("Elements:\n\n"));
++			scols_print_table(subtab);
++		}
++	}
++
++	scols_free_iter(itr);
++	return 0;
++
++}
++
++static int print_table(struct lsipc_control *ctl, struct libscols_table *tb)
++{
++	if (ctl->outmode == OUT_PRETTY)
++		print_pretty(tb);
++	else
++		scols_print_table(tb);
++	return 0;
++}
++static struct timeval now;
++
++static int date_is_today(time_t t)
++{
++	if (now.tv_sec == 0)
++		gettimeofday(&now, NULL);
++	return t / (3600 * 24) == now.tv_sec / (3600 * 24);
++}
++
++static int date_is_thisyear(time_t t)
++{
++	if (now.tv_sec == 0)
++		gettimeofday(&now, NULL);
++	return t / (3600 * 24 * 365) == now.tv_sec / (3600 * 24 * 365);
++}
++
++static char *make_time(int mode, time_t time)
++{
++	char *s;
++	struct tm tm;
++	char buf[64] = {0};
++
++	localtime_r(&time, &tm);
++
++	switch(mode) {
++	case TIME_FULL:
++		asctime_r(&tm, buf);
++		if (*(s = buf + strlen(buf) - 1) == '\n')
++			*s = '\0';
++		break;
++	case TIME_SHORT:
++		if (date_is_today(time))
++			strftime(buf, sizeof(buf), "%H:%M", &tm);
++		else if (date_is_thisyear(time))
++			strftime(buf, sizeof(buf), "%b%d", &tm);
++		else
++			strftime(buf, sizeof(buf), "%Y-%b%d", &tm);
++		break;
++	case TIME_ISO:
++		strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", &tm);
++		break;
++	default:
++		errx(EXIT_FAILURE, _("unsupported time type"));
++	}
++	return xstrdup(buf);
++}
++
++static void global_set_data(struct libscols_table *tb, const char *resource,
++			    const char *desc, uintmax_t used, uintmax_t limit, int usage)
++{
++	struct libscols_line *ln;
++	size_t n;
++
++	ln = scols_table_new_line(tb, NULL);
++	if (!ln)
++		err_oom();
++
++	for (n = 0; n < ncolumns; n++) {
++		int rc = 0;
++		char *arg = NULL;
++
++		switch (columns[n]) {
++		case COL_RESOURCE:
++			rc = scols_line_set_data(ln, n, resource);
++			break;
++		case COL_DESC:
++			rc = scols_line_set_data(ln, n, desc);
++			break;
++		case COL_USED:
++			if (usage) {
++				xasprintf(&arg, "%ju", used);
++				rc = scols_line_refer_data(ln, n, arg);
++			} else
++				rc = scols_line_set_data(ln, n, "-");
++			break;
++		case COL_USEPERC:
++			if (usage) {
++				xasprintf(&arg, "%2.2f%%", (double) used / limit * 100);
++				rc = scols_line_refer_data(ln, n, arg);
++			} else
++				rc = scols_line_set_data(ln, n, "-");
++			break;
++		case COL_LIMIT:
++			xasprintf(&arg, "%ju", limit);
++			rc = scols_line_refer_data(ln, n, arg);
++			break;
++		}
++
++		if (rc != 0)
++			err(EXIT_FAILURE, _("failed to set data"));
++	}
++}
++
++static void setup_sem_elements_columns(struct libscols_table *tb)
++{
++	if (!scols_table_new_column(tb, "SEMNUM", 0, SCOLS_FL_RIGHT))
++		err_oom();
++	if (!scols_table_new_column(tb, "VALUE", 0, SCOLS_FL_RIGHT))
++		err_oom();
++	if (!scols_table_new_column(tb, "NCOUNT", 0, SCOLS_FL_RIGHT))
++		err_oom();
++	if (!scols_table_new_column(tb, "ZCOUNT", 0, SCOLS_FL_RIGHT))
++		err_oom();
++	if (!scols_table_new_column(tb, "PID", 0, SCOLS_FL_RIGHT))
++		err_oom();
++	if (!scols_table_new_column(tb, "COMMAND", 0, SCOLS_FL_RIGHT))
++		err_oom();
++}
++
++static void do_sem(int id, struct lsipc_control *ctl, struct libscols_table *tb)
++{
++	struct libscols_line *ln;
++	struct passwd *pw = NULL, *cpw = NULL;
++	struct group *gr = NULL, *cgr = NULL;
++	struct sem_data *semds, *semdsp;
++	char *arg = NULL;
++
++	if (ipc_sem_get_info(id, &semds) < 1) {
++		if (id > -1)
++			warnx(_("id %d not found"), id);
++		return;
++	}
++	for (semdsp = semds;  semdsp->next != NULL || id > -1; semdsp = semdsp->next) {
++		size_t n;
++		ln = scols_table_new_line(tb, NULL);
++
++		for (n = 0; n < ncolumns; n++) {
++			int rc = 0;
++			switch (columns[n]) {
++			case COL_KEY:
++				xasprintf(&arg, "0x%08x",semdsp->sem_perm.key);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_ID:
++				xasprintf(&arg, "%d",semdsp->sem_perm.id);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_OWNER:
++				arg = get_username(&pw, semdsp->sem_perm.uid);
++				if (!arg)
++					xasprintf(&arg, "%u", semdsp->sem_perm.uid);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_PERMS:
++				if (ctl->numperms)
++					xasprintf(&arg, "%#o", semdsp->sem_perm.mode & 0777);
++				else {
++					arg = xmalloc(11);
++					strmode(semdsp->sem_perm.mode & 0777, arg);
++				}
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_CUID:
++				xasprintf(&arg, "%u", semdsp->sem_perm.cuid);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_CUSER:
++				arg = get_username(&cpw, semdsp->sem_perm.cuid);
++				if (arg)
++					rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_CGID:
++				xasprintf(&arg, "%u", semdsp->sem_perm.cgid);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_CGROUP:
++				arg = get_groupname(&cgr, semdsp->sem_perm.cgid);
++				if (arg)
++					rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_UID:
++				xasprintf(&arg, "%u", semdsp->sem_perm.uid);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_USER:
++				arg = get_username(&pw, semdsp->sem_perm.uid);
++				if (arg)
++					rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_GID:
++				xasprintf(&arg, "%u", semdsp->sem_perm.gid);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_GROUP:
++				arg = get_groupname(&gr, semdsp->sem_perm.gid);
++				if (arg)
++					rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_CTIME:
++				if (semdsp->sem_ctime != 0) {
++					rc = scols_line_refer_data(ln, n,
++							make_time(ctl->time_mode,
++							  (time_t)semdsp->sem_ctime));
++				}
++				break;
++			case COL_NSEMS:
++				xasprintf(&arg, "%ju", semdsp->sem_nsems);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_OTIME:
++				if (semdsp->sem_otime != 0) {
++					rc = scols_line_refer_data(ln, n,
++							make_time(ctl->time_mode,
++							  (time_t)semdsp->sem_otime));
++				}
++				break;
++			}
++			if (rc != 0)
++				err(EXIT_FAILURE, _("failed to set data"));
++			arg = NULL;
++		}
++
++		if (id > -1 && semds->sem_nsems) {
++			/* Create extra table with ID specific semaphore elements */
++			struct libscols_table *sub = new_table(ctl);
++			size_t i;
++			int rc = 0;
++
++			scols_table_enable_noheadings(sub, 0);
++			setup_sem_elements_columns(sub);
++
++			for (i = 0; i < semds->sem_nsems; i++) {
++				struct sem_elem *e = &semds->elements[i];
++				struct libscols_line *sln = scols_table_new_line(sub, NULL);
++
++				/* SEMNUM */
++				xasprintf(&arg, "%zu", i);
++				rc = scols_line_refer_data(sln, 0, arg);
++				if (rc)
++					break;
++
++				/* VALUE */
++				xasprintf(&arg, "%d", e->semval);
++				rc = scols_line_refer_data(sln, 1, arg);
++				if (rc)
++					break;
++
++				/* NCOUNT */
++				xasprintf(&arg, "%d", e->ncount);
++				rc = scols_line_refer_data(sln, 2, arg);
++				if (rc)
++					break;
++
++				/* ZCOUNT */
++				xasprintf(&arg, "%d", e->zcount);
++				rc = scols_line_refer_data(sln, 3, arg);
++				if (rc)
++					break;
++
++				/* PID */
++				xasprintf(&arg, "%d", e->pid);
++				rc = scols_line_refer_data(sln, 4, arg);
++				if (rc)
++					break;
++
++				/* COMMAND */
++				arg = proc_get_command(e->pid);
++				rc = scols_line_refer_data(sln, 5, arg);
++				if (rc)
++					break;
++			}
++
++			if (rc != 0)
++				err(EXIT_FAILURE, _("failed to set data"));
++
++			scols_line_set_userdata(ln, (void *)sub);
++			break;
++		}
++	}
++	ipc_sem_free_info(semds);
++}
++
++static void do_sem_global(struct libscols_table *tb)
++{
++	struct sem_data *semds, *semdsp;
++	struct ipc_limits lim;
++	int nsems = 0, nsets = 0;
++
++	ipc_sem_get_limits(&lim);
++
++	if (ipc_sem_get_info(-1, &semds) > 0) {
++		for (semdsp = semds; semdsp->next != NULL; semdsp = semdsp->next) {
++			++nsets;
++			nsems += semds->sem_nsems;
++		}
++		ipc_sem_free_info(semds);
++	}
++
++	global_set_data(tb, "SEMMNI", _("Number of semaphore identifiers"), nsets, lim.semmni, 1);
++	global_set_data(tb, "SEMMNS", _("Total number of semaphores"), nsems, lim.semmns, 1);
++	global_set_data(tb, "SEMMSL", _("Max semaphores per semaphore set."), 0, lim.semmsl, 0);
++	global_set_data(tb, "SEMOPM", _("Max number of operations per semop(2)"), 0, lim.semopm, 0);
++	global_set_data(tb, "SEMVMX", _("Semaphore max value"), 0, lim.semvmx, 0);
++}
++
++static void do_msg(int id, struct lsipc_control *ctl, struct libscols_table *tb)
++{
++	struct libscols_line *ln;
++	struct passwd *pw = NULL;
++	struct group *gr = NULL;
++	struct msg_data *msgds, *msgdsp;
++	char *arg = NULL;
++
++	if (ipc_msg_get_info(id, &msgds) < 1) {
++		if (id > -1)
++			warnx(_("id %d not found"), id);
++		return;
++	}
++
++	for (msgdsp = msgds; msgdsp->next != NULL || id > -1 ; msgdsp = msgdsp->next) {
++		size_t n;
++		ln = scols_table_new_line(tb, NULL);
++
++		/* no need to call getpwuid() for the same user */
++		if (!(pw && pw->pw_uid == msgdsp->msg_perm.uid))
++			pw = getpwuid(msgdsp->msg_perm.uid);
++
++		/* no need to call getgrgid() for the same user */
++		if (!(gr && gr->gr_gid == msgdsp->msg_perm.gid))
++			gr = getgrgid(msgdsp->msg_perm.gid);
++
++		for (n = 0; n < ncolumns; n++) {
++			int rc = 0;
++
++			switch (columns[n]) {
++			case COL_KEY:
++				xasprintf(&arg, "0x%08x",msgdsp->msg_perm.key);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_ID:
++				xasprintf(&arg, "%d",msgdsp->msg_perm.id);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_OWNER:
++				arg = get_username(&pw, msgdsp->msg_perm.uid);
++				if (!arg)
++					xasprintf(&arg, "%u", msgdsp->msg_perm.uid);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_PERMS:
++				if (ctl->numperms)
++					xasprintf(&arg, "%#o", msgdsp->msg_perm.mode & 0777);
++				else {
++					arg = xmalloc(11);
++					strmode(msgdsp->msg_perm.mode & 0777, arg);
++					rc = scols_line_refer_data(ln, n, arg);
++				}
++				break;
++			case COL_CUID:
++				xasprintf(&arg, "%u", msgdsp->msg_perm.cuid);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_CUSER:
++				arg = get_username(&pw, msgdsp->msg_perm.cuid);
++				if (arg)
++					rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_CGID:
++				xasprintf(&arg, "%u", msgdsp->msg_perm.cuid);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_CGROUP:
++				arg = get_groupname(&gr, msgdsp->msg_perm.cgid);
++				if (arg)
++					rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_UID:
++				xasprintf(&arg, "%u", msgdsp->msg_perm.uid);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_USER:
++				arg = get_username(&pw, msgdsp->msg_perm.uid);
++				if (arg)
++					rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_GID:
++				xasprintf(&arg, "%u", msgdsp->msg_perm.gid);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_GROUP:
++				arg = get_groupname(&gr,msgdsp->msg_perm.gid);
++				if (arg)
++					rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_CTIME:
++				if (msgdsp->q_ctime != 0)
++					rc = scols_line_refer_data(ln, n,
++						make_time(ctl->time_mode,
++							  (time_t)msgdsp->q_ctime));
++				break;
++			case COL_USEDBYTES:
++				xasprintf(&arg, "%ju", msgdsp->q_cbytes);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_MSGS:
++				xasprintf(&arg, "%ju", msgdsp->q_qnum);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_SEND:
++				if (msgdsp->q_stime != 0)
++					rc = scols_line_refer_data(ln, n,
++						make_time(ctl->time_mode,
++							  (time_t)msgdsp->q_stime));
++				break;
++			case COL_RECV:
++				if (msgdsp->q_rtime != 0)
++					rc = scols_line_refer_data(ln, n,
++						make_time(ctl->time_mode,
++							  (time_t)msgdsp->q_rtime));
++				break;
++			case COL_LSPID:
++				xasprintf(&arg, "%u", msgdsp->q_lspid);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_LRPID:
++				xasprintf(&arg, "%u", msgdsp->q_lrpid);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			}
++			if (rc != 0)
++				err(EXIT_FAILURE, _("failed to set data"));
++			arg = NULL;
++		}
++		if (id > -1)
++			break;
++	}
++	ipc_msg_free_info(msgds);
++}
++
++
++static void do_msg_global(struct libscols_table *tb)
++{
++	struct msg_data *msgds, *msgdsp;
++	struct ipc_limits lim;
++	int msgqs = 0;
++
++	ipc_msg_get_limits(&lim);
++
++	/* count number of used queues */
++	if (ipc_msg_get_info(-1, &msgds) > 0) {
++		for (msgdsp = msgds; msgdsp->next != NULL; msgdsp = msgdsp->next)
++			++msgqs;
++		ipc_msg_free_info(msgds);
++	}
++
++	global_set_data(tb, "MSGMNI", _("Number of message queues"), msgqs, lim.msgmni, 1);
++	global_set_data(tb, "MSGMAX", _("Max size of message (bytes)"),	0, lim.msgmax, 0);
++	global_set_data(tb, "MSGMNB", _("Default max size of queue (bytes)"), 0, lim.msgmnb, 0);
++}
++
++
++static void do_shm(int id, struct lsipc_control *ctl, struct libscols_table *tb)
++{
++	struct libscols_line *ln;
++	struct passwd *pw = NULL;
++	struct group *gr = NULL;
++	struct shm_data *shmds, *shmdsp;
++	char *arg = NULL;
++
++	if (ipc_shm_get_info(id, &shmds) < 1) {
++		if (id > -1)
++			warnx(_("id %d not found"), id);
++		return;
++	}
++
++	for (shmdsp = shmds; shmdsp->next != NULL || id > -1 ; shmdsp = shmdsp->next) {
++		size_t n;
++		ln = scols_table_new_line(tb, NULL);
++		if (!ln)
++			err_oom();
++
++		for (n = 0; n < ncolumns; n++) {
++			int rc = 0;
++
++			switch (columns[n]) {
++			case COL_KEY:
++				xasprintf(&arg, "0x%08x",shmdsp->shm_perm.key);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_ID:
++				xasprintf(&arg, "%d",shmdsp->shm_perm.id);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_OWNER:
++				arg = get_username(&pw, shmdsp->shm_perm.uid);
++				if (!arg)
++					xasprintf(&arg, "%u", shmdsp->shm_perm.uid);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_PERMS:
++				if (ctl->numperms)
++					xasprintf(&arg, "%#o", shmdsp->shm_perm.mode & 0777);
++				else {
++					arg = xmalloc(11);
++					strmode(shmdsp->shm_perm.mode & 0777, arg);
++				}
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_CUID:
++				xasprintf(&arg, "%u", shmdsp->shm_perm.cuid);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_CUSER:
++				arg = get_username(&pw, shmdsp->shm_perm.cuid);
++				if (arg)
++					rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_CGID:
++				xasprintf(&arg, "%u", shmdsp->shm_perm.cuid);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_CGROUP:
++				arg = get_groupname(&gr, shmdsp->shm_perm.cgid);
++				if (arg)
++					rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_UID:
++				xasprintf(&arg, "%u", shmdsp->shm_perm.uid);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_USER:
++				arg = get_username(&pw, shmdsp->shm_perm.uid);
++				if (arg)
++					rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_GID:
++				xasprintf(&arg, "%u", shmdsp->shm_perm.gid);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_GROUP:
++				arg = get_groupname(&gr, shmdsp->shm_perm.gid);
++				if (arg)
++					rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_CTIME:
++				if (shmdsp->shm_ctim != 0)
++					rc = scols_line_refer_data(ln, n,
++						make_time(ctl->time_mode,
++							  (time_t)shmdsp->shm_ctim));
++				break;
++			case COL_SIZE:
++				if (ctl->bytes)
++					xasprintf(&arg, "%ju", shmdsp->shm_segsz);
++				else
++					arg = size_to_human_string(SIZE_SUFFIX_1LETTER, shmdsp->shm_segsz);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_NATTCH:
++				xasprintf(&arg, "%ju", shmdsp->shm_nattch);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_STATUS: {
++					int comma = 0;
++					size_t offt = 0;
++
++					free(arg);
++					arg = xcalloc(1, sizeof(char) * strlen(_("dest"))
++							+ strlen(_("locked"))
++							+ strlen(_("hugetlb"))
++							+ strlen(_("noreserve")) + 4);
++#ifdef SHM_DEST
++					if (shmdsp->shm_perm.mode & SHM_DEST) {
++						offt += sprintf(arg, "%s", _("dest"));
++						comma++;
++					}
++#endif
++#ifdef SHM_LOCKED
++					if (shmdsp->shm_perm.mode & SHM_LOCKED) {
++						if (comma)
++							arg[offt++] = ',';
++						offt += sprintf(arg + offt, "%s", _("locked"));
++					}
++#endif
++#ifdef SHM_HUGETLB
++					if (shmdsp->shm_perm.mode & SHM_HUGETLB) {
++						if (comma)
++							arg[offt++] = ',';
++						offt += sprintf(arg + offt, "%s", _("hugetlb"));
++					}
++#endif
++#ifdef SHM_NORESERVE
++					if (shmdsp->shm_perm.mode & SHM_NORESERVE) {
++						if (comma)
++							arg[offt++] = ',';
++						sprintf(arg + offt, "%s", _("noreserve"));
++					}
++#endif
++					rc = scols_line_refer_data(ln, n, arg);
++				}
++				break;
++			case COL_ATTACH:
++				if (shmdsp->shm_atim != 0)
++					rc = scols_line_refer_data(ln, n,
++							make_time(ctl->time_mode,
++							  (time_t)shmdsp->shm_atim));
++				break;
++			case COL_DETACH:
++				if (shmdsp->shm_dtim != 0)
++					rc = scols_line_refer_data(ln, n,
++							make_time(ctl->time_mode,
++							  (time_t)shmdsp->shm_dtim));
++				break;
++			case COL_CPID:
++				xasprintf(&arg, "%u", shmdsp->shm_cprid);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_LPID:
++				xasprintf(&arg, "%u", shmdsp->shm_lprid);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			case COL_COMMAND:
++				arg = proc_get_command(shmdsp->shm_cprid);
++				rc = scols_line_refer_data(ln, n, arg);
++				break;
++			}
++			if (rc != 0)
++				err(EXIT_FAILURE, _("failed to set data"));
++			arg = NULL;
++		}
++		if (id > -1)
++			break;
++	}
++	ipc_shm_free_info(shmds);
++}
++
++static void do_shm_global(struct libscols_table *tb)
++{
++	struct shm_data *shmds, *shmdsp;
++	uint64_t nsegs = 0, sum_segsz = 0;
++	struct ipc_limits lim;
++
++	ipc_shm_get_limits(&lim);
++
++	if (ipc_shm_get_info(-1, &shmds) > 0) {
++		for (shmdsp = shmds; shmdsp->next != NULL; shmdsp = shmdsp->next) {
++			++nsegs;
++			sum_segsz += shmdsp->shm_segsz;
++		}
++		ipc_shm_free_info(shmds);
++	}
++
++	global_set_data(tb, "SHMMNI", _("Shared memory segments"), nsegs, lim.shmmni, 1);
++	global_set_data(tb, "SHMALL", _("Shared memory pages"), sum_segsz / getpagesize(), lim.shmall, 1);
++	global_set_data(tb, "SHMMAX", _("Max size of shared memory segment (bytes)"), 0, lim.shmmax, 0);
++	global_set_data(tb, "SHMMIN", _("Min size of shared memory segment (bytes)"), 0, lim.shmmin, 0);
++}
++
++int main(int argc, char *argv[])
++{
++	int opt, msg = 0, sem = 0, shm = 0, id = -1;
++	int show_time = 0, show_creat = 0, global = 0;
++	size_t i;
++	struct lsipc_control *ctl = xcalloc(1, sizeof(struct lsipc_control));
++	static struct libscols_table *tb;
++	char *outarg = NULL;
++
++	/* long only options. */
++	enum {
++		OPT_NOTRUNC = CHAR_MAX + 1,
++		OPT_NOHEAD,
++		OPT_TIME_FMT
++	};
++
++	static const struct option longopts[] = {
++		{ "bytes",          no_argument,        0, 'b' },
++		{ "creator",        no_argument,	0, 'c' },
++		{ "export",         no_argument,	0, 'e' },
++		{ "global",         no_argument,	0, 'g' },
++		{ "help",           no_argument,	0, 'h' },
++		{ "id",             required_argument,	0, 'i' },
++		{ "list",           no_argument,        0, 'l' },
++		{ "newline",        no_argument,	0, 'n' },
++		{ "noheadings",     no_argument,	0, OPT_NOHEAD },
++		{ "notruncate",     no_argument,	0, OPT_NOTRUNC },
++		{ "numeric-perms",  no_argument,	0, 'P' },
++		{ "output",         required_argument,	0, 'o' },
++		{ "pid",            no_argument,	0, 'p' },
++		{ "queues",         no_argument,	0, 'q' },
++		{ "raw",            no_argument,	0, 'r' },
++		{ "semaphores",     no_argument,	0, 's' },
++		{ "shmems",         no_argument,	0, 'm' },
++		{ "time",           no_argument,	0, 't' },
++		{ "time-format",    required_argument,	0, OPT_TIME_FMT },
++		{ "version",        no_argument,	0, 'V' },
++		{NULL, 0, NULL, 0}
++	};
++
++	static const ul_excl_t excl[] = {	/* rows and cols in ASCII order */
++		{ 'J', 'e', 'l', 'n', 'r' },
++		{ 'g', 'i' },
++		{ 'c', 'o', 't' },
++		{ 'm', 'q', 's' },
++		{ 0 }
++	};
++	int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
++
++	setlocale(LC_ALL, "");
++	bindtextdomain(PACKAGE, LOCALEDIR);
++	textdomain(PACKAGE);
++	atexit(close_stdout);
++
++	ctl->time_mode = 0;
++
++	scols_init_debug(0);
++
++	while ((opt = getopt_long(argc, argv, "bceghi:lmno:PqrstuV", longopts, NULL)) != -1) {
++
++		err_exclusive_options(opt, longopts, excl, excl_st);
++
++		switch (opt) {
++		case 'b':
++			ctl->bytes = 1;
++			break;
++		case 'i':
++			id = strtos32_or_err(optarg, _("failed to parse IPC identifier"));
++			break;
++		case 'e':
++			ctl->outmode = OUT_EXPORT;
++			break;
++		case 'r':
++			ctl->outmode = OUT_RAW;
++			break;
++		case 'o':
++			outarg = optarg;
++			break;
++		case 'g':
++			global = 1;
++			break;
++		case 'q':
++			msg = 1;
++			add_column(columns, ncolumns++, COL_KEY);
++			add_column(columns, ncolumns++, COL_ID);
++			add_column(columns, ncolumns++, COL_PERMS);
++			add_column(columns, ncolumns++, COL_OWNER);
++			add_column(columns, ncolumns++, COL_USEDBYTES);
++			add_column(columns, ncolumns++, COL_MSGS);
++			add_column(columns, ncolumns++, COL_LSPID);
++			add_column(columns, ncolumns++, COL_LRPID);
++			LOWER = COLDESC_IDX_MSG_FIRST;
++			UPPER = COLDESC_IDX_MSG_LAST;
++			break;
++		case 'l':
++			ctl->outmode = OUT_LIST;
++			break;
++		case 'm':
++			shm = 1;
++			add_column(columns, ncolumns++, COL_KEY);
++			add_column(columns, ncolumns++, COL_ID);
++			add_column(columns, ncolumns++, COL_PERMS);
++			add_column(columns, ncolumns++, COL_OWNER);
++			add_column(columns, ncolumns++, COL_SIZE);
++			add_column(columns, ncolumns++, COL_NATTCH);
++			add_column(columns, ncolumns++, COL_STATUS);
++			add_column(columns, ncolumns++, COL_CTIME);
++			add_column(columns, ncolumns++, COL_CPID);
++			add_column(columns, ncolumns++, COL_LPID);
++			add_column(columns, ncolumns++, COL_COMMAND);
++			LOWER = COLDESC_IDX_SHM_FIRST;
++			UPPER = COLDESC_IDX_SHM_LAST;
++			break;
++		case 'n':
++			ctl->outmode = OUT_NEWLINE;
++			break;
++		case 'P':
++			ctl->numperms = 1;
++			break;
++		case 's':
++			sem = 1;
++			add_column(columns, ncolumns++, COL_KEY);
++			add_column(columns, ncolumns++, COL_ID);
++			add_column(columns, ncolumns++, COL_PERMS);
++			add_column(columns, ncolumns++, COL_OWNER);
++			add_column(columns, ncolumns++, COL_NSEMS);
++			LOWER = COLDESC_IDX_SEM_FIRST;
++			UPPER = COLDESC_IDX_SEM_LAST;
++			break;
++		case OPT_NOTRUNC:
++			ctl->notrunc = 1;
++			break;
++		case OPT_NOHEAD:
++			ctl->noheadings = 1;
++			break;
++		case OPT_TIME_FMT:
++			ctl->time_mode = parse_time_mode(optarg);
++			break;
++		case 't':
++			show_time = 1;
++			break;
++		case 'c':
++			show_creat = 1;
++			break;
++		case 'h':
++			usage(stdout);
++		case 'V':
++			printf(UTIL_LINUX_VERSION);
++			return EXIT_SUCCESS;
++		default:
++			usage(stderr);
++		}
++	}
++
++	/* default is global */
++	if (msg + shm + sem == 0) {
++		msg = shm = sem = global = 1;
++		if (show_time || show_creat || id != -1)
++			errx(EXIT_FAILURE, _("--global is mutually exclusive with --creator, --id and --time"));
++	}
++	if (global) {
++		add_column(columns, ncolumns++, COL_RESOURCE);
++		add_column(columns, ncolumns++, COL_DESC);
++		add_column(columns, ncolumns++, COL_LIMIT);
++		add_column(columns, ncolumns++, COL_USED);
++		add_column(columns, ncolumns++, COL_USEPERC);
++		LOWER = COLDESC_IDX_SUM_FIRST;
++		UPPER = COLDESC_IDX_SUM_LAST;
++	}
++
++	/* default to pretty-print if --id specified */
++	if (id != -1 && !ctl->outmode)
++		ctl->outmode = OUT_PRETTY;
++
++	if (!ctl->time_mode)
++		ctl->time_mode = ctl->outmode == OUT_PRETTY ? TIME_FULL : TIME_SHORT;
++
++	if (ctl->outmode == OUT_PRETTY && !(optarg || show_creat || show_time)) {
++		/* all columns for lsipc --<RESOURCE> --id <ID> */
++		for (ncolumns = 0, i = 0; i < ARRAY_SIZE(coldescs); i++)
++			 columns[ncolumns++] = i;
++	} else {
++		if (show_creat) {
++			add_column(columns, ncolumns++, COL_CUID);
++			add_column(columns, ncolumns++, COL_CGID);
++			add_column(columns, ncolumns++, COL_UID);
++			add_column(columns, ncolumns++, COL_GID);
++		}
++		if (msg && show_time) {
++			add_column(columns, ncolumns++, COL_SEND);
++			add_column(columns, ncolumns++, COL_RECV);
++			add_column(columns, ncolumns++, COL_CTIME);
++		}
++		if (shm && show_time) {
++			/* keep "COMMAND" as last column */
++			size_t cmd = columns[ncolumns - 1] == COL_COMMAND;
++
++			if (cmd)
++				ncolumns--;
++			add_column(columns, ncolumns++, COL_ATTACH);
++			add_column(columns, ncolumns++, COL_DETACH);
++			if (cmd)
++				add_column(columns, ncolumns++, COL_COMMAND);
++		}
++		if (sem && show_time) {
++			add_column(columns, ncolumns++, COL_OTIME);
++			add_column(columns, ncolumns++, COL_CTIME);
++		}
++	}
++
++	if (outarg && string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns),
++					 (int *) &ncolumns, column_name_to_id) < 0)
++		return EXIT_FAILURE;
++
++	tb = setup_table(ctl);
++	if (!tb)
++		return EXIT_FAILURE;
++
++	if (msg) {
++		if (global)
++			do_msg_global(tb);
++		else
++			do_msg(id, ctl, tb);
++	}
++	if (shm) {
++		if (global)
++			do_shm_global(tb);
++		else
++			do_shm(id, ctl, tb);
++	}
++	if (sem) {
++		if (global)
++			do_sem_global(tb);
++		else
++			do_sem(id, ctl, tb);
++	}
++
++	print_table(ctl, tb);
++
++	scols_unref_table(tb);
++	free(ctl);
++
++	return EXIT_SUCCESS;
++}
++
+diff --git a/tests/functions.sh b/tests/functions.sh
+index 123f6c3..b2d493c 100644
+--- a/tests/functions.sh
++++ b/tests/functions.sh
+@@ -50,16 +50,25 @@ function ts_skip_nonroot {
+ }
+ 
+ function ts_failed_subtest {
++	local msg="FAILED"
++	local ret=1
++	if [ "$TS_KNOWN_FAIL" = "yes" ]; then
++		msg="KNOWN FAILED"
++		ret=0
++	fi
++
+ 	if [ x"$1" == x"" ]; then
+-		echo " FAILED ($TS_NS)"
++		echo " $msg ($TS_NS)"
+ 	else
+-		echo " FAILED ($1)"
++		echo " $msg ($1)"
+ 	fi
++
++	return $ret
+ }
+ 
+ function ts_failed {
+ 	ts_failed_subtest "$1"
+-	exit 1
++	exit $?
+ }
+ 
+ function ts_ok_subtest {
+@@ -150,6 +159,7 @@ function ts_init_env {
+ 	TS_SUBDIR=$(dirname $TS_SCRIPT)
+ 	TS_TESTNAME=$(basename $TS_SCRIPT)
+ 	TS_COMPONENT=$(basename $TS_SUBDIR)
++	TS_KNOWN_FAIL="no"
+ 
+ 	TS_NSUBTESTS=0
+ 	TS_NSUBFAILED=0
+diff --git a/tests/ts/ipcs/limits2 b/tests/ts/ipcs/limits2
+index f99a354..63f834d 100755
+--- a/tests/ts/ipcs/limits2
++++ b/tests/ts/ipcs/limits2
+@@ -16,15 +16,20 @@
+ # GNU General Public License for more details.
+ #
+ 
+-TS_TOPDIR="$(dirname $0)/../.."
++TS_TOPDIR="${0%/*}/../.."
+ TS_DESC="basic limits"
+ 
+ . $TS_TOPDIR/functions.sh
+ ts_init "$*"
+-type bc >/dev/null 2>&1 || ts_skip "cannot find bc command"
+ 
+ . $TS_SELF/functions.sh
+ 
++# TODO https://github.com/karelzak/util-linux/issues/51
++SHMALL=$(</proc/sys/kernel/shmall)
++if [ $(bc <<<"(2^64 / $PAGE_SIZE) <= $SHMALL") -eq 1 ]; then
++	TS_KNOWN_FAIL="yes"
++fi
++
+ ts_log "check for difference between kernel and IPC"
+ ipcs_limits_check >> $TS_OUTPUT
+ 
+-- 
+2.7.4
+
diff --git a/SOURCES/0079-blkdiscard-backport-zeroout-support.patch b/SOURCES/0079-blkdiscard-backport-zeroout-support.patch
new file mode 100644
index 0000000..22edece
--- /dev/null
+++ b/SOURCES/0079-blkdiscard-backport-zeroout-support.patch
@@ -0,0 +1,278 @@
+From ca291153ff2c696696c1406aca6433aab6e412a1 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Fri, 24 Jun 2016 13:36:32 +0200
+Subject: [PATCH 79/84] blkdiscard: backport --zeroout support
+
+The patch also includes upstream cleanups.
+
+Upstream: http://github.com/karelzak/util-linux/commit/0e765365798c54d412e355798ad584a52035f228
+Upstream: http://github.com/karelzak/util-linux/commit/a3e91e26467a0f644ee568bb0b3d481591834015
+Upstream: http://github.com/karelzak/util-linux/commit/eeae448805c0eb2ef130a6ac301750706bb80420
+Upstream: http://github.com/karelzak/util-linux/commit/7154cc892688f3c58cbbcdc2055f2635c1d0ef5b
+Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1327886
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ bash-completion/blkdiscard |   2 +-
+ sys-utils/blkdiscard.8     |   7 +--
+ sys-utils/blkdiscard.c     | 122 ++++++++++++++++++++++++++++++++++-----------
+ 3 files changed, 98 insertions(+), 33 deletions(-)
+
+diff --git a/bash-completion/blkdiscard b/bash-completion/blkdiscard
+index 310cdfb..fb3cb1e 100644
+--- a/bash-completion/blkdiscard
++++ b/bash-completion/blkdiscard
+@@ -15,7 +15,7 @@ _blkdiscard_module()
+ 	esac
+ 	case $cur in
+ 		-*)
+-			OPTS="--offset --length --secure --verbose --help --version"
++			OPTS="--offset --length --secure --zeroout --verbose --help --version"
+ 			COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) )
+ 			return 0
+ 			;;
+diff --git a/sys-utils/blkdiscard.8 b/sys-utils/blkdiscard.8
+index 5e094d4..71180e9 100644
+--- a/sys-utils/blkdiscard.8
++++ b/sys-utils/blkdiscard.8
+@@ -1,15 +1,13 @@
+-.\" -*- nroff -*-
+ .TH BLKDISCARD 8 "July 2014" "util-linux" "System Administration"
+ .SH NAME
+ blkdiscard \- discard sectors on a device
+ .SH SYNOPSIS
+ .B blkdiscard
++[options]
+ .RB [ \-o
+ .IR offset ]
+ .RB [ \-l
+ .IR length ]
+-.RB [ \-s ]
+-.RB [ \-v ]
+ .I device
+ .SH DESCRIPTION
+ .B blkdiscard
+@@ -59,6 +57,9 @@ Perform a secure discard.  A secure discard is the same as a regular discard
+ except that all copies of the discarded blocks that were possibly created by
+ garbage collection must also be erased.  This requires support from the device.
+ .TP
++.BR \-z , " \-\-zeroout"
++Zero-fill rather than discard.
++.TP
+ .BR \-v , " \-\-verbose"
+ Display the aligned values of
+ .I offset
+diff --git a/sys-utils/blkdiscard.c b/sys-utils/blkdiscard.c
+index 92ca52a..0ba99ee 100644
+--- a/sys-utils/blkdiscard.c
++++ b/sys-utils/blkdiscard.c
+@@ -44,43 +44,95 @@
+ #include "closestream.h"
+ 
+ #ifndef BLKDISCARD
+-#define BLKDISCARD	_IO(0x12,119)
++# define BLKDISCARD	_IO(0x12,119)
+ #endif
+ 
+ #ifndef BLKSECDISCARD
+-#define BLKSECDISCARD	_IO(0x12,125)
++# define BLKSECDISCARD	_IO(0x12,125)
+ #endif
+ 
+-#define print_stats(path, stats) \
+-	printf(_("%s: Discarded %" PRIu64 " bytes from the " \
+-		 "offset %" PRIu64"\n"), path, stats[1], stats[0]);
++#ifndef BLKZEROOUT
++# define BLKZEROOUT	_IO(0x12,127)
++#endif
++
++enum {
++	ACT_DISCARD = 0,	/* default */
++	ACT_ZEROOUT,
++	ACT_SECURE
++};
++
++/* RHEL: backport from upstream lib/monotonic.c */
++static int gettime_monotonic(struct timeval *tv)
++{
++#ifdef CLOCK_MONOTONIC
++	/* Can slew only by ntp and adjtime */
++	int ret;
++	struct timespec ts;
++
++# ifdef CLOCK_MONOTONIC_RAW
++	/* Linux specific, can't slew */
++	if (!(ret = clock_gettime(CLOCK_MONOTONIC_RAW, &ts))) {
++# else
++	if (!(ret = clock_gettime(CLOCK_MONOTONIC, &ts))) {
++# endif
++		tv->tv_sec = ts.tv_sec;
++		tv->tv_usec = ts.tv_nsec / 1000;
++	}
++	return ret;
++#else
++	return gettimeofday(tv, NULL);
++#endif
++}
++
++static void print_stats(int act, char *path, uint64_t stats[])
++{
++	switch (act) {
++	case ACT_ZEROOUT:
++		printf(_("%s: Zero-filled %" PRIu64 " bytes from the offset %" PRIu64"\n"), \
++			path, stats[1], stats[0]);
++		break;
++	case ACT_SECURE:
++	case ACT_DISCARD:
++		printf(_("%s: Discarded %" PRIu64 " bytes from the offset %" PRIu64"\n"), \
++			path, stats[1], stats[0]);
++		break;
++	}
++}
+ 
+ static void __attribute__((__noreturn__)) usage(FILE *out)
+ {
+ 	fputs(USAGE_HEADER, out);
+ 	fprintf(out,
+ 	      _(" %s [options] <device>\n"), program_invocation_short_name);
++
++	fputs(USAGE_SEPARATOR, out);
++	fputs(_("Discard the content of sectors on a device.\n"), out);
++
+ 	fputs(USAGE_OPTIONS, out);
+-	fputs(_(" -o, --offset <num>  offset in bytes to discard from\n"
+-		" -l, --length <num>  length of bytes to discard from the offset\n"
+-		" -p, --step <num>    size of the discard iterations within the offset\n"
+-		" -s, --secure        perform secure discard\n"
+-		" -v, --verbose       print aligned length and offset\n"),
+-		out);
++	fputs(_(" -o, --offset <num>  offset in bytes to discard from\n"), out);
++	fputs(_(" -l, --length <num>  length of bytes to discard from the offset\n"), out);
++	fputs(_(" -p, --step <num>    size of the discard iterations within the offset\n"), out);
++	fputs(_(" -s, --secure        perform secure discard\n"), out);
++	fputs(_(" -z, --zeroout       zero-fill rather than discard\n"), out);
++	fputs(_(" -v, --verbose       print aligned length and offset\n"), out);
++
+ 	fputs(USAGE_SEPARATOR, out);
+ 	fputs(USAGE_HELP, out);
+ 	fputs(USAGE_VERSION, out);
++
+ 	fprintf(out, USAGE_MAN_TAIL("blkdiscard(8)"));
+ 	exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
+ }
+ 
++
+ int main(int argc, char **argv)
+ {
+ 	char *path;
+-	int c, fd, verbose = 0, secure = 0, secsize;
++	int c, fd, verbose = 0, secsize;
+ 	uint64_t end, blksize, step, range[2], stats[2];
+ 	struct stat sb;
+-	struct timespec now, last;
++	struct timeval now, last;
++	int act = ACT_DISCARD;
+ 
+ 	static const struct option longopts[] = {
+ 	    { "help",      0, 0, 'h' },
+@@ -90,6 +142,7 @@ int main(int argc, char **argv)
+ 	    { "step",      1, 0, 'p' },
+ 	    { "secure",    0, 0, 's' },
+ 	    { "verbose",   0, 0, 'v' },
++	    { "zeroout",   0, 0, 'z' },
+ 	    { NULL,        0, 0, 0 }
+ 	};
+ 
+@@ -102,7 +155,7 @@ int main(int argc, char **argv)
+ 	range[1] = ULLONG_MAX;
+ 	step = 0;
+ 
+-	while ((c = getopt_long(argc, argv, "hVsvo:l:p:", longopts, NULL)) != -1) {
++	while ((c = getopt_long(argc, argv, "hVsvo:l:p:z", longopts, NULL)) != -1) {
+ 		switch(c) {
+ 		case 'h':
+ 			usage(stdout);
+@@ -123,11 +176,14 @@ int main(int argc, char **argv)
+ 					_("failed to parse step"));
+ 			break;
+ 		case 's':
+-			secure = 1;
++			act = ACT_SECURE;
+ 			break;
+ 		case 'v':
+ 			verbose = 1;
+ 			break;
++		case 'z':
++			act = ACT_ZEROOUT;
++			break;
+ 		default:
+ 			usage(stderr);
+ 			break;
+@@ -149,7 +205,7 @@ int main(int argc, char **argv)
+ 		err(EXIT_FAILURE, _("cannot open %s"), path);
+ 
+ 	if (fstat(fd, &sb) == -1)
+-		err(EXIT_FAILURE, _("stat failed %s"), path);
++		err(EXIT_FAILURE, _("stat of %s failed"), path);
+ 	if (!S_ISBLK(sb.st_mode))
+ 		errx(EXIT_FAILURE, _("%s: not a block device"), path);
+ 
+@@ -178,35 +234,43 @@ int main(int argc, char **argv)
+ 			 "to sector size %i"), path, range[1], secsize);
+ 
+ 	stats[0] = range[0], stats[1] = 0;
+-	clock_gettime(CLOCK_MONOTONIC, &last);
++	gettime_monotonic(&last);
+ 
+-	for (range[0] = range[0]; range[0] < end; range[0] += range[1]) {
++	for (/* nothing */; range[0] < end; range[0] += range[1]) {
+ 		if (range[0] + range[1] > end)
+ 			range[1] = end - range[0];
+ 
+-		if (secure) {
++		switch (act) {
++		case ACT_ZEROOUT:
++			if (ioctl(fd, BLKZEROOUT, &range))
++				 err(EXIT_FAILURE, _("%s: BLKZEROOUT ioctl failed"), path);
++			break;
++		case ACT_SECURE:
+ 			if (ioctl(fd, BLKSECDISCARD, &range))
+ 				err(EXIT_FAILURE, _("%s: BLKSECDISCARD ioctl failed"), path);
+-		} else {
++			break;
++		case ACT_DISCARD:
+ 			if (ioctl(fd, BLKDISCARD, &range))
+ 				err(EXIT_FAILURE, _("%s: BLKDISCARD ioctl failed"), path);
++			break;
+ 		}
+ 
+-		/* reporting progress */
++		stats[1] += range[1];
++
++		/* reporting progress at most once per second */
+ 		if (verbose && step) {
+-			clock_gettime(CLOCK_MONOTONIC, &now);
+-			if (last.tv_sec < now.tv_sec) {
+-				print_stats(path, stats);
+-				stats[0] = range[0], stats[1] = 0;
++			gettime_monotonic(&now);
++			if (now.tv_sec > last.tv_sec &&
++			    (now.tv_usec >= last.tv_usec || now.tv_sec > last.tv_sec + 1)) {
++				print_stats(act, path, stats);
++				stats[0] += stats[1], stats[1] = 0;
+ 				last = now;
+ 			}
+ 		}
+-
+-		stats[1] += range[1];
+ 	}
+ 
+-	if (verbose)
+-		print_stats(path, stats);
++	if (verbose && stats[1])
++		print_stats(act, path, stats);
+ 
+ 	close(fd);
+ 	return EXIT_SUCCESS;
+-- 
+2.7.4
+
diff --git a/SOURCES/0080-sulogin-and-agetty-virtual-consoles-support-xvc-and-.patch b/SOURCES/0080-sulogin-and-agetty-virtual-consoles-support-xvc-and-.patch
new file mode 100644
index 0000000..ae2bc6b
--- /dev/null
+++ b/SOURCES/0080-sulogin-and-agetty-virtual-consoles-support-xvc-and-.patch
@@ -0,0 +1,125 @@
+From 46537bc28d48acb9ae5cac76535262e6b2ec48a2 Mon Sep 17 00:00:00 2001
+From: Werner Fink <werner@suse.de>
+Date: Thu, 8 May 2014 12:09:25 +0200
+Subject: [PATCH 80/84] sulogin: (and agetty) virtual consoles support, xvc and
+ hvc device
+
+For this approach do not use the ioctl TIOCMGET anymore as this
+is for real serial lines only. But switch over to use the ioctl
+KDGKBMODE as this is unique to the virtual console lines only.
+
+Upstream: http://github.com/karelzak/util-linux/commit/b9c7390948c7850db2bee82ad64624930962cc14
+Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1029385
+Signed-off-by: Werner Fink <werner@suse.de>
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ login-utils/sulogin.c | 17 ++++++++++++-----
+ term-utils/agetty.c   | 23 +++++++++++------------
+ 2 files changed, 23 insertions(+), 17 deletions(-)
+
+diff --git a/login-utils/sulogin.c b/login-utils/sulogin.c
+index 32ae9a2..bbd67b3 100644
+--- a/login-utils/sulogin.c
++++ b/login-utils/sulogin.c
+@@ -49,6 +49,11 @@
+ # include <selinux/get_context_list.h>
+ #endif
+ 
++#ifdef __linux__
++# include <sys/kd.h>
++# include <sys/param.h>
++#endif
++
+ #include "c.h"
+ #include "closestream.h"
+ #include "nls.h"
+@@ -93,10 +98,14 @@ static void tcinit(struct console *con)
+ 		return;
+ 	}
+ 
+-	/* Handle serial lines here */
+-	if (ioctl(fd, TIOCMGET, (char *) &mode) == 0) {
++	/* Handle lines other than virtual consoles here */
++#if defined(KDGKBMODE)
++	if (ioctl(fd, KDGKBMODE, &mode) < 0)
++#endif
++	{
+ 		speed_t ispeed, ospeed;
+ 		struct winsize ws;
++		errno = 0;
+ 
+ 		/* this is a modem line */
+ 		con->flags |= CON_SERIAL;
+@@ -142,9 +151,7 @@ static void tcinit(struct console *con)
+ 		goto setattr;
+ 	}
+ #if defined(IUTF8) && defined(KDGKBMODE)
+-	/* Detect mode of current keyboard setup, e.g. for UTF-8 */
+-	if (ioctl(fd, KDGKBMODE, &mode) < 0)
+-		mode = K_RAW;
++	/* Handle mode of current keyboard setup, e.g. for UTF-8 */
+ 	switch(mode) {
+ 	case K_UNICODE:
+ 		setlocale(LC_CTYPE, "C.UTF-8");
+diff --git a/term-utils/agetty.c b/term-utils/agetty.c
+index c7af154..5692126 100644
+--- a/term-utils/agetty.c
++++ b/term-utils/agetty.c
+@@ -134,6 +134,7 @@ struct options {
+ 	int nice;			/* Run login with this priority */
+ 	int numspeed;			/* number of baud rates to try */
+ 	int clocal;			/* CLOCAL_MODE_* */
++	int kbmode;			/* Keyboard mode if virtual console */
+ 	speed_t speeds[MAX_SPEED];	/* baud rates to be tried */
+ };
+ 
+@@ -886,7 +887,7 @@ static void update_utmp(struct options *op)
+ static void open_tty(char *tty, struct termios *tp, struct options *op)
+ {
+ 	const pid_t pid = getpid();
+-	int serial, closed = 0;
++	int closed = 0;
+ 
+ 	/* Set up new standard input, unless we are given an already opened port. */
+ 
+@@ -1016,15 +1017,18 @@ static void open_tty(char *tty, struct termios *tp, struct options *op)
+ 
+ 	/*
+ 	 * Detect if this is a virtual console or serial/modem line.
+-	 * In case of a virtual console the ioctl TIOCMGET fails and
+-	 * the error number will be set to EINVAL.
++	 * In case of a virtual console the ioctl KDGKBMODE succeeds
++	 * whereas on other lines it will fails.
+ 	 */
+-	if (ioctl(STDIN_FILENO, TIOCMGET, &serial) < 0 && (errno == EINVAL)) {
++	if (ioctl(STDIN_FILENO, KDGKBMODE, &op->kbmode) == 0) {
+ 		op->flags |= F_VCONSOLE;
+ 		if (!op->term)
+ 			op->term = DEFAULT_VCTERM;
+-	} else if (!op->term)
+-		op->term = DEFAULT_STERM;
++	} else {
++		op->kbmode = K_RAW;
++		if (!op->term)
++			op->term = DEFAULT_STERM;
++	}
+ 
+ 	setenv("TERM", op->term, 1);
+ }
+@@ -1037,12 +1041,7 @@ static void termio_init(struct options *op, struct termios *tp)
+ 
+ 	if (op->flags & F_VCONSOLE) {
+ #if defined(IUTF8) && defined(KDGKBMODE)
+-		int mode;
+-
+-		/* Detect mode of current keyboard setup, e.g. for UTF-8 */
+-		if (ioctl(STDIN_FILENO, KDGKBMODE, &mode) < 0)
+-			mode = K_RAW;
+-		switch(mode) {
++		switch(op->kbmode) {
+ 		case K_UNICODE:
+ 			setlocale(LC_CTYPE, "C.UTF-8");
+ 			op->flags |= F_UTF8;
+-- 
+2.7.4
+
diff --git a/SOURCES/0081-chrt-backport-DEADLINE-scheduler-support.patch b/SOURCES/0081-chrt-backport-DEADLINE-scheduler-support.patch
new file mode 100644
index 0000000..fda445b
--- /dev/null
+++ b/SOURCES/0081-chrt-backport-DEADLINE-scheduler-support.patch
@@ -0,0 +1,791 @@
+From 674769893bb8d5f1991c6a3e5d96337b37aeb86f Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Mon, 27 Jun 2016 14:14:28 +0200
+Subject: [PATCH 81/86] chrt: backport DEADLINE scheduler support
+
+Backport upstream commits:
+
+2e31d1c chrt: validate priority before trying to use it
+b3a5067 chrt: make --sched-* short options to require an argument
+a03eac5 chrt: restore removed ifdef SCHED_RESET_ON_FORK
+59e4a38 chrt: fix case SCHED_RR
+acde3a0 chrt: use sched_getattr()
+1a7e639 chrt: add support for SCHED_DEADLINE
+1516758 chrt: use sched_setattr() if available
+a6fec53 chrt: make usage more readable
+4820a73 chrt: set function refactoring
+a30cf65 chrt: output function refactoring
+7a4ea56 chrt: add control struct
+9acbe2a chrt: slice up the usage text and normalize its layout
+4e4bc0c chrt: make the usage synopsis clearer
+3fabc36 chrt: fix --help inconsistency
+451dbcf textual: add a docstring to most of the utilities
+a587cc5 textual: use manual tail usage() macro
+f627750 textual: use version printing macro everywhere
+a7560c0 textual: make the license of chrt and taskset slightly more explicit
+4ce393f textual: fix several typos and angular brackets in messages
+6f27e44 chrt: add fallback to be usable on kernels without sched_{get,set}attr
+
+* Fri Jul 01 2016 re-spin [kzak]:
+- add fallback for old glibc-headers without SYS_sched_{set,get}attr
+
+* Tue Jul 12 016 re-spin [kzak]:
+- add runtime fallback for systems without sched_{get,set}attr syscalls
+
+Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1298384
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ configure.ac      |  17 +-
+ m4/ul.m4          |   8 -
+ schedutils/chrt.c | 547 ++++++++++++++++++++++++++++++++++++++----------------
+ 3 files changed, 400 insertions(+), 172 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index fe0a011..266ef08 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -338,6 +338,8 @@ AC_CHECK_FUNCS([ \
+ 	scandirat \
+ 	setresgid \
+ 	setresuid \
++	sched_setattr \
++	sched_setscheduler \
+ 	sigqueue \
+ 	srandom \
+ 	strnchr \
+@@ -1383,6 +1385,20 @@ UL_REQUIRES_SYSCALL_CHECK([taskset],
+ AM_CONDITIONAL(BUILD_TASKSET, test "x$build_taskset" = xyes)
+ 
+ 
++have_schedsetter=no
++AS_IF([test "x$ac_cv_func_sched_setscheduler" = xyes], [have_schedsetter=yes],
++      [test "x$ac_cv_func_sched_setattr" = xyes], [have_schedsetter=yes])
++
++UL_BUILD_INIT([chrt], [check])
++UL_REQUIRES_BUILD([chrt], [schedutils])
++UL_REQUIRES_HAVE([chrt], [schedsetter], [sched_set functions])
++AM_CONDITIONAL([BUILD_CHRT], [test "x$build_chrt" = xyes])
++
++AS_IF([test "x$build_chrt" = xyes], [
++	UL_CHECK_SYSCALL([sched_setattr])
++])
++
++
+ AC_ARG_ENABLE([wall],
+   AS_HELP_STRING([--disable-wall], [do not build wall]),
+   [], enable_wall=yes
+@@ -1562,7 +1578,6 @@ AC_ARG_VAR([SOLIB_LDFLAGS],
+ 
+ LIBS=""
+ 
+-
+ AC_CONFIG_HEADERS(config.h)
+ 
+ #
+diff --git a/m4/ul.m4 b/m4/ul.m4
+index c0082d0..db44589 100644
+--- a/m4/ul.m4
++++ b/m4/ul.m4
+@@ -92,7 +92,6 @@ AC_DEFUN([UL_CHECK_SYSCALL], [
+       ])
+     ul_cv_syscall_$1=$syscall
+     ])
+-  AM_CONDITIONAL([HAVE_]m4_toupper($1), [test "x$ul_cv_syscall_$1" != xno])
+   case $ul_cv_syscall_$1 in #(
+   no) AC_MSG_WARN([Unable to detect syscall $1.]) ;;
+   SYS_*) ;;
+@@ -266,13 +265,6 @@ AC_DEFUN([UL_REQUIRES_SYSCALL_CHECK], [
+   m4_define([suffix], m4_default([$4],$1))
+   m4_define([callname], m4_default([$3],$1))
+ 
+-  dnl This is default, $3 will redefine the condition
+-  dnl
+-  dnl TODO: remove this junk, AM_CONDITIONAL should not be used for any HAVE_*
+-  dnl       variables, all we need is BUILD_* only.
+-  dnl
+-  AM_CONDITIONAL([HAVE_]m4_toupper(callname), [false])
+-
+   if test "x$[build_]suffix" != xno; then
+     if test "x$[enable_]suffix" = xno; then
+       [build_]suffix=no
+diff --git a/schedutils/chrt.c b/schedutils/chrt.c
+index 20df6fa..edae0d9 100644
+--- a/schedutils/chrt.c
++++ b/schedutils/chrt.c
+@@ -1,13 +1,11 @@
+ /*
+- * chrt.c - chrt
+- * Command-line utility for manipulating a task's real-time attributes 
++ * chrt.c - manipulate a task's real-time attributes
+  *
+- * Robert Love <rml@tech9.net>
+- * 27-Apr-2002: initial version
+- * 04-May-2011: make thread aware - Davidlohr Bueso <dave@gnu.org>
++ * 27-Apr-2002: initial version - Robert Love <rml@tech9.net>
++ * 04-May-2011: make it thread-aware - Davidlohr Bueso <dave@gnu.org>
+  *
+  * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License, v2, as
++ * it under the terms of the GNU General Public License, version 2, as
+  * published by the Free Software Foundation
+  *
+  * This program is distributed in the hope that it will be useful,
+@@ -50,108 +48,260 @@
+ # define SCHED_IDLE 5
+ #endif
+ 
++/* flag by sched_getscheduler() */
+ #if defined(__linux__) && !defined(SCHED_RESET_ON_FORK)
+-#define SCHED_RESET_ON_FORK 0x40000000
++# define SCHED_RESET_ON_FORK 0x40000000
+ #endif
+ 
++/* flag by sched_getattr() */
++#if defined(__linux__) && !defined(SCHED_FLAG_RESET_ON_FORK)
++# define SCHED_FLAG_RESET_ON_FORK 0x01
++#endif
+ 
+-static void __attribute__((__noreturn__)) show_usage(int rc)
+-{
+-	FILE *out = rc == EXIT_SUCCESS ? stdout : stderr;
++#if defined (__linux__) && !defined(HAVE_SCHED_SETATTR)
++# include <sys/syscall.h>
++#endif
+ 
+-	fprintf(out, _(
+-	"\nchrt - manipulate real-time attributes of a process\n"
+-	"\nSet policy:\n"
+-	"  chrt [options] [-policy] <priority> [-p <pid> | <command> <arg> ...]\n"
+-	"\nGet policy:\n"
+-	"  chrt [options] -p <pid>\n"));
+-
+-	fprintf(out, _(
+-	"\nScheduling policies:\n"
+-	"  -b | --batch         set policy to SCHED_BATCH\n"
+-	"  -f | --fifo          set policy to SCHED_FIFO\n"
+-	"  -i | --idle          set policy to SCHED_IDLE\n"
+-	"  -o | --other         set policy to SCHED_OTHER\n"
+-	"  -r | --rr            set policy to SCHED_RR (default)\n"));
++/* usable kernel-headers, but old glibc-headers */
++#if defined (__linux__) && !defined(SYS_sched_setattr) && defined(__NR_sched_setattr)
++# define SYS_sched_setattr __NR_sched_setattr
++#endif
+ 
+-#ifdef SCHED_RESET_ON_FORK
+-	fprintf(out, _(
+-	"\nScheduling flags:\n"
+-	"  -R | --reset-on-fork set SCHED_RESET_ON_FORK for FIFO or RR\n"));
++#if defined (__linux__) && !defined(SYS_sched_getattr) && defined(__NR_sched_getattr)
++# define SYS_sched_getattr __NR_sched_getattr
+ #endif
+-	fprintf(out, _(
+-	"\nOptions:\n"
+-	"  -a | --all-tasks     operate on all the tasks (threads) for a given pid\n"
+-	"  -h | --help          display this help\n"
+-	"  -m | --max           show min and max valid priorities\n"
+-	"  -p | --pid           operate on existing given pid\n"
+-	"  -v | --verbose       display status information\n"
+-	"  -V | --version       output version information\n\n"));
+ 
+-	exit(rc);
++#if defined (__linux__) && !defined(HAVE_SCHED_SETATTR) && defined(SYS_sched_setattr)
++# define HAVE_SCHED_SETATTR
++
++struct sched_attr {
++	uint32_t size;
++	uint32_t sched_policy;
++	uint64_t sched_flags;
++
++	/* SCHED_NORMAL, SCHED_BATCH */
++	int32_t sched_nice;
++
++	/* SCHED_FIFO, SCHED_RR */
++	uint32_t sched_priority;
++
++	/* SCHED_DEADLINE (nsec) */
++	uint64_t sched_runtime;
++	uint64_t sched_deadline;
++	uint64_t sched_period;
++};
++
++static int sched_setattr(pid_t pid, const struct sched_attr *attr, unsigned int flags)
++{
++	return syscall(SYS_sched_setattr, pid, attr, flags);
+ }
+ 
+-static void show_rt_info(pid_t pid, int isnew)
++static int sched_getattr(pid_t pid, struct sched_attr *attr, unsigned int size, unsigned int flags)
+ {
+-	struct sched_param sp;
+-	int policy;
++	return syscall(SYS_sched_getattr, pid, attr, size, flags);
++}
++#endif
+ 
+-	/* don't display "pid 0" as that is confusing */
+-	if (!pid)
+-		pid = getpid();
++/* the SCHED_DEADLINE is supported since Linux 3.14
++ * commit id aab03e05e8f7e26f51dee792beddcb5cca9215a5
++ * -- sched_setattr() is required for this policy!
++ */
++#if defined (__linux__) && !defined(SCHED_DEADLINE) && defined(HAVE_SCHED_SETATTR)
++# define SCHED_DEADLINE 6
++#endif
+ 
+-	policy = sched_getscheduler(pid);
+-	if (policy == -1)
+-		err(EXIT_FAILURE, _("failed to get pid %d's policy"), pid);
++/* control struct */
++struct chrt_ctl {
++	pid_t	pid;
++	int	policy;				/* SCHED_* */
++	int	priority;
+ 
+-	if (isnew)
+-		printf(_("pid %d's new scheduling policy: "), pid);
+-	else
+-		printf(_("pid %d's current scheduling policy: "), pid);
++	uint64_t runtime;			/* --sched-* options */
++	uint64_t deadline;
++	uint64_t period;
++
++	unsigned int all_tasks : 1,		/* all threads of the PID */
++		     reset_on_fork : 1,		/* SCHED_RESET_ON_FORK */
++		     altered : 1,		/* sched_set**() used */
++		     verbose : 1;		/* verbose output */
++};
++
++static void __attribute__((__noreturn__)) show_usage(int rc)
++{
++	FILE *out = rc == EXIT_SUCCESS ? stdout : stderr;
+ 
++	fputs(_("Show or change the real-time scheduling attributes of a process.\n"), out);
++	fputs(USAGE_SEPARATOR, out);
++	fputs(_("Set policy:\n"
++	" chrt [options] <priority> <command> [<arg>...]\n"
++	" chrt [options] --pid <priority> <pid>\n"), out);
++	fputs(USAGE_SEPARATOR, out);
++	fputs(_("Get policy:\n"
++	" chrt [options] -p <pid>\n"), out);
++
++	fputs(USAGE_SEPARATOR, out);
++	fputs(_("Policy options:\n"), out);
++	fputs(_(" -b, --batch          set policy to SCHED_BATCH\n"), out);
++	fputs(_(" -d, --deadline       set policy to SCHED_DEADLINE\n"), out);
++	fputs(_(" -f, --fifo           set policy to SCHED_FIFO\n"), out);
++	fputs(_(" -i, --idle           set policy to SCHED_IDLE\n"), out);
++	fputs(_(" -o, --other          set policy to SCHED_OTHER\n"), out);
++	fputs(_(" -r, --rr             set policy to SCHED_RR (default)\n"), out);
++
++	fputs(USAGE_SEPARATOR, out);
++	fputs(_("Scheduling options:\n"), out);
++	fputs(_(" -R, --reset-on-fork       set SCHED_RESET_ON_FORK for FIFO or RR\n"), out);
++	fputs(_(" -T, --sched-runtime <ns>  runtime parameter for DEADLINE\n"), out);
++	fputs(_(" -P, --sched-period <ns>   period parameter for DEADLINE\n"), out);
++	fputs(_(" -D, --sched-deadline <ns> deadline parameter for DEADLINE\n"), out);
++
++	fputs(USAGE_SEPARATOR, out);
++	fputs(_("Other options:\n"), out);
++	fputs(_(" -a, --all-tasks      operate on all the tasks (threads) for a given pid\n"), out);
++	fputs(_(" -m, --max            show min and max valid priorities\n"), out);
++	fputs(_(" -p, --pid            operate on existing given pid\n"), out);
++	fputs(_(" -v, --verbose        display status information\n"), out);
++
++	fputs(USAGE_SEPARATOR, out);
++	fputs(USAGE_HELP, out);
++	fputs(USAGE_VERSION, out);
++
++	fprintf(out, USAGE_MAN_TAIL("chrt(1)"));
++	exit(rc);
++}
++
++static const char *get_policy_name(int policy)
++{
+ 	switch (policy) {
+ 	case SCHED_OTHER:
+-		printf("SCHED_OTHER\n");
+-		break;
++		return "SCHED_OTHER";
+ 	case SCHED_FIFO:
+-		printf("SCHED_FIFO\n");
+-		break;
+ #ifdef SCHED_RESET_ON_FORK
+ 	case SCHED_FIFO | SCHED_RESET_ON_FORK:
+-		printf("SCHED_FIFO|SCHED_RESET_ON_FORK\n");
+-		break;
+ #endif
++		return "SCHED_FIFO";
+ #ifdef SCHED_IDLE
+ 	case SCHED_IDLE:
+-		printf("SCHED_IDLE\n");
+-		break;
++		return "SCHED_IDLE";
+ #endif
+ 	case SCHED_RR:
+-		printf("SCHED_RR\n");
+-		break;
+ #ifdef SCHED_RESET_ON_FORK
+ 	case SCHED_RR | SCHED_RESET_ON_FORK:
+-		printf("SCHED_RR|SCHED_RESET_ON_FORK\n");
+-		break;
+ #endif
++		return "SCHED_RR";
+ #ifdef SCHED_BATCH
+ 	case SCHED_BATCH:
+-		printf("SCHED_BATCH\n");
+-		break;
++		return "SCHED_BATCH";
++#endif
++#ifdef SCHED_DEADLINE
++	case SCHED_DEADLINE:
++		return "SCHED_DEADLINE";
+ #endif
+ 	default:
+-		warnx(_("unknown scheduling policy"));
++		break;
++	}
++
++	return _("unknown");
++}
++
++static void show_sched_pid_info(struct chrt_ctl *ctl, pid_t pid)
++{
++	int policy, reset_on_fork = 0, prio = 0;
++#ifdef SCHED_DEADLINE
++	uint64_t deadline = 0, runtime = 0, period = 0;
++#endif
++
++	/* don't display "pid 0" as that is confusing */
++	if (!pid)
++		pid = getpid();
++
++	errno = 0;
++
++	/*
++	 * New way
++	 */
++#ifdef HAVE_SCHED_SETATTR
++	{
++		struct sched_attr sa;
++
++		if (sched_getattr(pid, &sa, sizeof(sa), 0) != 0) {
++			if (errno == ENOSYS)
++				goto fallback;
++			err(EXIT_FAILURE, _("failed to get pid %d's policy"), pid);
++		}
++
++		policy = sa.sched_policy;
++		prio = sa.sched_priority;
++		reset_on_fork = sa.sched_flags & SCHED_FLAG_RESET_ON_FORK;
++		deadline = sa.sched_deadline;
++		runtime = sa.sched_runtime;
++		period = sa.sched_period;
+ 	}
++#endif
++
++	/*
++	 * Old way
++	 */
++fallback:
++	if (errno == ENOSYS) {
++		struct sched_param sp;
+ 
+-	if (sched_getparam(pid, &sp))
+-		err(EXIT_FAILURE, _("failed to get pid %d's attributes"), pid);
++		policy = sched_getscheduler(pid);
++		if (policy == -1)
++			err(EXIT_FAILURE, _("failed to get pid %d's policy"), pid);
+ 
+-	if (isnew)
+-		printf(_("pid %d's new scheduling priority: %d\n"),
+-		       pid, sp.sched_priority);
++		if (sched_getparam(pid, &sp) != 0)
++			err(EXIT_FAILURE, _("failed to get pid %d's attributes"), pid);
++		else
++			prio = sp.sched_priority;
++# ifdef SCHED_RESET_ON_FORK
++		if (policy == (SCHED_FIFO|SCHED_RESET_ON_FORK) || policy == (SCHED_BATCH|SCHED_RESET_ON_FORK))
++			reset_on_fork = 1;
++# endif
++	}
++
++	if (ctl->altered)
++		printf(_("pid %d's new scheduling policy: %s"), pid, get_policy_name(policy));
++	else
++		printf(_("pid %d's current scheduling policy: %s"), pid, get_policy_name(policy));
++
++	if (reset_on_fork)
++		printf("|SCHED_RESET_ON_FORK");
++	putchar('\n');
++
++	if (ctl->altered)
++		printf(_("pid %d's new scheduling priority: %d\n"), pid, prio);
+ 	else
+-		printf(_("pid %d's current scheduling priority: %d\n"),
+-		       pid, sp.sched_priority);
++		printf(_("pid %d's current scheduling priority: %d\n"), pid, prio);
++
++#ifdef SCHED_DEADLINE
++	if (policy == SCHED_DEADLINE) {
++		if (ctl->altered)
++			printf(_("pid %d's new runtime/deadline/period parameters: %ju/%ju/%ju\n"),
++					pid, runtime, deadline, period);
++		else
++			printf(_("pid %d's current runtime/deadline/period parameters: %ju/%ju/%ju\n"),
++					pid, runtime, deadline, period);
++	}
++#endif
++}
++
++
++static void show_sched_info(struct chrt_ctl *ctl)
++{
++	if (ctl->all_tasks) {
++		pid_t tid;
++		struct proc_tasks *ts = proc_open_tasks(ctl->pid);
++
++		if (!ts)
++			err(EXIT_FAILURE, _("cannot obtain the list of tasks"));
++
++		while (!proc_next_tid(ts, &tid))
++			show_sched_pid_info(ctl, tid);
++
++		proc_close_tasks(ts);
++	} else
++		show_sched_pid_info(ctl, ctl->pid);
+ }
+ 
+ static void show_min_max(void)
+@@ -167,52 +317,116 @@ static void show_min_max(void)
+ #ifdef SCHED_IDLE
+ 		SCHED_IDLE,
+ #endif
+-	};
+-	const char *names[] = {
+-		"OTHER",
+-		"FIFO",
+-		"RR",
+-#ifdef SCHED_BATCH
+-		"BATCH",
+-#endif
+-#ifdef SCHED_IDLE
+-		"IDLE",
++#ifdef SCHED_DEADLINE
++		SCHED_DEADLINE,
+ #endif
+ 	};
+ 
+ 	for (i = 0; i < ARRAY_SIZE(policies); i++) {
+-		int max = sched_get_priority_max(policies[i]);
+-		int min = sched_get_priority_min(policies[i]);
++		int plc = policies[i];
++		int max = sched_get_priority_max(plc);
++		int min = sched_get_priority_min(plc);
+ 
+ 		if (max >= 0 && min >= 0)
+-			printf(_("SCHED_%s min/max priority\t: %d/%d\n"),
+-					names[i], min, max);
++			printf(_("%s min/max priority\t: %d/%d\n"),
++					get_policy_name(plc), min, max);
+ 		else
+-			printf(_("SCHED_%s not supported?\n"), names[i]);
++			printf(_("%s not supported?\n"), get_policy_name(plc));
+ 	}
+ }
+ 
++static int set_sched_one_by_setscheduler(struct chrt_ctl *ctl, pid_t pid)
++{
++	struct sched_param sp = { .sched_priority = ctl->priority };
++	int policy = ctl->policy;
++
++# ifdef SCHED_RESET_ON_FORK
++	if (ctl->reset_on_fork)
++		policy |= SCHED_RESET_ON_FORK;
++# endif
++	return sched_setscheduler(pid, policy, &sp);
++}
++
++
++#ifndef HAVE_SCHED_SETATTR
++static int set_sched_one(struct chrt_ctl *ctl, pid_t pid)
++{
++	return set_sched_one_by_setscheduler(ctl, pid);
++}
++
++#else /* !HAVE_SCHED_SETATTR */
++static int set_sched_one(struct chrt_ctl *ctl, pid_t pid)
++{
++	/* use main() to check if the setting makes sense */
++	struct sched_attr sa = {
++		.size		= sizeof(struct sched_attr),
++		.sched_policy	= ctl->policy,
++		.sched_priority	= ctl->priority,
++		.sched_runtime  = ctl->runtime,
++		.sched_period   = ctl->period,
++		.sched_deadline = ctl->deadline
++	};
++	int rc;
++
++# ifdef SCHED_RESET_ON_FORK
++	if (ctl->reset_on_fork)
++		sa.sched_flags |= SCHED_RESET_ON_FORK;
++# endif
++	errno = 0;
++	rc = sched_setattr(pid, &sa, 0);
++
++	if (rc != 0 && errno == ENOSYS && ctl->policy != SCHED_DEADLINE)
++		/* fallback -- build with new kernel/libc, but executed on old kernels */
++		rc = set_sched_one_by_setscheduler(ctl, pid);
++
++	return rc;
++}
++#endif /* HAVE_SCHED_SETATTR */
++
++static void set_sched(struct chrt_ctl *ctl)
++{
++	if (ctl->all_tasks) {
++		pid_t tid;
++		struct proc_tasks *ts = proc_open_tasks(ctl->pid);
++
++		if (!ts)
++			err(EXIT_FAILURE, _("cannot obtain the list of tasks"));
++
++		while (!proc_next_tid(ts, &tid))
++			if (set_sched_one(ctl, tid) == -1)
++				err(EXIT_FAILURE, _("failed to set tid %d's policy"), tid);
++
++		proc_close_tasks(ts);
++
++	} else if (set_sched_one(ctl, ctl->pid) == -1)
++		err(EXIT_FAILURE, _("failed to set pid %d's policy"), ctl->pid);
++
++	ctl->altered = 1;
++}
++
+ int main(int argc, char **argv)
+ {
+-	int i, policy = SCHED_RR, priority = 0, verbose = 0, policy_flag = 0,
+-	    all_tasks = 0;
+-	struct sched_param sp;
+-	pid_t pid = -1;
++	struct chrt_ctl _ctl = { .pid = -1 }, *ctl = &_ctl;
++	int c;
+ 
+ 	static const struct option longopts[] = {
+-		{ "all-tasks",  0, NULL, 'a' },
+-		{ "batch",	0, NULL, 'b' },
+-		{ "fifo",	0, NULL, 'f' },
+-		{ "idle",	0, NULL, 'i' },
+-		{ "pid",	0, NULL, 'p' },
+-		{ "help",	0, NULL, 'h' },
+-		{ "max",        0, NULL, 'm' },
+-		{ "other",	0, NULL, 'o' },
+-		{ "rr",		0, NULL, 'r' },
+-		{ "reset-on-fork", 0, NULL, 'R' },
+-		{ "verbose",	0, NULL, 'v' },
+-		{ "version",	0, NULL, 'V' },
+-		{ NULL,		0, NULL, 0 }
++		{ "all-tasks",  no_argument, NULL, 'a' },
++		{ "batch",	no_argument, NULL, 'b' },
++		{ "deadline",   no_argument, NULL, 'd' },
++		{ "fifo",	no_argument, NULL, 'f' },
++		{ "idle",	no_argument, NULL, 'i' },
++		{ "pid",	no_argument, NULL, 'p' },
++		{ "help",	no_argument, NULL, 'h' },
++		{ "max",        no_argument, NULL, 'm' },
++		{ "other",	no_argument, NULL, 'o' },
++		{ "rr",		no_argument, NULL, 'r' },
++		{ "sched-runtime",  required_argument, NULL, 'T' },
++		{ "sched-period",   required_argument, NULL, 'P' },
++		{ "sched-deadline", required_argument, NULL, 'D' },
++		{ "reset-on-fork",  no_argument,       NULL, 'R' },
++		{ "verbose",	no_argument, NULL, 'v' },
++		{ "version",	no_argument, NULL, 'V' },
++		{ NULL,		no_argument, NULL, 0 }
+ 	};
+ 
+ 	setlocale(LC_ALL, "");
+@@ -220,51 +434,63 @@ int main(int argc, char **argv)
+ 	textdomain(PACKAGE);
+ 	atexit(close_stdout);
+ 
+-	while((i = getopt_long(argc, argv, "+abfiphmoRrvV", longopts, NULL)) != -1)
++	while((c = getopt_long(argc, argv, "+abdD:fiphmoP:T:rRvV", longopts, NULL)) != -1)
+ 	{
+ 		int ret = EXIT_FAILURE;
+ 
+-		switch (i) {
++		switch (c) {
+ 		case 'a':
+-			all_tasks = 1;
++			ctl->all_tasks = 1;
+ 			break;
+ 		case 'b':
+ #ifdef SCHED_BATCH
+-			policy = SCHED_BATCH;
++			ctl->policy = SCHED_BATCH;
++#endif
++			break;
++
++		case 'd':
++#ifdef SCHED_DEADLINE
++			ctl->policy = SCHED_DEADLINE;
+ #endif
+ 			break;
+ 		case 'f':
+-			policy = SCHED_FIFO;
++			ctl->policy = SCHED_FIFO;
+ 			break;
+ 		case 'R':
+-#ifdef SCHED_RESET_ON_FORK
+-			policy_flag |= SCHED_RESET_ON_FORK;
+-#endif
++			ctl->reset_on_fork = 1;
+ 			break;
+ 		case 'i':
+ #ifdef SCHED_IDLE
+-			policy = SCHED_IDLE;
++			ctl->policy = SCHED_IDLE;
+ #endif
+ 			break;
+ 		case 'm':
+ 			show_min_max();
+ 			return EXIT_SUCCESS;
+ 		case 'o':
+-			policy = SCHED_OTHER;
++			ctl->policy = SCHED_OTHER;
+ 			break;
+ 		case 'p':
+ 			errno = 0;
+-			pid = strtos32_or_err(argv[argc - 1], _("invalid PID argument"));
++			ctl->pid = strtos32_or_err(argv[argc - 1], _("invalid PID argument"));
+ 			break;
+ 		case 'r':
+-			policy = SCHED_RR;
++			ctl->policy = SCHED_RR;
+ 			break;
+ 		case 'v':
+-			verbose = 1;
++			ctl->verbose = 1;
++			break;
++		case 'T':
++			ctl->runtime = strtou64_or_err(optarg, _("invalid runtime argument"));
++			break;
++		case 'P':
++			ctl->period = strtou64_or_err(optarg, _("invalid period argument"));
++			break;
++		case 'D':
++			ctl->deadline = strtou64_or_err(optarg, _("invalid deadline argument"));
+ 			break;
+ 		case 'V':
+-			printf(_("%s from %s\n"), program_invocation_short_name,
+-			       PACKAGE_STRING);
++			printf(UTIL_LINUX_VERSION);
+ 			return EXIT_SUCCESS;
+ 		case 'h':
+ 			ret = EXIT_SUCCESS;
+@@ -274,61 +500,56 @@ int main(int argc, char **argv)
+ 		}
+ 	}
+ 
+-	if (((pid > -1) && argc - optind < 1) ||
+-	    ((pid == -1) && argc - optind < 2))
++	if (((ctl->pid > -1) && argc - optind < 1) ||
++	    ((ctl->pid == -1) && argc - optind < 2))
+ 		show_usage(EXIT_FAILURE);
+ 
+-	if ((pid > -1) && (verbose || argc - optind == 1)) {
+-		if (all_tasks) {
+-			pid_t tid;
+-			struct proc_tasks *ts = proc_open_tasks(pid);
+-
+-			if (!ts)
+-				err(EXIT_FAILURE, _("cannot obtain the list of tasks"));
+-			while (!proc_next_tid(ts, &tid))
+-				show_rt_info(tid, FALSE);
+-			proc_close_tasks(ts);
+-		} else
+-			show_rt_info(pid, FALSE);
+-
++	if ((ctl->pid > -1) && (ctl->verbose || argc - optind == 1)) {
++		show_sched_info(ctl);
+ 		if (argc - optind == 1)
+ 			return EXIT_SUCCESS;
+ 	}
+ 
+ 	errno = 0;
+-	priority = strtos32_or_err(argv[optind], _("invalid priority argument"));
++	ctl->priority = strtos32_or_err(argv[optind], _("invalid priority argument"));
+ 
+ #ifdef SCHED_RESET_ON_FORK
+-	/* sanity check */
+-	if ((policy_flag & SCHED_RESET_ON_FORK) &&
+-	    !(policy == SCHED_FIFO || policy == SCHED_RR))
+-		errx(EXIT_FAILURE, _("SCHED_RESET_ON_FORK flag is supported for "
++	if (ctl->reset_on_fork && ctl->policy != SCHED_FIFO && ctl->policy != SCHED_RR)
++		errx(EXIT_FAILURE, _("--reset-on-fork option is supported for "
+ 				     "SCHED_FIFO and SCHED_RR policies only"));
+ #endif
+-
+-	policy |= policy_flag;
+-
+-	if (pid == -1)
+-		pid = 0;
+-	sp.sched_priority = priority;
+-
+-	if (all_tasks) {
+-		pid_t tid;
+-		struct proc_tasks *ts = proc_open_tasks(pid);
+-
+-		if (!ts)
+-			err(EXIT_FAILURE, _("cannot obtain the list of tasks"));
+-		while (!proc_next_tid(ts, &tid))
+-			if (sched_setscheduler(tid, policy, &sp) == -1)
+-				err(EXIT_FAILURE, _("failed to set tid %d's policy"), tid);
+-		proc_close_tasks(ts);
+-	} else if (sched_setscheduler(pid, policy, &sp) == -1)
+-		err(EXIT_FAILURE, _("failed to set pid %d's policy"), pid);
+-
+-	if (verbose)
+-		show_rt_info(pid, TRUE);
+-
+-	if (!pid) {
++#ifdef SCHED_DEADLINE
++	if ((ctl->runtime || ctl->deadline || ctl->period) && ctl->policy != SCHED_DEADLINE)
++		errx(EXIT_FAILURE, _("--sched-{runtime,deadline,period} options "
++				     "are supported for SCHED_DEADLINE only"));
++	if (ctl->policy == SCHED_DEADLINE) {
++		/* The basic rule is runtime <= deadline <= period, so we can
++		 * make deadline and runtime optional on command line. Note we
++		 * don't check any values or set any defaults, it's kernel
++		 * responsibility.
++		 */
++		if (ctl->deadline == 0)
++			ctl->deadline = ctl->period;
++		if (ctl->runtime == 0)
++			ctl->runtime = ctl->deadline;
++	}
++#else
++	if (ctl->runtime || ctl->deadline || ctl->period)
++		errx(EXIT_FAILURE, _("SCHED_DEADLINE is unsupported"));
++#endif
++	if (ctl->pid == -1)
++		ctl->pid = 0;
++	if (ctl->priority < sched_get_priority_min(ctl->policy) ||
++	    sched_get_priority_max(ctl->policy) < ctl->priority)
++		errx(EXIT_FAILURE,
++		     _("unsupported priority value for the policy: %d: see --max for valid range"),
++		     ctl->priority);
++	set_sched(ctl);
++
++	if (ctl->verbose)
++		show_sched_info(ctl);
++
++	if (!ctl->pid) {
+ 		argv += optind + 1;
+ 		execvp(argv[0], argv);
+ 		err(EXIT_FAILURE, _("failed to execute %s"), argv[0]);
+-- 
+2.7.4
+
diff --git a/SOURCES/0082-fdisk-backport-DOS-logical-partitions-chain-reorder.patch b/SOURCES/0082-fdisk-backport-DOS-logical-partitions-chain-reorder.patch
new file mode 100644
index 0000000..23b1f47
--- /dev/null
+++ b/SOURCES/0082-fdisk-backport-DOS-logical-partitions-chain-reorder.patch
@@ -0,0 +1,211 @@
+From 28b08b639aeaadbfcc3fb66558e6b392b2b5d44c Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 28 Jun 2016 11:30:21 +0200
+Subject: [PATCH 82/86] fdisk: backport DOS logical partitions chain reorder
+
+... from the current upstream.
+
+Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1304246
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ fdisks/fdiskdoslabel.c | 170 +++++++++++++++++++++++++++++++++----------------
+ 1 file changed, 116 insertions(+), 54 deletions(-)
+
+diff --git a/fdisks/fdiskdoslabel.c b/fdisks/fdiskdoslabel.c
+index fe04ac7..b7eb35a 100644
+--- a/fdisks/fdiskdoslabel.c
++++ b/fdisks/fdiskdoslabel.c
+@@ -55,6 +55,22 @@ static int MBRbuffer_changed;
+ #define cround(c, n)	(fdisk_context_use_cylinders(c) ? \
+ 				((n) / fdisk_context_get_units_per_sector(c)) + 1 : (n))
+ 
++
++static unsigned long long
++get_abs_partition_start(struct pte *pe)
++{
++	return pe->offset + get_start_sect(pe->part_table);
++}
++
++static unsigned long long
++get_abs_partition_end(struct pte *pe)
++{
++	unsigned long long size;
++
++	size = get_nr_sects(pe->part_table);
++	return get_abs_partition_start(pe) + size - (size ? 1 : 0);
++}
++
+ static void warn_alignment(struct fdisk_context *cxt)
+ {
+ 	if (nowarn)
+@@ -1254,67 +1270,113 @@ void dos_list_table_expert(struct fdisk_context *cxt, int extend)
+ 	}
+ }
+ 
+-/*
+- * Fix the chain of logicals.
+- * extended_offset is unchanged, the set of sectors used is unchanged
+- * The chain is sorted so that sectors increase, and so that
+- * starting sectors increase.
+- *
+- * After this it may still be that cfdisk doesn't like the table.
+- * (This is because cfdisk considers expanded parts, from link to
+- * end of partition, and these may still overlap.)
+- * Now
+- *   sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
+- * may help.
+- */
++
++static void print_chain_of_logicals(struct fdisk_context *cxt)
++{
++	size_t i;
++
++	fputc('\n', stdout);
++
++	for (i = 4; i < cxt->label->nparts_max; i++) {
++		struct pte *pe = &ptes[i];
++
++		fprintf(stderr, "#%02zu EBR [%10ju], "
++			"data[start=%10ju (%10ju), size=%10ju], "
++			"link[start=%10ju (%10ju), size=%10ju]\n",
++			i, (uintmax_t) pe->offset,
++			/* data */
++			(uintmax_t) get_start_sect(pe->part_table),
++			(uintmax_t) get_abs_partition_start(pe),
++			(uintmax_t) get_nr_sects(pe->part_table),
++			/* link */
++			(uintmax_t) get_start_sect(pe->ext_pointer),
++			(uintmax_t) (extended_offset + get_start_sect(pe->ext_pointer)),
++			(uintmax_t) get_nr_sects(pe->ext_pointer));
++	}
++}
++
++static int cmp_ebr_offsets(const void *a, const void *b)
++{
++	struct pte *ae = (struct pte *) a,
++		   *be = (struct pte *) b;
++
++	if (ae->offset == 0 && be->offset == 0)
++		return 0;
++	if (ae->offset == 0)
++		return 1;
++	if (be->offset == 0)
++		return -1;
++
++	return cmp_numbers(ae->offset, be->offset);
++}
++
+ static void fix_chain_of_logicals(struct fdisk_context *cxt)
+ {
+-	size_t j, oj, ojj, sj, sjj;
+-	struct partition *pj,*pjj,tmp;
+-
+-	/* Stage 1: sort sectors but leave sector of part 4 */
+-	/* (Its sector is the global extended_offset.) */
+- stage1:
+-	for (j = 5; j < cxt->label->nparts_max - 1; j++) {
+-		oj = ptes[j].offset;
+-		ojj = ptes[j+1].offset;
+-		if (oj > ojj) {
+-			ptes[j].offset = ojj;
+-			ptes[j+1].offset = oj;
+-			pj = ptes[j].part_table;
+-			set_start_sect(pj, get_start_sect(pj)+oj-ojj);
+-			pjj = ptes[j+1].part_table;
+-			set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
+-			set_start_sect(ptes[j-1].ext_pointer,
+-				       ojj-extended_offset);
+-			set_start_sect(ptes[j].ext_pointer,
+-				       oj-extended_offset);
+-			goto stage1;
++	struct pte *last;
++	size_t i;
++
++	DBG(CONTEXT, print_chain_of_logicals(cxt));
++
++	/* Sort chain by EBR offsets */
++	qsort(&ptes[4], cxt->label->nparts_max - 4, sizeof(struct pte),
++			cmp_ebr_offsets);
++
++again:
++	/* Sort data partitions by start */
++	for (i = 4; i < cxt->label->nparts_max - 1; i++) {
++		struct pte *cur = &ptes[i],
++			   *nxt = &ptes[i + 1];
++
++		if (get_abs_partition_start(cur) >
++		    get_abs_partition_start(nxt)) {
++
++			struct partition tmp = *cur->part_table;
++			sector_t cur_start = get_abs_partition_start(cur),
++				 nxt_start = get_abs_partition_start(nxt);
++
++			/* swap data partitions */
++			*cur->part_table = *nxt->part_table;
++			*nxt->part_table = tmp;
++
++			/* Recount starts according to EBR offsets, the absolute
++			 * address still has to be the same! */
++			set_start_sect(cur->part_table, nxt_start - cur->offset);
++			set_start_sect(nxt->part_table, cur_start - nxt->offset);
++
++			cur->changed = 1;
++			nxt->changed = 1;
++			goto again;
+ 		}
+ 	}
+ 
+-	/* Stage 2: sort starting sectors */
+- stage2:
+-	for (j = 4; j < cxt->label->nparts_max - 1; j++) {
+-		pj = ptes[j].part_table;
+-		pjj = ptes[j+1].part_table;
+-		sj = get_start_sect(pj);
+-		sjj = get_start_sect(pjj);
+-		oj = ptes[j].offset;
+-		ojj = ptes[j+1].offset;
+-		if (oj+sj > ojj+sjj) {
+-			tmp = *pj;
+-			*pj = *pjj;
+-			*pjj = tmp;
+-			set_start_sect(pj, ojj+sjj-oj);
+-			set_start_sect(pjj, oj+sj-ojj);
+-			goto stage2;
+-		}
++	/* Update EBR links */
++	for (i = 4; i < cxt->label->nparts_max - 1; i++) {
++		struct pte *cur = &ptes[i],
++			   *nxt = &ptes[i + 1];
++
++		sector_t noff = nxt->offset - extended_offset,
++		         ooff = get_start_sect(cur->ext_pointer);
++
++		if (noff == ooff)
++			continue;
++
++		DBG(CONTEXT, dbgprint("DOS: fix EBR [%10ju] link %ju -> %ju",
++			(uintmax_t) cur->offset,
++			(uintmax_t) ooff, (uintmax_t) noff));
++
++		set_partition(cxt, i, 1, nxt->offset,
++				get_abs_partition_end(nxt),
++				EXTENDED);
++	}
++
++	/* always terminate the chain ! */
++	last = &ptes[cxt->label->nparts_max - 1];
++	if (last) {
++		clear_partition(last->ext_pointer);
++		last->changed = 1;
+ 	}
+ 
+-	/* Probably something was changed */
+-	for (j = 4; j < cxt->label->nparts_max; j++)
+-		ptes[j].changed = 1;
++	DBG(CONTEXT, print_chain_of_logicals(cxt));
+ }
+ 
+ void dos_fix_partition_table_order(struct fdisk_context *cxt)
+-- 
+2.7.4
+
diff --git a/SOURCES/0083-tests-cleanup-tests.patch b/SOURCES/0083-tests-cleanup-tests.patch
new file mode 100644
index 0000000..10da5f2
--- /dev/null
+++ b/SOURCES/0083-tests-cleanup-tests.patch
@@ -0,0 +1,276 @@
+From d35dfbe11f7c6b84d40a6e54611dc3a8c9c27b4d Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Thu, 30 Jun 2016 11:00:54 +0200
+Subject: [PATCH 83/86] tests: cleanup tests
+
+... mostly to be more portable to the new kernels and userspace.
+
+Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1153770
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ tests/commands.sh                           |  1 +
+ tests/expected/blkid/md-raid0-whole         |  2 +-
+ tests/expected/blkid/md-raid1-part          |  2 +-
+ tests/expected/blkid/md-raid1-whole         |  2 +-
+ tests/expected/fdisk/align-512-4K           |  2 +-
+ tests/expected/fdisk/align-512-4K-63        |  2 +-
+ tests/expected/fdisk/align-512-4K-md        |  4 ++--
+ tests/expected/fdisk/align-512-512          |  2 +-
+ tests/expected/fdisk/align-512-512-topology |  2 +-
+ tests/expected/ipcs/limits                  |  4 ----
+ tests/functions.sh                          | 29 +++++++++++++++++++++++------
+ tests/ts/ipcs/limits                        |  5 +----
+ tests/ts/ipcs/limits2                       |  2 ++
+ tests/ts/libmount/context-utab              | 10 ++++++++--
+ 14 files changed, 44 insertions(+), 25 deletions(-)
+
+diff --git a/tests/commands.sh b/tests/commands.sh
+index a2948c9..e769b5d 100644
+--- a/tests/commands.sh
++++ b/tests/commands.sh
+@@ -64,3 +64,4 @@ TS_CMD_UL=${TS_CMD_UL-"$top_builddir/ul"}
+ TS_CMD_UMOUNT=${TS_CMD_UMOUNT:-"$top_builddir/umount"}
+ TS_CMD_UTMPDUMP=${TS_CMD_UTMPDUMP-"$top_builddir/utmpdump"}
+ TS_CMD_WHEREIS=${TS_CMD_WHEREIS-"$top_builddir/whereis"}
++TS_CMD_WIPEFS=${TS_CMD_WIPEFS-"$top_builddir/wipefs"}
+diff --git a/tests/expected/blkid/md-raid0-whole b/tests/expected/blkid/md-raid0-whole
+index 37dabf3..30825de 100644
+--- a/tests/expected/blkid/md-raid0-whole
++++ b/tests/expected/blkid/md-raid0-whole
+@@ -26,7 +26,7 @@ Command (m for help):
+ Disk /dev/md8: 104 MB, 104726528 bytes, 204544 sectors
+ Units = sectors of 1 * 512 = 512 bytes
+ Sector size (logical/physical): 512 bytes / 512 bytes
+-I/O size (minimum/optimal): 65536 bytes / 131072 bytes
++I/O size (minimum/optimal): 65536 bytes / <removed> bytes
+ Disk label type: dos
+ 
+ 
+diff --git a/tests/expected/blkid/md-raid1-part b/tests/expected/blkid/md-raid1-part
+index f409952..3d1b38c 100644
+--- a/tests/expected/blkid/md-raid1-part
++++ b/tests/expected/blkid/md-raid1-part
+@@ -24,7 +24,7 @@ Command (m for help):
+ Disk /dev/...: 53 MB, 53477376 bytes, 104448 sectors
+ Units = sectors of 1 * 512 = 512 bytes
+ Sector size (logical/physical): 512 bytes / 512 bytes
+-I/O size (minimum/optimal): 512 bytes / 32768 bytes
++I/O size (minimum/optimal): 512 bytes / <removed> bytes
+ Disk label type: dos
+ 
+ 
+diff --git a/tests/expected/blkid/md-raid1-whole b/tests/expected/blkid/md-raid1-whole
+index 8977312..8ab1da2 100644
+--- a/tests/expected/blkid/md-raid1-whole
++++ b/tests/expected/blkid/md-raid1-whole
+@@ -25,7 +25,7 @@ Command (m for help):
+ Disk /dev/md8: 52 MB, 52363264 bytes, 102272 sectors
+ Units = sectors of 1 * 512 = 512 bytes
+ Sector size (logical/physical): 512 bytes / 512 bytes
+-I/O size (minimum/optimal): 512 bytes / 512 bytes
++I/O size (minimum/optimal): 512 bytes / <removed> bytes
+ Disk label type: dos
+ 
+ 
+diff --git a/tests/expected/fdisk/align-512-4K b/tests/expected/fdisk/align-512-4K
+index e5a28f5..7b52fd2 100644
+--- a/tests/expected/fdisk/align-512-4K
++++ b/tests/expected/fdisk/align-512-4K
+@@ -57,7 +57,7 @@ Command (m for help):
+ Disk /dev/...: 52 MB, 52428800 bytes, 102400 sectors
+ Units = sectors of 1 * 512 = 512 bytes
+ Sector size (logical/physical): 512 bytes / 4096 bytes
+-I/O size (minimum/optimal): 4096 bytes / 32768 bytes
++I/O size (minimum/optimal): 4096 bytes / <removed> bytes
+ Disk label type: dos
+ 
+ 
+diff --git a/tests/expected/fdisk/align-512-4K-63 b/tests/expected/fdisk/align-512-4K-63
+index 7e236ce..302a429 100644
+--- a/tests/expected/fdisk/align-512-4K-63
++++ b/tests/expected/fdisk/align-512-4K-63
+@@ -57,7 +57,7 @@ Command (m for help):
+ Disk /dev/...: 52 MB, 52428800 bytes, 102400 sectors
+ Units = sectors of 1 * 512 = 512 bytes
+ Sector size (logical/physical): 512 bytes / 4096 bytes
+-I/O size (minimum/optimal): 4096 bytes / 32768 bytes
++I/O size (minimum/optimal): 4096 bytes / <removed> bytes
+ Alignment offset: 3584 bytes
+ Disk label type: dos
+ 
+diff --git a/tests/expected/fdisk/align-512-4K-md b/tests/expected/fdisk/align-512-4K-md
+index dbbbc05..e8f6ba1 100644
+--- a/tests/expected/fdisk/align-512-4K-md
++++ b/tests/expected/fdisk/align-512-4K-md
+@@ -28,7 +28,7 @@ Command (m for help):
+ Disk /dev/...: 52 MB, 52428800 bytes, 102400 sectors
+ Units = sectors of 1 * 512 = 512 bytes
+ Sector size (logical/physical): 512 bytes / 4096 bytes
+-I/O size (minimum/optimal): 4096 bytes / 32768 bytes
++I/O size (minimum/optimal): 4096 bytes / <removed> bytes
+ Disk label type: dos
+ 
+ 
+@@ -72,7 +72,7 @@ Command (m for help):
+ Disk /dev/md8: 51 MB, 51249152 bytes, 100096 sectors
+ Units = sectors of 1 * 512 = 512 bytes
+ Sector size (logical/physical): 512 bytes / 4096 bytes
+-I/O size (minimum/optimal): 65536 bytes / 131072 bytes
++I/O size (minimum/optimal): 65536 bytes / <removed> bytes
+ Disk label type: dos
+ 
+ 
+diff --git a/tests/expected/fdisk/align-512-512 b/tests/expected/fdisk/align-512-512
+index 018322f..8e03d90 100644
+--- a/tests/expected/fdisk/align-512-512
++++ b/tests/expected/fdisk/align-512-512
+@@ -53,7 +53,7 @@ Command (m for help):
+ Disk /dev/loop0: 52 MB, 52428800 bytes, 102400 sectors
+ Units = sectors of 1 * 512 = 512 bytes
+ Sector size (logical/physical): 512 bytes / 512 bytes
+-I/O size (minimum/optimal): 512 bytes / 512 bytes
++I/O size (minimum/optimal): 512 bytes / <removed> bytes
+ Disk label type: dos
+ 
+ 
+diff --git a/tests/expected/fdisk/align-512-512-topology b/tests/expected/fdisk/align-512-512-topology
+index b3d3114..fd57f60 100644
+--- a/tests/expected/fdisk/align-512-512-topology
++++ b/tests/expected/fdisk/align-512-512-topology
+@@ -53,7 +53,7 @@ Command (m for help):
+ Disk /dev/...: 52 MB, 52428800 bytes, 102400 sectors
+ Units = sectors of 1 * 512 = 512 bytes
+ Sector size (logical/physical): 512 bytes / 512 bytes
+-I/O size (minimum/optimal): 512 bytes / 32768 bytes
++I/O size (minimum/optimal): 512 bytes / <removed> bytes
+ Disk label type: dos
+ 
+ 
+diff --git a/tests/expected/ipcs/limits b/tests/expected/ipcs/limits
+index 7480a1e..e08fa54 100644
+--- a/tests/expected/ipcs/limits
++++ b/tests/expected/ipcs/limits
+@@ -1,8 +1,4 @@
+ load original values
+-check for difference between kernel and IPC
+-/proc/sys/kernel/shmmni OK
+-/proc/sys/kernel/shmall OK
+-/proc/sys/kernel/shmmax OK
+ maximalize kernel setting
+ re-check for difference between kernel and IPC
+ /proc/sys/kernel/shmmni OK
+diff --git a/tests/functions.sh b/tests/functions.sh
+index b2d493c..0d1c9c8 100644
+--- a/tests/functions.sh
++++ b/tests/functions.sh
+@@ -31,6 +31,17 @@ function ts_canonicalize {
+ 	fi
+ }
+ 
++function ts_check_test_command {
++	if [ ! -x "$1" ]; then
++		ts_skip "${1##*/} not found"
++	fi
++}
++
++function ts_check_prog {
++	local cmd=$1
++	type "$cmd" >/dev/null 2>&1 || ts_skip "missing in PATH: $cmd"
++}
++
+ function ts_skip_subtest {
+ 	echo " IGNORE ($1)"
+ }
+@@ -474,14 +485,20 @@ function ts_fdisk_clean {
+ 	local DEVNAME=$(basename "$1")
+ 
+ 	# remove non comparable parts of fdisk output
+-	if [ x"${DEVNAME}" != x"" ]; then
+-	       sed -i -e "s/\/dev\/${DEVNAME}/\/dev\/.../g" $TS_OUTPUT
++	if [ -n "${DEVNAME}" ]; then
++		sed -i -e "s@${DEVNAME}@...@;" $TS_OUTPUT
+ 	fi
+ 
+-	sed -i -e 's/Disk identifier:.*//g' \
+-	       -e 's/Building a new.*//g' \
+-	       -e 's/Welcome to fdisk.*//g' \
+-	       $TS_OUTPUT
++	sed -i \
++		-e 's/Disk identifier:.*//' \
++		-e 's/Building a new.*//' \
++		-e 's/Created a new.*//' \
++		-e 's/^Device[[:blank:]]*Start/Device             Start/' \
++		-e 's/^Device[[:blank:]]*Boot/Device     Boot/' \
++		-e 's/Welcome to fdisk.*//' \
++		-e 's/typescript file.*/typescript file <removed>./' \
++		-e 's@^\(I/O size (minimum/op.* bytes /\) [1-9][0-9]* @\1 <removed> @' \
++		$TS_OUTPUT
+ }
+ 
+ function ts_scsi_debug_init {
+diff --git a/tests/ts/ipcs/limits b/tests/ts/ipcs/limits
+index b44adb1..c4717c3 100755
+--- a/tests/ts/ipcs/limits
++++ b/tests/ts/ipcs/limits
+@@ -23,7 +23,7 @@ TS_DESC="limits overflow"
+ 
+ ts_init "$*"
+ ts_skip_nonroot
+-type bc >/dev/null 2>&1 || ts_skip "cannot find bc command"
++ts_check_prog "bc"
+ 
+ . $TS_SELF/functions.sh
+ 
+@@ -32,9 +32,6 @@ for i in $IPCS_IDX; do
+ 	SHM_ORG[$i]=$(cat ${IPCS_PROCFILES[$i]})
+ done >> $TS_OUTPUT
+ 
+-ts_log "check for difference between kernel and IPC"
+-ipcs_limits_check >> $TS_OUTPUT
+-
+ ts_log "maximalize kernel setting"
+ for i in $IPCS_IDX; do
+ 	echo ${IPCS_LIMITS[$i]} >> ${IPCS_PROCFILES[$i]}
+diff --git a/tests/ts/ipcs/limits2 b/tests/ts/ipcs/limits2
+index 63f834d..2eabfd2 100755
+--- a/tests/ts/ipcs/limits2
++++ b/tests/ts/ipcs/limits2
+@@ -22,6 +22,8 @@ TS_DESC="basic limits"
+ . $TS_TOPDIR/functions.sh
+ ts_init "$*"
+ 
++ts_check_prog "bc"
++
+ . $TS_SELF/functions.sh
+ 
+ # TODO https://github.com/karelzak/util-linux/issues/51
+diff --git a/tests/ts/libmount/context-utab b/tests/ts/libmount/context-utab
+index 859fc2b..b2bfefc 100755
+--- a/tests/ts/libmount/context-utab
++++ b/tests/ts/libmount/context-utab
+@@ -87,14 +87,20 @@ ts_finalize_subtest
+ 
+ 
+ if [ -x "/sbin/mkfs.btrfs" ]; then
++
+ 	$TS_CMD_WIPEFS -a  $DEVICE &> /dev/null
+ 	ts_log "Create filesystem [btrfs]"
+ 	/sbin/mkfs.btrfs -L "$LABEL" $DEVICE &> /dev/null
+ 	udevadm settle
+ 
+ 	mount -t btrfs $DEVICE $MOUNTPOINT &> /dev/null
+-	/sbin/btrfsctl -S sub $MOUNTPOINT &> /dev/null
+-	umount $MOUNTPOINT &> /dev/null
++
++	if [ -x "/sbin/btrfsctl" ]; then
++		/sbin/btrfsctl -S sub $MOUNTPOINT &> /dev/null
++	else
++		btrfs subvolume create $MOUNTPOINT/sub &> /dev/null
++	fi
++	umount $MOUNTPOINT #&> /dev/null
+ 
+ 	udevadm settle
+ 
+-- 
+2.7.4
+
diff --git a/SOURCES/0084-libmount-add-support-for-bind-ro.patch b/SOURCES/0084-libmount-add-support-for-bind-ro.patch
new file mode 100644
index 0000000..f86edbb
--- /dev/null
+++ b/SOURCES/0084-libmount-add-support-for-bind-ro.patch
@@ -0,0 +1,160 @@
+From 2218dc0d130bb72809e2d8b26a36402bf6293727 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Mon, 17 Aug 2015 11:54:26 +0200
+Subject: [PATCH 84/86] libmount: add support for "bind,ro"
+
+Now it's necessary to use two mount(8) calls to create a read-only
+mount:
+
+  mount /foo /bar -o bind
+  mount /bar -o remount,ro,bind
+
+This patch allows to specify "bind,ro" and the remount is done
+automatically by libmount by additional mount(2) syscall. It's not
+atomic of course.
+
+Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1281839
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libmount/src/context_mount.c | 46 ++++++++++++++++++++++++++++++++++++++++++++
+ sys-utils/mount.8            | 37 ++++++++++++++++++-----------------
+ 2 files changed, 65 insertions(+), 18 deletions(-)
+
+diff --git a/libmount/src/context_mount.c b/libmount/src/context_mount.c
+index d6691eb..4df2646 100644
+--- a/libmount/src/context_mount.c
++++ b/libmount/src/context_mount.c
+@@ -62,6 +62,10 @@ static int mnt_context_append_additional_mount(struct libmnt_context *cxt,
+ 	return 0;
+ }
+ 
++/*
++ * add additional mount(2) syscall requests when necessary to set propagation flags
++ * after regular mount(2).
++ */
+ static int init_propagation(struct libmnt_context *cxt)
+ {
+ 	char *name;
+@@ -102,6 +106,41 @@ static int init_propagation(struct libmnt_context *cxt)
+ }
+ 
+ /*
++ * add additional mount(2) syscall request to implement "ro,bind", the first regular
++ * mount(2) is the "bind" operation, the second is "remount,ro,bind" call.
++ *
++ * Note that we don't remove "ro" from the first syscall (kernel silently
++ * ignores this flags for bind operation) -- maybe one day kernel will support
++ * read-only binds in one step and then all will be done by the firts mount(2) and the
++ * second remount will be noop...
++ */
++static int init_robind(struct libmnt_context *cxt)
++{
++	struct libmnt_addmount *ad;
++	int rc;
++
++	assert(cxt);
++	assert(cxt->mountflags & MS_BIND);
++	assert(cxt->mountflags & MS_RDONLY);
++	assert(!(cxt->mountflags & MS_REMOUNT));
++
++	DBG(CXT, mnt_debug_h(cxt, "mount: initialize additional ro,bind mount"));
++
++	ad = mnt_new_addmount();
++	if (!ad)
++		return -ENOMEM;
++
++	ad->mountflags = MS_REMOUNT | MS_BIND | MS_RDONLY;
++	if (cxt->mountflags & MS_REC)
++		ad->mountflags |= MS_REC;
++	rc = mnt_context_append_additional_mount(cxt, ad);
++	if (rc)
++		return rc;
++
++	return 0;
++}
++
++/*
+  * this has to be called after mnt_context_evaluate_permissions()
+  */
+ static int fix_optstr(struct libmnt_context *cxt)
+@@ -174,6 +213,13 @@ static int fix_optstr(struct libmnt_context *cxt)
+ 		if (rc)
+ 			return rc;
+ 	}
++	if ((cxt->mountflags & MS_BIND)
++	    && (cxt->mountflags & MS_RDONLY)
++	    && !(cxt->mountflags & MS_REMOUNT)) {
++		rc = init_robind(cxt);
++		if (rc)
++			return rc;
++	}
+ 
+ 	next = fs->fs_optstr;
+ 
+diff --git a/sys-utils/mount.8 b/sys-utils/mount.8
+index 3648870..49cb281 100644
+--- a/sys-utils/mount.8
++++ b/sys-utils/mount.8
+@@ -388,25 +388,25 @@ or shortoption
+ .\" available since Linux 2.4.11.
+ 
+ Note that the filesystem mount options will remain the same as those
+-on the original mount point, and cannot be changed by passing the -o
+-option along with --bind/--rbind. The mount options can be
+-changed by a separate remount command, for example:
++on the original mount point.
++
++.BR mount(8)
++since v2.27 (backported to RHEL7.3) allow to change the options by passing the
++.B \-o
++option along with
++.BR \-\-bind
++for example:
+ 
+ .RS
+ .br
+-.B mount --bind
+-.I olddir newdir
+-.br
+-.B mount -o remount,ro
+-.I newdir
++.B mount \-\-bind,ro foo foo
+ .RE
+ 
+-Note that behavior of the remount operation depends on the /etc/mtab file. The
+-first command stores the 'bind' flag to the /etc/mtab file and the second
+-command reads the flag from the file.  If you have a system without the
+-/etc/mtab file or if you explicitly define source and target for the remount
+-command (then mount(8) does not read /etc/mtab), then you have to use bind flag
+-(or option) for the remount command too. For example:
++This feature is not supported by Linux kernel and it is implemented in userspace
++by additional remount mount(2) syscall. This solution is not atomic.
++
++The alternative (classic) way to create a read-only bind mount is to use remount
++operation, for example:
+ 
+ .RS
+ .br
+@@ -417,14 +417,15 @@ command (then mount(8) does not read /etc/mtab), then you have to use bind flag
+ .I olddir newdir
+ .RE
+ 
+-Note that
+-.I remount,ro,bind
+-will create a read-only mountpoint (VFS entry), but the original filesystem suberblock
+-will be still writable, it means that the
++Note that read-only bind will create a read-only mountpoint (VFS entry), but the
++original filesystem superblock will still be writable, meaning that the
+ .I olddir
+ will be writable, but the
+ .I newdir
+ will be read-only.
++
++It's impossible to change mount options recursively
++(for example with \fB -o rbind,ro\fR).
+ .RE
+ 
+ .B The move operation.
+-- 
+2.7.4
+
diff --git a/SOURCES/0085-libblkid-store-only-canonical-devnames-to-the-cache.patch b/SOURCES/0085-libblkid-store-only-canonical-devnames-to-the-cache.patch
new file mode 100644
index 0000000..0ee3aa3
--- /dev/null
+++ b/SOURCES/0085-libblkid-store-only-canonical-devnames-to-the-cache.patch
@@ -0,0 +1,176 @@
+From 75b6c0e045abb7e07773b924237c562ab9920c60 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Thu, 26 May 2016 12:02:12 +0200
+Subject: [PATCH 85/86] libblkid: store only canonical devnames to the cache
+
+Let's try to use symlink:
+
+ # ls -la /dev/block/8\:1
+ # lrwxrwxrwx 1 root root 7 May 25 16:42 /dev/block/8:1 -> ../sda1
+
+ # blkid /dev/block/8:1
+ /dev/block/8:3: LABEL="HOME" UUID="196972ad-3b13-4bba-ac54-4cb3f7b409a4" TYPE="ext4" PARTUUID="6073277f-87bc-43ff-bcfd-724c4484a63a"
+
+unfortunately the symlink is stored to the cache:
+
+ <device DEVNO="0x0803" TIME="1464253300.715279" LABEL="HOME" UUID="196972ad-3b13-4bba-ac54-4cb3f7b409a4" TYPE="ext4" PARTUUID="6073277f-87bc-43ff-bcfd-724c4484a63a">/dev/block/8:3</device>
+
+next time if you ask for LABEL=HOME the answer will be /dev/block/8:3
+rather than /dev/sda3.
+
+It seems better to canonicalize the paths we store to the cache.
+
+Unfortunately if you ask for /dev/block/8:3 then you probably expect
+that blkid_dev_devname() returns the same path. This patch introduces
+dev->bid_xname, this is the path used by application (and never stored
+in the cache).
+
+Upstream: http://github.com/karelzak/util-linux/commit/924c93d9df118338fd54cd73b4a45ccddc4ac103
+Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1007734
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libblkid/src/blkidP.h  |  4 +++-
+ libblkid/src/dev.c     | 11 +++++++++--
+ libblkid/src/devname.c | 43 +++++++++++++++++++++++++++++++++++++------
+ 3 files changed, 49 insertions(+), 9 deletions(-)
+
+diff --git a/libblkid/src/blkidP.h b/libblkid/src/blkidP.h
+index 7de84b4..8183c12 100644
+--- a/libblkid/src/blkidP.h
++++ b/libblkid/src/blkidP.h
+@@ -44,7 +44,7 @@ struct blkid_struct_dev
+ 	struct list_head	bid_devs;	/* All devices in the cache */
+ 	struct list_head	bid_tags;	/* All tags for this device */
+ 	blkid_cache		bid_cache;	/* Dev belongs to this cache */
+-	char			*bid_name;	/* Device inode pathname */
++	char			*bid_name;	/* Device real pathn (as used in cache) */
+ 	char			*bid_type;	/* Preferred device TYPE */
+ 	int			bid_pri;	/* Device priority */
+ 	dev_t			bid_devno;	/* Device major/minor number */
+@@ -53,6 +53,8 @@ struct blkid_struct_dev
+ 	unsigned int		bid_flags;	/* Device status bitflags */
+ 	char			*bid_label;	/* Shortcut to device LABEL */
+ 	char			*bid_uuid;	/* Shortcut to binary UUID */
++
++	char			*bid_xname;	/* Device path as used by application (maybe symlink..) */
+ };
+ 
+ #define BLKID_BID_FL_VERIFIED	0x0001	/* Device data validated from disk */
+diff --git a/libblkid/src/dev.c b/libblkid/src/dev.c
+index a4b2aea..d2fd3f4 100644
+--- a/libblkid/src/dev.c
++++ b/libblkid/src/dev.c
+@@ -60,16 +60,23 @@ void blkid_free_dev(blkid_dev dev)
+ 					   bit_tags);
+ 		blkid_free_tag(tag);
+ 	}
++	free(dev->bid_xname);
+ 	free(dev->bid_name);
+ 	free(dev);
+ }
+ 
+ /*
+- * Given a blkid device, return its name
++ * Given a blkid device, return its name. The function returns the name
++ * previously used for blkid_get_dev(). This name does not have to be canonical
++ * (real path) name, but for example symlink.
+  */
+ const char *blkid_dev_devname(blkid_dev dev)
+ {
+-	return dev ? dev->bid_name : NULL;
++	if (!dev)
++		return NULL;
++	if (dev->bid_xname)
++		return dev->bid_xname;
++	return dev->bid_name;
+ }
+ 
+ #ifdef CONFIG_BLKID_DEBUG
+diff --git a/libblkid/src/devname.c b/libblkid/src/devname.c
+index 497deaf..55b9594 100644
+--- a/libblkid/src/devname.c
++++ b/libblkid/src/devname.c
+@@ -51,28 +51,55 @@ blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags)
+ {
+ 	blkid_dev dev = NULL, tmp;
+ 	struct list_head *p, *pnext;
++	char *cn = NULL;
+ 
+ 	if (!cache || !devname)
+ 		return NULL;
+ 
++	/* search by name */
+ 	list_for_each(p, &cache->bic_devs) {
+ 		tmp = list_entry(p, struct blkid_struct_dev, bid_devs);
+ 		if (strcmp(tmp->bid_name, devname))
+ 			continue;
+-
+-		DBG(DEVNAME, blkid_debug("found devname %s in cache", tmp->bid_name));
+ 		dev = tmp;
+ 		break;
+ 	}
+ 
++	/* try canonicalize the name */
++	if (!dev && (cn = canonicalize_path(devname))) {
++		if (strcmp(cn, devname) != 0) {
++			DBG(DEVNAME, blkid_debug("search cannonical %s", cn));
++			list_for_each(p, &cache->bic_devs) {
++				tmp = list_entry(p, struct blkid_struct_dev, bid_devs);
++				if (strcmp(tmp->bid_name, cn))
++					continue;
++				dev = tmp;
++
++				/* update name returned by blkid_dev_devname() */
++				free(dev->bid_xname);
++				dev->bid_xname = strdup(devname);
++				break;
++			}
++		} else {
++			free(cn);
++			cn = NULL;
++		}
++	}
++
+ 	if (!dev && (flags & BLKID_DEV_CREATE)) {
+ 		if (access(devname, F_OK) < 0)
+-			return NULL;
++			goto done;
+ 		dev = blkid_new_dev();
+ 		if (!dev)
+-			return NULL;
++			goto done;
+ 		dev->bid_time = INT_MIN;
+-		dev->bid_name = strdup(devname);
++		if (cn) {
++			dev->bid_name = cn;
++			dev->bid_xname = strdup(devname);
++			cn = NULL;	/* see free() below */
++		} else
++			dev->bid_name = strdup(devname);
++
+ 		dev->bid_cache = cache;
+ 		list_add_tail(&dev->bid_devs, &cache->bic_devs);
+ 		cache->bic_flags |= BLKID_BIC_FL_CHANGED;
+@@ -81,7 +108,7 @@ blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags)
+ 	if (flags & BLKID_DEV_VERIFY) {
+ 		dev = blkid_verify(cache, dev);
+ 		if (!dev || !(dev->bid_flags & BLKID_BID_FL_VERIFIED))
+-			return dev;
++			goto done;
+ 		/*
+ 		 * If the device is verified, then search the blkid
+ 		 * cache for any entries that match on the type, uuid,
+@@ -112,6 +139,10 @@ blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags)
+ 				blkid_free_dev(dev2);
+ 		}
+ 	}
++done:
++	if (dev)
++		DBG(DEVNAME, blkid_debug("%s requested, found %s in cache", devname, dev->bid_name));
++	free(cn);
+ 	return dev;
+ }
+ 
+-- 
+2.7.4
+
diff --git a/SOURCES/0086-libblkid-avoid-recursion-in-EBR.patch b/SOURCES/0086-libblkid-avoid-recursion-in-EBR.patch
new file mode 100644
index 0000000..32b7f17
--- /dev/null
+++ b/SOURCES/0086-libblkid-avoid-recursion-in-EBR.patch
@@ -0,0 +1,102 @@
+From 8125a64ff9e98d09c659dbd5adbca521d63a268b Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Thu, 7 Jul 2016 14:22:41 +0200
+Subject: [PATCH 86/86] libblkid: avoid recursion in EBR
+
+Upstream: http://github.com/karelzak/util-linux/commit/7164a1c34d18831ac61c6744ad14ce916d389b3f
+Upstream: http://github.com/karelzak/util-linux/commit/50d1594c2e6142a3b51d2143c74027480df082e0
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1349536
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libblkid/src/partitions/dos.c        | 21 +++++++++++++++++++--
+ libblkid/src/partitions/partitions.c | 14 ++++++++++++++
+ libblkid/src/partitions/partitions.h |  2 ++
+ 3 files changed, 35 insertions(+), 2 deletions(-)
+
+diff --git a/libblkid/src/partitions/dos.c b/libblkid/src/partitions/dos.c
+index 2d4a537..563fe9a 100644
+--- a/libblkid/src/partitions/dos.c
++++ b/libblkid/src/partitions/dos.c
+@@ -48,6 +48,12 @@ static int parse_dos_extended(blkid_probe pr, blkid_parttable tab,
+ 	int ct_nodata = 0;	/* count ext.partitions without data partitions */
+ 	int i;
+ 
++	DBG(LOWPROBE, blkid_debug("parse EBR [start=%d, size=%d]", ex_start/ssf, ex_size/ssf));
++	if (ex_start == 0) {
++		DBG(LOWPROBE, blkid_debug("Bad offset in primary extended partition -- ignore"));
++		return 0;
++	}
++
+ 	while (1) {
+ 		struct dos_partition *p, *p0;
+ 		uint32_t start, size;
+@@ -100,6 +106,13 @@ static int parse_dos_extended(blkid_probe pr, blkid_parttable tab,
+ 					continue;
+ 			}
+ 
++			/* Avoid recursive non-empty links, see ct_nodata counter */
++			if (blkid_partlist_get_partition_by_start(ls, abs_start)) {
++				DBG(LOWPROBE, blkid_debug("#%d: EBR duplicate data partition [abs start=%u] -- ignore",
++							i + 1, abs_start));
++				continue;
++			}
++
+ 			par = blkid_partlist_add_partition(ls, tab, abs_start, size);
+ 			if (!par)
+ 				return -ENOMEM;
+@@ -116,8 +129,12 @@ static int parse_dos_extended(blkid_probe pr, blkid_parttable tab,
+ 			start = dos_partition_start(p) * ssf;
+ 			size = dos_partition_size(p) * ssf;
+ 
+-			if (size && is_extended(p))
+-				break;
++			if (size && is_extended(p)) {
++				if (start == 0)
++					DBG(LOWPROBE, blkid_debug("#%d: EBR link offset is zero -- ignore", i + 1));
++				else
++					break;
++			}
+ 		}
+ 		if (i == 4)
+ 			goto leave;
+diff --git a/libblkid/src/partitions/partitions.c b/libblkid/src/partitions/partitions.c
+index 752fc95..9d846ff 100644
+--- a/libblkid/src/partitions/partitions.c
++++ b/libblkid/src/partitions/partitions.c
+@@ -928,6 +928,20 @@ blkid_partition blkid_partlist_get_partition(blkid_partlist ls, int n)
+ 	return &ls->parts[n];
+ }
+ 
++blkid_partition blkid_partlist_get_partition_by_start(blkid_partlist ls, uint64_t start)
++{
++	int i, nparts;
++	blkid_partition par;
++
++	nparts = blkid_partlist_numof_partitions(ls);
++	for (i = 0; i < nparts; i++) {
++		par = blkid_partlist_get_partition(ls, i);
++		if ((uint64_t) blkid_partition_get_start(par) == start)
++			return par;
++	}
++	return NULL;
++}
++
+ /**
+  * blkid_partlist_devno_to_partition:
+  * @ls: partitions list
+diff --git a/libblkid/src/partitions/partitions.h b/libblkid/src/partitions/partitions.h
+index 61763bf..4e99e2a 100644
+--- a/libblkid/src/partitions/partitions.h
++++ b/libblkid/src/partitions/partitions.h
+@@ -20,6 +20,8 @@ extern int blkid_partlist_increment_partno(blkid_partlist ls);
+ 
+ extern blkid_partition blkid_partlist_get_parent(blkid_partlist ls);
+ 
++extern blkid_partition blkid_partlist_get_partition_by_start(blkid_partlist ls, uint64_t start);
++
+ extern int blkid_partitions_do_subprobe(blkid_probe pr,
+ 			blkid_partition parent, const struct blkid_idinfo *id);
+ 
+-- 
+2.7.4
+
diff --git a/SOURCES/0087-findmnt-fix-target-behaviour.patch b/SOURCES/0087-findmnt-fix-target-behaviour.patch
new file mode 100644
index 0000000..289e599
--- /dev/null
+++ b/SOURCES/0087-findmnt-fix-target-behaviour.patch
@@ -0,0 +1,106 @@
+From fbdd962ca187399cab3b0bf78d740e5fb304e0bf Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Fri, 16 Dec 2016 12:19:32 +0100
+Subject: [PATCH] findmnt: fix --target behaviour
+
+Upstream: https://github.com/karelzak/util-linux/commit/80c31a0b596125b387c6b27c899e8bad4e46680b
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1405238
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libmount/src/mountP.h |  1 +
+ libmount/src/tab.c    |  4 ++++
+ libmount/src/utils.c  |  9 +++++++++
+ misc-utils/findmnt.c  | 10 +++-------
+ 4 files changed, 17 insertions(+), 7 deletions(-)
+
+diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h
+index 7b0848f..6cabced 100644
+--- a/libmount/src/mountP.h
++++ b/libmount/src/mountP.h
+@@ -164,6 +164,7 @@ extern int mnt_get_filesystems(char ***filesystems, const char *pattern);
+ extern void mnt_free_filesystems(char **filesystems);
+ 
+ extern char *mnt_get_kernel_cmdline_option(const char *name);
++extern int mnt_stat_mountpoint(const char *target, struct stat *st);
+ 
+ /* tab.c */
+ extern int mnt_table_set_parser_fltrcb(	struct libmnt_table *tb,
+diff --git a/libmount/src/tab.c b/libmount/src/tab.c
+index 10ee7ce..5628da6 100644
+--- a/libmount/src/tab.c
++++ b/libmount/src/tab.c
+@@ -528,6 +528,7 @@ struct libmnt_fs *mnt_table_find_mountpoint(struct libmnt_table *tb,
+ 					    int direction)
+ {
+ 	char *mnt;
++	struct stat st;
+ 
+ 	if (!tb || !path || !*path)
+ 		return NULL;
+@@ -536,6 +537,9 @@ struct libmnt_fs *mnt_table_find_mountpoint(struct libmnt_table *tb,
+ 
+ 	DBG(TAB, mnt_debug_h(tb, "lookup MOUNTPOINT: '%s'", path));
+ 
++	if (mnt_stat_mountpoint(path, &st))
++		return NULL;
++
+ 	mnt = strdup(path);
+ 	if (!mnt)
+ 		return NULL;
+diff --git a/libmount/src/utils.c b/libmount/src/utils.c
+index c13fb96..5c374b4 100644
+--- a/libmount/src/utils.c
++++ b/libmount/src/utils.c
+@@ -104,6 +104,15 @@ static int fstype_cmp(const void *v1, const void *v2)
+ 	return strcmp(s1, s2);
+ }
+ 
++int mnt_stat_mountpoint(const char *target, struct stat *st)
++{
++#ifdef AT_NO_AUTOMOUNT
++	return fstatat(-1, target, st, AT_NO_AUTOMOUNT);
++#else
++	return stat(target, st);
++#endif
++}
++
+ /* returns basename and keeps dirname in the @path, if @path is "/" (root)
+  * then returns empty string */
+ char *stripoff_last_component(char *path)
+diff --git a/misc-utils/findmnt.c b/misc-utils/findmnt.c
+index fe899db..79ef12e 100644
+--- a/misc-utils/findmnt.c
++++ b/misc-utils/findmnt.c
+@@ -239,16 +239,15 @@ static void set_source_match(const char *data)
+ /* @tb has to be from kernel (so no fstab or so)! */
+ static void enable_extra_target_match(struct libmnt_table *tb)
+ {
+-	char *cn = NULL;
+-	const char *tgt = NULL, *mnt = NULL;
++	const char *tgt, *mnt = NULL;
+ 	struct libmnt_fs *fs;
+ 
+ 	/*
+ 	 * Check if match pattern is mountpoint, if not use the
+ 	 * real mountpoint.
+ 	 */
+-	cn = mnt_resolve_path(get_match(COL_TARGET), cache);
+-	if (!cn)
++	tgt = mnt_resolve_path(get_match(COL_TARGET), cache);
++	if (!tgt)
+ 		return;
+ 
+ 	fs = mnt_table_find_mountpoint(tb, tgt, MNT_ITER_BACKWARD);
+@@ -256,9 +255,6 @@ static void enable_extra_target_match(struct libmnt_table *tb)
+ 		mnt = mnt_fs_get_target(fs);
+ 	if (mnt && strcmp(mnt, tgt) != 0)
+ 		set_match(COL_TARGET, xstrdup(mnt));	/* replace the current setting */
+-
+-	/* replace the current setting with the real mountpoint */
+-	set_match(COL_TARGET, mnt);
+ }
+ 
+ 
+-- 
+2.7.4
+
diff --git a/SOURCES/0088-su-properly-clear-child-PID.patch b/SOURCES/0088-su-properly-clear-child-PID.patch
new file mode 100644
index 0000000..ae125a7
--- /dev/null
+++ b/SOURCES/0088-su-properly-clear-child-PID.patch
@@ -0,0 +1,64 @@
+From 756f8301d5f7959312bea3fa8865bb543d43fd50 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Wed, 8 Feb 2017 10:19:56 +0100
+Subject: [PATCH] su: properly clear child PID
+
+Upstream: http://github.com/karelzak/util-linux/commit/dffab154d29a288aa171ff50263ecc8f2e14a891
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1419474
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ login-utils/su-common.c | 25 +++++++++++++++----------
+ 1 file changed, 15 insertions(+), 10 deletions(-)
+
+diff --git a/login-utils/su-common.c b/login-utils/su-common.c
+index d53d690..9b3cad5 100644
+--- a/login-utils/su-common.c
++++ b/login-utils/su-common.c
+@@ -357,21 +357,26 @@ create_watching_parent (void)
+ 	    break;
+ 	}
+       if (pid != (pid_t)-1)
+-	if (WIFSIGNALED (status))
+-	  {
+-            fprintf (stderr, "%s%s\n", strsignal (WTERMSIG (status)),
+-                     WCOREDUMP (status) ? _(" (core dumped)") : "");
+-            status = WTERMSIG (status) + 128;
+-	  }
+-	else
+-	  status = WEXITSTATUS (status);
++	{
++	  if (WIFSIGNALED (status))
++	    {
++	      fprintf (stderr, "%s%s\n", strsignal (WTERMSIG (status)),
++                       WCOREDUMP (status) ? _(" (core dumped)") : "");
++	      status = WTERMSIG (status) + 128;
++	    }
++	  else
++	    status = WEXITSTATUS (status);
++
++          /* child is gone, don't use the PID anymore */
++          child = (pid_t) -1;
++	}
+       else
+ 	status = 1;
+     }
+   else
+     status = 1;
+ 
+-  if (caught_signal)
++  if (caught_signal && child != (pid_t)-1)
+     {
+       fprintf (stderr, _("\nSession terminated, killing shell..."));
+       kill (child, SIGTERM);
+@@ -379,7 +384,7 @@ create_watching_parent (void)
+ 
+   cleanup_pam (PAM_SUCCESS);
+ 
+-  if (caught_signal)
++  if (caught_signal && (child != (pid_t)-1))
+     {
+       sleep (2);
+       kill (child, SIGKILL);
+-- 
+2.7.4
+
diff --git a/SOURCES/0089-fdisk-fix-Blocks-column-calculation.patch b/SOURCES/0089-fdisk-fix-Blocks-column-calculation.patch
new file mode 100644
index 0000000..5e9aec0
--- /dev/null
+++ b/SOURCES/0089-fdisk-fix-Blocks-column-calculation.patch
@@ -0,0 +1,27 @@
+From acf8de63d2a797850935feeaf6bac2dd21c9b496 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Wed, 15 Mar 2017 13:23:56 +0100
+Subject: [PATCH 089/116] fdisk: fix Blocks column calculation
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1344102
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ fdisks/fdiskdoslabel.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fdisks/fdiskdoslabel.c b/fdisks/fdiskdoslabel.c
+index b7eb35a..6375692 100644
+--- a/fdisks/fdiskdoslabel.c
++++ b/fdisks/fdiskdoslabel.c
+@@ -1202,7 +1202,7 @@ int dos_list_table(struct fdisk_context *cxt,
+ 		p = pe->part_table;
+ 		if (p && !is_cleared_partition(p)) {
+ 			unsigned int psects = get_nr_sects(p);
+-			unsigned int pblocks = psects;
++			unsigned long pblocks = psects;
+ 			unsigned int podd = 0;
+ 			struct fdisk_parttype *type =
+ 					fdisk_get_parttype_from_code(cxt, p->sys_ind);
+-- 
+2.9.3
+
diff --git a/SOURCES/0090-fdisk-fix-menu-for-GPT.patch b/SOURCES/0090-fdisk-fix-menu-for-GPT.patch
new file mode 100644
index 0000000..efd40e2
--- /dev/null
+++ b/SOURCES/0090-fdisk-fix-menu-for-GPT.patch
@@ -0,0 +1,45 @@
+From 64107c0347dde0b7207b31132837864bd5f4c714 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Wed, 15 Mar 2017 14:16:25 +0100
+Subject: [PATCH 090/116] fdisk: fix menu for GPT
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1344720
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ fdisks/fdisk.c | 13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+diff --git a/fdisks/fdisk.c b/fdisks/fdisk.c
+index 2656711..0ec9909 100644
+--- a/fdisks/fdisk.c
++++ b/fdisks/fdisk.c
+@@ -87,18 +87,21 @@ static const struct menulist_descr menulist[] = {
+ 	{'n', N_("add a new partition"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF | FDISK_DISKLABEL_GPT, 0}},
+ 	{'o', N_("change rotation speed (rpm)"), {0, FDISK_DISKLABEL_SUN}},
+ 	{'o', N_("create a new empty DOS partition table"), {~FDISK_DISKLABEL_OSF, 0}},
+-	{'p', N_("print the partition table"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF, FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN}},
++	{'p', N_("print the partition table"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF | FDISK_DISKLABEL_GPT,
++						FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_GPT }},
+ 	{'q', N_("quit without saving changes"), {FDISK_DISKLABEL_ANY, FDISK_DISKLABEL_ANY}},
+-	{'r', N_("return to main menu"), {FDISK_DISKLABEL_OSF, FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF}},
++	{'r', N_("return to main menu"), {FDISK_DISKLABEL_OSF, FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF | FDISK_DISKLABEL_GPT}},
+ 	{'s', N_("change number of sectors/track"), {0, FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN}},
+ 	{'s', N_("create a new empty Sun disklabel"), {~FDISK_DISKLABEL_OSF, 0}},
+ 	{'s', N_("show complete disklabel"), {FDISK_DISKLABEL_OSF, 0}},
+ 	{'t', N_("change a partition's system id"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF, 0}},
+ 	{'u', N_("change display/entry units"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF, 0}},
+-	{'v', N_("verify the partition table"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI, FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI}},
++	{'v', N_("verify the partition table"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_GPT,
++						 FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_GPT}},
+ 	{'w', N_("write disklabel to disk"), {FDISK_DISKLABEL_OSF, 0}},
+-	{'w', N_("write table to disk and exit"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI  | FDISK_DISKLABEL_GPT, FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI}},
+-	{'x', N_("extra functionality (experts only)"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI, 0}},
++	{'w', N_("write table to disk and exit"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI  | FDISK_DISKLABEL_GPT,
++					           FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_GPT}},
++	{'x', N_("extra functionality (experts only)"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_GPT, 0}},
+ #if !defined (__alpha__)
+ 	{'x', N_("link BSD partition to non-BSD partition"), {FDISK_DISKLABEL_OSF, 0}},
+ #endif
+-- 
+2.9.3
+
diff --git a/SOURCES/0091-logger-backport-size.patch b/SOURCES/0091-logger-backport-size.patch
new file mode 100644
index 0000000..41d6ec5
--- /dev/null
+++ b/SOURCES/0091-logger-backport-size.patch
@@ -0,0 +1,165 @@
+From 1e0289af99737049de97b8cfe342b56d380560bf Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Thu, 16 Mar 2017 12:20:58 +0100
+Subject: [PATCH 091/116] logger: backport --size
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1323916
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ misc-utils/logger.1 |  6 ++++++
+ misc-utils/logger.c | 34 ++++++++++++++++++++++++----------
+ 2 files changed, 30 insertions(+), 10 deletions(-)
+
+diff --git a/misc-utils/logger.1 b/misc-utils/logger.1
+index 8c4faca..57ca0d5 100644
+--- a/misc-utils/logger.1
++++ b/misc-utils/logger.1
+@@ -98,6 +98,12 @@ logs the message as informational in the local3 facility.
+ The default is
+ .IR user.notice .
+ .TP
++\fB\-S\fR, \fB\-\-size\fR \fIsize\fR
++Sets the maximum permitted message size. The default is 1KiB, which is
++the limit traditionally used and specified in RFC 3164. When selecting a
++maximum message size, it is important to ensure that the receiver supports
++the max size as well, otherwise messages may become truncated.
++.TP
+ \fB\-s\fR, \fB\-\-stderr\fR
+ Output the message to standard error as well as to the system log.
+ .TP
+diff --git a/misc-utils/logger.c b/misc-utils/logger.c
+index a331869..dfda018 100644
+--- a/misc-utils/logger.c
++++ b/misc-utils/logger.c
+@@ -54,6 +54,8 @@
+ #include "closestream.h"
+ #include "nls.h"
+ #include "strutils.h"
++#include "xalloc.h"
++#include "all-io.h"
+ 
+ #define	SYSLOG_NAMES
+ #include <syslog.h>
+@@ -183,7 +185,7 @@ inet_socket(const char *servername, const char *port, const int socket_type)
+ 
+ static void
+ mysyslog(int fd, int logflags, int pri, char *tag, char *msg) {
+-       char buf[1000], pid[30], *cp, *tp;
++       char *buf, pid[30], *cp, *tp;
+        time_t now;
+ 
+        if (fd > -1) {
+@@ -201,11 +203,11 @@ mysyslog(int fd, int logflags, int pri, char *tag, char *msg) {
+                (void)time(&now);
+ 	       tp = ctime(&now)+4;
+ 
+-               snprintf(buf, sizeof(buf), "<%d>%.15s %.200s%s: %.400s",
++               xasprintf(&buf, "<%d>%.15s %.200s%s: %s",
+ 			pri, tp, cp, pid, msg);
+ 
+-               if (write(fd, buf, strlen(buf)+1) < 0)
+-                       return; /* error */
++	       write_all(fd, buf, strlen(buf)+1);
++	       free(buf);
+        }
+ }
+ 
+@@ -221,6 +223,7 @@ static void __attribute__ ((__noreturn__)) usage(FILE *out)
+ 		" -i, --id              log the process ID too\n"
+ 		" -f, --file <file>     log the contents of this file\n"
+ 		" -h, --help            display this help text and exit\n"), out);
++	fputs(_(" -S, --size <num>      maximum size for a single message (default 1024)\n"), out);
+ 	fputs(_(" -n, --server <name>   write to this remote syslog server\n"
+ 		" -P, --port <port>     use this port for UDP or TCP connection\n"
+ 		" -p, --priority <prio> mark given message with this priority\n"
+@@ -241,11 +244,12 @@ static void __attribute__ ((__noreturn__)) usage(FILE *out)
+ int
+ main(int argc, char **argv) {
+ 	int ch, logflags, pri;
+-	char *tag, buf[1024];
++	char *tag, *buf;
+ 	char *usock = NULL;
+ 	char *server = NULL;
+ 	char *port = NULL;
+ 	int LogSock = -1, socket_type = ALL_TYPES;
++	size_t max_message_size = 1024;
+ 
+ 	static const struct option longopts[] = {
+ 		{ "id",		no_argument,	    0, 'i' },
+@@ -253,6 +257,7 @@ main(int argc, char **argv) {
+ 		{ "file",	required_argument,  0, 'f' },
+ 		{ "priority",	required_argument,  0, 'p' },
+ 		{ "tag",	required_argument,  0, 't' },
++		{ "size",       required_argument,  0, 'S' },
+ 		{ "socket",	required_argument,  0, 'u' },
+ 		{ "udp",	no_argument,	    0, 'd' },
+ 		{ "tcp",	no_argument,	    0, 'T' },
+@@ -271,7 +276,7 @@ main(int argc, char **argv) {
+ 	tag = NULL;
+ 	pri = LOG_NOTICE;
+ 	logflags = 0;
+-	while ((ch = getopt_long(argc, argv, "f:ip:st:u:dTn:P:Vh",
++	while ((ch = getopt_long(argc, argv, "f:ip:st:u:dTn:P:S:Vh",
+ 					    longopts, NULL)) != -1) {
+ 		switch((char)ch) {
+ 		case 'f':		/* file to log */
+@@ -297,6 +302,10 @@ main(int argc, char **argv) {
+ 		case 'd':
+ 			socket_type = TYPE_UDP;
+ 			break;
++		case 'S':
++			max_message_size = strtosize_or_err(optarg,
++                                _("failed to parse message size"));
++			break;
+ 		case 'T':
+ 			socket_type = TYPE_TCP;
+ 			break;
+@@ -327,21 +336,23 @@ main(int argc, char **argv) {
+ 	else
+ 		openlog(tag ? tag : getlogin(), logflags, 0);
+ 
++	buf = xcalloc(1, max_message_size);
++
+ 	/* log input line if appropriate */
+ 	if (argc > 0) {
+ 		register char *p, *endp;
+ 		size_t len;
+ 
+-		for (p = buf, endp = buf + sizeof(buf) - 2; *argv;) {
++		for (p = buf, endp = buf + max_message_size - 2; *argv;) {
+ 			len = strlen(*argv);
+ 			if (p + len > endp && p > buf) {
+ 			    if (!usock && !server)
+ 				syslog(pri, "%s", buf);
+ 			    else
+ 				mysyslog(LogSock, logflags, pri, tag, buf);
+-				p = buf;
++			    p = buf;
+ 			}
+-			if (len > sizeof(buf) - 1) {
++			if (len > max_message_size - 1) {
+ 			    if (!usock && !server)
+ 				syslog(pri, "%s", *argv++);
+ 			    else
+@@ -360,7 +371,7 @@ main(int argc, char **argv) {
+ 			mysyslog(LogSock, logflags, pri, tag, buf);
+ 		}
+ 	} else {
+-		while (fgets(buf, sizeof(buf), stdin) != NULL) {
++		while (fgets(buf, max_message_size, stdin) != NULL) {
+ 		    /* glibc is buggy and adds an additional newline,
+ 		       so we have to remove it here until glibc is fixed */
+ 		    int len = strlen(buf);
+@@ -374,6 +385,9 @@ main(int argc, char **argv) {
+ 			mysyslog(LogSock, logflags, pri, tag, buf);
+ 		}
+ 	}
++
++	free(buf);
++
+ 	if (!usock && !server)
+ 		closelog();
+ 	else
+-- 
+2.9.3
+
diff --git a/SOURCES/0092-fdisk-print-header-UUID-for-GPT.patch b/SOURCES/0092-fdisk-print-header-UUID-for-GPT.patch
new file mode 100644
index 0000000..d7f91ed
--- /dev/null
+++ b/SOURCES/0092-fdisk-print-header-UUID-for-GPT.patch
@@ -0,0 +1,70 @@
+From 6f768ec049944ab39c79fcaa7bdf9622385b7672 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Thu, 16 Mar 2017 13:29:50 +0100
+Subject: [PATCH 092/116] fdisk: print header UUID for GPT
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1344726
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ fdisks/fdisk.c        |  2 ++
+ libfdisk/src/fdiskP.h |  1 +
+ libfdisk/src/gpt.c    | 18 ++++++++++++++++++
+ 3 files changed, 21 insertions(+)
+
+diff --git a/fdisks/fdisk.c b/fdisks/fdisk.c
+index 0ec9909..974d735 100644
+--- a/fdisks/fdisk.c
++++ b/fdisks/fdisk.c
+@@ -657,6 +657,8 @@ list_disk_geometry(struct fdisk_context *cxt) {
+ 		printf(_("Disk label type: %s\n"), cxt->label->name);
+ 	if (fdisk_is_disklabel(cxt, DOS))
+ 		dos_print_mbr_id(cxt);
++	if (fdisk_is_disklabel(cxt, GPT))
++		gpt_print_header_id(cxt);
+ 	printf("\n");
+ }
+ 
+diff --git a/libfdisk/src/fdiskP.h b/libfdisk/src/fdiskP.h
+index ce42860..6711ab8 100644
+--- a/libfdisk/src/fdiskP.h
++++ b/libfdisk/src/fdiskP.h
+@@ -315,6 +315,7 @@ extern void fdisk_deinit_label(struct fdisk_label *lb);
+ 
+ /* gpt.c -- temporary bypass library API... */
+ extern void gpt_list_table(struct fdisk_context *cxt, int xtra);
++extern void gpt_print_header_id(struct fdisk_context *cxt);
+ 
+ /* ask.c */
+ extern int fdisk_ask_partnum(struct fdisk_context *cxt, size_t *partnum, int wantnew);
+diff --git a/libfdisk/src/gpt.c b/libfdisk/src/gpt.c
+index d3bdc2d..899e1b2 100644
+--- a/libfdisk/src/gpt.c
++++ b/libfdisk/src/gpt.c
+@@ -341,6 +341,24 @@ static inline int partition_unused(const struct gpt_entry *e)
+ 			sizeof(struct gpt_guid));
+ }
+ 
++void gpt_print_header_id(struct fdisk_context *cxt)
++{
++	char str[37];
++	struct gpt_header *header;
++	struct fdisk_gpt_label *gpt;
++
++	assert(cxt);
++	assert(cxt->label);
++	assert(fdisk_is_disklabel(cxt, GPT));
++
++	gpt = self_label(cxt);
++	header = gpt->pheader ? gpt->pheader : gpt->bheader;
++
++	guid_to_string(&header->disk_guid, str);
++
++	printf("Disk identifier: %s\n", str);
++}
++
+ /*
+  * Builds a clean new valid protective MBR - will wipe out any existing data.
+  * Returns 0 on success, otherwise < 0 on error.
+-- 
+2.9.3
+
diff --git a/SOURCES/0093-fdisk-improve-l-error-handling.patch b/SOURCES/0093-fdisk-improve-l-error-handling.patch
new file mode 100644
index 0000000..8471c1a
--- /dev/null
+++ b/SOURCES/0093-fdisk-improve-l-error-handling.patch
@@ -0,0 +1,76 @@
+From e4f26d51bd06910634c2aaeccfecc7e6cd61ef0a Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Fri, 17 Mar 2017 11:47:00 +0100
+Subject: [PATCH 093/116] fdisk: improve -l error handling
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1362662
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ fdisks/fdisk.c | 23 ++++++++++++++++-------
+ 1 file changed, 16 insertions(+), 7 deletions(-)
+
+diff --git a/fdisks/fdisk.c b/fdisks/fdisk.c
+index 974d735..177921a 100644
+--- a/fdisks/fdisk.c
++++ b/fdisks/fdisk.c
+@@ -924,11 +924,15 @@ static int is_ide_cdrom_or_tape(char *device)
+ }
+ 
+ /* Print disk geometry and partition table of a specified device (-l option) */
+-static void print_partition_table_from_option(struct fdisk_context *cxt,
+-				char *device, unsigned long sector_size)
++static int print_partition_table_from_option(struct fdisk_context *cxt,
++				char *device, unsigned long sector_size,
++				int warnme)
+ {
+-	if (fdisk_context_assign_device(cxt, device, 1) != 0)	/* read-only */
+-		err(EXIT_FAILURE, _("cannot open %s"), device);
++	if (fdisk_context_assign_device(cxt, device, 1) != 0) {	/* read-only */
++		if (warnme || errno == EACCES)
++			warn(_("cannot open %s"), device);
++		return -1;
++	}
+ 
+ 	if (sector_size) /* passed -b option, override autodiscovery */
+ 		fdisk_override_sector_size(cxt, sector_size);
+@@ -941,6 +945,8 @@ static void print_partition_table_from_option(struct fdisk_context *cxt,
+ 		list_table(cxt, 0);
+ 	else
+ 		list_disk_geometry(cxt);
++
++	return 0;
+ }
+ 
+ /*
+@@ -971,7 +977,7 @@ print_all_partition_table_from_option(struct fdisk_context *cxt,
+ 			char *cn = canonicalize_path(devname);
+ 			if (cn) {
+ 				if (!is_ide_cdrom_or_tape(cn))
+-					print_partition_table_from_option(cxt, cn, sector_size);
++					print_partition_table_from_option(cxt, cn, sector_size, 0);
+ 				free(cn);
+ 			}
+ 		}
+@@ -1223,14 +1229,17 @@ int main(int argc, char **argv)
+ 			 " be used with one specified device\n"));
+ 
+ 	if (optl) {
++		int rc = 0;
++
+ 		nowarn = 1;
+ 		if (argc > optind) {
+ 			int k;
+ 			for (k = optind; k < argc; k++)
+-				print_partition_table_from_option(cxt, argv[k], sector_size);
++				rc += print_partition_table_from_option(cxt, argv[k], sector_size, 1);
+ 		} else
+ 			print_all_partition_table_from_option(cxt, sector_size);
+-		exit(EXIT_SUCCESS);
++
++		exit(rc ? EXIT_FAILURE : EXIT_SUCCESS);
+ 	}
+ 
+ 	if (opts) {
+-- 
+2.9.3
+
diff --git a/SOURCES/0094-losetup-improve-man-page-SYNOPSIS.patch b/SOURCES/0094-losetup-improve-man-page-SYNOPSIS.patch
new file mode 100644
index 0000000..df5427a
--- /dev/null
+++ b/SOURCES/0094-losetup-improve-man-page-SYNOPSIS.patch
@@ -0,0 +1,42 @@
+From 38899e30a9a195adb4732185ed62d55a03ecc96d Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Fri, 17 Mar 2017 14:02:39 +0100
+Subject: [PATCH 094/116] losetup: improve man page SYNOPSIS
+
+and remove obsolete "-p fd" from the man page.
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1369436
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ sys-utils/losetup.8 | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+diff --git a/sys-utils/losetup.8 b/sys-utils/losetup.8
+index bd73518..9a8c1d5 100644
+--- a/sys-utils/losetup.8
++++ b/sys-utils/losetup.8
+@@ -37,7 +37,7 @@ Print name of first unused loop device:
+ .B "losetup \-f"
+ .sp
+ .in -5
+-Setup loop device:
++Set up a loop device:
+ .sp
+ .in +5
+ .B losetup
+@@ -46,10 +46,8 @@ Setup loop device:
+ .RB [ \-\-sizelimit
+ .IR size ]
+ .in +8
+-.RB [ \-p
+-.IR pfd ]
+-.RB [ \-rP ]
+-.RB { \-f [ \-\-show ]| \fIloopdev\fP }
++.RB [ \-Pr ]
++.RB [ \-\-show ]  " \-f" | \fIloopdev\fP
+ .I file
+ .sp
+ .in -13
+-- 
+2.9.3
+
diff --git a/SOURCES/0095-libblkid-fix-potential-bufer-overflows.patch b/SOURCES/0095-libblkid-fix-potential-bufer-overflows.patch
new file mode 100644
index 0000000..5eceb9a
--- /dev/null
+++ b/SOURCES/0095-libblkid-fix-potential-bufer-overflows.patch
@@ -0,0 +1,103 @@
+From 55540ea3dfdc707dc998333fd0715549522464fb Mon Sep 17 00:00:00 2001
+From: Sebastian Krahmer <krahmer@suse.de>
+Date: Fri, 5 Dec 2014 10:06:42 +0100
+Subject: [PATCH 095/116] libblkid: fix potential bufer overflows
+
+While digging deeper into libblk probing, I found that some
+computations might wrap and allocate too few buffer space which then
+overflows. In particular on 32bit systems (chromebook) where size_t is
+32bit, this is problematic (for 64bit the result fits into the calloc
+size_t).
+
+Upstream: Upstream: https://github.com/karelzak/util-linux/commit/109df14fad4e9570e26950913ebace6c79289400
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1392656
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libblkid/src/partitions/gpt.c  | 12 ++++++++----
+ libblkid/src/probe.c           |  7 +++++++
+ libblkid/src/superblocks/zfs.c |  3 +++
+ 3 files changed, 18 insertions(+), 4 deletions(-)
+
+diff --git a/libblkid/src/partitions/gpt.c b/libblkid/src/partitions/gpt.c
+index 6ab0dc6..e801ea3 100644
+--- a/libblkid/src/partitions/gpt.c
++++ b/libblkid/src/partitions/gpt.c
+@@ -17,6 +17,7 @@
+ #include <stdlib.h>
+ #include <stdint.h>
+ #include <stddef.h>
++#include <limits.h>
+ 
+ #include "partitions.h"
+ #include "crc32.h"
+@@ -266,14 +267,17 @@ static struct gpt_header *get_gpt_header(
+ 		return NULL;
+ 	}
+ 
+-	/* Size of blocks with GPT entries */
+-	esz = le32_to_cpu(h->num_partition_entries) *
+-			le32_to_cpu(h->sizeof_partition_entry);
+-	if (!esz) {
++	if (le32_to_cpu(h->num_partition_entries) == 0 ||
++	    le32_to_cpu(h->sizeof_partition_entry) == 0 ||
++	    ULONG_MAX / le32_to_cpu(h->num_partition_entries) < le32_to_cpu(h->sizeof_partition_entry)) {
+ 		DBG(LOWPROBE, blkid_debug("GPT entries undefined"));
+ 		return NULL;
+ 	}
+ 
++	/* Size of blocks with GPT entries */
++	esz = le32_to_cpu(h->num_partition_entries) *
++			le32_to_cpu(h->sizeof_partition_entry);
++
+ 	/* The header seems valid, save it
+ 	 * (we don't care about zeros in hdr->reserved2 area) */
+ 	memcpy(hdr, h, sizeof(*h));
+diff --git a/libblkid/src/probe.c b/libblkid/src/probe.c
+index f9fab5b..9cf099a 100644
+--- a/libblkid/src/probe.c
++++ b/libblkid/src/probe.c
+@@ -103,6 +103,7 @@
+ #include <inttypes.h>
+ #include <stdint.h>
+ #include <stdarg.h>
++#include <limits.h>
+ 
+ #ifdef HAVE_LIBUUID
+ # include <uuid.h>
+@@ -565,6 +566,12 @@ unsigned char *blkid_probe_get_buffer(blkid_probe pr,
+ 			return NULL;
+ 		}
+ 
++		/* someone trying to overflow some buffers? */
++		if (len > ULONG_MAX - sizeof(struct blkid_bufinfo)) {
++			errno = ENOMEM;
++			return NULL;
++		}
++
+ 		/* allocate info and space for data by why call */
+ 		bf = calloc(1, sizeof(struct blkid_bufinfo) + len);
+ 		if (!bf) {
+diff --git a/libblkid/src/superblocks/zfs.c b/libblkid/src/superblocks/zfs.c
+index 406ba2b..56ee472 100644
+--- a/libblkid/src/superblocks/zfs.c
++++ b/libblkid/src/superblocks/zfs.c
+@@ -12,6 +12,7 @@
+ #include <errno.h>
+ #include <ctype.h>
+ #include <inttypes.h>
++#include <limits.h>
+ 
+ #include "superblocks.h"
+ 
+@@ -108,6 +109,8 @@ static void zfs_extract_guid_name(blkid_probe pr, loff_t offset)
+ 
+ 			nvs->nvs_type = be32_to_cpu(nvs->nvs_type);
+ 			nvs->nvs_strlen = be32_to_cpu(nvs->nvs_strlen);
++			if (nvs->nvs_strlen > UINT_MAX - sizeof(*nvs))
++				break;
+ 			avail -= nvs->nvs_strlen + sizeof(*nvs);
+ 			nvdebug("nvstring: type %u string %*s\n", nvs->nvs_type,
+ 				nvs->nvs_strlen, nvs->nvs_string);
+-- 
+2.9.3
+
diff --git a/SOURCES/0096-umount-fix-obsolete-info-about-loop-in-umount.8.patch b/SOURCES/0096-umount-fix-obsolete-info-about-loop-in-umount.8.patch
new file mode 100644
index 0000000..7d03314
--- /dev/null
+++ b/SOURCES/0096-umount-fix-obsolete-info-about-loop-in-umount.8.patch
@@ -0,0 +1,53 @@
+From ad1c931f24e81b169127d611eb8aac72665c4bf2 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 30 Aug 2016 10:25:44 +0200
+Subject: [PATCH 096/116] umount: fix obsolete info about loop= in umount.8
+
+Upstream: Upstream: Upstream: https://github.com/karelzak/util-linux/commit/d00eb87ba284635e72b10880dfcf409276fa41b0
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1370959
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ sys-utils/umount.8 | 20 ++++++++++++--------
+ 1 file changed, 12 insertions(+), 8 deletions(-)
+
+diff --git a/sys-utils/umount.8 b/sys-utils/umount.8
+index 1fa653c..f0a712b 100644
+--- a/sys-utils/umount.8
++++ b/sys-utils/umount.8
+@@ -78,8 +78,10 @@ Do not canonicalize paths.  For more details about this option see the
+ man page.
+ .TP
+ \fB\-d\fR, \fB\-\-detach\-loop\fR
+-In case the unmounted device was a loop device, also free this loop
+-device.
++When the unmounted device was a loop device, also free this loop
++device. This option is unnecessary for devices initialized by
++.BR mount (8),
++in this case "autoclear" functionality is enabled by default.
+ .TP
+ \fB\-\-fake\fP
+ Causes everything to be done except for the actual system call; this 'fakes'
+@@ -145,12 +147,14 @@ Print version and exit.
+ .SH "THE LOOP DEVICE"
+ The
+ .B umount
+-command will free the loop device (if any) associated with the mount, in
+-case it finds the option 'loop=...' in
+-.IR /etc/mtab ,
+-or when the \-d option was given.  Any pending loop devices can be freed
+-using 'losetup -d', see
+-.BR losetup (8).
++command will automatically detach loop device previously initialized by
++.BR mount (8)
++command independently of /etc/mtab.
++
++In this case the device is initialized with "autoclear" flag (see
++.BR losetup (8)
++output for more details), otherwise it's necessary to use the option \fB \-\-detach\-loop\fR
++or call \fBlosetup -d <device>\fR. The autoclear feature is supported since Linux 2.6.25.
+ .SH NOTES
+ The syntax of external umount helpers is:
+ .PP
+-- 
+2.9.3
+
diff --git a/SOURCES/0097-mount-fix-all-and-nofail-return-code.patch b/SOURCES/0097-mount-fix-all-and-nofail-return-code.patch
new file mode 100644
index 0000000..0863b88
--- /dev/null
+++ b/SOURCES/0097-mount-fix-all-and-nofail-return-code.patch
@@ -0,0 +1,43 @@
+From d94c73b186ea4fec6333d1fb6cced1b4b8515d58 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Mon, 7 Apr 2014 11:53:05 +0200
+Subject: [PATCH 097/116] mount: fix --all and nofail return code
+
+Now the "nofail" affects warnings warning messages only. That's wrong
+and regression (against original non-libmount version). The nofail has
+to control return code too.
+
+Upstream: https://github.com/karelzak/util-linux/commit/8ab82185eed76bc20694a197fe10c5f9fb795b80
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1357746
+Reported-by: Patrick McLean <chutzpah@gentoo.org>
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ sys-utils/mount.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/sys-utils/mount.c b/sys-utils/mount.c
+index f332070..44e2b7c 100644
+--- a/sys-utils/mount.c
++++ b/sys-utils/mount.c
+@@ -197,12 +197,14 @@ static int mount_all(struct libmnt_context *cxt)
+ 			if (mnt_context_is_verbose(cxt))
+ 				printf("%-25s: mount successfully forked\n", tgt);
+ 		} else {
+-			mk_exit_code(cxt, mntrc);	/* to print warnings */
+-
+-			if (mnt_context_get_status(cxt)) {
++			if (mk_exit_code(cxt, mntrc) == MOUNT_EX_SUCCESS) {
+ 				nsucc++;
+ 
+-				if (mnt_context_is_verbose(cxt))
++				/* Note that MOUNT_EX_SUCCESS return code does
++				 * not mean that FS has been really mounted
++				 * (e.g. nofail option) */
++				if (mnt_context_get_status(cxt) 
++				    && mnt_context_is_verbose(cxt))
+ 					printf("%-25s: successfully mounted\n", tgt);
+ 			} else
+ 				nerrs++;
+-- 
+2.9.3
+
diff --git a/SOURCES/0098-umount-exclude-selinuxfs-from-all.patch b/SOURCES/0098-umount-exclude-selinuxfs-from-all.patch
new file mode 100644
index 0000000..aeb6279
--- /dev/null
+++ b/SOURCES/0098-umount-exclude-selinuxfs-from-all.patch
@@ -0,0 +1,28 @@
+From 92da0dea47ffceffb4a049a0a1094e41e212ceee Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Thu, 9 Feb 2017 11:21:49 +0100
+Subject: [PATCH 098/116] umount: exclude selinuxfs from --all
+
+Upstream: https://github.com/karelzak/util-linux/commit/9e66fd30d7bfbd7279db6100830aa9045d0255ca
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1417722
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ sys-utils/umount.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/sys-utils/umount.c b/sys-utils/umount.c
+index 9c47744..48483dc 100644
+--- a/sys-utils/umount.c
++++ b/sys-utils/umount.c
+@@ -605,7 +605,7 @@ int main(int argc, char **argv)
+ 
+ 	if (all) {
+ 		if (!types)
+-			types = "noproc,nodevfs,nodevpts,nosysfs,norpc_pipefs,nonfsd";
++			types = "noproc,nodevfs,nodevpts,nosysfs,norpc_pipefs,nonfsd,noselinuxfs";
+ 
+ 		mnt_context_set_fstype_pattern(cxt, types);
+ 		rc = umount_all(cxt);
+-- 
+2.9.3
+
diff --git a/SOURCES/0099-sfdisk-remove-useless-CDROM-detection-for-s.patch b/SOURCES/0099-sfdisk-remove-useless-CDROM-detection-for-s.patch
new file mode 100644
index 0000000..deca6be
--- /dev/null
+++ b/SOURCES/0099-sfdisk-remove-useless-CDROM-detection-for-s.patch
@@ -0,0 +1,61 @@
+From 8229770ff79a383d7e5b133f94609e861aae4283 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Fri, 17 Mar 2017 15:03:28 +0100
+Subject: [PATCH 099/116] sfdisk: remove useless CDROM detection for -s
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1402825
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ fdisks/sfdisk.c | 16 ++++++----------
+ 1 file changed, 6 insertions(+), 10 deletions(-)
+
+diff --git a/fdisks/sfdisk.c b/fdisks/sfdisk.c
+index 93bca27..afb15fc 100644
+--- a/fdisks/sfdisk.c
++++ b/fdisks/sfdisk.c
+@@ -2905,36 +2905,32 @@ do_pt_geom(char *dev, int silent) {
+ /* for compatibility with earlier fdisk: provide option -s */
+ static void
+ do_size(char *dev, int silent) {
+-    int fd;
++    int fd, rc;
+     unsigned long long size;
+ 
+     fd = my_open(dev, 0, silent);
+     if (fd < 0)
+ 	return;
+ 
+-    if (blkdev_get_sectors(fd, &size) == -1) {
++    rc = blkdev_get_sectors(fd, &size);
++    close(fd);
++
++    if (rc == -1) {
+ 	if (!silent) {
+ 	    perror(dev);
+ 	    errx(EXIT_FAILURE, _("Cannot get size of %s"), dev);
+ 	}
+-	goto done;
++	return;
+     }
+ 
+     size /= 2;			/* convert sectors to blocks */
+ 
+-    /* a CDROM drive without mounted CD yields MAXINT */
+-    if (silent && size == ((1 << 30) - 1))
+-	goto done;
+-
+     if (silent)
+ 	printf("%s: %9llu\n", dev, size);
+     else
+ 	printf("%llu\n", size);
+ 
+     total_size += size;
+-
+-done:
+-    close(fd);
+ }
+ 
+ /*
+-- 
+2.9.3
+
diff --git a/SOURCES/0100-more-fix-repeat-search-crash.patch b/SOURCES/0100-more-fix-repeat-search-crash.patch
new file mode 100644
index 0000000..edfd77f
--- /dev/null
+++ b/SOURCES/0100-more-fix-repeat-search-crash.patch
@@ -0,0 +1,41 @@
+From d7e6a773863ad47dbdab9244b6629590d4b46f0e Mon Sep 17 00:00:00 2001
+From: Sami Kerola <kerolasa@iki.fi>
+Date: Tue, 27 Jan 2015 22:28:57 +0000
+Subject: [PATCH 100/116] more: fix repeat search crash
+
+Repeating a search for a pattern that did not found made more(1) to
+crash.  To reproduce 'more /etc/services' and search for 'doom'; you will
+find a service in port 666 - pressing '.' after that result used to cause
+core dump.
+
+Upstream: https://github.com/karelzak/util-linux/commit/bc1ed338814f69473629b04c5e9efae5d7db3b72
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1403973
+Signed-off-by: Sami Kerola <kerolasa@iki.fi>
+---
+ text-utils/more.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/text-utils/more.c b/text-utils/more.c
+index 496b116..0e9c2bd 100644
+--- a/text-utils/more.c
++++ b/text-utils/more.c
+@@ -1588,6 +1588,8 @@ void search(char buf[], FILE *file, register int n)
+ 	context.line = saveln = Currline;
+ 	context.chrctr = startline;
+ 	lncount = 0;
++	if (!buf)
++		goto notfound;
+ 	if ((rc = regcomp(&re, buf, REG_NOSUB)) != 0) {
+ 		char s[REGERR_BUF];
+ 		regerror(rc, &re, s, sizeof s);
+@@ -1644,6 +1646,7 @@ void search(char buf[], FILE *file, register int n)
+ 		}
+ 		free(previousre);
+ 		previousre = NULL;
++notfound:
+ 		more_error(_("Pattern not found"));
+ 	}
+ }
+-- 
+2.9.3
+
diff --git a/SOURCES/0101-more-avoid-double-free-on-exit.patch b/SOURCES/0101-more-avoid-double-free-on-exit.patch
new file mode 100644
index 0000000..87d1c36
--- /dev/null
+++ b/SOURCES/0101-more-avoid-double-free-on-exit.patch
@@ -0,0 +1,42 @@
+From f98c5f53d4661ec22097d36f5debd195491ec3c6 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Thu, 15 Dec 2016 14:40:26 +0100
+Subject: [PATCH 101/116] more: avoid double free() on exit
+
+On 'q' command more(1) calls end_it() function with _exit(). The
+_exit() may suspend program execution due to pending I/O on very
+loaded server. In this time SIGINT may be delivered due to impatient
+user who will press ^C.
+
+And then end_it() cleanup function may be executed by signal handler
+too. The result is double free()...
+
+Upstream: https://github.com/karelzak/util-linux/commit/0ed2a954714992938b35893b70197090a61b3b2e
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1403971
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ text-utils/more.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/text-utils/more.c b/text-utils/more.c
+index 0e9c2bd..f98cb14 100644
+--- a/text-utils/more.c
++++ b/text-utils/more.c
+@@ -763,6 +763,14 @@ void chgwinsz(int dummy __attribute__((__unused__)))
+ /* Clean up terminal state and exit. Also come here if interrupt signal received */
+ void __attribute__((__noreturn__)) end_it(int dummy __attribute__((__unused__)))
+ {
++	/* May be executed as a signal handler as well as by main process.
++	 *
++	 * The _exit() may wait for pending I/O for really long time, be sure
++	 * that signal handler is not executed in this time to avoid double
++	 * de-initialization (free() calls, etc.).
++	 */
++	signal(SIGINT, SIG_IGN);
++
+ 	reset_tty();
+ 	if (clreol) {
+ 		putchar('\r');
+-- 
+2.9.3
+
diff --git a/SOURCES/0102-ipcs-show-gid-instead-of-uid.patch b/SOURCES/0102-ipcs-show-gid-instead-of-uid.patch
new file mode 100644
index 0000000..b549099
--- /dev/null
+++ b/SOURCES/0102-ipcs-show-gid-instead-of-uid.patch
@@ -0,0 +1,48 @@
+From a04fe4b347e563d7ff8d116fde6c6f26646ffadd Mon Sep 17 00:00:00 2001
+From: Hushan Jia <hushan.jia@gmail.com>
+Date: Sun, 21 Feb 2016 21:10:24 -0800
+Subject: [PATCH 102/116] ipcs: show gid instead of uid
+
+ipcs -i incorrectly used uid where it should be gid
+
+Upstream: https://github.com/karelzak/util-linux/commit/e0bbe3d6ffed13ca5e4af450b8de775ddc5b30f3
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1358095
+Signed-off-by: Hushan Jia <hushan.jia@gmail.com>
+---
+ sys-utils/ipcs.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/sys-utils/ipcs.c b/sys-utils/ipcs.c
+index 1843cd5..1db7fd0 100644
+--- a/sys-utils/ipcs.c
++++ b/sys-utils/ipcs.c
+@@ -564,7 +564,7 @@ static void print_shm(int shmid, int unit)
+ 
+ 	printf(_("\nShared memory Segment shmid=%d\n"), shmid);
+ 	printf(_("uid=%u\tgid=%u\tcuid=%u\tcgid=%u\n"),
+-	       shmdata->shm_perm.uid, shmdata->shm_perm.uid,
++	       shmdata->shm_perm.uid, shmdata->shm_perm.gid,
+ 	       shmdata->shm_perm.cuid, shmdata->shm_perm.cgid);
+ 	printf(_("mode=%#o\taccess_perms=%#o\n"), shmdata->shm_perm.mode,
+ 	       shmdata->shm_perm.mode & 0777);
+@@ -594,7 +594,7 @@ void print_msg(int msgid, int unit)
+ 
+ 	printf(_("\nMessage Queue msqid=%d\n"), msgid);
+ 	printf(_("uid=%u\tgid=%u\tcuid=%u\tcgid=%u\tmode=%#o\n"),
+-	       msgdata->msg_perm.uid, msgdata->msg_perm.uid,
++	       msgdata->msg_perm.uid, msgdata->msg_perm.gid,
+ 	       msgdata->msg_perm.cuid, msgdata->msg_perm.cgid,
+ 	       msgdata->msg_perm.mode);
+ 	ipc_print_size(unit, unit == IPC_UNIT_HUMAN ? _("csize=") : _("cbytes="),
+@@ -627,7 +627,7 @@ static void print_sem(int semid)
+ 
+ 	printf(_("\nSemaphore Array semid=%d\n"), semid);
+ 	printf(_("uid=%u\t gid=%u\t cuid=%u\t cgid=%u\n"),
+-	       semdata->sem_perm.uid, semdata->sem_perm.uid,
++	       semdata->sem_perm.uid, semdata->sem_perm.gid,
+ 	       semdata->sem_perm.cuid, semdata->sem_perm.cgid);
+ 	printf(_("mode=%#o, access_perms=%#o\n"),
+ 	       semdata->sem_perm.mode, semdata->sem_perm.mode & 0777);
+-- 
+2.9.3
+
diff --git a/SOURCES/0103-ipcs-fix-JP-status-message.patch b/SOURCES/0103-ipcs-fix-JP-status-message.patch
new file mode 100644
index 0000000..91260b0
--- /dev/null
+++ b/SOURCES/0103-ipcs-fix-JP-status-message.patch
@@ -0,0 +1,27 @@
+From 68e4765ff497c6274c337a03874d2e4e8b04166d Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Mon, 20 Mar 2017 11:47:02 +0100
+Subject: [PATCH 103/116] ipcs: fix JP status message
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1358097
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ po/ja.po | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/po/ja.po b/po/ja.po
+index 4c748de..f0d3645 100644
+--- a/po/ja.po
++++ b/po/ja.po
+@@ -13013,7 +13013,7 @@ msgstr "セットされていません"
+ 
+ #: sys-utils/ipcs.c:327
+ msgid "dest"
+-msgstr "対象"
++msgstr "削除"
+ 
+ #: sys-utils/ipcs.c:328
+ msgid "locked"
+-- 
+2.9.3
+
diff --git a/SOURCES/0104-swapon-fix-discard-option-parsing.patch b/SOURCES/0104-swapon-fix-discard-option-parsing.patch
new file mode 100644
index 0000000..4de1ff6
--- /dev/null
+++ b/SOURCES/0104-swapon-fix-discard-option-parsing.patch
@@ -0,0 +1,44 @@
+From 294a277fceb5cd6640a9b7a6e8af7b2567150f34 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Mon, 20 Mar 2017 12:03:40 +0100
+Subject: [PATCH 104/116] swapon: fix discard option parsing
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1378100
+Upstream: https://github.com/karelzak/util-linux/commit/07332bfa1ec122a251194a62f91319841121d5aa
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ sys-utils/swapon.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/sys-utils/swapon.c b/sys-utils/swapon.c
+index d85b910..d4f2c08 100644
+--- a/sys-utils/swapon.c
++++ b/sys-utils/swapon.c
+@@ -632,20 +632,21 @@ static int swapon_all(void)
+ 
+ 	while (mnt_table_find_next_fs(tb, itr, match_swap, NULL, &fs) == 0) {
+ 		/* defaults */
++		size_t argsz = 0;
+ 		int pri = priority, dsc = discard, nofail = ifexists;
+ 		char *p, *src, *dscarg;
+ 
+ 		if (mnt_fs_get_option(fs, "noauto", NULL, NULL) == 0)
+ 			continue;
+-		if (mnt_fs_get_option(fs, "discard", &dscarg, NULL) == 0) {
++		if (mnt_fs_get_option(fs, "discard", &dscarg, &argsz) == 0) {
+ 			dsc |= SWAP_FLAG_DISCARD;
+ 			if (dscarg) {
+ 				/* only single-time discards are wanted */
+-				if (strcmp(dscarg, "once") == 0)
++				if (strncmp(dscarg, "once", argsz) == 0)
+ 					dsc |= SWAP_FLAG_DISCARD_ONCE;
+ 
+ 				/* do discard for every released swap page */
+-				if (strcmp(dscarg, "pages") == 0)
++				if (strncmp(dscarg, "pages", argsz) == 0)
+ 					dsc |= SWAP_FLAG_DISCARD_PAGES;
+ 			}
+ 		}
+-- 
+2.9.3
+
diff --git a/SOURCES/0105-fallocate-Added-posix_fallocate-support.patch b/SOURCES/0105-fallocate-Added-posix_fallocate-support.patch
new file mode 100644
index 0000000..f200f20
--- /dev/null
+++ b/SOURCES/0105-fallocate-Added-posix_fallocate-support.patch
@@ -0,0 +1,207 @@
+From e3cfe198ebff9721efe6dd063da4b7b2dfe1d8b9 Mon Sep 17 00:00:00 2001
+From: Denis Chaplygin <dchaplyg@redhat.com>
+Date: Tue, 31 Jan 2017 12:51:28 +0100
+Subject: [PATCH 105/116] fallocate: Added posix_fallocate() support.
+
+No all filesystems support Linux fallocate. The new option allow use
+posix implementation if necessary.
+
+Upstream: https://github.com/karelzak/util-linux/commit/833f9a7aae713278eec5f85266597482f18c7370
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1416467
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ AUTHORS               |  1 +
+ configure.ac          | 28 ++++++++++++++++++++++++++++
+ sys-utils/fallocate.1 | 10 ++++++++++
+ sys-utils/fallocate.c | 44 ++++++++++++++++++++++++++++++++++++++++++--
+ 4 files changed, 81 insertions(+), 2 deletions(-)
+
+diff --git a/AUTHORS b/AUTHORS
+index cd40985..3e02181 100644
+--- a/AUTHORS
++++ b/AUTHORS
+@@ -148,6 +148,7 @@ CONTRIBUTORS:
+       David Miller <davem@davemloft.net>
+       David Prévot <david@tilapin.org>
+       David Woodhouse <dwmw2@infradead.org>
++      Denis Chaplygin <dchaplyg@redhat.com>
+       Denis ChengRq <crquan@gmail.com>
+       Dennis Gilmore <dennis@ausil.us>
+       Dennis Jensen <dennis.h.jensen@siemens.com>
+diff --git a/configure.ac b/configure.ac
+index 266ef08..f87a885 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -917,6 +917,34 @@ if test "x$build_fallocate" = xyes; then
+   AC_MSG_RESULT([no])])
+ fi
+ 
++AS_IF([test "x$build_fallocate" = xyes], [
++  dnl check for valid posix_fallocate() function
++  AC_MSG_CHECKING([for valid posix_fallocate() function])
++  AC_LINK_IFELSE([AC_LANG_PROGRAM([[
++#ifdef HAVE_UNISTD_H
++# include <unistd.h>
++#endif
++#ifdef HAVE_SYS_TYPES_H
++# include <sys/types.h>
++#endif
++#ifdef HAVE_LINUX_FALLOC_H
++# include <linux/falloc.h>
++#endif
++#ifdef HAVE_FCNTL_H
++# include <fcntl.h>
++#endif
++]],[[
++   long ret;
++   ret = posix_fallocate(0, 0xfffffffful, 0xfffffffful);
++   if (ret != 0) {
++      return 1;
++   }
++   ]])],[
++  AC_MSG_RESULT([yes])
++  AC_DEFINE([HAVE_POSIX_FALLOCATE], [1], [Have valid posix_fallocate() function])],[
++  AC_MSG_RESULT([no])])
++])
++
+ 
+ AC_ARG_ENABLE([unshare],
+   AS_HELP_STRING([--disable-unshare], [do not build unshare]),
+diff --git a/sys-utils/fallocate.1 b/sys-utils/fallocate.1
+index 49d26e4..3763530 100644
+--- a/sys-utils/fallocate.1
++++ b/sys-utils/fallocate.1
+@@ -11,6 +11,13 @@ fallocate \- preallocate space to a file
+ .B \-l
+ .IR length
+ .I filename
++.PP
++.B fallocate \-x
++.RB [ \-o
++.IR offset ]
++.RB \-l
++.IR length
++.I filename
+ .SH DESCRIPTION
+ .B fallocate
+ is used to preallocate blocks to a file.  For filesystems which support the
+@@ -39,6 +46,9 @@ Punch holes in the file, the range should not exceed the length of the file.
+ Specifies the beginning offset of the allocation, in bytes.
+ .IP "\fB\-l, \-\-length\fP \fIlength\fP
+ Specifies the length of the allocation, in bytes.
++.IP "\fB\-x , \-\-posix\fP
++Enable POSIX operation mode. In that mode allocation operation always completes,
++but it may take longer time when fast allocation is not supported by the underlying filesystem.
+ .IP "\fB\-h, \-\-help\fP"
+ Print help and exit.
+ .IP "\fB-V, \-\-version"
+diff --git a/sys-utils/fallocate.c b/sys-utils/fallocate.c
+index ff0f9e6..17ae5fe 100644
+--- a/sys-utils/fallocate.c
++++ b/sys-utils/fallocate.c
+@@ -52,6 +52,7 @@
+ #include "strutils.h"
+ #include "c.h"
+ #include "closestream.h"
++#include "optutils.h"
+ 
+ static void __attribute__((__noreturn__)) usage(FILE *out)
+ {
+@@ -63,6 +64,9 @@ static void __attribute__((__noreturn__)) usage(FILE *out)
+ 		" -p, --punch-hole    punch holes in the file\n"
+ 		" -o, --offset <num>  offset of the allocation, in bytes\n"
+ 		" -l, --length <num>  length of the allocation, in bytes\n"), out);
++#ifdef HAVE_POSIX_FALLOCATE
++	fputs(_(" -x, --posix         use posix_fallocate(3) instead of fallocate(2)\n"), out);
++#endif
+ 	fputs(USAGE_SEPARATOR, out);
+ 	fputs(USAGE_HELP, out);
+ 	fputs(USAGE_VERSION, out);
+@@ -71,6 +75,18 @@ static void __attribute__((__noreturn__)) usage(FILE *out)
+ 	exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
+ }
+ 
++
++#ifdef HAVE_POSIX_FALLOCATE
++static void xposix_fallocate(int fd, off_t offset, off_t length)
++{
++	int error = posix_fallocate(fd, offset, length);
++	if (error < 0) {
++		err(EXIT_FAILURE, _("fallocate failed"));
++	}
++}
++#endif
++
++
+ static loff_t cvtnum(char *s)
+ {
+ 	uintmax_t x;
+@@ -85,9 +101,10 @@ int main(int argc, char **argv)
+ {
+ 	char	*fname;
+ 	int	c;
+-	int	error;
++	int	error = 0;
+ 	int	fd;
+ 	int	mode = 0;
++	int	posix = 0;
+ 	loff_t	length = -2LL;
+ 	loff_t	offset = 0;
+ 
+@@ -98,15 +115,25 @@ int main(int argc, char **argv)
+ 	    { "punch-hole", 0, 0, 'p' },
+ 	    { "offset",    1, 0, 'o' },
+ 	    { "length",    1, 0, 'l' },
++	    { "posix",     0, 0, 'x' },
+ 	    { NULL,        0, 0, 0 }
+ 	};
+ 
++	static const ul_excl_t excl[] = {       /* rows and cols in ASCII order */
++		{ 'x', 'n', 'p' },
++		{ 0 }
++	};
++	int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
++
+ 	setlocale(LC_ALL, "");
+ 	bindtextdomain(PACKAGE, LOCALEDIR);
+ 	textdomain(PACKAGE);
+ 	atexit(close_stdout);
+ 
+-	while ((c = getopt_long(argc, argv, "hVnpl:o:", longopts, NULL)) != -1) {
++	while ((c = getopt_long(argc, argv, "hVnpl:o:x", longopts, NULL)) != -1) {
++
++		err_exclusive_options(c, longopts, excl, excl_st);
++
+ 		switch(c) {
+ 		case 'h':
+ 			usage(stdout);
+@@ -126,6 +153,13 @@ int main(int argc, char **argv)
+ 		case 'o':
+ 			offset = cvtnum(optarg);
+ 			break;
++		case 'x':
++#ifdef HAVE_POSIX_FALLOCATE
++			posix = 1;
++			break;
++#else
++			errx(EXIT_FAILURE, _("posix_fallocate support is not compiled"))
++#endif
+ 		default:
+ 			usage(stderr);
+ 			break;
+@@ -152,6 +186,12 @@ int main(int argc, char **argv)
+ 	if (fd < 0)
+ 		err(EXIT_FAILURE, _("cannot open %s"), fname);
+ 
++#ifdef HAVE_POSIX_FALLOCATE
++	if (posix)
++		xposix_fallocate(fd, offset, length);
++	else
++#endif
++
+ #ifdef HAVE_FALLOCATE
+ 	error = fallocate(fd, mode, offset, length);
+ #else
+-- 
+2.9.3
+
diff --git a/SOURCES/0106-zramctl-backport-from-v2.29.patch b/SOURCES/0106-zramctl-backport-from-v2.29.patch
new file mode 100644
index 0000000..2f87a48
--- /dev/null
+++ b/SOURCES/0106-zramctl-backport-from-v2.29.patch
@@ -0,0 +1,1723 @@
+From c43588bf03cc05b2eae724751b6652949e5c9caa Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 21 Mar 2017 13:04:17 +0100
+Subject: [PATCH 106/116] zramctl: backport from v2.29
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1358755
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ .gitignore              |   1 +
+ configure.ac            |   6 +
+ include/Makemodule.am   |   1 +
+ include/c.h             |   8 +
+ include/strutils.h      |   9 +
+ include/strv.h          |  55 ++++
+ include/sysfs.h         |   3 +
+ lib/Makemodule.am       |   3 +-
+ lib/strutils.c          | 129 +++++++++
+ lib/strv.c              | 403 ++++++++++++++++++++++++++
+ lib/sysfs.c             |  45 ++-
+ sys-utils/Makemodule.am |   7 +
+ sys-utils/zramctl.8     | 123 ++++++++
+ sys-utils/zramctl.c     | 736 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 14 files changed, 1524 insertions(+), 5 deletions(-)
+ create mode 100644 include/strv.h
+ create mode 100644 lib/strv.c
+ create mode 100644 sys-utils/zramctl.8
+ create mode 100644 sys-utils/zramctl.c
+
+diff --git a/configure.ac b/configure.ac
+index f87a885..db7095a 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -826,6 +826,12 @@ UL_REQUIRES_LINUX([losetup])
+ AM_CONDITIONAL(BUILD_LOSETUP, test "x$build_losetup" = xyes)
+ 
+ 
++UL_BUILD_INIT([zramctl], [check])
++UL_REQUIRES_LINUX([zramctl])
++UL_REQUIRES_BUILD([zramctl], [libsmartcols])
++AM_CONDITIONAL([BUILD_ZRAMCTL], [test "x$build_zramctl" = xyes])
++
++
+ AC_ARG_ENABLE([cytune],
+   AS_HELP_STRING([--disable-cytune], [do not build cytune]),
+   [], enable_cytune=check
+diff --git a/include/Makemodule.am b/include/Makemodule.am
+index 757f317..1680296 100644
+--- a/include/Makemodule.am
++++ b/include/Makemodule.am
+@@ -39,6 +39,7 @@ dist_noinst_HEADERS += \
+ 	include/readutmp.h \
+ 	include/setproctitle.h \
+ 	include/strutils.h \
++	include/strv.h \
+ 	include/swapheader.h \
+ 	include/sysfs.h \
+ 	include/timer.h \
+diff --git a/include/c.h b/include/c.h
+index a2779a5..3754e75 100644
+--- a/include/c.h
++++ b/include/c.h
+@@ -309,6 +309,14 @@ static inline int usleep(useconds_t usec)
+ #endif
+ 
+ /*
++ * Macros to convert #define'itions to strings, for example
++ * #define XYXXY 42
++ * printf ("%s=%s\n", stringify(XYXXY), stringify_value(XYXXY));
++ */
++#define stringify_value(s) stringify(s)
++#define stringify(s) #s
++
++/*
+  * Note that sysconf(_SC_GETPW_R_SIZE_MAX) returns *initial* suggested size for
+  * pwd buffer and in some cases it is not large enough. See POSIX and
+  * getpwnam_r man page for more details.
+diff --git a/include/strutils.h b/include/strutils.h
+index 709fcad..aa7b95f 100644
+--- a/include/strutils.h
++++ b/include/strutils.h
+@@ -5,6 +5,7 @@
+ #include <inttypes.h>
+ #include <string.h>
+ #include <sys/types.h>
++#include <stdio.h>
+ 
+ /* default strtoxx_or_err() exit code */
+ #ifndef STRTOXX_EXIT_CODE
+@@ -102,4 +103,12 @@ extern int parse_range(const char *str, int *lower, int *upper, int def);
+ 
+ extern int streq_except_trailing_slash(const char *s1, const char *s2);
+ 
++extern char *strnappend(const char *s, const char *suffix, size_t b);
++extern char *strappend(const char *s, const char *suffix);
++extern char *strfappend(const char *s, const char *format, ...)
++		 __attribute__ ((__format__ (__printf__, 2, 0)));
++extern const char *split(const char **state, size_t *l, const char *separator, int quoted);
++
++extern int skip_fline(FILE *fp);
++
+ #endif
+diff --git a/include/strv.h b/include/strv.h
+new file mode 100644
+index 0000000..260ad12
+--- /dev/null
++++ b/include/strv.h
+@@ -0,0 +1,55 @@
++#ifndef UTIL_LINUX_STRV
++#define UTIL_LINUX_STRV
++
++#include <stdarg.h>
++
++#include "c.h"
++
++char **strv_free(char **l);
++void strv_clear(char **l);
++char **strv_copy(char * const *l);
++unsigned strv_length(char * const *l);
++
++int strv_extend_strv(char ***a, char **b);
++int strv_extend_strv_concat(char ***a, char **b, const char *suffix);
++int strv_extend(char ***l, const char *value);
++int strv_extendv(char ***l, const char *format, va_list ap);
++int strv_extendf(char ***l, const char *format, ...)
++			__attribute__ ((__format__ (__printf__, 2, 0)));
++int strv_push(char ***l, char *value);
++int strv_push_prepend(char ***l, char *value);
++int strv_consume(char ***l, char *value);
++int strv_consume_prepend(char ***l, char *value);
++
++char **strv_remove(char **l, const char *s);
++
++char **strv_new(const char *x, ...);
++char **strv_new_ap(const char *x, va_list ap);
++
++static inline const char* STRV_IFNOTNULL(const char *x) {
++        return x ? x : (const char *) -1;
++}
++
++static inline int strv_isempty(char * const *l) {
++        return !l || !*l;
++}
++
++char **strv_split(const char *s, const char *separator);
++char *strv_join(char **l, const char *separator);
++
++#define STRV_FOREACH(s, l)                      \
++        for ((s) = (l); (s) && *(s); (s)++)
++
++#define STRV_FOREACH_BACKWARDS(s, l)            \
++        STRV_FOREACH(s, l)                      \
++                ;                               \
++        for ((s)--; (l) && ((s) >= (l)); (s)--)
++
++
++#define STRV_MAKE_EMPTY ((char*[1]) { NULL })
++
++char **strv_reverse(char **l);
++
++#endif /* UTIL_LINUX_STRV */
++
++
+diff --git a/include/sysfs.h b/include/sysfs.h
+index 0a9c218..a547005 100644
+--- a/include/sysfs.h
++++ b/include/sysfs.h
+@@ -58,6 +58,9 @@ extern int sysfs_read_s64(struct sysfs_cxt *cxt, const char *attr, int64_t *res)
+ extern int sysfs_read_u64(struct sysfs_cxt *cxt, const char *attr, uint64_t *res);
+ extern int sysfs_read_int(struct sysfs_cxt *cxt, const char *attr, int *res);
+ 
++extern int sysfs_write_string(struct sysfs_cxt *cxt, const char *attr, const char *str);
++extern int sysfs_write_u64(struct sysfs_cxt *cxt, const char *attr, uint64_t num);
++
+ extern char *sysfs_get_devname(struct sysfs_cxt *cxt, char *buf, size_t bufsiz);
+ 
+ extern char *sysfs_strdup(struct sysfs_cxt *cxt, const char *attr);
+diff --git a/lib/Makemodule.am b/lib/Makemodule.am
+index 73280f9..faf9d74 100644
+--- a/lib/Makemodule.am
++++ b/lib/Makemodule.am
+@@ -27,7 +27,8 @@ libcommon_la_SOURCES = \
+ 	lib/ttyutils.c \
+ 	lib/xgetpass.c \
+ 	lib/exec_shell.c \
+-	lib/readutmp.c
++	lib/readutmp.c \
++	lib/strv.c
+ 
+ if LINUX
+ libcommon_la_SOURCES += \
+diff --git a/lib/strutils.c b/lib/strutils.c
+index f9cdcbb..4b8a813 100644
+--- a/lib/strutils.c
++++ b/lib/strutils.c
+@@ -10,6 +10,7 @@
+ #include <errno.h>
+ #include <sys/stat.h>
+ #include <string.h>
++#include <assert.h>
+ 
+ #include "c.h"
+ #include "nls.h"
+@@ -687,6 +688,134 @@ int streq_except_trailing_slash(const char *s1, const char *s2)
+ 	return equal;
+ }
+ 
++char *strnappend(const char *s, const char *suffix, size_t b)
++{
++        size_t a;
++        char *r;
++
++        if (!s && !suffix)
++                return strdup("");
++        if (!s)
++                return strndup(suffix, b);
++        if (!suffix)
++                return strdup(s);
++
++        assert(s);
++        assert(suffix);
++
++        a = strlen(s);
++        if (b > ((size_t) -1) - a)
++                return NULL;
++
++        r = malloc(a + b + 1);
++        if (!r)
++                return NULL;
++
++        memcpy(r, s, a);
++        memcpy(r + a, suffix, b);
++        r[a+b] = 0;
++
++        return r;
++}
++
++char *strappend(const char *s, const char *suffix)
++{
++        return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
++}
++
++char *strfappend(const char *s, const char *format, ...)
++{
++	va_list ap;
++	char *val, *res;
++	int sz;
++
++	va_start(ap, format);
++	sz = vasprintf(&val, format, ap);
++	va_end(ap);
++
++	if (sz < 0)
++		return NULL;
++
++	res = strnappend(s, val, sz);
++	free(val);
++	return res;
++}
++
++static size_t strcspn_escaped(const char *s, const char *reject)
++{
++        int escaped = 0;
++        int n;
++
++        for (n=0; s[n]; n++) {
++                if (escaped)
++                        escaped = 0;
++                else if (s[n] == '\\')
++                        escaped = 1;
++                else if (strchr(reject, s[n]))
++                        break;
++        }
++
++        /* if s ends in \, return index of previous char */
++        return n - escaped;
++}
++
++/* Split a string into words. */
++const char *split(const char **state, size_t *l, const char *separator, int quoted)
++{
++        const char *current;
++
++        current = *state;
++
++        if (!*current) {
++                assert(**state == '\0');
++                return NULL;
++        }
++
++        current += strspn(current, separator);
++        if (!*current) {
++                *state = current;
++                return NULL;
++        }
++
++        if (quoted && strchr("\'\"", *current)) {
++                char quotechars[2] = {*current, '\0'};
++
++                *l = strcspn_escaped(current + 1, quotechars);
++                if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] ||
++                    (current[*l + 2] && !strchr(separator, current[*l + 2]))) {
++                        /* right quote missing or garbage at the end */
++                        *state = current;
++                        return NULL;
++                }
++                *state = current++ + *l + 2;
++        } else if (quoted) {
++                *l = strcspn_escaped(current, separator);
++                if (current[*l] && !strchr(separator, current[*l])) {
++                        /* unfinished escape */
++                        *state = current;
++                        return NULL;
++                }
++                *state = current + *l;
++        } else {
++                *l = strcspn(current, separator);
++                *state = current + *l;
++        }
++
++        return current;
++}
++
++/* Rewind file pointer forward to new line.  */
++int skip_fline(FILE *fp)
++{
++	int ch;
++
++	do {
++		if ((ch = fgetc(fp)) == EOF)
++			return 1;
++		if (ch == '\n')
++			return 0;
++	} while (1);
++}
+ 
+ #ifdef TEST_PROGRAM
+ 
+diff --git a/lib/strv.c b/lib/strv.c
+new file mode 100644
+index 0000000..ddc2a0c
+--- /dev/null
++++ b/lib/strv.c
+@@ -0,0 +1,403 @@
++/*
++ *
++ * Copyright 2010 Lennart Poettering
++ *
++ * This is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Lesser General Public License as published by
++ * the Free Software Foundation; either version 2.1 of the License, or
++ * (at your option) any later version.
++ *
++ *
++ * Copyright (C) 2015 Karel Zak <kzak@redhat.com>
++ *    Modified the original version from systemd project for util-linux.
++ */
++
++#include <stdlib.h>
++#include <stdarg.h>
++#include <string.h>
++#include <errno.h>
++#include <stdbool.h>
++#include <assert.h>
++
++#include "strutils.h"
++#include "strv.h"
++
++void strv_clear(char **l) {
++        char **k;
++
++        if (!l)
++                return;
++
++        for (k = l; *k; k++)
++                free(*k);
++
++        *l = NULL;
++}
++
++char **strv_free(char **l) {
++        strv_clear(l);
++        free(l);
++        return NULL;
++}
++
++char **strv_copy(char * const *l) {
++        char **r, **k;
++
++        k = r = malloc(sizeof(char *) * (strv_length(l) + 1));
++        if (!r)
++                return NULL;
++
++        if (l)
++                for (; *l; k++, l++) {
++                        *k = strdup(*l);
++                        if (!*k) {
++                                strv_free(r);
++                                return NULL;
++                        }
++                }
++
++        *k = NULL;
++        return r;
++}
++
++unsigned strv_length(char * const *l) {
++        unsigned n = 0;
++
++        if (!l)
++                return 0;
++
++        for (; *l; l++)
++                n++;
++
++        return n;
++}
++
++char **strv_new_ap(const char *x, va_list ap) {
++        const char *s;
++        char **a;
++        unsigned n = 0, i = 0;
++        va_list aq;
++
++        /* As a special trick we ignore all listed strings that equal
++         * (const char*) -1. This is supposed to be used with the
++         * STRV_IFNOTNULL() macro to include possibly NULL strings in
++         * the string list. */
++
++        if (x) {
++                n = x == (const char*) -1 ? 0 : 1;
++
++                va_copy(aq, ap);
++                while ((s = va_arg(aq, const char*))) {
++                        if (s == (const char*) -1)
++                                continue;
++
++                        n++;
++                }
++
++                va_end(aq);
++        }
++
++        a = malloc(sizeof(char *) * (n + 1));
++        if (!a)
++                return NULL;
++
++        if (x) {
++                if (x != (const char*) -1) {
++                        a[i] = strdup(x);
++                        if (!a[i])
++                                goto fail;
++                        i++;
++                }
++
++                while ((s = va_arg(ap, const char*))) {
++
++                        if (s == (const char*) -1)
++                                continue;
++
++                        a[i] = strdup(s);
++                        if (!a[i])
++                                goto fail;
++
++                        i++;
++                }
++        }
++
++        a[i] = NULL;
++
++        return a;
++
++fail:
++        strv_free(a);
++        return NULL;
++}
++
++char **strv_new(const char *x, ...) {
++        char **r;
++        va_list ap;
++
++        va_start(ap, x);
++        r = strv_new_ap(x, ap);
++        va_end(ap);
++
++        return r;
++}
++
++int strv_extend_strv(char ***a, char **b) {
++        int r;
++        char **s;
++
++        STRV_FOREACH(s, b) {
++                r = strv_extend(a, *s);
++                if (r < 0)
++                        return r;
++        }
++
++        return 0;
++}
++
++int strv_extend_strv_concat(char ***a, char **b, const char *suffix) {
++        int r;
++        char **s;
++
++        STRV_FOREACH(s, b) {
++                char *v;
++
++                v = strappend(*s, suffix);
++                if (!v)
++                        return -ENOMEM;
++
++                r = strv_push(a, v);
++                if (r < 0) {
++                        free(v);
++                        return r;
++                }
++        }
++
++        return 0;
++}
++
++
++#define _FOREACH_WORD(word, length, s, separator, quoted, state)        \
++        for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted)))
++
++#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state)       \
++        _FOREACH_WORD(word, length, s, separator, false, state)
++
++
++char **strv_split(const char *s, const char *separator) {
++        const char *word, *state;
++        size_t l;
++        unsigned n, i;
++        char **r;
++
++        assert(s);
++
++        n = 0;
++        FOREACH_WORD_SEPARATOR(word, l, s, separator, state)
++                n++;
++
++        r = malloc(sizeof(char *) * (n + 1));
++        if (!r)
++                return NULL;
++
++        i = 0;
++        FOREACH_WORD_SEPARATOR(word, l, s, separator, state) {
++                r[i] = strndup(word, l);
++                if (!r[i]) {
++                        strv_free(r);
++                        return NULL;
++                }
++
++                i++;
++        }
++
++        r[i] = NULL;
++        return r;
++}
++
++char *strv_join(char **l, const char *separator) {
++        char *r, *e;
++        char **s;
++        size_t n, k;
++
++        if (!separator)
++                separator = " ";
++
++        k = strlen(separator);
++
++        n = 0;
++        STRV_FOREACH(s, l) {
++                if (n != 0)
++                        n += k;
++                n += strlen(*s);
++        }
++
++        r = malloc(n + 1);
++        if (!r)
++                return NULL;
++
++        e = r;
++        STRV_FOREACH(s, l) {
++                if (e != r)
++                        e = stpcpy(e, separator);
++
++                e = stpcpy(e, *s);
++        }
++
++        *e = 0;
++
++        return r;
++}
++
++int strv_push(char ***l, char *value) {
++        char **c;
++        unsigned n, m;
++
++        if (!value)
++                return 0;
++
++        n = strv_length(*l);
++
++        /* Increase and check for overflow */
++        m = n + 2;
++        if (m < n)
++                return -ENOMEM;
++
++        c = realloc(*l, sizeof(char *) * m);
++        if (!c)
++                return -ENOMEM;
++
++        c[n] = value;
++        c[n+1] = NULL;
++
++        *l = c;
++        return 0;
++}
++
++int strv_push_prepend(char ***l, char *value) {
++        char **c;
++        unsigned n, m, i;
++
++        if (!value)
++                return 0;
++
++        n = strv_length(*l);
++
++        /* increase and check for overflow */
++        m = n + 2;
++        if (m < n)
++                return -ENOMEM;
++
++        c = malloc(sizeof(char *) * m);
++        if (!c)
++                return -ENOMEM;
++
++        for (i = 0; i < n; i++)
++                c[i+1] = (*l)[i];
++
++        c[0] = value;
++        c[n+1] = NULL;
++
++        free(*l);
++        *l = c;
++
++        return 0;
++}
++
++int strv_consume(char ***l, char *value) {
++        int r;
++
++        r = strv_push(l, value);
++        if (r < 0)
++                free(value);
++
++        return r;
++}
++
++int strv_consume_prepend(char ***l, char *value) {
++        int r;
++
++        r = strv_push_prepend(l, value);
++        if (r < 0)
++                free(value);
++
++        return r;
++}
++
++int strv_extend(char ***l, const char *value) {
++        char *v;
++
++        if (!value)
++                return 0;
++
++        v = strdup(value);
++        if (!v)
++                return -ENOMEM;
++
++        return strv_consume(l, v);
++}
++
++char **strv_remove(char **l, const char *s) {
++        char **f, **t;
++
++        if (!l)
++                return NULL;
++
++        assert(s);
++
++        /* Drops every occurrence of s in the string list, edits
++         * in-place. */
++
++        for (f = t = l; *f; f++)
++                if (strcmp(*f, s) == 0)
++                        free(*f);
++                else
++                        *(t++) = *f;
++
++        *t = NULL;
++        return l;
++}
++
++int strv_extendf(char ***l, const char *format, ...) {
++        va_list ap;
++        char *x;
++        int r;
++
++        va_start(ap, format);
++        r = vasprintf(&x, format, ap);
++        va_end(ap);
++
++        if (r < 0)
++                return -ENOMEM;
++
++        return strv_consume(l, x);
++}
++
++int strv_extendv(char ***l, const char *format, va_list ap) {
++        char *x;
++        int r;
++
++        r = vasprintf(&x, format, ap);
++        if (r < 0)
++                return -ENOMEM;
++
++        return strv_consume(l, x);
++}
++
++char **strv_reverse(char **l) {
++        unsigned n, i;
++
++        n = strv_length(l);
++        if (n <= 1)
++                return l;
++
++        for (i = 0; i < n / 2; i++) {
++                char *t;
++
++                t = l[i];
++                l[i] = l[n-1-i];
++                l[n-1-i] = t;
++        }
++
++        return l;
++}
+diff --git a/lib/sysfs.c b/lib/sysfs.c
+index 0bfd622..65a8394 100644
+--- a/lib/sysfs.c
++++ b/lib/sysfs.c
+@@ -10,6 +10,7 @@
+ #include "at.h"
+ #include "pathnames.h"
+ #include "sysfs.h"
++#include "all-io.h"
+ 
+ char *sysfs_devno_attribute_path(dev_t devno, char *buf,
+ 				 size_t bufsiz, const char *attr)
+@@ -203,9 +204,9 @@ int sysfs_has_attribute(struct sysfs_cxt *cxt, const char *attr)
+ 	return sysfs_stat(cxt, attr, &st) == 0;
+ }
+ 
+-static int sysfs_open(struct sysfs_cxt *cxt, const char *attr)
++static int sysfs_open(struct sysfs_cxt *cxt, const char *attr, int flags)
+ {
+-	int fd = open_at(cxt->dir_fd, cxt->dir_path, attr, O_RDONLY|O_CLOEXEC);
++	int fd = open_at(cxt->dir_fd, cxt->dir_path, attr, flags);
+ 
+ 	if (fd == -1 && errno == ENOENT &&
+ 	    strncmp(attr, "queue/", 6) == 0 && cxt->parent) {
+@@ -238,7 +239,7 @@ DIR *sysfs_opendir(struct sysfs_cxt *cxt, const char *attr)
+ 	int fd = -1;
+ 
+ 	if (attr)
+-		fd = sysfs_open(cxt, attr);
++		fd = sysfs_open(cxt, attr, O_RDONLY|O_CLOEXEC);
+ 
+ 	else if (cxt->dir_fd >= 0)
+ 		/* request to open root of device in sysfs (/sys/block/<dev>)
+@@ -263,7 +264,7 @@ DIR *sysfs_opendir(struct sysfs_cxt *cxt, const char *attr)
+ 
+ static FILE *sysfs_fopen(struct sysfs_cxt *cxt, const char *attr)
+ {
+-	int fd = sysfs_open(cxt, attr);
++	int fd = sysfs_open(cxt, attr, O_RDONLY|O_CLOEXEC);
+ 
+ 	return fd < 0 ? NULL : fdopen(fd, "r" UL_CLOEXECSTR);
+ }
+@@ -417,6 +418,42 @@ int sysfs_read_int(struct sysfs_cxt *cxt, const char *attr, int *res)
+ 	return -1;
+ }
+ 
++int sysfs_write_string(struct sysfs_cxt *cxt, const char *attr, const char *str)
++{
++	int fd = sysfs_open(cxt, attr, O_WRONLY|O_CLOEXEC);
++	int rc, errsv;
++
++	if (fd < 0)
++		return -errno;
++	rc = write_all(fd, str, strlen(str));
++
++	errsv = errno;
++	close(fd);
++	errno = errsv;
++	return rc;
++}
++
++int sysfs_write_u64(struct sysfs_cxt *cxt, const char *attr, uint64_t num)
++{
++	char buf[sizeof(stringify_value(ULLONG_MAX))];
++	int fd, rc = 0, len, errsv;
++
++	fd = sysfs_open(cxt, attr, O_WRONLY|O_CLOEXEC);
++	if (fd < 0)
++		return -errno;
++
++	len = snprintf(buf, sizeof(buf), "%" PRIu64, num);
++	if (len < 0 || (size_t) len >= sizeof(buf))
++		rc = len < 0 ? -errno : -E2BIG;
++	else
++		rc = write_all(fd, buf, len);
++
++	errsv = errno;
++	close(fd);
++	errno = errsv;
++	return rc;
++}
++
+ char *sysfs_strdup(struct sysfs_cxt *cxt, const char *attr)
+ {
+ 	char buf[1024];
+diff --git a/sys-utils/Makemodule.am b/sys-utils/Makemodule.am
+index 6badd17..408e884 100644
+--- a/sys-utils/Makemodule.am
++++ b/sys-utils/Makemodule.am
+@@ -184,6 +184,13 @@ losetup_static_LDADD = $(losetup_LDADD)
+ endif
+ endif # BUILD_LOSETUP
+ 
++if BUILD_ZRAMCTL
++sbin_PROGRAMS += zramctl
++dist_man_MANS += sys-utils/zramctl.8
++zramctl_SOURCES = sys-utils/zramctl.c
++zramctl_LDADD = $(LDADD) libcommon.la libsmartcols.la
++zramctl_CFLAGS = $(AM_CFLAGS) -I$(ul_libsmartcols_incdir)
++endif
+ 
+ if BUILD_PRLIMIT
+ usrbin_exec_PROGRAMS += prlimit
+diff --git a/sys-utils/zramctl.8 b/sys-utils/zramctl.8
+new file mode 100644
+index 0000000..f6fc45c
+--- /dev/null
++++ b/sys-utils/zramctl.8
+@@ -0,0 +1,123 @@
++.TH ZRAMCTL 8 "July 2014" "util-linux" "System Administration"
++.SH NAME
++zramctl \- set up and control zram devices
++.SH SYNOPSIS
++.ad l
++Get info:
++.sp
++.in +5
++.BR zramctl " [options]"
++.sp
++.in -5
++Reset zram:
++.sp
++.in +5
++.B "zramctl \-r"
++.IR zramdev ...
++.sp
++.in -5
++Print name of first unused zram device:
++.sp
++.in +5
++.B "zramctl \-f"
++.sp
++.in -5
++Set up a zram device:
++.sp
++.in +5
++.B zramctl
++.RB [ \-f " | "\fIzramdev\fP ]
++.RB [ \-s
++.IR size ]
++.RB [ \-t
++.IR number ]
++.RB [ \-a
++.IR algorithm ]
++.sp
++.in -5
++.ad b
++.SH DESCRIPTION
++.B zramctl
++is used to quickly set up zram device parameters, to reset zram devices, and to
++query the status of used zram devices.  If no option is given, all zram devices
++are shown.
++
++.SH OPTIONS
++.TP
++.BR \-a , " \-\-algorithm lzo" | lz4
++Set the compression algorithm to be used for compressing data in the zram device.
++.TP
++.BR \-f , " \-\-find"
++Find the first unused zram device.  If a \fB--size\fR argument is present, then
++initialize the device.
++.TP
++.BR \-n , " \-\-noheadings"
++Do not print a header line in status output.
++.TP
++.BR \-o , " \-\-output " \fIlist
++Define the status output columns to be used.  If no output arrangement is
++specified, then a default set is used.
++Use \fB\-\-help\fP to get a list of all supported columns.
++.TP
++.B \-\-raw
++Use the raw format for status output.
++.TP
++.BR \-r , " \-\-reset"
++Reset the options of the specified zram device(s).  Zram device settings
++can be changed only after a reset.
++.TP
++.BR \-s , " \-\-size " \fIsize
++Create a zram device of the specified \fIsize\fR.
++Zram devices are aligned to memory pages; when the requested \fIsize\fR is
++not a multiple of the page size, it will be rounded up to the next multiple.
++When not otherwise specified, the unit of the \fIsize\fR parameter is bytes.
++.IP
++The \fIsize\fR argument may be followed by the multiplicative suffixes KiB (=1024),
++MiB (=1024*1024), and so on for GiB, TiB, PiB, EiB, ZiB and YiB (the "iB"
++is optional, e.g., "K" has the same meaning as "KiB") or the suffixes
++KB (=1000), MB (=1000*1000), and so on for GB, TB, PB, EB, ZB and YB.
++.TP
++.BR \-t , " \-\-streams " \fInumber
++Set the maximum number of compression streams that can be used for the device.
++The default is one stream.
++.TP
++.BR \-V , " \-\-version"
++Display version information and exit.
++.TP
++.BR \-h , " \-\-help"
++Display help text and exit.
++
++.SH RETURN VALUE
++.B zramctl
++returns 0 on success, nonzero on failure.
++
++.SH FILES
++.TP
++.I /dev/zram[0..N]
++zram block devices
++
++.SH EXAMPLE
++The following commands set up a zram device with a size of one gigabyte
++and use it as swap device.
++.nf
++.IP
++# zramctl --find --size 1024M
++/dev/zram0
++# mkswap /dev/zram0
++# swapon /dev/zram0
++ ...
++# swapoff /dev/zram0
++# zramctl --reset /dev/zram0
++.fi
++.SH SEE ALSO
++.UR http://git.\:kernel.\:org\:/cgit\:/linux\:/kernel\:/git\:/torvalds\:/linux.git\:/tree\:/Documentation\:/blockdev\:/zram.txt
++Linux kernel documentation
++.UE .
++.SH AUTHORS
++.nf
++Timofey Titovets <nefelim4ag@gmail.com>
++Karel Zak <kzak@redhat.com>
++.fi
++.SH AVAILABILITY
++The zramctl command is part of the util-linux package and is available from
++https://www.kernel.org/pub/linux/utils/util-linux/.
+diff --git a/sys-utils/zramctl.c b/sys-utils/zramctl.c
+new file mode 100644
+index 0000000..853401c
+--- /dev/null
++++ b/sys-utils/zramctl.c
+@@ -0,0 +1,736 @@
++/*
++ * zramctl - control compressed block devices in RAM
++ *
++ * Copyright (c) 2014 Timofey Titovets <Nefelim4ag@gmail.com>
++ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it would 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 <getopt.h>
++#include <stdlib.h>
++#include <string.h>
++#include <stdarg.h>
++#include <assert.h>
++
++#include <libsmartcols.h>
++
++#include "c.h"
++#include "nls.h"
++#include "closestream.h"
++#include "strutils.h"
++#include "xalloc.h"
++#include "sysfs.h"
++#include "optutils.h"
++#include "ismounted.h"
++#include "strv.h"
++#include "path.h"
++#include "pathnames.h"
++
++/*#define CONFIG_ZRAM_DEBUG*/
++
++#ifdef CONFIG_ZRAM_DEBUG
++# define DBG(x)	 do { fputs("zram: ", stderr); x; fputc('\n', stderr); } while(0)
++#else
++# define DBG(x)
++#endif
++
++/* status output columns */
++struct colinfo {
++	const char *name;
++	double whint;
++	int flags;
++	const char *help;
++};
++
++enum {
++	COL_NAME = 0,
++	COL_DISKSIZE,
++	COL_ORIG_SIZE,
++	COL_COMP_SIZE,
++	COL_ALGORITHM,
++	COL_STREAMS,
++	COL_ZEROPAGES,
++	COL_MEMTOTAL,
++	COL_MEMLIMIT,
++	COL_MEMUSED,
++	COL_MIGRATED,
++	COL_MOUNTPOINT
++};
++
++static const struct colinfo infos[] = {
++	[COL_NAME]      = { "NAME",      0.25, 0, N_("zram device name") },
++	[COL_DISKSIZE]  = { "DISKSIZE",     5, SCOLS_FL_RIGHT, N_("limit on the uncompressed amount of data") },
++	[COL_ORIG_SIZE] = { "DATA",         5, SCOLS_FL_RIGHT, N_("uncompressed size of stored data") },
++	[COL_COMP_SIZE] = { "COMPR",        5, SCOLS_FL_RIGHT, N_("compressed size of stored data") },
++	[COL_ALGORITHM] = { "ALGORITHM",    3, 0, N_("the selected compression algorithm") },
++	[COL_STREAMS]   = { "STREAMS",      3, SCOLS_FL_RIGHT, N_("number of concurrent compress operations") },
++	[COL_ZEROPAGES] = { "ZERO-PAGES",   3, SCOLS_FL_RIGHT, N_("empty pages with no allocated memory") },
++	[COL_MEMTOTAL]  = { "TOTAL",        5, SCOLS_FL_RIGHT, N_("all memory including allocator fragmentation and metadata overhead") },
++	[COL_MEMLIMIT]  = { "MEM-LIMIT",    5, SCOLS_FL_RIGHT, N_("memory limit used to store compressed data") },
++	[COL_MEMUSED]   = { "MEM-USED",     5, SCOLS_FL_RIGHT, N_("memory zram have been consumed to store compressed data") },
++	[COL_MIGRATED]  = { "MIGRATED",     5, SCOLS_FL_RIGHT, N_("number of objects migrated by compaction") },
++	[COL_MOUNTPOINT]= { "MOUNTPOINT",0.10, SCOLS_FL_TRUNC, N_("where the device is mounted") },
++};
++
++static int columns[ARRAY_SIZE(infos) * 2] = {-1};
++static int ncolumns;
++
++enum {
++	MM_ORIG_DATA_SIZE = 0,
++	MM_COMPR_DATA_SIZE,
++	MM_MEM_USED_TOTAL,
++	MM_MEM_LIMIT,
++	MM_MEM_USED_MAX,
++	MM_ZERO_PAGES,
++	MM_NUM_MIGRATED
++};
++
++static const char *mm_stat_names[] = {
++	[MM_ORIG_DATA_SIZE]  = "orig_data_size",
++	[MM_COMPR_DATA_SIZE] = "compr_data_size",
++	[MM_MEM_USED_TOTAL]  = "mem_used_total",
++	[MM_MEM_LIMIT]       = "mem_limit",
++	[MM_MEM_USED_MAX]    = "mem_used_max",
++	[MM_ZERO_PAGES]      = "zero_pages",
++	[MM_NUM_MIGRATED]    = "num_migrated"
++};
++
++
++struct zram {
++	char	devname[32];
++	struct sysfs_cxt sysfs;
++	char	**mm_stat;
++
++	unsigned int mm_stat_probed : 1,
++		     control_probed : 1,
++		     has_control : 1;	/* has /sys/class/zram-control/ */
++};
++
++#define ZRAM_EMPTY	{ .devname = { '\0' }, .sysfs = UL_SYSFSCXT_EMPTY }
++
++static unsigned int raw, no_headings, inbytes;
++
++
++static int get_column_id(int num)
++{
++	assert(num < ncolumns);
++	assert(columns[num] < (int) ARRAY_SIZE(infos));
++	return columns[num];
++}
++
++static const struct colinfo *get_column_info(int num)
++{
++	return &infos[ get_column_id(num) ];
++}
++
++static int column_name_to_id(const char *name, size_t namesz)
++{
++	size_t i;
++
++	for (i = 0; i < ARRAY_SIZE(infos); i++) {
++		const char *cn = infos[i].name;
++
++		if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
++			return i;
++	}
++	warnx(_("unknown column: %s"), name);
++	return -1;
++}
++
++static void zram_reset_stat(struct zram *z)
++{
++	if (z) {
++		strv_free(z->mm_stat);
++		z->mm_stat = NULL;
++		z->mm_stat_probed = 0;
++	}
++}
++
++static void zram_set_devname(struct zram *z, const char *devname, size_t n)
++{
++	assert(z);
++
++	if (!devname)
++		snprintf(z->devname, sizeof(z->devname), "/dev/zram%zu", n);
++	else {
++		strncpy(z->devname, devname, sizeof(z->devname));
++		z->devname[sizeof(z->devname) - 1] = '\0';
++	}
++
++	DBG(fprintf(stderr, "set devname: %s", z->devname));
++	sysfs_deinit(&z->sysfs);
++	zram_reset_stat(z);
++}
++
++static int zram_get_devnum(struct zram *z)
++{
++	int n;
++
++	assert(z);
++
++	if (sscanf(z->devname, "/dev/zram%d", &n) == 1)
++		return n;
++	return -EINVAL;
++}
++
++static struct zram *new_zram(const char *devname)
++{
++	struct zram *z = xcalloc(1, sizeof(struct zram));
++
++	DBG(fprintf(stderr, "new: %p", z));
++	if (devname)
++		zram_set_devname(z, devname, 0);
++	return z;
++}
++
++static void free_zram(struct zram *z)
++{
++	if (!z)
++		return;
++	DBG(fprintf(stderr, "free: %p", z));
++	sysfs_deinit(&z->sysfs);
++	zram_reset_stat(z);
++	free(z);
++}
++
++static struct sysfs_cxt *zram_get_sysfs(struct zram *z)
++{
++	assert(z);
++
++	if (!z->sysfs.devno) {
++		dev_t devno = sysfs_devname_to_devno(z->devname, NULL);
++		if (!devno)
++			return NULL;
++		if (sysfs_init(&z->sysfs, devno, NULL))
++			return NULL;
++		if (*z->devname != '/') {
++			/* canonicalize the device name according to /sys */
++			char name[PATH_MAX];
++			if (sysfs_get_devname(&z->sysfs, name, sizeof(name)))
++				snprintf(z->devname, sizeof(z->devname), "/dev/%s", name);
++		}
++	}
++
++	return &z->sysfs;
++}
++
++static inline int zram_exist(struct zram *z)
++{
++	assert(z);
++
++	errno = 0;
++	if (zram_get_sysfs(z) == NULL) {
++		errno = ENODEV;
++		return 0;
++	}
++
++	DBG(fprintf(stderr, "%s exists", z->devname));
++	return 1;
++}
++
++static int zram_set_u64parm(struct zram *z, const char *attr, uint64_t num)
++{
++	struct sysfs_cxt *sysfs = zram_get_sysfs(z);
++	if (!sysfs)
++		return -EINVAL;
++	DBG(fprintf(stderr, "%s writing %ju to %s", z->devname, num, attr));
++	return sysfs_write_u64(sysfs, attr, num);
++}
++
++static int zram_set_strparm(struct zram *z, const char *attr, const char *str)
++{
++	struct sysfs_cxt *sysfs = zram_get_sysfs(z);
++	if (!sysfs)
++		return -EINVAL;
++	DBG(fprintf(stderr, "%s writing %s to %s", z->devname, str, attr));
++	return sysfs_write_string(sysfs, attr, str);
++}
++
++
++static int zram_used(struct zram *z)
++{
++	uint64_t size;
++	struct sysfs_cxt *sysfs = zram_get_sysfs(z);
++
++	if (sysfs &&
++	    sysfs_read_u64(sysfs, "disksize", &size) == 0 &&
++	    size > 0) {
++
++		DBG(fprintf(stderr, "%s used", z->devname));
++		return 1;
++	}
++	DBG(fprintf(stderr, "%s unused", z->devname));
++	return 0;
++}
++
++static int zram_has_control(struct zram *z)
++{
++	if (!z->control_probed) {
++		z->has_control = access(_PATH_SYS_CLASS "/zram-control/", F_OK) == 0 ? 1 : 0;
++		z->control_probed = 1;
++		DBG(fprintf(stderr, "zram-control: %s", z->has_control ? "yes" : "no"));
++	}
++
++	return z->has_control;
++}
++
++static int zram_control_add(struct zram *z)
++{
++	int n;
++
++	if (!zram_has_control(z))
++		return -ENOSYS;
++
++	n = path_read_s32(_PATH_SYS_CLASS "/zram-control/hot_add");
++	if (n < 0)
++		return n;
++
++	DBG(fprintf(stderr, "hot-add: %d", n));
++	zram_set_devname(z, NULL, n);
++	return 0;
++}
++
++static int zram_control_remove(struct zram *z)
++{
++	char str[sizeof stringify_value(INT_MAX)];
++	int n;
++
++	if (!zram_has_control(z))
++		return -ENOSYS;
++
++	n = zram_get_devnum(z);
++	if (n < 0)
++		return n;
++
++	DBG(fprintf(stderr, "hot-remove: %d", n));
++	snprintf(str, sizeof(str), "%d", n);
++	return path_write_str(str, _PATH_SYS_CLASS "/zram-control/hot_remove");
++}
++
++static struct zram *find_free_zram(void)
++{
++	struct zram *z = new_zram(NULL);
++	size_t i;
++	int isfree = 0;
++
++	for (i = 0; isfree == 0; i++) {
++		DBG(fprintf(stderr, "find free: checking zram%zu", i));
++		zram_set_devname(z, NULL, i);
++		if (!zram_exist(z) && zram_control_add(z) != 0)
++			break;
++		isfree = !zram_used(z);
++	}
++	if (!isfree) {
++		free_zram(z);
++		z = NULL;
++	}
++	return z;
++}
++
++static char *get_mm_stat(struct zram *z, size_t idx, int bytes)
++{
++	struct sysfs_cxt *sysfs;
++	const char *name;
++	uint64_t num;
++
++	assert(idx < ARRAY_SIZE(mm_stat_names));
++	assert(z);
++
++	sysfs = zram_get_sysfs(z);
++	if (!sysfs)
++		return NULL;
++
++	/* Linux >= 4.1 uses /sys/block/zram<id>/mm_stat */
++	if (!z->mm_stat && !z->mm_stat_probed) {
++		char *str;
++
++		str = sysfs_strdup(sysfs, "mm_stat");
++		if (str) {
++			z->mm_stat = strv_split(str, " ");
++			if (strv_length(z->mm_stat) < ARRAY_SIZE(mm_stat_names))
++				errx(EXIT_FAILURE, _("Failed to parse mm_stat"));
++		}
++		z->mm_stat_probed = 1;
++		free(str);
++
++	}
++
++	if (z->mm_stat) {
++		if (bytes)
++			return xstrdup(z->mm_stat[idx]);
++
++		num = strtou64_or_err(z->mm_stat[idx], _("Failed to parse mm_stat"));
++		return size_to_human_string(SIZE_SUFFIX_1LETTER, num);
++	}
++
++	/* Linux < 4.1 uses /sys/block/zram<id>/<attrname> */
++	name = mm_stat_names[idx];
++	if (bytes)
++		return sysfs_strdup(sysfs, name);
++	else if (sysfs_read_u64(sysfs, name, &num) == 0)
++		return size_to_human_string(SIZE_SUFFIX_1LETTER, num);
++	return NULL;
++}
++
++static void fill_table_row(struct libscols_table *tb, struct zram *z)
++{
++	static struct libscols_line *ln;
++	struct sysfs_cxt *sysfs;
++	size_t i;
++	uint64_t num;
++
++	assert(tb);
++	assert(z);
++
++	DBG(fprintf(stderr, "%s: filling status table", z->devname));
++
++	sysfs = zram_get_sysfs(z);
++	if (!sysfs)
++		return;
++
++	ln = scols_table_new_line(tb, NULL);
++	if (!ln)
++		err(EXIT_FAILURE, _("failed to initialize output line"));
++
++	for (i = 0; i < (size_t) ncolumns; i++) {
++		char *str = NULL;
++
++		switch (get_column_id(i)) {
++		case COL_NAME:
++			str = xstrdup(z->devname);
++			break;
++		case COL_DISKSIZE:
++			if (inbytes)
++				str = sysfs_strdup(sysfs, "disksize");
++			else if (sysfs_read_u64(sysfs, "disksize", &num) == 0)
++				str = size_to_human_string(SIZE_SUFFIX_1LETTER, num);
++			break;
++		case COL_ALGORITHM:
++		{
++			char *alg = sysfs_strdup(sysfs, "comp_algorithm");
++			if (!alg)
++				break;
++			if (strstr(alg, "[lzo]") == NULL) {
++				if (strstr(alg, "[lz4]") == NULL)
++					;
++				else
++					str = xstrdup("lz4");
++			} else
++				str = xstrdup("lzo");
++			free(alg);
++			break;
++		}
++		case COL_MOUNTPOINT:
++		{
++			char path[PATH_MAX] = { '\0' };
++			int fl;
++
++			check_mount_point(z->devname, &fl, path, sizeof(path));
++			if (*path)
++				str = xstrdup(path);
++			break;
++		}
++		case COL_STREAMS:
++			str = sysfs_strdup(sysfs, "max_comp_streams");
++			break;
++		case COL_ZEROPAGES:
++			str = get_mm_stat(z, MM_ZERO_PAGES, 1);
++			break;
++		case COL_ORIG_SIZE:
++			str = get_mm_stat(z, MM_ORIG_DATA_SIZE, inbytes);
++			break;
++		case COL_COMP_SIZE:
++			str = get_mm_stat(z, MM_COMPR_DATA_SIZE, inbytes);
++			break;
++		case COL_MEMTOTAL:
++			str = get_mm_stat(z, MM_MEM_USED_TOTAL, inbytes);
++			break;
++		case COL_MEMLIMIT:
++			str = get_mm_stat(z, MM_MEM_LIMIT, inbytes);
++			break;
++		case COL_MEMUSED:
++			str = get_mm_stat(z, MM_MEM_USED_MAX, inbytes);
++			break;
++		case COL_MIGRATED:
++			str = get_mm_stat(z, MM_NUM_MIGRATED, inbytes);
++			break;
++		}
++		if (str)
++			scols_line_refer_data(ln, i, str);
++	}
++}
++
++static void status(struct zram *z)
++{
++	struct libscols_table *tb;
++	size_t i;
++
++	scols_init_debug(0);
++
++	tb = scols_new_table();
++	if (!tb)
++		err(EXIT_FAILURE, _("failed to initialize output table"));
++
++	scols_table_enable_raw(tb, raw);
++	scols_table_enable_noheadings(tb, no_headings);
++
++	for (i = 0; i < (size_t) ncolumns; i++) {
++		const struct colinfo *col = get_column_info(i);
++
++		if (!scols_table_new_column(tb, col->name, col->whint, col->flags))
++			err(EXIT_FAILURE, _("failed to initialize output column"));
++	}
++
++	if (z)
++		fill_table_row(tb, z);		/* just one device specified */
++	else {
++		/* list all used devices */
++		z = new_zram(NULL);
++
++		for (i = 0; ; i++) {
++			zram_set_devname(z, NULL, i);
++			if (!zram_exist(z))
++				break;
++			if (zram_used(z))
++				fill_table_row(tb, z);
++		}
++		free_zram(z);
++	}
++
++	scols_print_table(tb);
++	scols_unref_table(tb);
++}
++
++static void __attribute__ ((__noreturn__)) usage(FILE * out)
++{
++	size_t i;
++
++	fputs(USAGE_HEADER, out);
++	fprintf(out, _(	" %1$s [options] <device>\n"
++			" %1$s -r <device> [...]\n"
++			" %1$s [options] -f | <device> -s <size>\n"),
++			program_invocation_short_name);
++
++	fputs(USAGE_SEPARATOR, out);
++	fputs(_("Set up and control zram devices.\n"), out);
++
++	fputs(USAGE_OPTIONS, out);
++	fputs(_(" -a, --algorithm lzo|lz4   compression algorithm to use\n"), out);
++	fputs(_(" -b, --bytes               print sizes in bytes rather than in human readable format\n"), out);
++	fputs(_(" -f, --find                find a free device\n"), out);
++	fputs(_(" -n, --noheadings          don't print headings\n"), out);
++	fputs(_(" -o, --output <list>       columns to use for status output\n"), out);
++	fputs(_("     --raw                 use raw status output format\n"), out);
++	fputs(_(" -r, --reset               reset all specified devices\n"), out);
++	fputs(_(" -s, --size <size>         device size\n"), out);
++	fputs(_(" -t, --streams <number>    number of compression streams\n"), out);
++
++	fputs(USAGE_SEPARATOR, out);
++	fputs(USAGE_HELP, out);
++	fputs(USAGE_VERSION, out);
++
++	fputs(_("\nAvailable columns (for --output):\n"), out);
++	for (i = 0; i < ARRAY_SIZE(infos); i++)
++		fprintf(out, " %11s  %s\n", infos[i].name, _(infos[i].help));
++
++	fprintf(out, USAGE_MAN_TAIL("zramctl(8)"));
++	exit(out == stderr ? 1 : EXIT_SUCCESS);
++}
++
++/* actions */
++enum {
++	A_NONE = 0,
++	A_STATUS,
++	A_CREATE,
++	A_FINDONLY,
++	A_RESET
++};
++
++int main(int argc, char **argv)
++{
++	uintmax_t size = 0, nstreams = 0;
++	char *algorithm = NULL;
++	int rc = 0, c, find = 0, act = A_NONE;
++	struct zram *zram = NULL;
++
++	enum { OPT_RAW = CHAR_MAX + 1 };
++
++	static const struct option longopts[] = {
++		{ "algorithm", required_argument, NULL, 'a' },
++		{ "bytes",     no_argument, NULL, 'b' },
++		{ "find",      no_argument, NULL, 'f' },
++		{ "help",      no_argument, NULL, 'h' },
++		{ "output",    required_argument, NULL, 'o' },
++		{ "noheadings",no_argument, NULL, 'n' },
++		{ "reset",     no_argument, NULL, 'r' },
++		{ "raw",       no_argument, NULL, OPT_RAW },
++		{ "size",      required_argument, NULL, 's' },
++		{ "streams",   required_argument, NULL, 't' },
++		{ "version",   no_argument, NULL, 'V' },
++		{ NULL, 0, NULL, 0 }
++	};
++
++	static const ul_excl_t excl[] = {
++		{ 'f', 'o', 'r' },
++		{ 'o', 'r', 's' },
++		{ 0 }
++	};
++	int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
++
++	setlocale(LC_ALL, "");
++	bindtextdomain(PACKAGE, LOCALEDIR);
++	textdomain(PACKAGE);
++	atexit(close_stdout);
++
++	while ((c = getopt_long(argc, argv, "a:bfho:nrs:t:V", longopts, NULL)) != -1) {
++
++		err_exclusive_options(c, longopts, excl, excl_st);
++
++		switch (c) {
++		case 'a':
++			if (strcmp(optarg,"lzo") && strcmp(optarg,"lz4"))
++				errx(EXIT_FAILURE, _("unsupported algorithm: %s"),
++					     optarg);
++			algorithm = optarg;
++			break;
++		case 'b':
++			inbytes = 1;
++			break;
++		case 'f':
++			find = 1;
++			break;
++		case 'o':
++			ncolumns = string_to_idarray(optarg,
++						     columns, ARRAY_SIZE(columns),
++						     column_name_to_id);
++			if (ncolumns < 0)
++				return EXIT_FAILURE;
++			break;
++		case 's':
++			size = strtosize_or_err(optarg, _("failed to parse size"));
++			act = A_CREATE;
++			break;
++		case 't':
++			nstreams = strtou64_or_err(optarg, _("failed to parse streams"));
++			break;
++		case 'r':
++			act = A_RESET;
++			break;
++		case OPT_RAW:
++			raw = 1;
++			break;
++		case 'n':
++			no_headings = 1;
++			break;
++		case 'V':
++			printf(UTIL_LINUX_VERSION);
++			return EXIT_SUCCESS;
++		case 'h':
++			usage(stdout);
++		default:
++			usage(stderr);
++		}
++	}
++
++	if (find && optind < argc)
++		errx(EXIT_FAILURE, _("option --find is mutually exclusive "
++				     "with <device>"));
++	if (act == A_NONE)
++		act = find ? A_FINDONLY : A_STATUS;
++
++	if (act != A_RESET && optind + 1 < argc)
++		errx(EXIT_FAILURE, _("only one <device> at a time is allowed"));
++
++	if ((act == A_STATUS || act == A_FINDONLY) && (algorithm || nstreams))
++		errx(EXIT_FAILURE, _("options --algorithm and --streams "
++				     "must be combined with --size"));
++
++	switch (act) {
++	case A_STATUS:
++		if (!ncolumns) {		/* default columns */
++			columns[ncolumns++] = COL_NAME;
++			columns[ncolumns++] = COL_ALGORITHM;
++			columns[ncolumns++] = COL_DISKSIZE;
++			columns[ncolumns++] = COL_ORIG_SIZE;
++			columns[ncolumns++] = COL_COMP_SIZE;
++			columns[ncolumns++] = COL_MEMTOTAL;
++			columns[ncolumns++] = COL_STREAMS;
++			columns[ncolumns++] = COL_MOUNTPOINT;
++		}
++		if (optind < argc) {
++			zram = new_zram(argv[optind++]);
++			if (!zram_exist(zram))
++				err(EXIT_FAILURE, "%s", zram->devname);
++		}
++		status(zram);
++		free_zram(zram);
++		break;
++	case A_RESET:
++		if (optind == argc)
++			errx(EXIT_FAILURE, _("no device specified"));
++		while (optind < argc) {
++			zram = new_zram(argv[optind]);
++			if (!zram_exist(zram)
++			    || zram_set_u64parm(zram, "reset", 1)) {
++				warn(_("%s: failed to reset"), zram->devname);
++				rc = 1;
++			}
++			zram_control_remove(zram);
++			free_zram(zram);
++			optind++;
++		}
++		break;
++	case A_FINDONLY:
++		zram = find_free_zram();
++		if (!zram)
++			errx(EXIT_FAILURE, _("no free zram device found"));
++		printf("%s\n", zram->devname);
++		free_zram(zram);
++		break;
++	case A_CREATE:
++		if (find) {
++			zram = find_free_zram();
++			if (!zram)
++				errx(EXIT_FAILURE, _("no free zram device found"));
++		} else if (optind == argc)
++			errx(EXIT_FAILURE, _("no device specified"));
++		else {
++			zram = new_zram(argv[optind]);
++			if (!zram_exist(zram))
++				err(EXIT_FAILURE, "%s", zram->devname);
++		}
++
++		if (zram_set_u64parm(zram, "reset", 1))
++			err(EXIT_FAILURE, _("%s: failed to reset"), zram->devname);
++
++		if (nstreams &&
++		    zram_set_u64parm(zram, "max_comp_streams", nstreams))
++			err(EXIT_FAILURE, _("%s: failed to set number of streams"), zram->devname);
++
++		if (algorithm &&
++		    zram_set_strparm(zram, "comp_algorithm", algorithm))
++			err(EXIT_FAILURE, _("%s: failed to set algorithm"), zram->devname);
++
++		if (zram_set_u64parm(zram, "disksize", size))
++			err(EXIT_FAILURE, _("%s: failed to set disksize (%ju bytes)"),
++				zram->devname, size);
++		if (find)
++			printf("%s\n", zram->devname);
++		free_zram(zram);
++		break;
++	}
++
++	return rc ? EXIT_FAILURE : EXIT_SUCCESS;
++}
+-- 
+2.9.3
+
diff --git a/SOURCES/0107-libblkid-zfs-let-s-keep-compiler-happy.patch b/SOURCES/0107-libblkid-zfs-let-s-keep-compiler-happy.patch
new file mode 100644
index 0000000..ca625de
--- /dev/null
+++ b/SOURCES/0107-libblkid-zfs-let-s-keep-compiler-happy.patch
@@ -0,0 +1,28 @@
+From eda050c1fc9f65fc138c9fabf35ef7865c5b10a7 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Fri, 30 May 2014 11:27:41 +0200
+Subject: [PATCH 107/116] libblkid: (zfs) let's keep compiler happy
+
+Upstream: http://github.com/karelzak/util-linux/commit/59cbbd71cdfb6a6fc6901e287b300aa8d45d6606
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1392661
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libblkid/src/superblocks/zfs.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/libblkid/src/superblocks/zfs.c b/libblkid/src/superblocks/zfs.c
+index 56ee472..86da59d 100644
+--- a/libblkid/src/superblocks/zfs.c
++++ b/libblkid/src/superblocks/zfs.c
+@@ -171,7 +171,7 @@ static int probe_zfs(blkid_probe pr,
+ 	uint64_t swab_magic = swab64(UBERBLOCK_MAGIC);
+ 	struct zfs_uberblock *ub;
+ 	int swab_endian;
+-	loff_t offset, ub_offset;
++	loff_t offset, ub_offset = 0;
+ 	int tried;
+ 	int found;
+ 
+-- 
+2.9.3
+
diff --git a/SOURCES/0108-blkid-make-zfs-detection-more-robust.patch b/SOURCES/0108-blkid-make-zfs-detection-more-robust.patch
new file mode 100644
index 0000000..7d929bd
--- /dev/null
+++ b/SOURCES/0108-blkid-make-zfs-detection-more-robust.patch
@@ -0,0 +1,112 @@
+From a0e00751052b06508f6cfe4a434ebf2e1a04bf07 Mon Sep 17 00:00:00 2001
+From: Michal Humpula <michal.humpula@hudrydum.cz>
+Date: Wed, 25 Feb 2015 20:25:05 +0100
+Subject: [PATCH 108/116] blkid: make zfs detection more robust
+
+Try to use all the possible uberblock locations.
+
+Upstream: https://github.com/karelzak/util-linux/commit/5dd705ba65dc80cf8630b3b1b4f3a1ba153e7eec
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1392661
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libblkid/src/superblocks/zfs.c | 42 +++++++++++++++++++++++++++---------------
+ 1 file changed, 27 insertions(+), 15 deletions(-)
+
+diff --git a/libblkid/src/superblocks/zfs.c b/libblkid/src/superblocks/zfs.c
+index 86da59d..4a64a03 100644
+--- a/libblkid/src/superblocks/zfs.c
++++ b/libblkid/src/superblocks/zfs.c
+@@ -19,6 +19,7 @@
+ #define VDEV_LABEL_UBERBLOCK	(128 * 1024ULL)
+ #define VDEV_LABEL_NVPAIR	( 16 * 1024ULL)
+ #define VDEV_LABEL_SIZE		(256 * 1024ULL)
++#define UBERBLOCK_SIZE		1024ULL
+ 
+ /* #include <sys/uberblock_impl.h> */
+ #define UBERBLOCK_MAGIC         0x00bab10c              /* oo-ba-bloc!  */
+@@ -31,7 +32,7 @@ struct zfs_uberblock {
+ 	char		ub_rootbp;	/* MOS objset_phys_t		*/
+ } __attribute__((packed));
+ 
+-#define ZFS_TRIES	64
++#define ZFS_TRIES	512
+ #define ZFS_WANT	 4
+ 
+ #define DATA_TYPE_UINT64 8
+@@ -162,11 +163,10 @@ static void zfs_extract_guid_name(blkid_probe pr, loff_t offset)
+ #define zdebug(fmt, ...)	do {} while(0)
+ /*#define zdebug(fmt, a...)	fprintf(stderr, fmt, ##a)*/
+ 
+-/* ZFS has 128x1kB host-endian root blocks, stored in 2 areas at the start
+- * of the disk, and 2 areas at the end of the disk.  Check only some of them...
+- * #4 (@ 132kB) is the first one written on a new filesystem. */
+-static int probe_zfs(blkid_probe pr,
+-		const struct blkid_idmag *mag __attribute__((__unused__)))
++/* ZFS has 128x1kB host-endian root blocks, stored in 2 areas (labels)
++ * at the start of the disk, and 2 areas at the end of the disk.
++ */
++static int probe_zfs(blkid_probe pr, const struct blkid_idmag *mag)
+ {
+ 	uint64_t swab_magic = swab64(UBERBLOCK_MAGIC);
+ 	struct zfs_uberblock *ub;
+@@ -174,15 +174,29 @@ static int probe_zfs(blkid_probe pr,
+ 	loff_t offset, ub_offset = 0;
+ 	int tried;
+ 	int found;
++	loff_t blk_align = (pr->size % (256 * 1024ULL));
+ 
+ 	zdebug("probe_zfs\n");
+-	/* Look for at least 4 uberblocks to ensure a positive match */
++	/* Look for at least 4 uberblocks to ensure a positive match.
++	   Begin with Label 0 (L0) at the start of the block device. */
+ 	for (tried = found = 0, offset = VDEV_LABEL_UBERBLOCK;
+-	     tried < ZFS_TRIES && found < ZFS_WANT;
+-	     tried++, offset += 4096) {
+-		/* also try the second uberblock copy */
+-		if (tried == (ZFS_TRIES / 2))
++	     found < ZFS_WANT && tried < ZFS_TRIES;
++	     tried++, offset += UBERBLOCK_SIZE)
++	{
++		/* Leave L0 to try other labels */
++		switch(tried) {
++		case 128: // jump to L1, just after L0
+ 			offset = VDEV_LABEL_SIZE + VDEV_LABEL_UBERBLOCK;
++			break;
++		case 256: // jump to L2 near the far end of the block device
++			offset = pr->size - 2 * VDEV_LABEL_SIZE + VDEV_LABEL_UBERBLOCK - blk_align;
++			zdebug("probe_zfs: l2 offset %llu\n", offset >> 10);
++			break;
++		case 384: // jump to L3 at the furthest end of the block device
++			offset = pr->size - VDEV_LABEL_SIZE + VDEV_LABEL_UBERBLOCK - blk_align;
++			zdebug("probe_zfs: l3 offset %llu\n", offset >> 10);
++			break;
++		}
+ 
+ 		ub = (struct zfs_uberblock *)
+ 			blkid_probe_get_buffer(pr, offset,
+@@ -193,15 +207,14 @@ static int probe_zfs(blkid_probe pr,
+ 		if (ub->ub_magic == UBERBLOCK_MAGIC) {
+ 			ub_offset = offset;
+ 			found++;
++			zdebug("probe_zfs: found little-endian uberblock at %llu\n", offset >> 10);
+ 		}
+ 
+ 		if ((swab_endian = (ub->ub_magic == swab_magic))) {
+ 			ub_offset = offset;
+ 			found++;
++			zdebug("probe_zfs: found big-endian uberblock at %llu\n", offset >> 10);
+ 		}
+-
+-		zdebug("probe_zfs: found %s-endian uberblock at %llu\n",
+-		       swab_endian ? "big" : "little", offset >> 10);
+ 	}
+ 
+ 	if (found < 4)
+@@ -230,4 +243,3 @@ const struct blkid_idinfo zfs_idinfo =
+ 	.minsz		= 64 * 1024 * 1024,
+ 	.magics		= BLKID_NONE_MAGIC
+ };
+-
+-- 
+2.9.3
+
diff --git a/SOURCES/0109-zfs-make-less-syscalls.patch b/SOURCES/0109-zfs-make-less-syscalls.patch
new file mode 100644
index 0000000..b43620d
--- /dev/null
+++ b/SOURCES/0109-zfs-make-less-syscalls.patch
@@ -0,0 +1,154 @@
+From 8646f60d1b421b48b43405fa286548a0bf3f5da4 Mon Sep 17 00:00:00 2001
+From: Michal Humpula <michal.humpula@hudrydum.cz>
+Date: Sat, 28 Feb 2015 21:19:42 +0100
+Subject: [PATCH 109/116] zfs: make less syscalls
+
+Upstream: https://github.com/karelzak/util-linux/commit/e44a4c7ac9522c03b76d8b62ce88b443771fdb0b
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1392661
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libblkid/src/superblocks/zfs.c | 95 ++++++++++++++++++++++++++----------------
+ 1 file changed, 58 insertions(+), 37 deletions(-)
+
+diff --git a/libblkid/src/superblocks/zfs.c b/libblkid/src/superblocks/zfs.c
+index 4a64a03..9b5601e 100644
+--- a/libblkid/src/superblocks/zfs.c
++++ b/libblkid/src/superblocks/zfs.c
+@@ -20,6 +20,7 @@
+ #define VDEV_LABEL_NVPAIR	( 16 * 1024ULL)
+ #define VDEV_LABEL_SIZE		(256 * 1024ULL)
+ #define UBERBLOCK_SIZE		1024ULL
++#define UBERBLOCKS_COUNT   128
+ 
+ /* #include <sys/uberblock_impl.h> */
+ #define UBERBLOCK_MAGIC         0x00bab10c              /* oo-ba-bloc!  */
+@@ -32,7 +33,6 @@ struct zfs_uberblock {
+ 	char		ub_rootbp;	/* MOS objset_phys_t		*/
+ } __attribute__((packed));
+ 
+-#define ZFS_TRIES	512
+ #define ZFS_WANT	 4
+ 
+ #define DATA_TYPE_UINT64 8
+@@ -163,61 +163,82 @@ static void zfs_extract_guid_name(blkid_probe pr, loff_t offset)
+ #define zdebug(fmt, ...)	do {} while(0)
+ /*#define zdebug(fmt, a...)	fprintf(stderr, fmt, ##a)*/
+ 
+-/* ZFS has 128x1kB host-endian root blocks, stored in 2 areas (labels)
+- * at the start of the disk, and 2 areas at the end of the disk.
+- */
++static int find_uberblocks(const void *label, loff_t *ub_offset, int *swap_endian)
++{
++	uint64_t swab_magic = swab64(UBERBLOCK_MAGIC);
++	struct zfs_uberblock *ub;
++	int i, found = 0;
++	loff_t offset = VDEV_LABEL_UBERBLOCK;
++
++	for (i = 0; i < UBERBLOCKS_COUNT; i++, offset += UBERBLOCK_SIZE) {
++		ub = (struct zfs_uberblock *)(label + offset);
++
++		if (ub->ub_magic == UBERBLOCK_MAGIC) {
++			*ub_offset = offset;
++			*swap_endian = 0;
++			found++;
++			zdebug("probe_zfs: found little-endian uberblock at %llu\n", offset >> 10);
++		}
++
++		if (ub->ub_magic == swab_magic) {
++			*ub_offset = offset;
++			*swap_endian = 1;
++			found++;
++			zdebug("probe_zfs: found big-endian uberblock at %llu\n", offset >> 10);
++		}
++  }
++
++  return found;
++}
++
++/* ZFS has 128x1kB host-endian root blocks, stored in 2 areas at the start
++ * of the disk, and 2 areas at the end of the disk.  Check only some of them...
++ * #4 (@ 132kB) is the first one written on a new filesystem. */
+ static int probe_zfs(blkid_probe pr, const struct blkid_idmag *mag)
+ {
+ 	uint64_t swab_magic = swab64(UBERBLOCK_MAGIC);
++	int swab_endian = 0;
+ 	struct zfs_uberblock *ub;
+-	int swab_endian;
+ 	loff_t offset, ub_offset = 0;
+-	int tried;
+-	int found;
++	int label_no, found = 0, found_in_label;
++	void *label;
+ 	loff_t blk_align = (pr->size % (256 * 1024ULL));
+ 
+ 	zdebug("probe_zfs\n");
+-	/* Look for at least 4 uberblocks to ensure a positive match.
+-	   Begin with Label 0 (L0) at the start of the block device. */
+-	for (tried = found = 0, offset = VDEV_LABEL_UBERBLOCK;
+-	     found < ZFS_WANT && tried < ZFS_TRIES;
+-	     tried++, offset += UBERBLOCK_SIZE)
+-	{
+-		/* Leave L0 to try other labels */
+-		switch(tried) {
+-		case 128: // jump to L1, just after L0
+-			offset = VDEV_LABEL_SIZE + VDEV_LABEL_UBERBLOCK;
++	/* Look for at least 4 uberblocks to ensure a positive match */
++	for (label_no = 0; label_no < 4; label_no++) {
++		switch(label_no) {
++		case 0: // jump to L0
++			offset = 0;
+ 			break;
+-		case 256: // jump to L2 near the far end of the block device
+-			offset = pr->size - 2 * VDEV_LABEL_SIZE + VDEV_LABEL_UBERBLOCK - blk_align;
+-			zdebug("probe_zfs: l2 offset %llu\n", offset >> 10);
++		case 1: // jump to L1
++			offset = VDEV_LABEL_SIZE;
+ 			break;
+-		case 384: // jump to L3 at the furthest end of the block device
+-			offset = pr->size - VDEV_LABEL_SIZE + VDEV_LABEL_UBERBLOCK - blk_align;
+-			zdebug("probe_zfs: l3 offset %llu\n", offset >> 10);
++		case 2: // jump to L2
++			offset = pr->size - 2 * VDEV_LABEL_SIZE - blk_align;
++			break;
++		case 3: // jump to L3
++			offset = pr->size - VDEV_LABEL_SIZE - blk_align;
+ 			break;
+ 		}
+ 
+-		ub = (struct zfs_uberblock *)
+-			blkid_probe_get_buffer(pr, offset,
+-					       sizeof(struct zfs_uberblock));
+-		if (ub == NULL)
++		label = blkid_probe_get_buffer(pr, offset, VDEV_LABEL_SIZE);
++		if (label == NULL)
+ 			return errno ? -errno : 1;
+ 
+-		if (ub->ub_magic == UBERBLOCK_MAGIC) {
+-			ub_offset = offset;
+-			found++;
+-			zdebug("probe_zfs: found little-endian uberblock at %llu\n", offset >> 10);
+-		}
++		found_in_label = find_uberblocks(label, &ub_offset, &swab_endian);
+ 
+-		if ((swab_endian = (ub->ub_magic == swab_magic))) {
+-			ub_offset = offset;
+-			found++;
+-			zdebug("probe_zfs: found big-endian uberblock at %llu\n", offset >> 10);
++		if (found_in_label > 0) {
++			found+= found_in_label;
++			ub = (struct zfs_uberblock *)(label + ub_offset);
++			ub_offset += offset;
++
++			if (found >= ZFS_WANT)
++				break;
+ 		}
+ 	}
+ 
+-	if (found < 4)
++	if (found < ZFS_WANT)
+ 		return 1;
+ 
+ 	/* If we found the 4th uberblock, then we will have exited from the
+-- 
+2.9.3
+
diff --git a/SOURCES/0110-libblkid-zfs-keep-bufferes-read-only.patch b/SOURCES/0110-libblkid-zfs-keep-bufferes-read-only.patch
new file mode 100644
index 0000000..ad08711
--- /dev/null
+++ b/SOURCES/0110-libblkid-zfs-keep-bufferes-read-only.patch
@@ -0,0 +1,48 @@
+From eeb629102da9a9a916d201bbd5f13ee7ad23844d Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 22 Sep 2015 15:27:39 +0200
+Subject: [PATCH 110/116] libblkid: (zfs) keep bufferes read-only
+
+Upstream: https://github.com/karelzak/util-linux/commit/9325a8be9e55cc01d9f580e14dd2193829245183
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1392661
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libblkid/src/superblocks/zfs.c | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+diff --git a/libblkid/src/superblocks/zfs.c b/libblkid/src/superblocks/zfs.c
+index 9b5601e..8e88b39 100644
+--- a/libblkid/src/superblocks/zfs.c
++++ b/libblkid/src/superblocks/zfs.c
+@@ -70,9 +70,10 @@ struct nvlist {
+ 
+ static void zfs_extract_guid_name(blkid_probe pr, loff_t offset)
+ {
++	unsigned char *p, buff[4096];
+ 	struct nvlist *nvl;
+ 	struct nvpair *nvp;
+-	size_t left = 4096;
++	size_t left = sizeof(buff);
+ 	int found = 0;
+ 
+ 	offset = (offset & ~(VDEV_LABEL_SIZE - 1)) + VDEV_LABEL_NVPAIR;
+@@ -81,10 +82,14 @@ static void zfs_extract_guid_name(blkid_probe pr, loff_t offset)
+ 	 * the first 4k (left) of the nvlist.  This is true for all pools
+ 	 * I've seen, and simplifies this code somewhat, because we don't
+ 	 * have to handle an nvpair crossing a buffer boundary. */
+-	nvl = (struct nvlist *)blkid_probe_get_buffer(pr, offset, left);
+-	if (nvl == NULL)
++	p = blkid_probe_get_buffer(pr, offset, left);
++	if (!p)
+ 		return;
+ 
++	/* libblkid buffers are strictly readonly, but the code below modifies nvpair etc. */
++	memcpy(buff, p, sizeof(buff));
++	nvl = (struct nvlist *) buff;
++
+ 	nvdebug("zfs_extract: nvlist offset %llu\n", offset);
+ 
+ 	nvp = &nvl->nvl_nvpair;
+-- 
+2.9.3
+
diff --git a/SOURCES/0111-libblkid-don-t-mark-zfs-as-RAID.patch b/SOURCES/0111-libblkid-don-t-mark-zfs-as-RAID.patch
new file mode 100644
index 0000000..8436e87
--- /dev/null
+++ b/SOURCES/0111-libblkid-don-t-mark-zfs-as-RAID.patch
@@ -0,0 +1,28 @@
+From 400facb19f228e3507de2137e2f9165b3365b7df Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Wed, 18 Nov 2015 11:55:35 +0100
+Subject: [PATCH 111/116] libblkid: don't mark zfs as RAID
+
+Upstream: https://github.com/karelzak/util-linux/commit/710dd492394be6cd2f3dd65c057ae7827ee6e89d
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1392661
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libblkid/src/superblocks/zfs.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/libblkid/src/superblocks/zfs.c b/libblkid/src/superblocks/zfs.c
+index 8e88b39..5074495 100644
+--- a/libblkid/src/superblocks/zfs.c
++++ b/libblkid/src/superblocks/zfs.c
+@@ -264,7 +264,7 @@ static int probe_zfs(blkid_probe pr, const struct blkid_idmag *mag)
+ const struct blkid_idinfo zfs_idinfo =
+ {
+ 	.name		= "zfs_member",
+-	.usage		= BLKID_USAGE_RAID,
++	.usage		= BLKID_USAGE_FILESYSTEM,
+ 	.probefunc	= probe_zfs,
+ 	.minsz		= 64 * 1024 * 1024,
+ 	.magics		= BLKID_NONE_MAGIC
+-- 
+2.9.3
+
diff --git a/SOURCES/0112-tests-update-ZFS-test.patch b/SOURCES/0112-tests-update-ZFS-test.patch
new file mode 100644
index 0000000..9368222
--- /dev/null
+++ b/SOURCES/0112-tests-update-ZFS-test.patch
@@ -0,0 +1,28 @@
+From 0f0a36e64ed47721e8b8d41b81ae3b1817d19194 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Thu, 19 Nov 2015 19:08:00 +0100
+Subject: [PATCH 112/116] tests: update ZFS test
+
+Upstream: https://github.com/karelzak/util-linux/commit/0172ebba52718afe89b5d1941266825b065358cb
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1392661
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ tests/expected/blkid/low-probe-zfs | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/tests/expected/blkid/low-probe-zfs b/tests/expected/blkid/low-probe-zfs
+index 46727de..952e0e5 100644
+--- a/tests/expected/blkid/low-probe-zfs
++++ b/tests/expected/blkid/low-probe-zfs
+@@ -1,7 +1,7 @@
+ ID_FS_LABEL=tank
+ ID_FS_LABEL_ENC=tank
+ ID_FS_TYPE=zfs_member
+-ID_FS_USAGE=raid
++ID_FS_USAGE=filesystem
+ ID_FS_UUID=1782036546311300980
+ ID_FS_UUID_ENC=1782036546311300980
+ ID_FS_UUID_SUB=13179280127379850514
+-- 
+2.9.3
+
diff --git a/SOURCES/0113-libblkid-zfs-add-cast-to-fix-UB-cppcheck.patch b/SOURCES/0113-libblkid-zfs-add-cast-to-fix-UB-cppcheck.patch
new file mode 100644
index 0000000..6ac7f51
--- /dev/null
+++ b/SOURCES/0113-libblkid-zfs-add-cast-to-fix-UB-cppcheck.patch
@@ -0,0 +1,31 @@
+From a569050329d914ad5aa15978f2a4a3d969c7c8b1 Mon Sep 17 00:00:00 2001
+From: Boris Egorov <egorov@linux.com>
+Date: Tue, 19 Jan 2016 11:37:57 +0600
+Subject: [PATCH 113/116] libblkid: (zfs) add cast to fix UB [cppcheck]
+
+[libblkid/src/superblocks/zfs.c:173]: (error) Shifting 32-bit value by 56 bits is undefined behaviour
+[libblkid/src/superblocks/zfs.c:173]: (error) Shifting 32-bit value by 40 bits is undefined behaviour
+
+Upstream: https://github.com/karelzak/util-linux/commit/18b76be61c11fd5f11fcb84aa6a946d3b03d7225
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1392661
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libblkid/src/superblocks/zfs.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/libblkid/src/superblocks/zfs.c b/libblkid/src/superblocks/zfs.c
+index 5074495..ff12fa6 100644
+--- a/libblkid/src/superblocks/zfs.c
++++ b/libblkid/src/superblocks/zfs.c
+@@ -170,7 +170,7 @@ static void zfs_extract_guid_name(blkid_probe pr, loff_t offset)
+ 
+ static int find_uberblocks(const void *label, loff_t *ub_offset, int *swap_endian)
+ {
+-	uint64_t swab_magic = swab64(UBERBLOCK_MAGIC);
++	uint64_t swab_magic = swab64((uint64_t)UBERBLOCK_MAGIC);
+ 	struct zfs_uberblock *ub;
+ 	int i, found = 0;
+ 	loff_t offset = VDEV_LABEL_UBERBLOCK;
+-- 
+2.9.3
+
diff --git a/SOURCES/0114-libblkid-Avoid-OOB-access-on-illegal-ZFS-superblocks.patch b/SOURCES/0114-libblkid-Avoid-OOB-access-on-illegal-ZFS-superblocks.patch
new file mode 100644
index 0000000..9d58bd6
--- /dev/null
+++ b/SOURCES/0114-libblkid-Avoid-OOB-access-on-illegal-ZFS-superblocks.patch
@@ -0,0 +1,48 @@
+From 7e1c9da4773237e368bdc0539ef91d55ef19806c Mon Sep 17 00:00:00 2001
+From: Tobias Stoeckmann <tobias@stoeckmann.org>
+Date: Sun, 28 Aug 2016 21:15:59 +0200
+Subject: [PATCH 114/116] libblkid: Avoid OOB access on illegal ZFS superblocks
+
+64 bit systems can trigger an out of boundary access while performing
+a ZFS superblock probe.
+
+This happens due to a possible integer overflow while calculating
+the remaining available bytes. The variable is of type "int" and the
+string length is allowed to be larger than INT_MAX, which means that
+avail calculation can overflow, circumventing the "avail < 0" check and
+therefore accessing memory outside the "buff" array later on.
+
+[kzak@redhat.com (rhel7): - remove unused swab_magic]
+
+Upstream: https://github.com/karelzak/util-linux/commit/8fa57ab0b5696031da800e243def32bc5265ff6d
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1392661
+Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libblkid/src/superblocks/zfs.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/libblkid/src/superblocks/zfs.c b/libblkid/src/superblocks/zfs.c
+index ff12fa6..2c7b4b7 100644
+--- a/libblkid/src/superblocks/zfs.c
++++ b/libblkid/src/superblocks/zfs.c
+@@ -115,7 +115,7 @@ static void zfs_extract_guid_name(blkid_probe pr, loff_t offset)
+ 
+ 			nvs->nvs_type = be32_to_cpu(nvs->nvs_type);
+ 			nvs->nvs_strlen = be32_to_cpu(nvs->nvs_strlen);
+-			if (nvs->nvs_strlen > UINT_MAX - sizeof(*nvs))
++			if (nvs->nvs_strlen > INT_MAX - sizeof(*nvs))
+ 				break;
+ 			avail -= nvs->nvs_strlen + sizeof(*nvs);
+ 			nvdebug("nvstring: type %u string %*s\n", nvs->nvs_type,
+@@ -201,7 +201,6 @@ static int find_uberblocks(const void *label, loff_t *ub_offset, int *swap_endia
+  * #4 (@ 132kB) is the first one written on a new filesystem. */
+ static int probe_zfs(blkid_probe pr, const struct blkid_idmag *mag)
+ {
+-	uint64_t swab_magic = swab64(UBERBLOCK_MAGIC);
+ 	int swab_endian = 0;
+ 	struct zfs_uberblock *ub;
+ 	loff_t offset, ub_offset = 0;
+-- 
+2.9.3
+
diff --git a/SOURCES/0115-lscpu-backport-from-v2.29.patch b/SOURCES/0115-lscpu-backport-from-v2.29.patch
new file mode 100644
index 0000000..9d95342
--- /dev/null
+++ b/SOURCES/0115-lscpu-backport-from-v2.29.patch
@@ -0,0 +1,2190 @@
+From 7ffb3c628dea313496c829bcb40447545470847e Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 21 Mar 2017 14:57:37 +0100
+Subject: [PATCH 115/116] lscpu: backport from v2.29
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1360764
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1397709
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ configure.ac            |   3 +-
+ include/c.h             |  30 ++
+ include/pathnames.h     |   2 +
+ include/xalloc.h        |  10 +
+ sys-utils/Makemodule.am |   8 +-
+ sys-utils/lscpu-dmi.c   | 285 ++++++++++++++
+ sys-utils/lscpu.1       |  53 ++-
+ sys-utils/lscpu.c       | 964 ++++++++++++++++++++++++++++++++++++++++--------
+ sys-utils/lscpu.h       |  26 ++
+ 9 files changed, 1220 insertions(+), 161 deletions(-)
+ create mode 100644 sys-utils/lscpu-dmi.c
+ create mode 100644 sys-utils/lscpu.h
+
+diff --git a/configure.ac b/configure.ac
+index db7095a..78258d6 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1059,8 +1059,9 @@ AM_CONDITIONAL(BUILD_LSBLK, test "x$build_lsblk" = xyes)
+ 
+ UL_BUILD_INIT([lscpu], [check])
+ UL_REQUIRES_LINUX([lscpu])
++UL_REQUIRES_BUILD([lscpu], [libsmartcols])
+ UL_REQUIRES_HAVE([lscpu], [cpu_set_t], [cpu_set_t type])
+-AM_CONDITIONAL(BUILD_LSCPU, test "x$build_lscpu" = xyes)
++AM_CONDITIONAL([BUILD_LSCPU], [test "x$build_lscpu" = xyes])
+ 
+ 
+ UL_BUILD_INIT([lslogins], [check])
+diff --git a/include/c.h b/include/c.h
+index 3754e75..8ff61b4 100644
+--- a/include/c.h
++++ b/include/c.h
+@@ -200,6 +200,19 @@ errmsg(char doexit, int excode, char adderr, const char *fmt, ...)
+ #endif
+ #endif /* !HAVE_ERR_H */
+ 
++/* Don't use inline function to avoid '#include "nls.h"' in c.h
++ */
++#define errtryhelp(eval) __extension__ ({ \
++	fprintf(stderr, _("Try '%s --help' for more information.\n"), \
++			program_invocation_short_name); \
++	exit(eval); \
++})
++
++#define errtryh(eval) __extension__ ({ \
++	fprintf(stderr, _("Try '%s -h' for more information.\n"), \
++			program_invocation_short_name); \
++	exit(eval); \
++})
+ 
+ static inline __attribute__((const)) int is_power_of_2(unsigned long num)
+ {
+@@ -317,6 +330,23 @@ static inline int usleep(useconds_t usec)
+ #define stringify(s) #s
+ 
+ /*
++ * UL_ASAN_BLACKLIST is a macro to tell AddressSanitizer (a compile-time
++ * instrumentation shipped with Clang and GCC) to not instrument the
++ * annotated function.  Furthermore, it will prevent the compiler from
++ * inlining the function because inlining currently breaks the blacklisting
++ * mechanism of AddressSanitizer.
++ */
++#if defined(__has_feature)
++# if __has_feature(address_sanitizer)
++#  define UL_ASAN_BLACKLIST __attribute__((noinline)) __attribute__((no_sanitize_memory)) __attribute__((no_sanitize_address))
++# else
++#  define UL_ASAN_BLACKLIST	/* nothing */
++# endif
++#else
++# define UL_ASAN_BLACKLIST	/* nothing */
++#endif
++
++/*
+  * Note that sysconf(_SC_GETPW_R_SIZE_MAX) returns *initial* suggested size for
+  * pwd buffer and in some cases it is not large enough. See POSIX and
+  * getpwnam_r man page for more details.
+diff --git a/include/pathnames.h b/include/pathnames.h
+index b648afc..fa4bddb 100644
+--- a/include/pathnames.h
++++ b/include/pathnames.h
+@@ -131,6 +131,8 @@
+ # define _PATH_DEV		"/dev/"
+ #endif
+ 
++#define _PATH_DEV_MEM           "/dev/mem"
++
+ #define _PATH_DEV_LOOP		"/dev/loop"
+ #define _PATH_DEV_LOOPCTL	"/dev/loop-control"
+ #define _PATH_DEV_TTY		"/dev/tty"
+diff --git a/include/xalloc.h b/include/xalloc.h
+index 1a1799a..883e472 100644
+--- a/include/xalloc.h
++++ b/include/xalloc.h
+@@ -99,6 +99,16 @@ static inline int __attribute__ ((__format__(printf, 2, 3)))
+ }
+ 
+ 
++static inline int  __attribute__ ((__format__(printf, 2, 0)))
++xvasprintf(char **strp, const char *fmt, va_list ap)
++{
++	int ret = vasprintf(&(*strp), fmt, ap);
++	if (ret < 0)
++		err(XALLOC_EXIT_CODE, "cannot allocate string");
++	return ret;
++}
++
++
+ static inline char *xgethostname(void)
+ {
+ 	char *name;
+diff --git a/sys-utils/Makemodule.am b/sys-utils/Makemodule.am
+index 408e884..0496b84 100644
+--- a/sys-utils/Makemodule.am
++++ b/sys-utils/Makemodule.am
+@@ -274,8 +274,12 @@ endif
+ 
+ if BUILD_LSCPU
+ usrbin_exec_PROGRAMS += lscpu
+-lscpu_SOURCES = sys-utils/lscpu.c
+-lscpu_LDADD = $(LDADD) libcommon.la
++lscpu_SOURCES = \
++	sys-utils/lscpu.c \
++	sys-utils/lscpu.h \
++	sys-utils/lscpu-dmi.c
++lscpu_LDADD = $(LDADD) libcommon.la libsmartcols.la $(RTAS_LIBS)
++lscpu_CFLAGS = $(AM_CFLAGS) -I$(ul_libsmartcols_incdir)
+ dist_man_MANS += sys-utils/lscpu.1
+ endif
+ 
+diff --git a/sys-utils/lscpu-dmi.c b/sys-utils/lscpu-dmi.c
+new file mode 100644
+index 0000000..0e497d1
+--- /dev/null
++++ b/sys-utils/lscpu-dmi.c
+@@ -0,0 +1,285 @@
++/*
++ * lscpu-dmi - Module to parse SMBIOS information
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it would 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.
++ *
++ * Code originally taken from the dmidecode utility and slightly rewritten
++ * to suite the needs of lscpu
++ */
++#include <errno.h>
++#include <stdlib.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdio.h>
++
++#include "c.h"
++#include "pathnames.h"
++#include "all-io.h"
++#include "lscpu.h"
++
++#define WORD(x) (uint16_t)(*(const uint16_t *)(x))
++#define DWORD(x) (uint32_t)(*(const uint32_t *)(x))
++
++struct dmi_header
++{
++	uint8_t type;
++	uint8_t length;
++	uint16_t handle;
++	uint8_t *data;
++};
++
++static int checksum(const uint8_t *buf, size_t len)
++{
++	uint8_t sum = 0;
++	size_t a;
++
++	for (a = 0; a < len; a++)
++		sum += buf[a];
++	return (sum == 0);
++}
++
++static void *get_mem_chunk(size_t base, size_t len, const char *devmem)
++{
++	void *p = NULL;
++	int fd;
++
++	if ((fd = open(devmem, O_RDONLY)) < 0)
++		return NULL;
++
++	if (!(p = malloc(len)))
++		goto nothing;
++	if (lseek(fd, base, SEEK_SET) == -1)
++		goto nothing;
++	if (read_all(fd, p, len) == -1)
++		goto nothing;
++
++	close(fd);
++	return p;
++
++nothing:
++	free(p);
++	close(fd);
++	return NULL;
++}
++
++static void to_dmi_header(struct dmi_header *h, uint8_t *data)
++{
++	h->type = data[0];
++	h->length = data[1];
++	h->handle = WORD(data + 2);
++	h->data = data;
++}
++
++static char *dmi_string(const struct dmi_header *dm, uint8_t s)
++{
++	char *bp = (char *)dm->data;
++
++	if (s == 0)
++		return NULL;
++
++	bp += dm->length;
++	while (s > 1 && *bp)
++	{
++		bp += strlen(bp);
++		bp++;
++		s--;
++	}
++
++	if (!*bp)
++		return NULL;
++
++	return bp;
++}
++
++static int hypervisor_from_dmi_table(uint32_t base, uint16_t len,
++				uint16_t num, const char *devmem)
++{
++	uint8_t *buf;
++	uint8_t *data;
++	int i = 0;
++	char *vendor = NULL;
++	char *product = NULL;
++	char *manufacturer = NULL;
++	int rc = HYPER_NONE;
++
++	data = buf = get_mem_chunk(base, len, devmem);
++	if (!buf)
++		goto done;
++
++	 /* 4 is the length of an SMBIOS structure header */
++	while (i < num && data + 4 <= buf + len) {
++		uint8_t *next;
++		struct dmi_header h;
++
++		to_dmi_header(&h, data);
++
++		/*
++		 * If a short entry is found (less than 4 bytes), not only it
++		 * is invalid, but we cannot reliably locate the next entry.
++		 * Better stop at this point.
++		 */
++		if (h.length < 4)
++			goto done;
++
++		/* look for the next handle */
++		next = data + h.length;
++		while (next - buf + 1 < len && (next[0] != 0 || next[1] != 0))
++			next++;
++		next += 2;
++		switch (h.type) {
++			case 0:
++				vendor = dmi_string(&h, data[0x04]);
++				break;
++			case 1:
++				manufacturer = dmi_string(&h, data[0x04]);
++				product = dmi_string(&h, data[0x05]);
++				break;
++			default:
++				break;
++		}
++
++		data = next;
++		i++;
++	}
++	if (manufacturer && !strcmp(manufacturer, "innotek GmbH"))
++		rc = HYPER_INNOTEK;
++	else if (manufacturer && strstr(manufacturer, "HITACHI") &&
++					product && strstr(product, "LPAR"))
++		rc = HYPER_HITACHI;
++	else if (vendor && !strcmp(vendor, "Parallels"))
++		rc = HYPER_PARALLELS;
++done:
++	free(buf);
++	return rc;
++}
++
++#if defined(__x86_64__) || defined(__i386__)
++static int hypervisor_decode_legacy(uint8_t *buf, const char *devmem)
++{
++	if (!checksum(buf, 0x0F))
++		return HYPER_NONE;
++
++	return hypervisor_from_dmi_table(DWORD(buf + 0x08), WORD(buf + 0x06),
++			 WORD(buf + 0x0C),
++		devmem);
++}
++#endif
++
++static int hypervisor_decode_smbios(uint8_t *buf, const char *devmem)
++{
++	if (!checksum(buf, buf[0x05])
++	    || memcmp(buf + 0x10, "_DMI_", 5) != 0
++	    || !checksum(buf + 0x10, 0x0F))
++		return -1;
++
++	return hypervisor_from_dmi_table(DWORD(buf + 0x18), WORD(buf + 0x16),
++			 WORD(buf + 0x1C),
++		devmem);
++}
++
++/*
++ * Probe for EFI interface
++ */
++#define EFI_NOT_FOUND   (-1)
++#define EFI_NO_SMBIOS   (-2)
++static int address_from_efi(size_t *address)
++{
++	FILE *tab;
++	char linebuf[64];
++	int ret;
++
++	*address = 0; /* Prevent compiler warning */
++
++	/*
++	 * Linux up to 2.6.6: /proc/efi/systab
++	 * Linux 2.6.7 and up: /sys/firmware/efi/systab
++	 */
++	if (!(tab = fopen("/sys/firmware/efi/systab", "r")) &&
++	    !(tab = fopen("/proc/efi/systab", "r")))
++		return EFI_NOT_FOUND;		/* No EFI interface */
++
++	ret = EFI_NO_SMBIOS;
++	while ((fgets(linebuf, sizeof(linebuf) - 1, tab)) != NULL) {
++		char *addrp = strchr(linebuf, '=');
++		if (!addrp)
++			continue;
++		*(addrp++) = '\0';
++		if (strcmp(linebuf, "SMBIOS") == 0) {
++			*address = strtoul(addrp, NULL, 0);
++			ret = 0;
++			break;
++		}
++	}
++
++	fclose(tab);
++	return ret;
++}
++
++int read_hypervisor_dmi(void)
++{
++	int rc = HYPER_NONE;
++	uint8_t *buf = NULL;
++	size_t fp = 0;
++
++	if (sizeof(uint8_t) != 1
++	    || sizeof(uint16_t) != 2
++	    || sizeof(uint32_t) != 4
++	    || '\0' != 0)
++		return rc;
++
++	/* First try EFI (ia64, Intel-based Mac) */
++	switch (address_from_efi(&fp)) {
++		case EFI_NOT_FOUND:
++			goto memory_scan;
++		case EFI_NO_SMBIOS:
++			goto done;
++	}
++
++	buf = get_mem_chunk(fp, 0x20, _PATH_DEV_MEM);
++	if (!buf)
++		goto done;
++
++	rc = hypervisor_decode_smbios(buf, _PATH_DEV_MEM);
++	if (rc)
++		goto done;
++	free(buf);
++	buf = NULL;
++memory_scan:
++#if defined(__x86_64__) || defined(__i386__)
++	/* Fallback to memory scan (x86, x86_64) */
++	buf = get_mem_chunk(0xF0000, 0x10000, _PATH_DEV_MEM);
++	if (!buf)
++		goto done;
++
++	for (fp = 0; fp <= 0xFFF0; fp += 16) {
++		if (memcmp(buf + fp, "_SM_", 4) == 0 && fp <= 0xFFE0) {
++			rc = hypervisor_decode_smbios(buf + fp, _PATH_DEV_MEM);
++			if (rc == -1)
++				fp += 16;
++
++		} else if (memcmp(buf + fp, "_DMI_", 5) == 0)
++			rc = hypervisor_decode_legacy(buf + fp, _PATH_DEV_MEM);
++
++		if (rc >= 0)
++			break;
++	}
++#endif
++done:
++	free(buf);
++	return rc;
++}
+diff --git a/sys-utils/lscpu.1 b/sys-utils/lscpu.1
+index f747a35..8636e52 100644
+--- a/sys-utils/lscpu.1
++++ b/sys-utils/lscpu.1
+@@ -1,34 +1,42 @@
+-.\" Process this file with
+-.\" groff -man -Tascii lscpu.1
+-.\"
+-.TH LSCPU 1 "January 2013" "util-linux" "User Commands"
++.TH LSCPU 1 "November 2015" "util-linux" "User Commands"
+ .SH NAME
+ lscpu \- display information about the CPU architecture
+ .SH SYNOPSIS
+ .B lscpu
+-.RB [ \-a | \-b | \-c "] [" \-x "] [" \-s " \fIdirectory\fP] [" \-e [=\fIlist\fP]| \-p [=\fIlist\fP]]
++.RB [ \-a | \-b | \-c | \-J "] [" \-x "] [" \-y "] [" \-s " \fIdirectory\fP] [" \-e [=\fIlist\fP]| \-p [=\fIlist\fP]]
+ .br
+ .B lscpu
+ .BR \-h | \-V
+ .SH DESCRIPTION
+ .B lscpu
+-gathers CPU architecture information from sysfs and /proc/cpuinfo.  The
++gathers CPU architecture information from sysfs, /proc/cpuinfo and any
++applicable architecture-specific libraries (e.g.\& librtas on Powerpc).  The
+ command output can be optimized for parsing or for easy readability by humans.
+ The information includes, for example, the number of CPUs, threads, cores,
+ sockets, and Non-Uniform Memory Access (NUMA) nodes.  There is also information
+ about the CPU caches and cache sharing, family, model, bogoMIPS, byte order,
+ and stepping.
+-
++.sp
++In virtualized environments, the CPU architecture information displayed
++reflects the configuration of the guest operating system which is
++typically different from the physical (host) system.  On architectures that
++support retrieving physical topology information,
++.B lscpu
++also displays the number of physical sockets, chips, cores in the host system.
++.sp
+ Options that result in an output table have a \fIlist\fP argument.  Use this
+ argument to customize the command output.  Specify a comma-separated list of
+ column labels to limit the output table to only the specified columns, arranged
+ in the specified order.  See \fBCOLUMNS\fP for a list of valid column labels.  The
+ column labels are not case sensitive.
+-
++.sp
+ Not all columns are supported on all architectures.  If an unsupported column is
+ specified, \fBlscpu\fP prints the column but does not provide any data for it.
+ 
+ .SS COLUMNS
++Note that topology elements (core, socket, etc.) use a sequential unique ID
++starting from zero, but CPU logical numbers follow the kernel where there is
++no guarantee of sequential numbering.
+ .TP
+ .B CPU
+ The logical CPU number of a CPU as used by the Linux kernel.
+@@ -42,8 +50,11 @@ The logical socket number.  A socket can contain several cores.
+ .B BOOK
+ The logical book number.  A book can contain several sockets.
+ .TP
++.B DRAWER
++The logical drawer number.  A drawer can contain several books.
++.TP
+ .B NODE
+-The logical NUMA node number.  A node may contain several books.
++The logical NUMA node number.  A node can contain several drawers.
+ .TP
+ .B CACHE
+ Information about how caches are shared between CPUs.
+@@ -77,6 +88,14 @@ For vertical polarization, the column also shows the degree of concentration,
+ high, medium, or low.  This column contains data only if your hardware system
+ and hypervisor support CPU polarization.
+ .RE
++.TP
++.B MAXMHZ
++Maximum megahertz value for the CPU. Useful when \fBlscpu\fP is used as hardware
++inventory information gathering tool.  Notice that the megahertz value is
++dynamic, and driven by CPU governor depending on current resource need.
++.TP
++.B MINMHZ
++Minimum megahertz value for the CPU.
+ .SH OPTIONS
+ .TP
+ .BR \-a , " \-\-all"
+@@ -92,7 +111,7 @@ Limit the output to offline CPUs.
+ This option may only be specified together with option \fB-e\fR or \fB-p\fR.
+ .TP
+ .BR \-e , " \-\-extended" [=\fIlist\fP]
+-Display the CPU information in human readable format.
++Display the CPU information in human-readable format.
+ 
+ If the \fIlist\fP argument is omitted, all columns for which data is available
+ are included in the command output.
+@@ -102,7 +121,7 @@ When specifying the \fIlist\fP argument, the string of option, equal sign (=), a
+ Examples: '\fB-e=cpu,node\fP' or '\fB--extended=cpu,node\fP'.
+ .TP
+ .BR \-h , " \-\-help"
+-Display help information and exit.
++Display help text and exit.
+ .TP
+ .BR \-p , " \-\-parse" [=\fIlist\fP]
+ Optimize the command output for easy parsing.
+@@ -126,6 +145,16 @@ of the Linux instance to be inspected.
+ Use hexadecimal masks for CPU sets (for example 0x3).  The default is to print
+ the sets in list format (for example 0,1).
+ .TP
++.BR \-y , " \-\-physical"
++Display physical IDs for all columns with topology elements (core, socket, etc.).
++Other than logical IDs, which are assigned by \fBlscpu\fP, physical IDs are
++platform-specific values that are provided by the kernel. Physical IDs are not
++necessarily unique and they might not be arranged sequentially.
++If the kernel could not retrieve a physical ID for an element \fBlscpu\fP prints
++the dash (-) character.
++
++The CPU logical numbers are not affected by this option.
++.TP
+ .BR \-V , " \-\-version"
+ Display version information and exit.
+ .SH BUGS
+@@ -145,4 +174,4 @@ Heiko Carstens <heiko.carstens@de.ibm.com>
+ .BR chcpu (8)
+ .SH AVAILABILITY
+ The lscpu command is part of the util-linux package and is available from
+-ftp://ftp.kernel.org/pub/linux/utils/util-linux/.
++https://www.kernel.org/pub/linux/utils/util-linux/.
+diff --git a/sys-utils/lscpu.c b/sys-utils/lscpu.c
+index 7a00636..683fd66 100644
+--- a/sys-utils/lscpu.c
++++ b/sys-utils/lscpu.c
+@@ -19,6 +19,7 @@
+  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+  */
+ 
++#include <assert.h>
+ #include <ctype.h>
+ #include <dirent.h>
+ #include <errno.h>
+@@ -33,21 +34,46 @@
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ 
++#if (defined(__x86_64__) || defined(__i386__))
++# if !defined( __SANITIZE_ADDRESS__)
++#  define INCLUDE_VMWARE_BDOOR
++# else
++#  warning VMWARE detection disabled by __SANITIZE_ADDRESS__
++# endif
++#endif
++
++#ifdef INCLUDE_VMWARE_BDOOR
++# include <stdint.h>
++# include <signal.h>
++# include <strings.h>
++# include <setjmp.h>
++# ifdef HAVE_SYS_IO_H
++#  include <sys/io.h>
++# endif
++#endif
++
++#if defined(HAVE_LIBRTAS)
++#include <librtas.h>
++#endif
++
++#include <libsmartcols.h>
++
+ #include "cpuset.h"
+ #include "nls.h"
+ #include "xalloc.h"
+ #include "c.h"
+ #include "strutils.h"
+ #include "bitops.h"
+-#include "tt.h"
+ #include "path.h"
+ #include "closestream.h"
+ #include "optutils.h"
++#include "lscpu.h"
+ 
+ #define CACHE_MAX 100
+ 
+ /* /sys paths */
+ #define _PATH_SYS_SYSTEM	"/sys/devices/system"
++#define _PATH_SYS_HYP_FEATURES "/sys/hypervisor/properties/features"
+ #define _PATH_SYS_CPU		_PATH_SYS_SYSTEM "/cpu"
+ #define _PATH_SYS_NODE		_PATH_SYS_SYSTEM "/node"
+ #define _PATH_PROC_XEN		"/proc/xen"
+@@ -55,35 +81,71 @@
+ #define _PATH_PROC_CPUINFO	"/proc/cpuinfo"
+ #define _PATH_PROC_PCIDEVS	"/proc/bus/pci/devices"
+ #define _PATH_PROC_SYSINFO	"/proc/sysinfo"
++#define _PATH_PROC_STATUS	"/proc/self/status"
++#define _PATH_PROC_VZ	"/proc/vz"
++#define _PATH_PROC_BC	"/proc/bc"
++#define _PATH_PROC_DEVICETREE	"/proc/device-tree"
++#define _PATH_DEV_MEM 		"/dev/mem"
++#define _PATH_PROC_OSRELEASE	"/proc/sys/kernel/osrelease"
++
++/* Xen Domain feature flag used for /sys/hypervisor/properties/features */
++#define XENFEAT_supervisor_mode_kernel		3
++#define XENFEAT_mmu_pt_update_preserve_ad	5
++#define XENFEAT_hvm_callback_vector			8
++
++#define XEN_FEATURES_PV_MASK	(1U << XENFEAT_mmu_pt_update_preserve_ad)
++#define XEN_FEATURES_PVH_MASK	( (1U << XENFEAT_supervisor_mode_kernel) \
++								| (1U << XENFEAT_hvm_callback_vector) )
+ 
+ /* virtualization types */
+ enum {
+ 	VIRT_NONE	= 0,
+ 	VIRT_PARA,
+-	VIRT_FULL
++	VIRT_FULL,
++	VIRT_CONT
+ };
+-const char *virt_types[] = {
++static const char *virt_types[] = {
+ 	[VIRT_NONE]	= N_("none"),
+ 	[VIRT_PARA]	= N_("para"),
+-	[VIRT_FULL]	= N_("full")
++	[VIRT_FULL]	= N_("full"),
++	[VIRT_CONT]	= N_("container"),
+ };
+ 
+-/* hypervisor vendors */
+-enum {
+-	HYPER_NONE	= 0,
+-	HYPER_XEN,
+-	HYPER_KVM,
+-	HYPER_MSHV,
+-	HYPER_VMWARE,
+-	HYPER_IBM
+-};
+-const char *hv_vendors[] = {
++static const char *hv_vendors[] = {
+ 	[HYPER_NONE]	= NULL,
+ 	[HYPER_XEN]	= "Xen",
+ 	[HYPER_KVM]	= "KVM",
+ 	[HYPER_MSHV]	= "Microsoft",
+ 	[HYPER_VMWARE]  = "VMware",
+-	[HYPER_IBM]	= "IBM"
++	[HYPER_IBM]	= "IBM",
++	[HYPER_VSERVER]	= "Linux-VServer",
++	[HYPER_UML]	= "User-mode Linux",
++	[HYPER_INNOTEK]	= "Innotek GmbH",
++	[HYPER_HITACHI]	= "Hitachi",
++	[HYPER_PARALLELS] = "Parallels",
++	[HYPER_VBOX]	= "Oracle",
++	[HYPER_OS400]	= "OS/400",
++	[HYPER_PHYP]	= "pHyp",
++	[HYPER_SPAR]	= "Unisys s-Par",
++	[HYPER_WSL]	= "Windows Subsystem for Linux"
++};
++
++static const int hv_vendor_pci[] = {
++	[HYPER_NONE]	= 0x0000,
++	[HYPER_XEN]	= 0x5853,
++	[HYPER_KVM]	= 0x0000,
++	[HYPER_MSHV]	= 0x1414,
++	[HYPER_VMWARE]	= 0x15ad,
++	[HYPER_VBOX]	= 0x80ee,
++};
++
++static const int hv_graphics_pci[] = {
++	[HYPER_NONE]	= 0x0000,
++	[HYPER_XEN]	= 0x0001,
++	[HYPER_KVM]	= 0x0000,
++	[HYPER_MSHV]	= 0x5353,
++	[HYPER_VMWARE]	= 0x0710,
++	[HYPER_VBOX]	= 0xbeef,
+ };
+ 
+ /* CPU modes */
+@@ -107,7 +169,7 @@ enum {
+ 	DISP_VERTICAL	= 1
+ };
+ 
+-const char *disp_modes[] = {
++static const char *disp_modes[] = {
+ 	[DISP_HORIZONTAL]	= N_("horizontal"),
+ 	[DISP_VERTICAL]		= N_("vertical")
+ };
+@@ -126,7 +188,7 @@ struct polarization_modes {
+ 	char *readable;
+ };
+ 
+-struct polarization_modes polar_modes[] = {
++static struct polarization_modes polar_modes[] = {
+ 	[POLAR_UNKNOWN]	   = {"U",  "-"},
+ 	[POLAR_VLOW]	   = {"VL", "vert-low"},
+ 	[POLAR_VMEDIUM]	   = {"VM", "vert-medium"},
+@@ -138,6 +200,7 @@ struct polarization_modes polar_modes[] = {
+ struct lscpu_desc {
+ 	char	*arch;
+ 	char	*vendor;
++	char	*machinetype;	/* s390 */
+ 	char	*family;
+ 	char	*model;
+ 	char	*modelname;
+@@ -148,9 +211,14 @@ struct lscpu_desc {
+ 	int	hyper;		/* hypervisor vendor ID */
+ 	int	virtype;	/* VIRT_PARA|FULL|NONE ? */
+ 	char	*mhz;
++	char	*dynamic_mhz;	/* dynamic mega hertz (s390) */
++	char	*static_mhz;	/* static mega hertz (s390) */
++	char	**maxmhz;	/* maximum mega hertz */
++	char	**minmhz;	/* minimum mega hertz */
+ 	char	*stepping;
+ 	char    *bogomips;
+ 	char	*flags;
++	char	*mtid;		/* maximum thread id (s390) */
+ 	int	dispatching;	/* none, horizontal or vertical */
+ 	int	mode;		/* rm, lm or/and tm */
+ 
+@@ -159,33 +227,58 @@ struct lscpu_desc {
+ 	cpu_set_t	*present;	/* mask with present CPUs */
+ 	cpu_set_t	*online;	/* mask with online CPUs */
+ 
++	int		nthreads;	/* number of online threads */
++
++	int		ncaches;
++	struct cpu_cache *caches;
++
++	int		necaches;	/* extra caches (s390) */
++	struct cpu_cache *ecaches;
++
++	/*
++	 * All maps are sequentially indexed (0..ncpuspos), the array index
++	 * does not have match with cpuX number as presented by kernel. You
++	 * have to use real_cpu_num() to get the real cpuX number.
++	 *
++	 * For example, the possible system CPUs are: 1,3,5, it means that
++	 * ncpuspos=3, so all arrays are in range 0..3.
++	 */
++	int		*idx2cpunum;	/* mapping index to CPU num */
++
+ 	int		nnodes;		/* number of NUMA modes */
+ 	int		*idx2nodenum;	/* Support for discontinuous nodes */
+ 	cpu_set_t	**nodemaps;	/* array with NUMA nodes */
+ 
++	/* drawers -- based on drawer_siblings (internal kernel map of cpuX's
++	 * hardware threads within the same drawer */
++	int		ndrawers;	/* number of all online drawers */
++	cpu_set_t	**drawermaps;	/* unique drawer_siblings */
++	int		*drawerids;	/* physical drawer ids */
++
+ 	/* books -- based on book_siblings (internal kernel map of cpuX's
+ 	 * hardware threads within the same book */
+ 	int		nbooks;		/* number of all online books */
+ 	cpu_set_t	**bookmaps;	/* unique book_siblings */
++	int		*bookids;	/* physical book ids */
+ 
+ 	/* sockets -- based on core_siblings (internal kernel map of cpuX's
+ 	 * hardware threads within the same physical_package_id (socket)) */
+ 	int		nsockets;	/* number of all online sockets */
+ 	cpu_set_t	**socketmaps;	/* unique core_siblings */
++	int		*socketids;	/* physical socket ids */
+ 
+-	/* cores -- based on thread_siblings (internel kernel map of cpuX's
++	/* cores -- based on thread_siblings (internal kernel map of cpuX's
+ 	 * hardware threads within the same core as cpuX) */
+ 	int		ncores;		/* number of all online cores */
+ 	cpu_set_t	**coremaps;	/* unique thread_siblings */
+-
+-	int		nthreads;	/* number of online threads */
+-
+-	int		ncaches;
+-	struct cpu_cache *caches;
++	int		*coreids;	/* physical core ids */
+ 
+ 	int		*polarization;	/* cpu polarization */
+ 	int		*addresses;	/* physical cpu addresses */
+ 	int		*configured;	/* cpu configured */
++	int		physsockets;	/* Physical sockets (modules) */
++	int		physchips;	/* Physical chips */
++	int		physcoresperchip;	/* Physical cores per chip */
+ };
+ 
+ enum {
+@@ -205,7 +298,8 @@ struct lscpu_modifier {
+ 	unsigned int	hex:1,		/* print CPU masks rather than CPU lists */
+ 			compat:1,	/* use backwardly compatible format */
+ 			online:1,	/* print online CPUs */
+-			offline:1;	/* print offline CPUs */
++			offline:1,	/* print offline CPUs */
++			physical:1;	/* use physical numbers */
+ };
+ 
+ static int maxcpus;		/* size in bits of kernel cpu mask */
+@@ -217,6 +311,8 @@ static int maxcpus;		/* size in bits of kernel cpu mask */
+ 	((_d) && (_d)->present ? \
+ 		CPU_ISSET_S((_cpu), CPU_ALLOC_SIZE(maxcpus), (_d)->present) : 0)
+ 
++#define real_cpu_num(_d, _i)	((_d)->idx2cpunum[(_i)])
++
+ /*
+  * IDs
+  */
+@@ -226,11 +322,14 @@ enum {
+ 	COL_SOCKET,
+ 	COL_NODE,
+ 	COL_BOOK,
++	COL_DRAWER,
+ 	COL_CACHE,
+ 	COL_POLARIZATION,
+ 	COL_ADDRESS,
+ 	COL_CONFIGURED,
+ 	COL_ONLINE,
++	COL_MAXMHZ,
++	COL_MINMHZ,
+ };
+ 
+ /* column description
+@@ -249,11 +348,14 @@ static struct lscpu_coldesc coldescs[] =
+ 	[COL_SOCKET]       = { "SOCKET", N_("logical socket number") },
+ 	[COL_NODE]         = { "NODE", N_("logical NUMA node number") },
+ 	[COL_BOOK]         = { "BOOK", N_("logical book number") },
++	[COL_DRAWER]       = { "DRAWER", N_("logical drawer number") },
+ 	[COL_CACHE]        = { "CACHE", N_("shows how caches are shared between CPUs") },
+ 	[COL_POLARIZATION] = { "POLARIZATION", N_("CPU dispatching mode on virtual hardware") },
+ 	[COL_ADDRESS]      = { "ADDRESS", N_("physical address of a CPU") },
+ 	[COL_CONFIGURED]   = { "CONFIGURED", N_("shows if the hypervisor has allocated the CPU") },
+-	[COL_ONLINE]       = { "ONLINE", N_("shows if Linux currently makes use of the CPU") }
++	[COL_ONLINE]       = { "ONLINE", N_("shows if Linux currently makes use of the CPU") },
++	[COL_MAXMHZ]	   = { "MAXMHZ", N_("shows the maximum MHz of the CPU") },
++	[COL_MINMHZ]	   = { "MINMHZ", N_("shows the minimum MHz of the CPU") }
+ };
+ 
+ static int
+@@ -282,7 +384,8 @@ lookup(char *line, char *pattern, char **value)
+ 	char *p, *v;
+ 	int len = strlen(pattern);
+ 
+-	if (!*line)
++	/* don't re-fill already found tags, first one wins */
++	if (!*line || *value)
+ 		return 0;
+ 
+ 	/* pattern */
+@@ -313,6 +416,63 @@ lookup(char *line, char *pattern, char **value)
+ 	return 1;
+ }
+ 
++/* Parse extra cache lines contained within /proc/cpuinfo but which are not
++ * part of the cache topology information within the sysfs filesystem.
++ * This is true for all shared caches on e.g. s390. When there are layers of
++ * hypervisors in between it is not knows which CPUs share which caches.
++ * Therefore information about shared caches is only available in
++ * /proc/cpuinfo.
++ * Format is:
++ * "cache<nr> : level=<lvl> type=<type> scope=<scope> size=<size> line_size=<lsz> associativity=<as>"
++ */
++static int
++lookup_cache(char *line, struct lscpu_desc *desc)
++{
++	struct cpu_cache *cache;
++	long long size;
++	char *p, type;
++	int level;
++
++	/* Make sure line starts with "cache<nr> :" */
++	if (strncmp(line, "cache", 5))
++		return 0;
++	for (p = line + 5; isdigit(*p); p++);
++	for (; isspace(*p); p++);
++	if (*p != ':')
++		return 0;
++
++	p = strstr(line, "scope=") + 6;
++	/* Skip private caches, also present in sysfs */
++	if (!p || strncmp(p, "Private", 7) == 0)
++		return 0;
++	p = strstr(line, "level=");
++	if (!p || sscanf(p, "level=%d", &level) != 1)
++		return 0;
++	p = strstr(line, "type=") + 5;
++	if (!p || !*p)
++		return 0;
++	type = 0;
++	if (strncmp(p, "Data", 4) == 0)
++		type = 'd';
++	if (strncmp(p, "Instruction", 11) == 0)
++		type = 'i';
++	p = strstr(line, "size=");
++	if (!p || sscanf(p, "size=%lld", &size) != 1)
++	       return 0;
++
++	desc->necaches++;
++	desc->ecaches = xrealloc(desc->ecaches,
++				 desc->necaches * sizeof(struct cpu_cache));
++	cache = &desc->ecaches[desc->necaches - 1];
++	memset(cache, 0 , sizeof(*cache));
++	if (type)
++		xasprintf(&cache->name, "L%d%c", level, type);
++	else
++		xasprintf(&cache->name, "L%d", level);
++	xasprintf(&cache->size, "%lldK", size);
++	return 1;
++}
++
+ /* Don't init the mode for platforms where we are not able to
+  * detect that CPU supports 64-bit mode.
+  */
+@@ -338,6 +498,45 @@ init_mode(struct lscpu_modifier *mod)
+ 	return m;
+ }
+ 
++#if defined(HAVE_LIBRTAS)
++#define PROCESSOR_MODULE_INFO	43
++static int strbe16toh(const char *buf, int offset)
++{
++	return (buf[offset] << 8) + buf[offset+1];
++}
++
++static void read_physical_info_powerpc(struct lscpu_desc *desc)
++{
++	char buf[BUFSIZ];
++	int rc, len, ntypes;
++
++	desc->physsockets = desc->physchips = desc->physcoresperchip = 0;
++
++	rc = rtas_get_sysparm(PROCESSOR_MODULE_INFO, sizeof(buf), buf);
++	if (rc < 0)
++		return;
++
++	len = strbe16toh(buf, 0);
++	if (len < 8)
++		return;
++
++	ntypes = strbe16toh(buf, 2);
++
++	assert(ntypes <= 1);
++	if (!ntypes)
++		return;
++
++	desc->physsockets = strbe16toh(buf, 4);
++	desc->physchips = strbe16toh(buf, 6);
++	desc->physcoresperchip = strbe16toh(buf, 8);
++}
++#else
++static void read_physical_info_powerpc(
++		struct lscpu_desc *desc __attribute__((__unused__)))
++{
++}
++#endif
++
+ static void
+ read_basicinfo(struct lscpu_desc *desc, struct lscpu_modifier *mod)
+ {
+@@ -361,13 +560,20 @@ read_basicinfo(struct lscpu_desc *desc, struct lscpu_modifier *mod)
+ 		else if (lookup(buf, "model name", &desc->modelname)) ;
+ 		else if (lookup(buf, "stepping", &desc->stepping)) ;
+ 		else if (lookup(buf, "cpu MHz", &desc->mhz)) ;
++		else if (lookup(buf, "cpu MHz dynamic", &desc->dynamic_mhz)) ; /* s390 */
++		else if (lookup(buf, "cpu MHz static", &desc->static_mhz)) ;   /* s390 */
+ 		else if (lookup(buf, "flags", &desc->flags)) ;		/* x86 */
+ 		else if (lookup(buf, "features", &desc->flags)) ;	/* s390 */
++		else if (lookup(buf, "Features", &desc->flags)) ;	/* aarch64 */
+ 		else if (lookup(buf, "type", &desc->flags)) ;		/* sparc64 */
+ 		else if (lookup(buf, "bogomips", &desc->bogomips)) ;
++		else if (lookup(buf, "BogoMIPS", &desc->bogomips)) ;	/* aarch64 */
+ 		else if (lookup(buf, "bogomips per cpu", &desc->bogomips)) ; /* s390 */
+ 		else if (lookup(buf, "cpu", &desc->cpu)) ;
+ 		else if (lookup(buf, "revision", &desc->revision)) ;
++		else if (lookup(buf, "CPU revision", &desc->revision)) ; /* aarch64 */
++		else if (lookup(buf, "max thread id", &desc->mtid)) ; /* s390 */
++		else if (lookup_cache(buf, desc)) ;
+ 		else
+ 			continue;
+ 	}
+@@ -397,9 +603,9 @@ read_basicinfo(struct lscpu_desc *desc, struct lscpu_modifier *mod)
+ 
+ 	fclose(fp);
+ 
+-	if (path_exist(_PATH_SYS_SYSTEM "/cpu/kernel_max"))
++	if (path_exist(_PATH_SYS_CPU "/kernel_max"))
+ 		/* note that kernel_max is maximum index [NR_CPUS-1] */
+-		maxcpus = path_read_s32(_PATH_SYS_SYSTEM "/cpu/kernel_max") + 1;
++		maxcpus = path_read_s32(_PATH_SYS_CPU "/kernel_max") + 1;
+ 
+ 	else if (mod->system == SYSTEM_LIVE)
+ 		/* the root is '/' so we are working with data from the current kernel */
+@@ -412,32 +618,49 @@ read_basicinfo(struct lscpu_desc *desc, struct lscpu_modifier *mod)
+ 
+ 	setsize = CPU_ALLOC_SIZE(maxcpus);
+ 
+-	if (path_exist(_PATH_SYS_SYSTEM "/cpu/possible")) {
+-		cpu_set_t *tmp = path_read_cpulist(maxcpus, _PATH_SYS_SYSTEM "/cpu/possible");
++	if (path_exist(_PATH_SYS_CPU "/possible")) {
++		cpu_set_t *tmp = path_read_cpulist(maxcpus, _PATH_SYS_CPU "/possible");
++		int num, idx;
++
+ 		desc->ncpuspos = CPU_COUNT_S(setsize, tmp);
++		desc->idx2cpunum = xcalloc(desc->ncpuspos, sizeof(int));
++
++		for (num = 0, idx = 0; num < maxcpus; num++) {
++			if (CPU_ISSET(num, tmp))
++				desc->idx2cpunum[idx++] = num;
++		}
+ 		cpuset_free(tmp);
+ 	} else
+ 		err(EXIT_FAILURE, _("failed to determine number of CPUs: %s"),
+-				_PATH_SYS_SYSTEM "/cpu/possible");
++				_PATH_SYS_CPU "/possible");
+ 
+ 
+ 	/* get mask for present CPUs */
+-	if (path_exist(_PATH_SYS_SYSTEM "/cpu/present")) {
+-		desc->present = path_read_cpulist(maxcpus, _PATH_SYS_SYSTEM "/cpu/present");
++	if (path_exist(_PATH_SYS_CPU "/present")) {
++		desc->present = path_read_cpulist(maxcpus, _PATH_SYS_CPU "/present");
+ 		desc->ncpus = CPU_COUNT_S(setsize, desc->present);
+ 	}
+ 
+ 	/* get mask for online CPUs */
+-	if (path_exist(_PATH_SYS_SYSTEM "/cpu/online")) {
+-		desc->online = path_read_cpulist(maxcpus, _PATH_SYS_SYSTEM "/cpu/online");
++	if (path_exist(_PATH_SYS_CPU "/online")) {
++		desc->online = path_read_cpulist(maxcpus, _PATH_SYS_CPU "/online");
+ 		desc->nthreads = CPU_COUNT_S(setsize, desc->online);
+ 	}
+ 
+ 	/* get dispatching mode */
+-	if (path_exist(_PATH_SYS_SYSTEM "/cpu/dispatching"))
+-		desc->dispatching = path_read_s32(_PATH_SYS_SYSTEM "/cpu/dispatching");
++	if (path_exist(_PATH_SYS_CPU "/dispatching"))
++		desc->dispatching = path_read_s32(_PATH_SYS_CPU "/dispatching");
+ 	else
+ 		desc->dispatching = -1;
++
++	if (mod->system == SYSTEM_LIVE)
++		read_physical_info_powerpc(desc);
++
++	if ((fp = path_fopen("r", 0, _PATH_PROC_SYSINFO))) {
++		while (fgets(buf, sizeof(buf), fp) != NULL && !desc->machinetype)
++			lookup(buf, "Type", &desc->machinetype);
++		fclose(fp);
++	}
+ }
+ 
+ static int
+@@ -483,10 +706,9 @@ cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx,
+ 	__asm__(
+ #if defined(__PIC__) && defined(__i386__)
+ 		/* x86 PIC cannot clobber ebx -- gcc bitches */
+-		"pushl %%ebx;"
++		"xchg %%ebx, %%esi;"
+ 		"cpuid;"
+-		"movl %%ebx, %%esi;"
+-		"popl %%ebx;"
++		"xchg %%esi, %%ebx;"
+ 		: "=S" (*ebx),
+ #else
+ 		"cpuid;"
+@@ -523,34 +745,230 @@ read_hypervisor_cpuid(struct lscpu_desc *desc)
+ 		desc->hyper = HYPER_MSHV;
+ 	else if (!strncmp("VMwareVMware", hyper_vendor_id, 12))
+ 		desc->hyper = HYPER_VMWARE;
++	else if (!strncmp("UnisysSpar64", hyper_vendor_id, 12))
++		desc->hyper = HYPER_SPAR;
+ }
+ 
+-#else	/* ! __x86_64__ */
++#else /* ! (__x86_64__ || __i386__) */
+ static void
+ read_hypervisor_cpuid(struct lscpu_desc *desc __attribute__((__unused__)))
+ {
+ }
+ #endif
+ 
++static int is_compatible(const char *path, const char *str)
++{
++	FILE *fd = path_fopen("r", 0, "%s", path);
++
++	if (fd) {
++		char buf[256];
++		size_t i, len;
++
++		memset(buf, 0, sizeof(buf));
++		len = fread(buf, 1, sizeof(buf) - 1, fd);
++		fclose(fd);
++
++		for (i = 0; i < len;) {
++			if (!strcmp(&buf[i], str))
++				return 1;
++			i += strlen(&buf[i]);
++			i++;
++		}
++	}
++
++	return 0;
++}
++
++static int
++read_hypervisor_powerpc(struct lscpu_desc *desc)
++{
++	assert(!desc->hyper);
++
++	 /* IBM iSeries: legacy, para-virtualized on top of OS/400 */
++	if (path_exist("/proc/iSeries")) {
++		desc->hyper = HYPER_OS400;
++		desc->virtype = VIRT_PARA;
++
++	/* PowerNV (POWER Non-Virtualized, bare-metal) */
++	} else if (is_compatible(_PATH_PROC_DEVICETREE "/compatible", "ibm,powernv")) {
++		desc->hyper = HYPER_NONE;
++		desc->virtype = VIRT_NONE;
++
++	/* PowerVM (IBM's proprietary hypervisor, aka pHyp) */
++	} else if (path_exist(_PATH_PROC_DEVICETREE "/ibm,partition-name")
++		   && path_exist(_PATH_PROC_DEVICETREE "/hmc-managed?")
++		   && !path_exist(_PATH_PROC_DEVICETREE "/chosen/qemu,graphic-width")) {
++		FILE *fd;
++		desc->hyper = HYPER_PHYP;
++		desc->virtype = VIRT_PARA;
++		fd = path_fopen("r", 0, _PATH_PROC_DEVICETREE "/ibm,partition-name");
++		if (fd) {
++			char buf[256];
++			if (fscanf(fd, "%255s", buf) == 1 && !strcmp(buf, "full"))
++				desc->virtype = VIRT_NONE;
++			fclose(fd);
++		}
++
++	/* Qemu */
++	} else if (is_compatible(_PATH_PROC_DEVICETREE "/compatible", "qemu,pseries")) {
++		desc->hyper = HYPER_KVM;
++		desc->virtype = VIRT_PARA;
++	}
++	return desc->hyper;
++}
++
++#ifdef INCLUDE_VMWARE_BDOOR
++
++#define VMWARE_BDOOR_MAGIC          0x564D5868
++#define VMWARE_BDOOR_PORT           0x5658
++#define VMWARE_BDOOR_CMD_GETVERSION 10
++
++static UL_ASAN_BLACKLIST
++void vmware_bdoor(uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
++{
++	__asm__(
++#if defined(__PIC__) && defined(__i386__)
++		/* x86 PIC cannot clobber ebx -- gcc bitches */
++		"xchg %%ebx, %%esi;"
++		"inl (%%dx), %%eax;"
++		"xchg %%esi, %%ebx;"
++		: "=S" (*ebx),
++#else
++		"inl (%%dx), %%eax;"
++		: "=b" (*ebx),
++#endif
++		  "=a" (*eax),
++		  "=c" (*ecx),
++		  "=d" (*edx)
++		: "0" (VMWARE_BDOOR_MAGIC),
++		  "1" (VMWARE_BDOOR_CMD_GETVERSION),
++		  "2" (VMWARE_BDOOR_PORT),
++		  "3" (0)
++		: "memory");
++}
++
++static jmp_buf segv_handler_env;
++
++static void
++segv_handler(__attribute__((__unused__)) int sig,
++             __attribute__((__unused__)) siginfo_t *info,
++             __attribute__((__unused__)) void *ignored)
++{
++	siglongjmp(segv_handler_env, 1);
++}
++
++static int
++is_vmware_platform(void)
++{
++	uint32_t eax, ebx, ecx, edx;
++	struct sigaction act, oact;
++
++	/*
++	 * FIXME: Not reliable for non-root users. Note it works as expected if
++	 * vmware_bdoor() is not optimized for PIE, but then it fails to build
++	 * on 32bit x86 systems. See lscpu git log for more details (commit
++	 * 7845b91dbc7690064a2be6df690e4aaba728fb04).     kzak [3-Nov-2016]
++	 */
++	if (getuid() != 0)
++		return 0;
++
++	/*
++	 * The assembly routine for vmware detection works
++	 * fine under vmware, even if ran as regular user. But
++	 * on real HW or under other hypervisors, it segfaults (which is
++	 * expected). So we temporarily install SIGSEGV handler to catch
++	 * the signal. All this magic is needed because lscpu
++	 * isn't supposed to require root privileges.
++	 */
++	if (sigsetjmp(segv_handler_env, 1))
++		return 0;
++
++	memset(&act, 0, sizeof(act));
++	act.sa_sigaction = segv_handler;
++	act.sa_flags = SA_SIGINFO;
++
++	if (sigaction(SIGSEGV, &act, &oact))
++		err(EXIT_FAILURE, _("cannot set signal handler"));
++
++	vmware_bdoor(&eax, &ebx, &ecx, &edx);
++
++	if (sigaction(SIGSEGV, &oact, NULL))
++		err(EXIT_FAILURE, _("cannot restore signal handler"));
++
++	return eax != (uint32_t)-1 && ebx == VMWARE_BDOOR_MAGIC;
++}
++
++#else /* ! INCLUDE_VMWARE_BDOOR */
++
++static int
++is_vmware_platform(void)
++{
++	return 0;
++}
++
++#endif /* INCLUDE_VMWARE_BDOOR */
++
+ static void
+ read_hypervisor(struct lscpu_desc *desc, struct lscpu_modifier *mod)
+ {
+-	if (mod->system != SYSTEM_SNAPSHOT)
++	FILE *fd;
++
++	/* We have to detect WSL first. is_vmware_platform() crashes on Windows 10. */
++
++	if ((fd = path_fopen("r", 0, _PATH_PROC_OSRELEASE))) {
++		char buf[256];
++
++		if (fgets(buf, sizeof(buf), fd) != NULL) {
++			if (strstr(buf, "Microsoft")) {
++				desc->hyper = HYPER_WSL;
++				desc->virtype = VIRT_CONT;
++			}
++		}
++		fclose(fd);
++		if (desc->virtype)
++			return;
++	}
++
++	if (mod->system != SYSTEM_SNAPSHOT) {
+ 		read_hypervisor_cpuid(desc);
++		if (!desc->hyper)
++			desc->hyper = read_hypervisor_dmi();
++		if (!desc->hyper && is_vmware_platform())
++			desc->hyper = HYPER_VMWARE;
++	}
+ 
+-	if (desc->hyper)
+-		/* hvm */
++	if (desc->hyper) {
+ 		desc->virtype = VIRT_FULL;
+ 
++		if (desc->hyper == HYPER_XEN) {
++			uint32_t features;
++
++			fd = path_fopen("r", 0, _PATH_SYS_HYP_FEATURES);
++			if (fd && fscanf(fd, "%x", &features) == 1) {
++				/* Xen PV domain */
++				if (features & XEN_FEATURES_PV_MASK)
++					desc->virtype = VIRT_PARA;
++				/* Xen PVH domain */
++				else if ((features & XEN_FEATURES_PVH_MASK)
++								== XEN_FEATURES_PVH_MASK)
++					desc->virtype = VIRT_PARA;
++				fclose(fd);
++			} else {
++				err(EXIT_FAILURE, _("failed to read from: %s"),
++						_PATH_SYS_HYP_FEATURES);
++			}
++		}
++	} else if (read_hypervisor_powerpc(desc) > 0) {}
++
++	/* Xen para-virt or dom0 */
+ 	else if (path_exist(_PATH_PROC_XEN)) {
+-		/* Xen para-virt or dom0 */
+-		FILE *fd = path_fopen("r", 0, _PATH_PROC_XENCAP);
+ 		int dom0 = 0;
++		fd = path_fopen("r", 0, _PATH_PROC_XENCAP);
+ 
+ 		if (fd) {
+ 			char buf[256];
+ 
+-			if (fscanf(fd, "%s", buf) == 1 &&
++			if (fscanf(fd, "%255s", buf) == 1 &&
+ 			    !strcmp(buf, "control_d"))
+ 				dom0 = 1;
+ 			fclose(fd);
+@@ -558,16 +976,21 @@ read_hypervisor(struct lscpu_desc *desc, struct lscpu_modifier *mod)
+ 		desc->virtype = dom0 ? VIRT_NONE : VIRT_PARA;
+ 		desc->hyper = HYPER_XEN;
+ 
+-	} else if (has_pci_device(0x5853, 0x0001)) {
+-		/* Xen full-virt on non-x86_64 */
++	/* Xen full-virt on non-x86_64 */
++	} else if (has_pci_device( hv_vendor_pci[HYPER_XEN], hv_graphics_pci[HYPER_XEN])) {
+ 		desc->hyper = HYPER_XEN;
+ 		desc->virtype = VIRT_FULL;
+-	} else if (path_exist(_PATH_PROC_SYSINFO)) {
+-		FILE *fd = path_fopen("r", 0, _PATH_PROC_SYSINFO);
++	} else if (has_pci_device( hv_vendor_pci[HYPER_VMWARE], hv_graphics_pci[HYPER_VMWARE])) {
++		desc->hyper = HYPER_VMWARE;
++		desc->virtype = VIRT_FULL;
++	} else if (has_pci_device( hv_vendor_pci[HYPER_VBOX], hv_graphics_pci[HYPER_VBOX])) {
++		desc->hyper = HYPER_VBOX;
++		desc->virtype = VIRT_FULL;
++
++	/* IBM PR/SM */
++	} else if ((fd = path_fopen("r", 0, _PATH_PROC_SYSINFO))) {
+ 		char buf[BUFSIZ];
+ 
+-		if (!fd)
+-			return;
+ 		desc->hyper = HYPER_IBM;
+ 		desc->hypervisor = "PR/SM";
+ 		desc->virtype = VIRT_FULL;
+@@ -597,6 +1020,45 @@ read_hypervisor(struct lscpu_desc *desc, struct lscpu_modifier *mod)
+ 		}
+ 		fclose(fd);
+ 	}
++
++	/* OpenVZ/Virtuozzo - /proc/vz dir should exist
++	 *		      /proc/bc should not */
++	else if (path_exist(_PATH_PROC_VZ) && !path_exist(_PATH_PROC_BC)) {
++		desc->hyper = HYPER_PARALLELS;
++		desc->virtype = VIRT_CONT;
++
++	/* IBM */
++	} else if (desc->vendor &&
++		 (strcmp(desc->vendor, "PowerVM Lx86") == 0 ||
++		  strcmp(desc->vendor, "IBM/S390") == 0)) {
++		desc->hyper = HYPER_IBM;
++		desc->virtype = VIRT_FULL;
++
++	/* User-mode-linux */
++	} else if (desc->modelname && strstr(desc->modelname, "UML")) {
++		desc->hyper = HYPER_UML;
++		desc->virtype = VIRT_PARA;
++
++	/* Linux-VServer */
++	} else if ((fd = path_fopen("r", 0, _PATH_PROC_STATUS))) {
++		char buf[BUFSIZ];
++		char *val = NULL;
++
++		while (fgets(buf, sizeof(buf), fd) != NULL) {
++			if (lookup(buf, "VxID", &val))
++				break;
++		}
++		fclose(fd);
++
++		if (val) {
++			while (isdigit(*val))
++				++val;
++			if (!*val) {
++				desc->hyper = HYPER_VSERVER;
++				desc->virtype = VIRT_CONT;
++			}
++		}
++	}
+ }
+ 
+ /* add @set to the @ary, unnecessary set is deallocated. */
+@@ -622,9 +1084,12 @@ static int add_cpuset_to_array(cpu_set_t **ary, int *items, cpu_set_t *set)
+ }
+ 
+ static void
+-read_topology(struct lscpu_desc *desc, int num)
++read_topology(struct lscpu_desc *desc, int idx)
+ {
+-	cpu_set_t *thread_siblings, *core_siblings, *book_siblings;
++	cpu_set_t *thread_siblings, *core_siblings;
++	cpu_set_t *book_siblings, *drawer_siblings;
++	int coreid, socketid, bookid, drawerid;
++	int i, num = real_cpu_num(desc, idx);
+ 
+ 	if (!path_exist(_PATH_SYS_CPU "/cpu%d/topology/thread_siblings", num))
+ 		return;
+@@ -634,13 +1099,32 @@ read_topology(struct lscpu_desc *desc, int num)
+ 	core_siblings = path_read_cpuset(maxcpus, _PATH_SYS_CPU
+ 					"/cpu%d/topology/core_siblings", num);
+ 	book_siblings = NULL;
+-	if (path_exist(_PATH_SYS_CPU "/cpu%d/topology/book_siblings", num)) {
++	if (path_exist(_PATH_SYS_CPU "/cpu%d/topology/book_siblings", num))
+ 		book_siblings = path_read_cpuset(maxcpus, _PATH_SYS_CPU
+ 					    "/cpu%d/topology/book_siblings", num);
+-	}
++	drawer_siblings = NULL;
++	if (path_exist(_PATH_SYS_CPU "/cpu%d/topology/drawer_siblings", num))
++		drawer_siblings = path_read_cpuset(maxcpus, _PATH_SYS_CPU
++					    "/cpu%d/topology/drawer_siblings", num);
++	coreid = -1;
++	if (path_exist(_PATH_SYS_CPU "/cpu%d/topology/core_id", num))
++		coreid = path_read_s32(_PATH_SYS_CPU
++				       "/cpu%d/topology/core_id", num);
++	socketid = -1;
++	if (path_exist(_PATH_SYS_CPU "/cpu%d/topology/physical_package_id", num))
++		socketid = path_read_s32(_PATH_SYS_CPU
++				       "/cpu%d/topology/physical_package_id", num);
++	bookid = -1;
++	if (path_exist(_PATH_SYS_CPU "/cpu%d/topology/book_id", num))
++		bookid = path_read_s32(_PATH_SYS_CPU
++				       "/cpu%d/topology/book_id", num);
++	drawerid = -1;
++	if (path_exist(_PATH_SYS_CPU "/cpu%d/topology/drawer_id", num))
++		drawerid = path_read_s32(_PATH_SYS_CPU
++				       "/cpu%d/topology/drawer_id", num);
+ 
+ 	if (!desc->coremaps) {
+-		int nbooks, nsockets, ncores, nthreads;
++		int ndrawers, nbooks, nsockets, ncores, nthreads;
+ 		size_t setsize = CPU_ALLOC_SIZE(maxcpus);
+ 
+ 		/* threads within one core */
+@@ -666,12 +1150,17 @@ read_topology(struct lscpu_desc *desc, int num)
+ 		if (!nbooks)
+ 			nbooks = 1;
+ 
++		/* number of drawers */
++		ndrawers = desc->ncpus / nbooks / nthreads / ncores / nsockets;
++		if (!ndrawers)
++			ndrawers = 1;
++
+ 		/* all threads, see also read_basicinfo()
+ 		 * -- fallback for kernels without
+ 		 *    /sys/devices/system/cpu/online.
+ 		 */
+ 		if (!desc->nthreads)
+-			desc->nthreads = nbooks * nsockets * ncores * nthreads;
++			desc->nthreads = ndrawers * nbooks * nsockets * ncores * nthreads;
+ 
+ 		/* For each map we make sure that it can have up to ncpuspos
+ 		 * entries. This is because we cannot reliably calculate the
+@@ -681,19 +1170,43 @@ read_topology(struct lscpu_desc *desc, int num)
+ 		 */
+ 		desc->coremaps = xcalloc(desc->ncpuspos, sizeof(cpu_set_t *));
+ 		desc->socketmaps = xcalloc(desc->ncpuspos, sizeof(cpu_set_t *));
+-		if (book_siblings)
++		desc->coreids = xcalloc(desc->ncpuspos, sizeof(*desc->drawerids));
++		desc->socketids = xcalloc(desc->ncpuspos, sizeof(*desc->drawerids));
++		for (i = 0; i < desc->ncpuspos; i++)
++			desc->coreids[i] = desc->socketids[i] = -1;
++		if (book_siblings) {
+ 			desc->bookmaps = xcalloc(desc->ncpuspos, sizeof(cpu_set_t *));
++			desc->bookids = xcalloc(desc->ncpuspos, sizeof(*desc->drawerids));
++			for (i = 0; i < desc->ncpuspos; i++)
++				desc->bookids[i] = -1;
++		}
++		if (drawer_siblings) {
++			desc->drawermaps = xcalloc(desc->ncpuspos, sizeof(cpu_set_t *));
++			desc->drawerids = xcalloc(desc->ncpuspos, sizeof(*desc->drawerids));
++			for (i = 0; i < desc->ncpuspos; i++)
++				desc->drawerids[i] = -1;
++		}
+ 	}
+ 
+ 	add_cpuset_to_array(desc->socketmaps, &desc->nsockets, core_siblings);
++	desc->coreids[idx] = coreid;
+ 	add_cpuset_to_array(desc->coremaps, &desc->ncores, thread_siblings);
+-	if (book_siblings)
++	desc->socketids[idx] = socketid;
++	if (book_siblings) {
+ 		add_cpuset_to_array(desc->bookmaps, &desc->nbooks, book_siblings);
++		desc->bookids[idx] = bookid;
++	}
++	if (drawer_siblings) {
++		add_cpuset_to_array(desc->drawermaps, &desc->ndrawers, drawer_siblings);
++		desc->drawerids[idx] = drawerid;
++	}
+ }
++
+ static void
+-read_polarization(struct lscpu_desc *desc, int num)
++read_polarization(struct lscpu_desc *desc, int idx)
+ {
+ 	char mode[64];
++	int num = real_cpu_num(desc, idx);
+ 
+ 	if (desc->dispatching < 0)
+ 		return;
+@@ -703,35 +1216,67 @@ read_polarization(struct lscpu_desc *desc, int num)
+ 		desc->polarization = xcalloc(desc->ncpuspos, sizeof(int));
+ 	path_read_str(mode, sizeof(mode), _PATH_SYS_CPU "/cpu%d/polarization", num);
+ 	if (strncmp(mode, "vertical:low", sizeof(mode)) == 0)
+-		desc->polarization[num] = POLAR_VLOW;
++		desc->polarization[idx] = POLAR_VLOW;
+ 	else if (strncmp(mode, "vertical:medium", sizeof(mode)) == 0)
+-		desc->polarization[num] = POLAR_VMEDIUM;
++		desc->polarization[idx] = POLAR_VMEDIUM;
+ 	else if (strncmp(mode, "vertical:high", sizeof(mode)) == 0)
+-		desc->polarization[num] = POLAR_VHIGH;
++		desc->polarization[idx] = POLAR_VHIGH;
+ 	else if (strncmp(mode, "horizontal", sizeof(mode)) == 0)
+-		desc->polarization[num] = POLAR_HORIZONTAL;
++		desc->polarization[idx] = POLAR_HORIZONTAL;
+ 	else
+-		desc->polarization[num] = POLAR_UNKNOWN;
++		desc->polarization[idx] = POLAR_UNKNOWN;
+ }
+ 
+ static void
+-read_address(struct lscpu_desc *desc, int num)
++read_address(struct lscpu_desc *desc, int idx)
+ {
++	int num = real_cpu_num(desc, idx);
++
+ 	if (!path_exist(_PATH_SYS_CPU "/cpu%d/address", num))
+ 		return;
+ 	if (!desc->addresses)
+ 		desc->addresses = xcalloc(desc->ncpuspos, sizeof(int));
+-	desc->addresses[num] = path_read_s32(_PATH_SYS_CPU "/cpu%d/address", num);
++	desc->addresses[idx] = path_read_s32(_PATH_SYS_CPU "/cpu%d/address", num);
+ }
+ 
+ static void
+-read_configured(struct lscpu_desc *desc, int num)
++read_configured(struct lscpu_desc *desc, int idx)
+ {
++	int num = real_cpu_num(desc, idx);
++
+ 	if (!path_exist(_PATH_SYS_CPU "/cpu%d/configure", num))
+ 		return;
+ 	if (!desc->configured)
+ 		desc->configured = xcalloc(desc->ncpuspos, sizeof(int));
+-	desc->configured[num] = path_read_s32(_PATH_SYS_CPU "/cpu%d/configure", num);
++	desc->configured[idx] = path_read_s32(_PATH_SYS_CPU "/cpu%d/configure", num);
++}
++
++static void
++read_max_mhz(struct lscpu_desc *desc, int idx)
++{
++	int num = real_cpu_num(desc, idx);
++
++	if (!path_exist(_PATH_SYS_CPU "/cpu%d/cpufreq/cpuinfo_max_freq", num))
++		return;
++	if (!desc->maxmhz)
++		desc->maxmhz = xcalloc(desc->ncpuspos, sizeof(char *));
++	xasprintf(&(desc->maxmhz[idx]), "%.4f",
++		  (float)path_read_s32(_PATH_SYS_CPU
++				       "/cpu%d/cpufreq/cpuinfo_max_freq", num) / 1000);
++}
++
++static void
++read_min_mhz(struct lscpu_desc *desc, int idx)
++{
++	int num = real_cpu_num(desc, idx);
++
++	if (!path_exist(_PATH_SYS_CPU "/cpu%d/cpufreq/cpuinfo_min_freq", num))
++		return;
++	if (!desc->minmhz)
++		desc->minmhz = xcalloc(desc->ncpuspos, sizeof(char *));
++	xasprintf(&(desc->minmhz[idx]), "%.4f",
++		  (float)path_read_s32(_PATH_SYS_CPU
++				       "/cpu%d/cpufreq/cpuinfo_min_freq", num) / 1000);
+ }
+ 
+ static int
+@@ -744,13 +1289,14 @@ cachecmp(const void *a, const void *b)
+ }
+ 
+ static void
+-read_cache(struct lscpu_desc *desc, int num)
++read_cache(struct lscpu_desc *desc, int idx)
+ {
+ 	char buf[256];
+ 	int i;
++	int num = real_cpu_num(desc, idx);
+ 
+ 	if (!desc->ncaches) {
+-		while(path_exist(_PATH_SYS_SYSTEM "/cpu/cpu%d/cache/index%d",
++		while(path_exist(_PATH_SYS_CPU "/cpu%d/cache/index%d",
+ 					num, desc->ncaches))
+ 			desc->ncaches++;
+ 
+@@ -763,7 +1309,7 @@ read_cache(struct lscpu_desc *desc, int num)
+ 		struct cpu_cache *ca = &desc->caches[i];
+ 		cpu_set_t *map;
+ 
+-		if (!path_exist(_PATH_SYS_SYSTEM "/cpu/cpu%d/cache/index%d",
++		if (!path_exist(_PATH_SYS_CPU "/cpu%d/cache/index%d",
+ 				num, i))
+ 			continue;
+ 		if (!ca->name) {
+@@ -791,10 +1337,13 @@ read_cache(struct lscpu_desc *desc, int num)
+ 			ca->name = xstrdup(buf);
+ 
+ 			/* cache size */
+-			path_read_str(buf, sizeof(buf),
+-					_PATH_SYS_CPU "/cpu%d/cache/index%d/size",
+-					num, i);
+-			ca->size = xstrdup(buf);
++			if (path_exist(_PATH_SYS_CPU "/cpu%d/cache/index%d/size",num, i)) {
++				path_read_str(buf, sizeof(buf),
++					_PATH_SYS_CPU "/cpu%d/cache/index%d/size", num, i);
++				ca->size = xstrdup(buf);
++			} else {
++				ca->size = xstrdup("unknown size");
++			}
+ 		}
+ 
+ 		/* information about how CPUs share different caches */
+@@ -867,17 +1416,18 @@ read_nodes(struct lscpu_desc *desc)
+ 	/* information about how nodes share different CPUs */
+ 	for (i = 0; i < desc->nnodes; i++)
+ 		desc->nodemaps[i] = path_read_cpuset(maxcpus,
+-					_PATH_SYS_SYSTEM "/node/node%d/cpumap",
++					_PATH_SYS_NODE "/node%d/cpumap",
+ 					desc->idx2nodenum[i]);
+ }
+ 
+ static char *
+-get_cell_data(struct lscpu_desc *desc, int cpu, int col,
++get_cell_data(struct lscpu_desc *desc, int idx, int col,
+ 	      struct lscpu_modifier *mod,
+ 	      char *buf, size_t bufsz)
+ {
+ 	size_t setsize = CPU_ALLOC_SIZE(maxcpus);
+-	size_t idx;
++	size_t i;
++	int cpu = real_cpu_num(desc, idx);
+ 
+ 	*buf = '\0';
+ 
+@@ -886,24 +1436,57 @@ get_cell_data(struct lscpu_desc *desc, int cpu, int col,
+ 		snprintf(buf, bufsz, "%d", cpu);
+ 		break;
+ 	case COL_CORE:
+-		if (cpuset_ary_isset(cpu, desc->coremaps,
+-				     desc->ncores, setsize, &idx) == 0)
+-			snprintf(buf, bufsz, "%zd", idx);
++		if (mod->physical) {
++			if (desc->coreids[idx] == -1)
++				snprintf(buf, bufsz, "-");
++			else
++				snprintf(buf, bufsz, "%d", desc->coreids[idx]);
++		} else {
++			if (cpuset_ary_isset(cpu, desc->coremaps,
++					     desc->ncores, setsize, &i) == 0)
++				snprintf(buf, bufsz, "%zu", i);
++		}
+ 		break;
+ 	case COL_SOCKET:
+-		if (cpuset_ary_isset(cpu, desc->socketmaps,
+-				     desc->nsockets, setsize, &idx) == 0)
+-			snprintf(buf, bufsz, "%zd", idx);
++		if (mod->physical) {
++			if (desc->socketids[idx] ==  -1)
++				snprintf(buf, bufsz, "-");
++			else
++				snprintf(buf, bufsz, "%d", desc->socketids[idx]);
++		} else {
++			if (cpuset_ary_isset(cpu, desc->socketmaps,
++					     desc->nsockets, setsize, &i) == 0)
++				snprintf(buf, bufsz, "%zu", i);
++		}
+ 		break;
+ 	case COL_NODE:
+ 		if (cpuset_ary_isset(cpu, desc->nodemaps,
+-				     desc->nnodes, setsize, &idx) == 0)
+-			snprintf(buf, bufsz, "%d", desc->idx2nodenum[idx]);
++				     desc->nnodes, setsize, &i) == 0)
++			snprintf(buf, bufsz, "%d", desc->idx2nodenum[i]);
++		break;
++	case COL_DRAWER:
++		if (mod->physical) {
++			if (desc->drawerids[idx] == -1)
++				snprintf(buf, bufsz, "-");
++			else
++				snprintf(buf, bufsz, "%d", desc->drawerids[idx]);
++		} else {
++			if (cpuset_ary_isset(cpu, desc->drawermaps,
++					     desc->ndrawers, setsize, &i) == 0)
++				snprintf(buf, bufsz, "%zu", i);
++		}
+ 		break;
+ 	case COL_BOOK:
+-		if (cpuset_ary_isset(cpu, desc->bookmaps,
+-				     desc->nbooks, setsize, &idx) == 0)
+-			snprintf(buf, bufsz, "%zd", idx);
++		if (mod->physical) {
++			if (desc->bookids[idx] == -1)
++				snprintf(buf, bufsz, "-");
++			else
++				snprintf(buf, bufsz, "%d", desc->bookids[idx]);
++		} else {
++			if (cpuset_ary_isset(cpu, desc->bookmaps,
++					     desc->nbooks, setsize, &i) == 0)
++				snprintf(buf, bufsz, "%zu", i);
++		}
+ 		break;
+ 	case COL_CACHE:
+ 	{
+@@ -915,24 +1498,26 @@ get_cell_data(struct lscpu_desc *desc, int cpu, int col,
+ 			struct cpu_cache *ca = &desc->caches[j];
+ 
+ 			if (cpuset_ary_isset(cpu, ca->sharedmaps,
+-					     ca->nsharedmaps, setsize, &idx) == 0) {
+-				int x = snprintf(p, sz, "%zd", idx);
+-				if (x <= 0 || (size_t) x + 2 >= sz)
++					     ca->nsharedmaps, setsize, &i) == 0) {
++				int x = snprintf(p, sz, "%zu", i);
++				if (x < 0 || (size_t) x >= sz)
+ 					return NULL;
+ 				p += x;
+ 				sz -= x;
+ 			}
+ 			if (j != 0) {
++				if (sz < 2)
++					return NULL;
+ 				*p++ = mod->compat ? ',' : ':';
+ 				*p = '\0';
+-				sz++;
++				sz--;
+ 			}
+ 		}
+ 		break;
+ 	}
+ 	case COL_POLARIZATION:
+ 		if (desc->polarization) {
+-			int x = desc->polarization[cpu];
++			int x = desc->polarization[idx];
+ 
+ 			snprintf(buf, bufsz, "%s",
+ 				 mod->mode == OUTPUT_PARSABLE ?
+@@ -942,28 +1527,36 @@ get_cell_data(struct lscpu_desc *desc, int cpu, int col,
+ 		break;
+ 	case COL_ADDRESS:
+ 		if (desc->addresses)
+-			snprintf(buf, bufsz, "%d", desc->addresses[cpu]);
++			snprintf(buf, bufsz, "%d", desc->addresses[idx]);
+ 		break;
+ 	case COL_CONFIGURED:
+ 		if (!desc->configured)
+ 			break;
+ 		if (mod->mode == OUTPUT_PARSABLE)
+-			snprintf(buf, bufsz,
+-				 desc->configured[cpu] ? _("Y") : _("N"));
++			snprintf(buf, bufsz, "%s",
++				 desc->configured[idx] ? _("Y") : _("N"));
+ 		else
+-			snprintf(buf, bufsz,
+-				 desc->configured[cpu] ? _("yes") : _("no"));
++			snprintf(buf, bufsz, "%s",
++				 desc->configured[idx] ? _("yes") : _("no"));
+ 		break;
+ 	case COL_ONLINE:
+ 		if (!desc->online)
+ 			break;
+ 		if (mod->mode == OUTPUT_PARSABLE)
+-			snprintf(buf, bufsz,
++			snprintf(buf, bufsz, "%s",
+ 				 is_cpu_online(desc, cpu) ? _("Y") : _("N"));
+ 		else
+-			snprintf(buf, bufsz,
++			snprintf(buf, bufsz, "%s",
+ 				 is_cpu_online(desc, cpu) ? _("yes") : _("no"));
+ 		break;
++	case COL_MAXMHZ:
++		if (desc->maxmhz)
++			xstrncpy(buf, desc->maxmhz[idx], bufsz);
++		break;
++	case COL_MINMHZ:
++		if (desc->minmhz)
++			xstrncpy(buf, desc->minmhz[idx], bufsz);
++		break;
+ 	}
+ 	return buf;
+ }
+@@ -982,14 +1575,16 @@ get_cell_header(struct lscpu_desc *desc, int col,
+ 
+ 		for (i = desc->ncaches - 1; i >= 0; i--) {
+ 			int x = snprintf(p, sz, "%s", desc->caches[i].name);
+-			if (x <= 0 || (size_t) x + 2 > sz)
++			if (x < 0 || (size_t) x >= sz)
+ 				return NULL;
+ 			sz -= x;
+ 			p += x;
+ 			if (i > 0) {
++				if (sz < 2)
++					return NULL;
+ 				*p++ = mod->compat ? ',' : ':';
+ 				*p = '\0';
+-				sz++;
++				sz--;
+ 			}
+ 		}
+ 		if (desc->ncaches)
+@@ -1073,12 +1668,13 @@ print_parsable(struct lscpu_desc *desc, int cols[], int ncols,
+ 	 */
+ 	for (i = 0; i < desc->ncpuspos; i++) {
+ 		int c;
++		int cpu = real_cpu_num(desc, i);
+ 
+-		if (!mod->offline && desc->online && !is_cpu_online(desc, i))
++		if (!mod->offline && desc->online && !is_cpu_online(desc, cpu))
+ 			continue;
+-		if (!mod->online && desc->online && is_cpu_online(desc, i))
++		if (!mod->online && desc->online && is_cpu_online(desc, cpu))
+ 			continue;
+-		if (desc->present && !is_cpu_present(desc, i))
++		if (desc->present && !is_cpu_present(desc, cpu))
+ 			continue;
+ 		for (c = 0; c < ncols; c++) {
+ 			if (mod->compat && cols[c] == COL_CACHE) {
+@@ -1106,38 +1702,49 @@ print_readable(struct lscpu_desc *desc, int cols[], int ncols,
+ 	       struct lscpu_modifier *mod)
+ {
+ 	int i;
+-	char buf[BUFSIZ], *data;
+-	struct tt *tt = tt_new_table(0);
++	char buf[BUFSIZ];
++	const char *data;
++	struct libscols_table *table;
+ 
+-	if (!tt)
++	scols_init_debug(0);
++
++	table = scols_new_table();
++	if (!table)
+ 		 err(EXIT_FAILURE, _("failed to initialize output table"));
+ 
+ 	for (i = 0; i < ncols; i++) {
+ 		data = get_cell_header(desc, cols[i], mod, buf, sizeof(buf));
+-		tt_define_column(tt, xstrdup(data), 0, 0);
++		if (!scols_table_new_column(table, xstrdup(data), 0, 0))
++			err(EXIT_FAILURE, _("failed to initialize output column"));
+ 	}
+ 
+ 	for (i = 0; i < desc->ncpuspos; i++) {
+ 		int c;
+-		struct tt_line *line;
++		struct libscols_line *line;
++		int cpu = real_cpu_num(desc, i);
+ 
+-		if (!mod->offline && desc->online && !is_cpu_online(desc, i))
++		if (!mod->offline && desc->online && !is_cpu_online(desc, cpu))
+ 			continue;
+-		if (!mod->online && desc->online && is_cpu_online(desc, i))
++		if (!mod->online && desc->online && is_cpu_online(desc, cpu))
+ 			continue;
+-		if (desc->present && !is_cpu_present(desc, i))
++		if (desc->present && !is_cpu_present(desc, cpu))
+ 			continue;
+ 
+-		line = tt_add_line(tt, NULL);
++		line = scols_table_new_line(table, NULL);
++		if (!line)
++			err(EXIT_FAILURE, _("failed to initialize output line"));
+ 
+ 		for (c = 0; c < ncols; c++) {
+ 			data = get_cell_data(desc, i, cols[c], mod,
+ 					     buf, sizeof(buf));
+-			tt_line_set_data(line, c, data && *data ? xstrdup(data) : "-");
++			if (!data || !*data)
++				data = "-";
++			scols_line_set_data(line, c, data);
+ 		}
+ 	}
+ 
+-	tt_print_table(tt);
++	scols_print_table(table);
++	scols_unref_table(table);
+ }
+ 
+ /* output formats "<key>  <value>"*/
+@@ -1211,8 +1818,9 @@ print_summary(struct lscpu_desc *desc, struct lscpu_modifier *mod)
+ 			err(EXIT_FAILURE, _("failed to callocate cpu set"));
+ 		CPU_ZERO_S(setsize, set);
+ 		for (i = 0; i < desc->ncpuspos; i++) {
+-			if (!is_cpu_online(desc, i) && is_cpu_present(desc, i))
+-				CPU_SET_S(i, setsize, set);
++			int cpu = real_cpu_num(desc, i);
++			if (!is_cpu_online(desc, cpu) && is_cpu_present(desc, cpu))
++				CPU_SET_S(cpu, setsize, set);
+ 		}
+ 		print_cpuset(mod->hex ? _("Off-line CPU(s) mask:") :
+ 					_("Off-line CPU(s) list:"),
+@@ -1221,9 +1829,12 @@ print_summary(struct lscpu_desc *desc, struct lscpu_modifier *mod)
+ 	}
+ 
+ 	if (desc->nsockets) {
+-		int cores_per_socket, sockets_per_book, books;
++		int threads_per_core, cores_per_socket, sockets_per_book;
++		int books_per_drawer, drawers;
++		FILE *fd;
+ 
+-		cores_per_socket = sockets_per_book = books = 0;
++		threads_per_core = cores_per_socket = sockets_per_book = 0;
++		books_per_drawer = drawers = 0;
+ 		/* s390 detects its cpu topology via /proc/sysinfo, if present.
+ 		 * Using simply the cpu topology masks in sysfs will not give
+ 		 * usable results since everything is virtualized. E.g.
+@@ -1232,27 +1843,36 @@ print_summary(struct lscpu_desc *desc, struct lscpu_modifier *mod)
+ 		 * If the cpu topology is not exported (e.g. 2nd level guest)
+ 		 * fall back to old calculation scheme.
+ 		 */
+-		if (path_exist(_PATH_PROC_SYSINFO)) {
+-			FILE *fd = path_fopen("r", 0, _PATH_PROC_SYSINFO);
++		if ((fd = path_fopen("r", 0, _PATH_PROC_SYSINFO))) {
+ 			char pbuf[BUFSIZ];
+-			int t0, t1, t2;
++			int t0, t1;
+ 
+ 			while (fd && fgets(pbuf, sizeof(pbuf), fd) != NULL) {
+ 				if (sscanf(pbuf, "CPU Topology SW:%d%d%d%d%d%d",
+-					   &t0, &t1, &t2, &books, &sockets_per_book,
++					   &t0, &t1, &drawers, &books_per_drawer,
++					   &sockets_per_book,
+ 					   &cores_per_socket) == 6)
+ 					break;
+ 			}
+ 			if (fd)
+ 				fclose(fd);
+ 		}
+-		print_n(_("Thread(s) per core:"), desc->nthreads / desc->ncores);
++		if (desc->mtid)
++			threads_per_core = atoi(desc->mtid) + 1;
++		print_n(_("Thread(s) per core:"),
++			threads_per_core ?: desc->nthreads / desc->ncores);
+ 		print_n(_("Core(s) per socket:"),
+ 			cores_per_socket ?: desc->ncores / desc->nsockets);
+ 		if (desc->nbooks) {
+ 			print_n(_("Socket(s) per book:"),
+ 				sockets_per_book ?: desc->nsockets / desc->nbooks);
+-			print_n(_("Book(s):"), books ?: desc->nbooks);
++			if (desc->ndrawers) {
++				print_n(_("Book(s) per drawer:"),
++					books_per_drawer ?: desc->nbooks / desc->ndrawers);
++				print_n(_("Drawer(s):"), drawers ?: desc->ndrawers);
++			} else {
++				print_n(_("Book(s):"), books_per_drawer ?: desc->nbooks);
++			}
+ 		} else {
+ 			print_n(_("Socket(s):"), sockets_per_book ?: desc->nsockets);
+ 		}
+@@ -1261,6 +1881,8 @@ print_summary(struct lscpu_desc *desc, struct lscpu_modifier *mod)
+ 		print_n(_("NUMA node(s):"), desc->nnodes);
+ 	if (desc->vendor)
+ 		print_s(_("Vendor ID:"), desc->vendor);
++	if (desc->machinetype)
++		print_s(_("Machine type:"), desc->machinetype);
+ 	if (desc->family)
+ 		print_s(_("CPU family:"), desc->family);
+ 	if (desc->model || desc->revision)
+@@ -1271,6 +1893,14 @@ print_summary(struct lscpu_desc *desc, struct lscpu_modifier *mod)
+ 		print_s(_("Stepping:"), desc->stepping);
+ 	if (desc->mhz)
+ 		print_s(_("CPU MHz:"), desc->mhz);
++	if (desc->dynamic_mhz)
++		print_s(_("CPU dynamic MHz:"), desc->dynamic_mhz);
++	if (desc->static_mhz)
++		print_s(_("CPU static MHz:"), desc->static_mhz);
++	if (desc->maxmhz)
++		print_s(_("CPU max MHz:"), desc->maxmhz[0]);
++	if (desc->minmhz)
++		print_s(_("CPU min MHz:"), desc->minmhz[0]);
+ 	if (desc->bogomips)
+ 		print_s(_("BogoMIPS:"), desc->bogomips);
+ 	if (desc->virtflag) {
+@@ -1297,10 +1927,29 @@ print_summary(struct lscpu_desc *desc, struct lscpu_modifier *mod)
+ 		}
+ 	}
+ 
++	if (desc->necaches) {
++		char cbuf[512];
++
++		for (i = desc->necaches - 1; i >= 0; i--) {
++			snprintf(cbuf, sizeof(cbuf),
++					_("%s cache:"), desc->ecaches[i].name);
++			print_s(cbuf, desc->ecaches[i].size);
++		}
++	}
++
+ 	for (i = 0; i < desc->nnodes; i++) {
+ 		snprintf(buf, sizeof(buf), _("NUMA node%d CPU(s):"), desc->idx2nodenum[i]);
+ 		print_cpuset(buf, desc->nodemaps[i], mod->hex);
+ 	}
++
++	if (desc->flags)
++		print_s(_("Flags:"), desc->flags);
++
++	if (desc->physsockets) {
++		print_n(_("Physical sockets:"), desc->physsockets);
++		print_n(_("Physical chips:"), desc->physchips);
++		print_n(_("Physical cores/chip:"), desc->physcoresperchip);
++	}
+ }
+ 
+ static void __attribute__((__noreturn__)) usage(FILE *out)
+@@ -1310,6 +1959,9 @@ static void __attribute__((__noreturn__)) usage(FILE *out)
+ 	fputs(USAGE_HEADER, out);
+ 	fprintf(out, _(" %s [options]\n"), program_invocation_short_name);
+ 
++	fputs(USAGE_SEPARATOR, out);
++	fputs(_("Display information about the CPU architecture.\n"), out);
++
+ 	fputs(USAGE_OPTIONS, out);
+ 	fputs(_(" -a, --all               print both online and offline CPUs (default for -e)\n"), out);
+ 	fputs(_(" -b, --online            print online CPUs only (default for -p)\n"), out);
+@@ -1318,6 +1970,7 @@ static void __attribute__((__noreturn__)) usage(FILE *out)
+ 	fputs(_(" -p, --parse[=<list>]    print out a parsable format\n"), out);
+ 	fputs(_(" -s, --sysroot <dir>     use specified directory as system root\n"), out);
+ 	fputs(_(" -x, --hex               print hexadecimal masks rather than lists of CPUs\n"), out);
++	fputs(_(" -y, --physical          print physical instead of logical IDs\n"), out);
+ 	fputs(USAGE_SEPARATOR, out);
+ 	fputs(USAGE_HELP, out);
+ 	fputs(USAGE_VERSION, out);
+@@ -1327,7 +1980,7 @@ static void __attribute__((__noreturn__)) usage(FILE *out)
+ 	for (i = 0; i < ARRAY_SIZE(coldescs); i++)
+ 		fprintf(out, " %13s  %s\n", coldescs[i].name, _(coldescs[i].help));
+ 
+-	fprintf(out, _("\nFor more details see lscpu(1).\n"));
++	fprintf(out, USAGE_MAN_TAIL("lscpu(1)"));
+ 
+ 	exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
+ }
+@@ -1335,22 +1988,23 @@ static void __attribute__((__noreturn__)) usage(FILE *out)
+ int main(int argc, char *argv[])
+ {
+ 	struct lscpu_modifier _mod = { .mode = OUTPUT_SUMMARY }, *mod = &_mod;
+-	struct lscpu_desc _desc = { .flags = 0 }, *desc = &_desc;
++	struct lscpu_desc _desc = { .flags = NULL }, *desc = &_desc;
+ 	int c, i;
+ 	int columns[ARRAY_SIZE(coldescs)], ncolumns = 0;
+ 	int cpu_modifier_specified = 0;
+ 
+ 	static const struct option longopts[] = {
+-		{ "all",        no_argument,       0, 'a' },
+-		{ "online",     no_argument,       0, 'b' },
+-		{ "offline",    no_argument,       0, 'c' },
+-		{ "help",	no_argument,       0, 'h' },
+-		{ "extended",	optional_argument, 0, 'e' },
+-		{ "parse",	optional_argument, 0, 'p' },
+-		{ "sysroot",	required_argument, 0, 's' },
+-		{ "hex",	no_argument,	   0, 'x' },
+-		{ "version",	no_argument,	   0, 'V' },
+-		{ NULL,		0, 0, 0 }
++		{ "all",        no_argument,       NULL, 'a' },
++		{ "online",     no_argument,       NULL, 'b' },
++		{ "offline",    no_argument,       NULL, 'c' },
++		{ "help",	no_argument,       NULL, 'h' },
++		{ "extended",	optional_argument, NULL, 'e' },
++		{ "parse",	optional_argument, NULL, 'p' },
++		{ "sysroot",	required_argument, NULL, 's' },
++		{ "physical",	no_argument,	   NULL, 'y' },
++		{ "hex",	no_argument,	   NULL, 'x' },
++		{ "version",	no_argument,	   NULL, 'V' },
++		{ NULL,		0, NULL, 0 }
+ 	};
+ 
+ 	static const ul_excl_t excl[] = {	/* rows and cols in ASCII order */
+@@ -1365,7 +2019,7 @@ int main(int argc, char *argv[])
+ 	textdomain(PACKAGE);
+ 	atexit(close_stdout);
+ 
+-	while ((c = getopt_long(argc, argv, "abce::hp::s:xV", longopts, NULL)) != -1) {
++	while ((c = getopt_long(argc, argv, "abce::hp::s:xyV", longopts, NULL)) != -1) {
+ 
+ 		err_exclusive_options(c, longopts, excl, excl_st);
+ 
+@@ -1404,12 +2058,14 @@ int main(int argc, char *argv[])
+ 		case 'x':
+ 			mod->hex = 1;
+ 			break;
++		case 'y':
++			mod->physical = 1;
++			break;
+ 		case 'V':
+-			printf(_("%s from %s\n"), program_invocation_short_name,
+-			       PACKAGE_STRING);
++			printf(UTIL_LINUX_VERSION);
+ 			return EXIT_SUCCESS;
+ 		default:
+-			usage(stderr);
++			errtryhelp(EXIT_FAILURE);
+ 		}
+ 	}
+ 
+@@ -1433,17 +2089,27 @@ int main(int argc, char *argv[])
+ 	read_basicinfo(desc, mod);
+ 
+ 	for (i = 0; i < desc->ncpuspos; i++) {
++		/* only consider present CPUs */
++		if (desc->present &&
++		    !CPU_ISSET(real_cpu_num(desc, i), desc->present))
++			continue;
+ 		read_topology(desc, i);
+ 		read_cache(desc, i);
+ 		read_polarization(desc, i);
+ 		read_address(desc, i);
+ 		read_configured(desc, i);
++		read_max_mhz(desc, i);
++		read_min_mhz(desc, i);
+ 	}
+ 
+ 	if (desc->caches)
+ 		qsort(desc->caches, desc->ncaches,
+ 				sizeof(struct cpu_cache), cachecmp);
+ 
++	if (desc->ecaches)
++		qsort(desc->ecaches, desc->necaches,
++				sizeof(struct cpu_cache), cachecmp);
++
+ 	read_nodes(desc);
+ 	read_hypervisor(desc, mod);
+ 
+@@ -1468,6 +2134,8 @@ int main(int argc, char *argv[])
+ 			columns[ncolumns++] = COL_CPU;
+ 			if (desc->nodemaps)
+ 				columns[ncolumns++] = COL_NODE;
++			if (desc->drawermaps)
++				columns[ncolumns++] = COL_DRAWER;
+ 			if (desc->bookmaps)
+ 				columns[ncolumns++] = COL_BOOK;
+ 			if (desc->socketmaps)
+@@ -1484,6 +2152,10 @@ int main(int argc, char *argv[])
+ 				columns[ncolumns++] = COL_POLARIZATION;
+ 			if (desc->addresses)
+ 				columns[ncolumns++] = COL_ADDRESS;
++			if (desc->maxmhz)
++				columns[ncolumns++] = COL_MAXMHZ;
++			if (desc->minmhz)
++				columns[ncolumns++] = COL_MINMHZ;
+ 		}
+ 		print_readable(desc, columns, ncolumns, mod);
+ 		break;
+diff --git a/sys-utils/lscpu.h b/sys-utils/lscpu.h
+new file mode 100644
+index 0000000..4906c26
+--- /dev/null
++++ b/sys-utils/lscpu.h
+@@ -0,0 +1,26 @@
++#ifndef LSCPU_H
++#define LSCPU_H
++
++/* hypervisor vendors */
++enum {
++	HYPER_NONE	= 0,
++	HYPER_XEN,
++	HYPER_KVM,
++	HYPER_MSHV,
++	HYPER_VMWARE,
++	HYPER_IBM,		/* sys-z powervm */
++	HYPER_VSERVER,
++	HYPER_UML,
++	HYPER_INNOTEK,		/* VBOX */
++	HYPER_HITACHI,
++	HYPER_PARALLELS,	/* OpenVZ/VIrtuozzo */
++	HYPER_VBOX,
++	HYPER_OS400,
++	HYPER_PHYP,
++	HYPER_SPAR,
++	HYPER_WSL,
++};
++
++extern int read_hypervisor_dmi(void);
++
++#endif /* LSCPU_H */
+-- 
+2.9.3
+
diff --git a/SOURCES/0116-fdisk-use-sysfs_devno_is_wholedisk.patch b/SOURCES/0116-fdisk-use-sysfs_devno_is_wholedisk.patch
new file mode 100644
index 0000000..e758236
--- /dev/null
+++ b/SOURCES/0116-fdisk-use-sysfs_devno_is_wholedisk.patch
@@ -0,0 +1,58 @@
+From e86fe103accdf5dd688b3710c873094cfa41ae5f Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 21 Mar 2017 15:11:29 +0100
+Subject: [PATCH 116/116] fdisk: use sysfs_devno_is_wholedisk()
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1402183
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ lib/wholedisk.c | 23 ++++++++---------------
+ 1 file changed, 8 insertions(+), 15 deletions(-)
+
+diff --git a/lib/wholedisk.c b/lib/wholedisk.c
+index 5161a1e..7c63204 100644
+--- a/lib/wholedisk.c
++++ b/lib/wholedisk.c
+@@ -1,14 +1,10 @@
+-/*
+- * No copyright is claimed.  This code is in the public domain; do with
+- * it what you wish.
+- *
+- * Written by Karel Zak <kzak@redhat.com>
+- */
++
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <ctype.h>
+ 
+ #include "blkdev.h"
++#include "sysfs.h"
+ #include "wholedisk.h"
+ 
+ int is_whole_disk_fd(int fd, const char *name)
+@@ -35,16 +31,13 @@ int is_whole_disk_fd(int fd, const char *name)
+ 
+ int is_whole_disk(const char *name)
+ {
+-	int fd = -1, res = 0;
+-#ifdef HDIO_GETGEO
+-	fd = open(name, O_RDONLY|O_CLOEXEC);
+-	if (fd != -1)
+-#endif
+-		res = is_whole_disk_fd(fd, name);
++	dev_t devno = sysfs_devname_to_devno(name, NULL);
++
++	if (sysfs_devno_is_lvm_private(devno) ||
++	    sysfs_devno_is_wholedisk(devno) <= 0)
++		return 0;
+ 
+-	if (fd != -1)
+-		close(fd);
+-	return res;
++	return 1;
+ }
+ 
+ #ifdef TEST_PROGRAM
+-- 
+2.9.3
+
diff --git a/SOURCES/0117-zramctl-add-bash-completion.patch b/SOURCES/0117-zramctl-add-bash-completion.patch
new file mode 100644
index 0000000..22f54f3
--- /dev/null
+++ b/SOURCES/0117-zramctl-add-bash-completion.patch
@@ -0,0 +1,93 @@
+From 0b8ef4d8289fa1af0296ae01faf0e60293c725fd Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Wed, 22 Mar 2017 12:13:43 +0100
+Subject: [PATCH] zramctl: add bash completion
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1358755
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ bash-completion/Makemodule.am |  3 ++-
+ bash-completion/zramctl       | 57 +++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 59 insertions(+), 1 deletion(-)
+ create mode 100644 bash-completion/zramctl
+
+diff --git a/bash-completion/Makemodule.am b/bash-completion/Makemodule.am
+index c3791e7..84ab258 100644
+--- a/bash-completion/Makemodule.am
++++ b/bash-completion/Makemodule.am
+@@ -30,7 +30,8 @@ dist_bashcompletion_DATA = \
+ 	bash-completion/setsid \
+ 	bash-completion/tailf \
+ 	bash-completion/whereis \
+-	bash-completion/wipefs
++	bash-completion/wipefs \
++	bash-completion/zramctl
+ 
+ # disk-utils...
+ if BUILD_BFS
+diff --git a/bash-completion/zramctl b/bash-completion/zramctl
+new file mode 100644
+index 0000000..a4ef536
+--- /dev/null
++++ b/bash-completion/zramctl
+@@ -0,0 +1,57 @@
++_zramctl_module()
++{
++	local cur prev OPTS
++	COMPREPLY=()
++	cur="${COMP_WORDS[COMP_CWORD]}"
++	prev="${COMP_WORDS[COMP_CWORD-1]}"
++	case $prev in
++		'-a'|'--algorithm')
++			COMPREPLY=( $(compgen -W "lzo lz4" -- $cur) )
++			return 0
++			;;
++		'-o'|'--output')
++			local prefix realcur OUTPUT_ALL OUTPUT
++			realcur="${cur##*,}"
++			prefix="${cur%$realcur}"
++			OUTPUT_ALL="NAME DISKSIZE DATA COMPR ALGORITHM STREAMS ZERO-PAGES TOTAL MOUNTPOINT"
++			for WORD in $OUTPUT_ALL; do
++				if ! [[ $prefix == *"$WORD"* ]]; then
++					OUTPUT="$WORD $OUTPUT"
++				fi
++			done
++			compopt -o nospace
++			COMPREPLY=( $(compgen -P "$prefix" -W "$OUTPUT" -S ',' -- $realcur) )
++			return 0
++			;;
++		'-s'|'--size')
++			COMPREPLY=( $(compgen -W "size" -- $cur) )
++			return 0
++			;;
++		'-t'|'--streams')
++			COMPREPLY=( $(compgen -W "number" -- $cur) )
++			return 0
++			;;
++	esac
++	case $cur in
++		-*)
++			OPTS="	--algorithm
++				--bytes
++				--find
++				--noheadings
++				--output
++				--raw
++				--reset
++				--size
++				--streams
++				--help
++				--version"
++			COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) )
++			return 0
++			;;
++	esac
++	local IFS=$'\n'
++	compopt -o filenames
++	COMPREPLY=( $(compgen -f -- ${cur:-"/dev/zram"}) )
++	return 0
++}
++complete -F _zramctl_module zramctl
+-- 
+2.9.3
+
diff --git a/SOURCES/0118-zramctl-make-mm_stat-parser-more-robust.patch b/SOURCES/0118-zramctl-make-mm_stat-parser-more-robust.patch
new file mode 100644
index 0000000..9e5c205
--- /dev/null
+++ b/SOURCES/0118-zramctl-make-mm_stat-parser-more-robust.patch
@@ -0,0 +1,38 @@
+From a7f11e525e9dd5abf844ada0ddd0ae74950e2e40 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Thu, 30 Mar 2017 12:10:01 +0200
+Subject: [PATCH] zramctl: make mm_stat parser more robust
+
+Let's fallback to attribute files if mm_stat file is incomplete. It
+should not happen, but I have seen RHEL7 kernel where is no
+num_migrated/pages_compacted attribute...
+
+Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1358755
+Upstream: http://github.com/karelzak/util-linux/commit/2546d54bd8b0ceac75d6d7e6c483479022d97509
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ sys-utils/zramctl.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/sys-utils/zramctl.c b/sys-utils/zramctl.c
+index 853401c..c3112d6 100644
+--- a/sys-utils/zramctl.c
++++ b/sys-utils/zramctl.c
+@@ -359,8 +359,12 @@ static char *get_mm_stat(struct zram *z, size_t idx, int bytes)
+ 		str = sysfs_strdup(sysfs, "mm_stat");
+ 		if (str) {
+ 			z->mm_stat = strv_split(str, " ");
+-			if (strv_length(z->mm_stat) < ARRAY_SIZE(mm_stat_names))
+-				errx(EXIT_FAILURE, _("Failed to parse mm_stat"));
++
++			/* make sure kernel provides mm_stat as expected */
++			if (strv_length(z->mm_stat) < ARRAY_SIZE(mm_stat_names)) {
++				strv_free(z->mm_stat);
++				z->mm_stat = NULL;
++			}
+ 		}
+ 		z->mm_stat_probed = 1;
+ 		free(str);
+-- 
+2.9.3
+
diff --git a/SOURCES/0119-fdisk-improve-menu-and-u-for-GPT.patch b/SOURCES/0119-fdisk-improve-menu-and-u-for-GPT.patch
new file mode 100644
index 0000000..2d8099a
--- /dev/null
+++ b/SOURCES/0119-fdisk-improve-menu-and-u-for-GPT.patch
@@ -0,0 +1,74 @@
+From 846f494a89cfe00bcea5e12d9526df76be9196a6 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 4 Apr 2017 11:12:29 +0200
+Subject: [PATCH] fdisk: improve menu and 'u' for GPT
+
+* print 't' in the menu for GPT
+* don't toggle to cylinders for GPT
+* force sectors if GPT detected
+* improve expert 'd' command description
+
+Addresses: Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1344720
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ fdisks/fdisk.c | 16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+diff --git a/fdisks/fdisk.c b/fdisks/fdisk.c
+index 177921a..b47b975 100644
+--- a/fdisks/fdisk.c
++++ b/fdisks/fdisk.c
+@@ -70,7 +70,7 @@ static const struct menulist_descr menulist[] = {
+ 	{'c', N_("toggle the dos compatibility flag"), {FDISK_DISKLABEL_DOS, 0}},
+ 	{'c', N_("toggle the mountable flag"), {FDISK_DISKLABEL_SUN, 0}},
+ 	{'d', N_("delete a partition"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF | FDISK_DISKLABEL_GPT, 0}},
+-	{'d', N_("print the raw data in the partition table"), {0, FDISK_DISKLABEL_ANY}},
++	{'d', N_("print the raw data in the first sector"), {0, FDISK_DISKLABEL_ANY}},
+ 	{'e', N_("change number of extra sectors per cylinder"), {0, FDISK_DISKLABEL_SUN}},
+ 	{'e', N_("edit drive data"), {FDISK_DISKLABEL_OSF, 0}},
+ 	{'e', N_("list extended partitions"), {0, FDISK_DISKLABEL_DOS}},
+@@ -94,7 +94,7 @@ static const struct menulist_descr menulist[] = {
+ 	{'s', N_("change number of sectors/track"), {0, FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN}},
+ 	{'s', N_("create a new empty Sun disklabel"), {~FDISK_DISKLABEL_OSF, 0}},
+ 	{'s', N_("show complete disklabel"), {FDISK_DISKLABEL_OSF, 0}},
+-	{'t', N_("change a partition's system id"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF, 0}},
++	{'t', N_("change a partition's system id"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF | FDISK_DISKLABEL_GPT, 0}},
+ 	{'u', N_("change display/entry units"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF, 0}},
+ 	{'v', N_("verify the partition table"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_GPT,
+ 						 FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_GPT}},
+@@ -1018,6 +1018,11 @@ static void command_prompt(struct fdisk_context *cxt)
+ 		fdisk_context_switch_label(cxt, "dos");
+ 	}
+ 
++	if (fdisk_is_disklabel(cxt, GPT) && fdisk_context_use_cylinders(cxt)) {
++		printf(_("Use cylinders for GPT is unsupported. "));
++		toggle_units(cxt);
++	}
++
+ 	while (1) {
+ 
+ 		assert(cxt->label);
+@@ -1073,6 +1078,8 @@ static void command_prompt(struct fdisk_context *cxt)
+ 			break;
+ 		case 'g':
+ 			fdisk_create_disklabel(cxt, "gpt");
++			if (fdisk_is_disklabel(cxt, GPT) && fdisk_context_use_cylinders(cxt))
++				toggle_units(cxt);
+ 			break;
+ 		case 'G':
+ 			fdisk_create_disklabel(cxt, "sgi");
+@@ -1107,7 +1114,10 @@ static void command_prompt(struct fdisk_context *cxt)
+ 			change_partition_type(cxt);
+ 			break;
+ 		case 'u':
+-			toggle_units(cxt);
++			if (fdisk_is_disklabel(cxt, GPT) && !fdisk_context_use_cylinders(cxt))
++				printf(_("Use cylinders for GPT is unsupported."));
++			else
++				toggle_units(cxt);
+ 			break;
+ 		case 'v':
+ 			verify(cxt);
+-- 
+2.9.3
+
diff --git a/SOURCES/0120-tests-update-for-RHEL7.4-changes.patch b/SOURCES/0120-tests-update-for-RHEL7.4-changes.patch
new file mode 100644
index 0000000..6e21777
--- /dev/null
+++ b/SOURCES/0120-tests-update-for-RHEL7.4-changes.patch
@@ -0,0 +1,209 @@
+From e5d31b4ffb3f978a8935d35301a59eeafe6a50d4 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 4 Apr 2017 11:58:09 +0200
+Subject: [PATCH 120/121] tests: update for RHEL7.4 changes
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1360764
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1344726
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1402183
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ lib/Makemodule.am                            | 1 +
+ tests/expected/fdisk/gpt                     | 5 +++++
+ tests/expected/lscpu/lscpu-armv7             | 5 +++++
+ tests/expected/lscpu/lscpu-s390-kvm          | 2 ++
+ tests/expected/lscpu/lscpu-s390-lpar         | 2 ++
+ tests/expected/lscpu/lscpu-s390-zvm          | 2 ++
+ tests/expected/lscpu/lscpu-x86_64-64cpu      | 5 ++++-
+ tests/expected/lscpu/lscpu-x86_64-dell_e4310 | 5 ++++-
+ tests/ts/fdisk/gpt                           | 3 ++-
+ 9 files changed, 27 insertions(+), 3 deletions(-)
+
+diff --git a/lib/Makemodule.am b/lib/Makemodule.am
+index faf9d74..acae27a 100644
+--- a/lib/Makemodule.am
++++ b/lib/Makemodule.am
+@@ -82,6 +82,7 @@ test_ismounted_LDADD = libcommon.la
+ 
+ test_wholedisk_SOURCES = lib/wholedisk.c
+ test_wholedisk_CFLAGS = -DTEST_PROGRAM
++test_wholedisk_LDADD = libcommon.la
+ 
+ test_mangle_SOURCES = lib/mangle.c
+ test_mangle_CFLAGS = -DTEST_PROGRAM
+diff --git a/tests/expected/fdisk/gpt b/tests/expected/fdisk/gpt
+index b73d5c3..017d819 100644
+--- a/tests/expected/fdisk/gpt
++++ b/tests/expected/fdisk/gpt
+@@ -7,6 +7,7 @@ Units = sectors of 1 * 512 = 512 bytes
+ Sector size (logical/physical): 512 bytes / 512 bytes
+ I/O size (minimum/optimal): 512 bytes / 512 bytes
+ Disk label type: gpt
++Disk identifier: <removed>
+ 
+ 
+ #         Start          End    Size  Type            Name
+@@ -21,6 +22,7 @@ Units = sectors of 1 * 512 = 512 bytes
+ Sector size (logical/physical): 512 bytes / 512 bytes
+ I/O size (minimum/optimal): 512 bytes / 512 bytes
+ Disk label type: gpt
++Disk identifier: <removed>
+ 
+ 
+ #         Start          End    Size  Type            Name
+@@ -42,6 +44,7 @@ Units = sectors of 1 * 512 = 512 bytes
+ Sector size (logical/physical): 512 bytes / 512 bytes
+ I/O size (minimum/optimal): 512 bytes / 512 bytes
+ Disk label type: gpt
++Disk identifier: <removed>
+ 
+ 
+ #         Start          End    Size  Type            Name
+@@ -63,6 +66,7 @@ Units = sectors of 1 * 512 = 512 bytes
+ Sector size (logical/physical): 512 bytes / 512 bytes
+ I/O size (minimum/optimal): 512 bytes / 512 bytes
+ Disk label type: gpt
++Disk identifier: <removed>
+ 
+ 
+ #         Start          End    Size  Type            Name
+@@ -83,6 +87,7 @@ Units = sectors of 1 * 512 = 512 bytes
+ Sector size (logical/physical): 512 bytes / 512 bytes
+ I/O size (minimum/optimal): 512 bytes / 512 bytes
+ Disk label type: gpt
++Disk identifier: <removed>
+ 
+ 
+ #         Start          End    Size  Type            Name
+diff --git a/tests/expected/lscpu/lscpu-armv7 b/tests/expected/lscpu/lscpu-armv7
+index a1b691c..bcb16cc 100644
+--- a/tests/expected/lscpu/lscpu-armv7
++++ b/tests/expected/lscpu/lscpu-armv7
+@@ -3,6 +3,11 @@ On-line CPU(s) list:   0,1
+ Thread(s) per core:    1
+ Core(s) per socket:    2
+ Socket(s):             1
++Model:                 4
++CPU max MHz:           1700.0000
++CPU min MHz:           200.0000
++BogoMIPS:              1694.10
++Flags:                 swp half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpv4 idiva idivt
+ 
+ # The following is the parsable format, which can be fed to other
+ # programs. Each different item in every column has an unique ID
+diff --git a/tests/expected/lscpu/lscpu-s390-kvm b/tests/expected/lscpu/lscpu-s390-kvm
+index 1aa42f9..66d1c04 100644
+--- a/tests/expected/lscpu/lscpu-s390-kvm
++++ b/tests/expected/lscpu/lscpu-s390-kvm
+@@ -6,11 +6,13 @@ Core(s) per socket:    1
+ Socket(s) per book:    1
+ Book(s):               3
+ Vendor ID:             IBM/S390
++Machine type:          2817
+ BogoMIPS:              14367.00
+ Hypervisor:            KVM/Linux
+ Hypervisor vendor:     KVM
+ Virtualization type:   full
+ Dispatching mode:      horizontal
++Flags:                 esan3 zarch stfle msa ldisp eimm dfp edat etf3eh highgprs
+ 
+ # The following is the parsable format, which can be fed to other
+ # programs. Each different item in every column has an unique ID
+diff --git a/tests/expected/lscpu/lscpu-s390-lpar b/tests/expected/lscpu/lscpu-s390-lpar
+index 0799ab9..9c8ac2c 100644
+--- a/tests/expected/lscpu/lscpu-s390-lpar
++++ b/tests/expected/lscpu/lscpu-s390-lpar
+@@ -7,11 +7,13 @@ Core(s) per socket:    4
+ Socket(s) per book:    6
+ Book(s):               4
+ Vendor ID:             IBM/S390
++Machine type:          2817
+ BogoMIPS:              14367.00
+ Hypervisor:            PR/SM
+ Hypervisor vendor:     IBM
+ Virtualization type:   full
+ Dispatching mode:      vertical
++Flags:                 esan3 zarch stfle msa ldisp eimm dfp etf3eh highgprs
+ 
+ # The following is the parsable format, which can be fed to other
+ # programs. Each different item in every column has an unique ID
+diff --git a/tests/expected/lscpu/lscpu-s390-zvm b/tests/expected/lscpu/lscpu-s390-zvm
+index 04dcf76..4cd6b8f 100644
+--- a/tests/expected/lscpu/lscpu-s390-zvm
++++ b/tests/expected/lscpu/lscpu-s390-zvm
+@@ -6,11 +6,13 @@ Core(s) per socket:    1
+ Socket(s) per book:    1
+ Book(s):               4
+ Vendor ID:             IBM/S390
++Machine type:          2817
+ BogoMIPS:              14367.00
+ Hypervisor:            z/VM 6.1.0
+ Hypervisor vendor:     IBM
+ Virtualization type:   full
+ Dispatching mode:      horizontal
++Flags:                 esan3 zarch stfle msa ldisp eimm dfp etf3eh highgprs
+ 
+ # The following is the parsable format, which can be fed to other
+ # programs. Each different item in every column has an unique ID
+diff --git a/tests/expected/lscpu/lscpu-x86_64-64cpu b/tests/expected/lscpu/lscpu-x86_64-64cpu
+index 32aa57c..07990ea 100644
+--- a/tests/expected/lscpu/lscpu-x86_64-64cpu
++++ b/tests/expected/lscpu/lscpu-x86_64-64cpu
+@@ -11,7 +11,9 @@ Model:                 46
+ Model name:            Intel(R) Xeon(R) CPU           X7550  @ 2.00GHz
+ Stepping:              6
+ CPU MHz:               1064.000
+-BogoMIPS:              3989.44
++CPU max MHz:           1996.0000
++CPU min MHz:           1064.0000
++BogoMIPS:              3990.31
+ Virtualization:        VT-x
+ L1d cache:             32K
+ L1i cache:             32K
+@@ -20,6 +22,7 @@ L3 cache:              18432K
+ NUMA node0 CPU(s):     0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62
+ NUMA node2 CPU(s):     1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61
+ NUMA node3 CPU(s):     3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63
++Flags:                 fpu vme de pse tsc msr pae mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good xtopology nonstop_tsc aperfmperf pni dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm dca sse4_1 sse4_2 x2apic popcnt lahf_lm ida epb dts tpr_shadow vnmi flexpriority ept vpid
+ 
+ # The following is the parsable format, which can be fed to other
+ # programs. Each different item in every column has an unique ID
+diff --git a/tests/expected/lscpu/lscpu-x86_64-dell_e4310 b/tests/expected/lscpu/lscpu-x86_64-dell_e4310
+index a81878d..39ec32c 100644
+--- a/tests/expected/lscpu/lscpu-x86_64-dell_e4310
++++ b/tests/expected/lscpu/lscpu-x86_64-dell_e4310
+@@ -11,13 +11,16 @@ Model:                 37
+ Model name:            Intel(R) Core(TM) i5 CPU       M 560  @ 2.67GHz
+ Stepping:              5
+ CPU MHz:               1199.000
+-BogoMIPS:              5319.97
++CPU max MHz:           2667.0000
++CPU min MHz:           1199.0000
++BogoMIPS:              5319.92
+ Virtualization:        VT-x
+ L1d cache:             32K
+ L1i cache:             32K
+ L2 cache:              256K
+ L3 cache:              3072K
+ NUMA node0 CPU(s):     0-3
++Flags:                 fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm sse4_1 sse4_2 popcnt aes lahf_lm ida arat dts tpr_shadow vnmi flexpriority ept vpid
+ 
+ # The following is the parsable format, which can be fed to other
+ # programs. Each different item in every column has an unique ID
+diff --git a/tests/ts/fdisk/gpt b/tests/ts/fdisk/gpt
+index a0902ca..ec3438f 100755
+--- a/tests/ts/fdisk/gpt
++++ b/tests/ts/fdisk/gpt
+@@ -38,7 +38,8 @@ function print_layout {
+ 	echo -ne "\n---layout----------" >> $TS_OUTPUT
+ 	$TS_CMD_FDISK -l ${TEST_IMAGE_NAME} 2> /dev/null | \
+ 		sed 's/^.*\.img/__ts_dev__/g;
+-		     s/^[[:blank:]]*Device Boot/     Device Boot/g' >> $TS_OUTPUT 2>&1
++		     s/^[[:blank:]]*Device Boot/     Device Boot/g;
++		     s/^Disk identifier:.*/Disk identifier: <removed>/g' >> $TS_OUTPUT 2>&1
+ 	echo -ne   "-------------------\n\n" >> $TS_OUTPUT
+ }
+ 
+-- 
+2.9.3
+
diff --git a/SOURCES/0121-zramctl-be-more-specific-about-default-output.patch b/SOURCES/0121-zramctl-be-more-specific-about-default-output.patch
new file mode 100644
index 0000000..105761a
--- /dev/null
+++ b/SOURCES/0121-zramctl-be-more-specific-about-default-output.patch
@@ -0,0 +1,31 @@
+From 46d4d1c8d1b62c8f2dda1639e75b5d0e6bafaf27 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 4 Apr 2017 12:06:45 +0200
+Subject: [PATCH 121/121] zramctl: be more specific about default output
+
+Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1358755
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ sys-utils/zramctl.8 | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/sys-utils/zramctl.8 b/sys-utils/zramctl.8
+index f6fc45c..9ca2983 100644
+--- a/sys-utils/zramctl.8
++++ b/sys-utils/zramctl.8
+@@ -39,9 +39,9 @@ Set up a zram device:
+ .SH DESCRIPTION
+ .B zramctl
+ is used to quickly set up zram device parameters, to reset zram devices, and to
+-query the status of used zram devices.  If no option is given, all zram devices
+-are shown.
+-
++query the status of used zram devices.
++.PP
++If no option is given, all non-zero size zram devices are shown.
+ .SH OPTIONS
+ .TP
+ .BR \-a , " \-\-algorithm lzo" | lz4
+-- 
+2.9.3
+
diff --git a/SOURCES/0122-libfdisk-gpt-fix-UUID-printing.patch b/SOURCES/0122-libfdisk-gpt-fix-UUID-printing.patch
new file mode 100644
index 0000000..eefa83f
--- /dev/null
+++ b/SOURCES/0122-libfdisk-gpt-fix-UUID-printing.patch
@@ -0,0 +1,46 @@
+From a95f7a89ed81fb3d7c3135baae20b056b7f8e661 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Wed, 10 May 2017 15:26:55 +0200
+Subject: [PATCH] libfdisk: (gpt) fix UUID printing
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1344726
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libfdisk/src/gpt.c | 14 +++-----------
+ 1 file changed, 3 insertions(+), 11 deletions(-)
+
+diff --git a/libfdisk/src/gpt.c b/libfdisk/src/gpt.c
+index 899e1b2..612ce09 100644
+--- a/libfdisk/src/gpt.c
++++ b/libfdisk/src/gpt.c
+@@ -1690,7 +1690,7 @@ static int gpt_create_disklabel(struct fdisk_context *cxt)
+ {
+ 	int rc = 0;
+ 	ssize_t esz = 0;
+-	struct gpt_guid *uid;
++	char str[37];
+ 	struct fdisk_gpt_label *gpt;
+ 
+ 	assert(cxt);
+@@ -1746,16 +1746,8 @@ static int gpt_create_disklabel(struct fdisk_context *cxt)
+ 	cxt->label->nparts_max = le32_to_cpu(gpt->pheader->npartition_entries);
+ 	cxt->label->nparts_cur = 0;
+ 
+-	uid = &gpt->pheader->disk_guid;
+-	fdisk_info(cxt, _("Building a new GPT disklabel "
+-			    "(GUID: %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X)\n"),
+-			    uid->time_low, uid->time_mid,
+-			    uid->time_hi_and_version,
+-			    uid->clock_seq_hi,
+-			    uid->clock_seq_low,
+-			    uid->node[0], uid->node[1],
+-			    uid->node[2], uid->node[3],
+-			    uid->node[4], uid->node[5]);
++	guid_to_string(&gpt->pheader->disk_guid, str);
++	fdisk_info(cxt, _("Building a new GPT disklabel (GUID: %s)\n"), str);
+ 	fdisk_label_set_changed(cxt->label, 1);
+ done:
+ 	return rc;
+-- 
+2.9.3
+
diff --git a/SOURCES/0123-libblkid-Add-metadata-signature-check-for-IMSM-on-4K.patch b/SOURCES/0123-libblkid-Add-metadata-signature-check-for-IMSM-on-4K.patch
new file mode 100644
index 0000000..b17f426
--- /dev/null
+++ b/SOURCES/0123-libblkid-Add-metadata-signature-check-for-IMSM-on-4K.patch
@@ -0,0 +1,60 @@
+From 2181ce4a5726c4c72e68e6964b7ef7442e507707 Mon Sep 17 00:00:00 2001
+From: Alexey Obitotskiy <aleksey.obitotskiy@intel.com>
+Date: Fri, 24 Jun 2016 11:59:35 +0200
+Subject: [PATCH] libblkid: Add metadata signature check for IMSM on 4Kn drives
+
+Drives with 512 and 4K sectors have different offset for
+metadata signature. Without signature detected on 4Kn drives
+those drives will not be recognized as raid member. This
+patch adds checking for IMSM signature for 4Kn drives.
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1451704
+Signed-off-by: Alexey Obitotskiy <aleksey.obitotskiy@intel.com>
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libblkid/src/superblocks/isw_raid.c | 13 +++++++------
+ 1 file changed, 7 insertions(+), 6 deletions(-)
+
+diff --git a/libblkid/src/superblocks/isw_raid.c b/libblkid/src/superblocks/isw_raid.c
+index 065c2b2..81d53a1 100644
+--- a/libblkid/src/superblocks/isw_raid.c
++++ b/libblkid/src/superblocks/isw_raid.c
+@@ -25,11 +25,11 @@ struct isw_metadata {
+ 
+ #define ISW_SIGNATURE		"Intel Raid ISM Cfg Sig. "
+ 
+-
+ static int probe_iswraid(blkid_probe pr,
+ 		const struct blkid_idmag *mag __attribute__((__unused__)))
+ {
+ 	uint64_t off;
++	unsigned int sector_size;
+ 	struct isw_metadata *isw;
+ 
+ 	if (pr->size < 0x10000)
+@@ -37,16 +37,17 @@ static int probe_iswraid(blkid_probe pr,
+ 	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+ 		return 1;
+ 
+-	off = ((pr->size / 0x200) - 2) * 0x200;
+-	isw = (struct isw_metadata *)
+-			blkid_probe_get_buffer(pr,
+-					off,
+-					sizeof(struct isw_metadata));
++	sector_size = blkid_probe_get_sectorsize(pr);
++	off = ((pr->size / sector_size) - 2) * sector_size;
++
++	isw = (struct isw_metadata *)blkid_probe_get_buffer(pr,
++			off, sizeof(struct isw_metadata));
+ 	if (!isw)
+ 		return errno ? -errno : 1;
+ 
+ 	if (memcmp(isw->sig, ISW_SIGNATURE, sizeof(ISW_SIGNATURE)-1) != 0)
+ 		return 1;
++
+ 	if (blkid_probe_sprintf_version(pr, "%6s",
+ 			&isw->sig[sizeof(ISW_SIGNATURE)-1]) != 0)
+ 		return 1;
+-- 
+2.9.4
+
diff --git a/SOURCES/0124-lscpu-use-sysfs-for-table-access-if-available.patch b/SOURCES/0124-lscpu-use-sysfs-for-table-access-if-available.patch
new file mode 100644
index 0000000..d31a3ca
--- /dev/null
+++ b/SOURCES/0124-lscpu-use-sysfs-for-table-access-if-available.patch
@@ -0,0 +1,66 @@
+From 6999f3f3ca525bb6b132f4ed804e7f8fe62e5f79 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+Date: Wed, 12 Apr 2017 10:11:29 +0100
+Subject: [PATCH] lscpu: use sysfs for table access if available
+
+On ARM systems, accessing SMBIOS tables via /dev/mem using read()
+calls is not supported. The reason is that such tables are usually
+located in EFI_RUNTIME_SERVICE_DATA memory, which is not covered
+by the linear mapping on those systems, and so read() calls will
+fail.
+
+So instead, use the /sys/firmware/dmi/tables/DMI sysfs file, which
+contains the entire structure table array, and will be available
+on any recent Linux system, even on ones that only export the rev3
+SMBIOS entry point, which is currently ignored by lscpu.
+
+Note that the max 'num' value is inferred from the size. This is not
+a limitation of the sysfs interface, but a limitation of the rev3
+entry point, which no longer carries a number of array elements.
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1455664
+Upstream: http://github.com/karelzak/util-linux/commit/92a6392c41c11bcb49af9f129dfbd1fed651f044
+Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+Tested-by: Alexander Graf <agraf@suse.de>
+Reviewed-by: Alexander Graf <agraf@suse.de>
+---
+ sys-utils/lscpu-dmi.c | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+diff --git a/sys-utils/lscpu-dmi.c b/sys-utils/lscpu-dmi.c
+index 0e497d1..a8298ff 100644
+--- a/sys-utils/lscpu-dmi.c
++++ b/sys-utils/lscpu-dmi.c
+@@ -192,6 +192,18 @@ static int hypervisor_decode_smbios(uint8_t *buf, const char *devmem)
+ 		devmem);
+ }
+ 
++static int hypervisor_decode_sysfw(void)
++{
++	static char const sys_fw_dmi_tables[] = "/sys/firmware/dmi/tables/DMI";
++	struct stat st;
++
++	if (stat(sys_fw_dmi_tables, &st))
++		return -1;
++
++	return hypervisor_from_dmi_table(0, st.st_size, st.st_size / 4,
++					 sys_fw_dmi_tables);
++}
++
+ /*
+  * Probe for EFI interface
+  */
+@@ -242,6 +254,10 @@ int read_hypervisor_dmi(void)
+ 	    || '\0' != 0)
+ 		return rc;
+ 
++	rc = hypervisor_decode_sysfw();
++	if (rc >= 0)
++		return rc;
++
+ 	/* First try EFI (ia64, Intel-based Mac) */
+ 	switch (address_from_efi(&fp)) {
+ 		case EFI_NOT_FOUND:
+-- 
+2.9.4
+
diff --git a/SOURCES/0125-lscpu-improve-for-offline-CPUs-on-AMD.patch b/SOURCES/0125-lscpu-improve-for-offline-CPUs-on-AMD.patch
new file mode 100644
index 0000000..a6a214c
--- /dev/null
+++ b/SOURCES/0125-lscpu-improve-for-offline-CPUs-on-AMD.patch
@@ -0,0 +1,44 @@
+From 4150eb1025c059f9459f98ef6c6c3fac730eaf93 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Thu, 1 Jun 2017 12:07:41 +0200
+Subject: [PATCH] lscpu: improve for offline CPUs on AMD
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1457744
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ sys-utils/lscpu.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/sys-utils/lscpu.c b/sys-utils/lscpu.c
+index 683fd66..1ee73f3 100644
+--- a/sys-utils/lscpu.c
++++ b/sys-utils/lscpu.c
+@@ -1550,11 +1550,11 @@ get_cell_data(struct lscpu_desc *desc, int idx, int col,
+ 				 is_cpu_online(desc, cpu) ? _("yes") : _("no"));
+ 		break;
+ 	case COL_MAXMHZ:
+-		if (desc->maxmhz)
++		if (desc->maxmhz && desc->maxmhz[idx])
+ 			xstrncpy(buf, desc->maxmhz[idx], bufsz);
+ 		break;
+ 	case COL_MINMHZ:
+-		if (desc->minmhz)
++		if (desc->minmhz && desc->minmhz[idx])
+ 			xstrncpy(buf, desc->minmhz[idx], bufsz);
+ 		break;
+ 	}
+@@ -1897,9 +1897,9 @@ print_summary(struct lscpu_desc *desc, struct lscpu_modifier *mod)
+ 		print_s(_("CPU dynamic MHz:"), desc->dynamic_mhz);
+ 	if (desc->static_mhz)
+ 		print_s(_("CPU static MHz:"), desc->static_mhz);
+-	if (desc->maxmhz)
++	if (desc->maxmhz && desc->maxmhz[0])
+ 		print_s(_("CPU max MHz:"), desc->maxmhz[0]);
+-	if (desc->minmhz)
++	if (desc->minmhz && desc->minmhz[0])
+ 		print_s(_("CPU min MHz:"), desc->minmhz[0]);
+ 	if (desc->bogomips)
+ 		print_s(_("BogoMIPS:"), desc->bogomips);
+-- 
+2.9.4
+
diff --git a/SOURCES/0126-libmount-use-eacess-rather-than-open-to-check-mtab-u.patch b/SOURCES/0126-libmount-use-eacess-rather-than-open-to-check-mtab-u.patch
new file mode 100644
index 0000000..60e8fa4
--- /dev/null
+++ b/SOURCES/0126-libmount-use-eacess-rather-than-open-to-check-mtab-u.patch
@@ -0,0 +1,68 @@
+From 04cad06bed055a5dd373b2f5babc8000a76597a6 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Mon, 9 Oct 2017 12:44:48 +0200
+Subject: [PATCH] libmount: use eacess() rather than open() to check mtab/utab
+
+The open() syscall is probably the most strong way how to check write
+accessibility in all situations, but it's overkill and on some
+paranoid systems with enabled audit/selinux. It fills logs with
+"Permission denied" entries. Let's use eaccess() if available.
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1499760
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ configure.ac         |  1 +
+ libmount/src/utils.c | 19 +++++++++++++------
+ 2 files changed, 14 insertions(+), 6 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 78258d677..96c5838cf 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -315,6 +315,7 @@ AC_CHECK_FUNCS([ \
+ 	__fpending \
+ 	secure_getenv \
+ 	__secure_getenv \
++	eaccess \
+ 	err \
+ 	errx \
+ 	fsync \
+diff --git a/libmount/src/utils.c b/libmount/src/utils.c
+index 5c374b432..a275d0a0e 100644
+--- a/libmount/src/utils.c
++++ b/libmount/src/utils.c
+@@ -653,18 +653,25 @@ done:
+ 
+ static int try_write(const char *filename)
+ {
+-	int fd;
++	int rc = 0;
+ 
+ 	if (!filename)
+ 		return -EINVAL;
+ 
+-	fd = open(filename, O_RDWR|O_CREAT|O_CLOEXEC,
++#ifdef HAVE_EACCESS
++	if (eaccess(filename, R_OK|W_OK) != 0)
++		rc = -errno;
++#else
++	{
++		int fd = open(filename, O_RDWR|O_CREAT|O_CLOEXEC,
+ 			    S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH);
+-	if (fd >= 0) {
+-		close(fd);
+-		return 0;
++		if (fd < 0)
++			rc = -errno;
++		else
++			close(fd);
+ 	}
+-	return -errno;
++#endif
++	return rc;
+ }
+ 
+ /**
+-- 
+2.13.6
+
diff --git a/SOURCES/0127-libmount-fix-access-utab-write-test.patch b/SOURCES/0127-libmount-fix-access-utab-write-test.patch
new file mode 100644
index 0000000..02caa94
--- /dev/null
+++ b/SOURCES/0127-libmount-fix-access-utab-write-test.patch
@@ -0,0 +1,226 @@
+From 945d26162e639fd9ae3a774f1debaaa9511c7919 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Wed, 8 Nov 2017 16:47:40 +0100
+Subject: [PATCH] libmount: fix access() utab write test
+
+The commit c08396c7691e1e6a04b6b45892e7e4612ceed8d7 replaces
+open(O_CREATE) with ecaccess(). Unfortunately, another code depends on
+the original behavior.
+
+* let's make utab when really necessary rather than in the try_write() test
+
+* __mnt_new_table_from_file() returns NULL if tab-file does not
+ exists. This is incorrect for tab_update.c stuff. We need empty table
+ in this case.
+
+* we can check /run/mount/ directory for write access if
+  eaccess(filename) return ENOENT (because file does not exist)
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1499760
+Upstream: http://github.com/karelzak/util-linux/commit/06ff935ec3ad2290025b555ff32b590680af565f
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libmount/src/mountP.h     |  2 +-
+ libmount/src/tab_parse.c  | 11 +++++++----
+ libmount/src/tab_update.c |  9 +++++----
+ libmount/src/utils.c      | 42 +++++++++++++++++++++++++++++++-----------
+ 4 files changed, 44 insertions(+), 20 deletions(-)
+
+diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h
+index 6cabcedeb..8b3f92e17 100644
+--- a/libmount/src/mountP.h
++++ b/libmount/src/mountP.h
+@@ -278,7 +278,7 @@ struct libmnt_table {
+ 	struct list_head	ents;	/* list of entries (libmnt_fs) */
+ };
+ 
+-extern struct libmnt_table *__mnt_new_table_from_file(const char *filename, int fmt);
++extern struct libmnt_table *__mnt_new_table_from_file(const char *filename, int fmt, int empty_for_enoent);
+ 
+ /*
+  * Tab file format
+diff --git a/libmount/src/tab_parse.c b/libmount/src/tab_parse.c
+index 987e671fa..c629c67ad 100644
+--- a/libmount/src/tab_parse.c
++++ b/libmount/src/tab_parse.c
+@@ -714,7 +714,7 @@ int mnt_table_parse_dir(struct libmnt_table *tb, const char *dirname)
+ 	return __mnt_table_parse_dir(tb, dirname);
+ }
+ 
+-struct libmnt_table *__mnt_new_table_from_file(const char *filename, int fmt)
++struct libmnt_table *__mnt_new_table_from_file(const char *filename, int fmt, int empty_for_enoent)
+ {
+ 	struct libmnt_table *tb;
+ 	struct stat st;
+@@ -723,7 +723,8 @@ struct libmnt_table *__mnt_new_table_from_file(const char *filename, int fmt)
+ 	if (!filename)
+ 		return NULL;
+ 	if (stat(filename, &st))
+-		return NULL;
++		return empty_for_enoent ? mnt_new_table() : NULL;
++
+ 	tb = mnt_new_table();
+ 	if (tb) {
+ 		tb->fmt = fmt;
+@@ -748,8 +749,10 @@ struct libmnt_table *__mnt_new_table_from_file(const char *filename, int fmt)
+  */
+ struct libmnt_table *mnt_new_table_from_file(const char *filename)
+ {
+-	assert(filename);
+-	return __mnt_new_table_from_file(filename, MNT_FMT_GUESS);
++	if (!filename)
++		return NULL;
++
++	return __mnt_new_table_from_file(filename, MNT_FMT_GUESS, 0);
+ }
+ 
+ /**
+diff --git a/libmount/src/tab_update.c b/libmount/src/tab_update.c
+index 1e7f32be0..5f503cad7 100644
+--- a/libmount/src/tab_update.c
++++ b/libmount/src/tab_update.c
+@@ -567,6 +567,7 @@ leave:
+ 
+ 	unlink(uq);	/* be paranoid */
+ 	free(uq);
++	DBG(UPDATE, mnt_debug_h(upd, "%s: done [rc=%d]", upd->filename, rc));
+ 	return rc;
+ }
+ 
+@@ -600,7 +601,7 @@ static int update_add_entry(struct libmnt_update *upd, struct libmnt_lock *lc)
+ 		return rc;
+ 
+ 	tb = __mnt_new_table_from_file(upd->filename,
+-			upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB);
++			upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB, 1);
+ 	if (tb)
+ 		rc = add_file_entry(tb, upd);
+ 	if (lc)
+@@ -626,7 +627,7 @@ static int update_remove_entry(struct libmnt_update *upd, struct libmnt_lock *lc
+ 		return rc;
+ 
+ 	tb = __mnt_new_table_from_file(upd->filename,
+-			upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB);
++			upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB, 1);
+ 	if (tb) {
+ 		struct libmnt_fs *rem = mnt_table_find_target(tb, upd->target, MNT_ITER_BACKWARD);
+ 		if (rem) {
+@@ -656,7 +657,7 @@ static int update_modify_target(struct libmnt_update *upd, struct libmnt_lock *l
+ 		return rc;
+ 
+ 	tb = __mnt_new_table_from_file(upd->filename,
+-			upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB);
++			upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB, 1);
+ 	if (tb) {
+ 		struct libmnt_fs *cur = mnt_table_find_target(tb,
+ 				mnt_fs_get_srcpath(upd->fs), MNT_ITER_BACKWARD);
+@@ -693,7 +694,7 @@ static int update_modify_options(struct libmnt_update *upd, struct libmnt_lock *
+ 		return rc;
+ 
+ 	tb = __mnt_new_table_from_file(upd->filename,
+-			upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB);
++			upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB, 1);
+ 	if (tb) {
+ 		struct libmnt_fs *cur = mnt_table_find_target(tb,
+ 					mnt_fs_get_target(fs),
+diff --git a/libmount/src/utils.c b/libmount/src/utils.c
+index a275d0a0e..fa33bd9a1 100644
+--- a/libmount/src/utils.c
++++ b/libmount/src/utils.c
+@@ -651,18 +651,37 @@ done:
+ 	return rc;
+ }
+ 
+-static int try_write(const char *filename)
++static int try_write(const char *filename, const char *directory)
+ {
+ 	int rc = 0;
+ 
+ 	if (!filename)
+ 		return -EINVAL;
+ 
++	DBG(UTILS, mnt_debug("try write %s dir: %s", filename, directory));
++
+ #ifdef HAVE_EACCESS
+-	if (eaccess(filename, R_OK|W_OK) != 0)
+-		rc = -errno;
+-#else
++	/* Try eaccess() first, because open() is overkill, may be monitored by
++	 * audit and we don't want to fill logs by our checks...
++	 */
++	if (eaccess(filename, R_OK|W_OK) == 0) {
++		DBG(UTILS, mnt_debug(" access OK"));
++		return 0;
++	} else if (errno != ENOENT) {
++		DBG(UTILS, mnt_debug(" access FAILED"));
++		return -errno;
++	} else if (directory) {
++		/* file does not exist; try if directory is writable */
++		if (eaccess(directory, R_OK|W_OK) != 0)
++			rc = -errno;
++
++		DBG(UTILS, mnt_debug(" access %s [%s]", rc ? "FAILED" : "OK", directory));
++		return rc;
++	} else
++#endif
+ 	{
++		DBG(UTILS, mnt_debug(" doing open-write test"));
++
+ 		int fd = open(filename, O_RDWR|O_CREAT|O_CLOEXEC,
+ 			    S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH);
+ 		if (fd < 0)
+@@ -670,7 +689,6 @@ static int try_write(const char *filename)
+ 		else
+ 			close(fd);
+ 	}
+-#endif
+ 	return rc;
+ }
+ 
+@@ -704,7 +722,7 @@ int mnt_has_regular_mtab(const char **mtab, int *writable)
+ 		/* file exist */
+ 		if (S_ISREG(st.st_mode)) {
+ 			if (writable)
+-				*writable = !try_write(filename);
++				*writable = !try_write(filename, NULL);
+ 			return 1;
+ 		}
+ 		goto done;
+@@ -712,7 +730,7 @@ int mnt_has_regular_mtab(const char **mtab, int *writable)
+ 
+ 	/* try to create the file */
+ 	if (writable) {
+-		*writable = !try_write(filename);
++		*writable = !try_write(filename, NULL);
+ 		if (*writable)
+ 			return 1;
+ 	}
+@@ -750,7 +768,7 @@ int mnt_has_regular_utab(const char **utab, int *writable)
+ 		/* file exist */
+ 		if (S_ISREG(st.st_mode)) {
+ 			if (writable)
+-				*writable = !try_write(filename);
++				*writable = !try_write(filename, NULL);
+ 			return 1;
+ 		}
+ 		goto done;	/* it's not regular file */
+@@ -767,11 +785,13 @@ int mnt_has_regular_utab(const char **utab, int *writable)
+ 		rc = mkdir(dirname, S_IWUSR|
+ 				    S_IRUSR|S_IRGRP|S_IROTH|
+ 				    S_IXUSR|S_IXGRP|S_IXOTH);
+-		free(dirname);
+-		if (rc && errno != EEXIST)
++		if (rc && errno != EEXIST) {
++			free(dirname);
+ 			goto done;			/* probably EACCES */
++		}
+ 
+-		*writable = !try_write(filename);
++		*writable = !try_write(filename, dirname);
++		free(dirname);
+ 		if (*writable)
+ 			return 1;
+ 	}
+-- 
+2.13.6
+
diff --git a/SOURCES/2.17-kill-strtol.patch b/SOURCES/2.17-kill-strtol.patch
new file mode 100644
index 0000000..bedd0ab
--- /dev/null
+++ b/SOURCES/2.17-kill-strtol.patch
@@ -0,0 +1,22 @@
+diff -up util-linux-2.23.2/misc-utils/kill.c.kzak util-linux-2.23.2/misc-utils/kill.c
+--- util-linux-2.23.2/misc-utils/kill.c.kzak	2013-06-13 09:46:10.448650861 +0200
++++ util-linux-2.23.2/misc-utils/kill.c	2014-09-25 10:08:27.879359310 +0200
+@@ -48,6 +48,7 @@
+ #include <ctype.h>		/* for isdigit() */
+ #include <unistd.h>
+ #include <signal.h>
++#include <errno.h>
+ 
+ #include "c.h"
+ #include "nls.h"
+@@ -279,8 +280,9 @@ int main (int argc, char *argv[])
+ 	the rest of the arguments should be process ids and names.
+ 	kill them.  */
+     for (errors = 0; (arg = *argv) != NULL; argv++) {
++	errno = 0;
+ 	pid = strtol (arg, &ep, 10);
+-	if (! *ep)
++	if (errno == 0 && ep && *ep == '\0' && arg < ep)
+ 	    errors += kill_verbose (arg, pid, numsig);
+ 	else  {
+ 	    struct proc_processes *ps = proc_open_processes();
diff --git a/SOURCES/2.23-login-lastlog-create.patch b/SOURCES/2.23-login-lastlog-create.patch
new file mode 100644
index 0000000..839193a
--- /dev/null
+++ b/SOURCES/2.23-login-lastlog-create.patch
@@ -0,0 +1,12 @@
+diff -up util-linux-2.23.2/login-utils/login.c.kzak util-linux-2.23.2/login-utils/login.c
+--- util-linux-2.23.2/login-utils/login.c.kzak	2013-07-30 10:39:26.222738397 +0200
++++ util-linux-2.23.2/login-utils/login.c	2013-09-09 09:01:39.923225757 +0200
+@@ -502,7 +502,7 @@ static void log_lastlog(struct login_con
+ 	if (!cxt->pwd)
+ 		return;
+ 
+-	fd = open(_PATH_LASTLOG, O_RDWR, 0);
++	fd = open(_PATH_LASTLOG, O_RDWR | O_CREAT, 0);
+ 	if (fd < 0)
+ 		return;
+ 
diff --git a/SOURCES/2.24-agetty-clocal.patch b/SOURCES/2.24-agetty-clocal.patch
new file mode 100644
index 0000000..22fe361
--- /dev/null
+++ b/SOURCES/2.24-agetty-clocal.patch
@@ -0,0 +1,149 @@
+diff -up util-linux-2.23.2/term-utils/agetty.c.kzak util-linux-2.23.2/term-utils/agetty.c
+--- util-linux-2.23.2/term-utils/agetty.c.kzak	2013-07-30 11:14:18.124912322 +0200
++++ util-linux-2.23.2/term-utils/agetty.c	2013-09-09 09:07:46.406689270 +0200
+@@ -132,13 +132,20 @@ struct options {
+ 	int delay;			/* Sleep seconds before prompt */
+ 	int nice;			/* Run login with this priority */
+ 	int numspeed;			/* number of baud rates to try */
++	int clocal;			/* CLOCAL_MODE_* */
+ 	speed_t speeds[MAX_SPEED];	/* baud rates to be tried */
+ };
+ 
++enum {
++	CLOCAL_MODE_AUTO = 0,
++	CLOCAL_MODE_ALWAYS,
++	CLOCAL_MODE_NEVER
++};
++
+ #define	F_PARSE		(1<<0)	/* process modem status messages */
+ #define	F_ISSUE		(1<<1)	/* display /etc/issue */
+ #define	F_RTSCTS	(1<<2)	/* enable RTS/CTS flow control */
+-#define F_LOCAL		(1<<3)	/* force local */
++
+ #define F_INITSTRING    (1<<4)	/* initstring is set */
+ #define F_WAITCRLF	(1<<5)	/* wait for CR or LF */
+ #define F_CUSTISSUE	(1<<6)	/* give alternative issue file */
+@@ -235,10 +242,13 @@ static void login_options_to_argv(char *
+ static char *fakehost;
+ 
+ #ifdef DEBUGGING
+-#define debug(s) do { fprintf(dbf,s); fflush(dbf); } while (0)
++# ifndef DEBUG_OUTPUT
++#  define DEBUG_OUTPUT "/dev/ttyp0"
++# endif
++# define debug(s) do { fprintf(dbf,s); fflush(dbf); } while (0)
+ FILE *dbf;
+ #else
+-#define debug(s) do { ; } while (0)
++# define debug(s) do { ; } while (0)
+ #endif
+ 
+ int main(int argc, char **argv)
+@@ -270,7 +280,7 @@ int main(int argc, char **argv)
+ 	sigaction(SIGINT, &sa, &sa_int);
+ 
+ #ifdef DEBUGGING
+-	dbf = fopen("/dev/ttyp0", "w");
++	dbf = fopen(DEBUG_OUTPUT, "w");
+ 	for (int i = 1; i < argc; i++)
+ 		debug(argv[i]);
+ #endif				/* DEBUGGING */
+@@ -311,8 +321,10 @@ int main(int argc, char **argv)
+ 			   strlen(options.initstring));
+ 	}
+ 
+-	if (!serial_tty_option(&options, F_LOCAL))
+-		/* Go to blocking write mode unless -L is specified. */
++	if (options.flags & F_VCONSOLE || options.clocal != CLOCAL_MODE_ALWAYS)
++		/* Go to blocking mode unless -L is specified, this change
++		 * affects stdout, stdin and stderr as all the file descriptors
++		 * are created by dup().   */
+ 		fcntl(STDOUT_FILENO, F_SETFL,
+ 		      fcntl(STDOUT_FILENO, F_GETFL, 0) & ~O_NONBLOCK);
+ 
+@@ -420,6 +432,12 @@ int main(int argc, char **argv)
+ 				options.tty);
+ 	}
+ 
++#ifdef DEBUGGING
++	fprintf(dbf, "read %c\n", ch);
++	if (close_stream(dbf) != 0)
++		log_err("write failed: %s", DEBUG_OUTPUT);
++#endif
++
+ 	/* Let the login program take care of password validation. */
+ 	execv(options.login, login_argv);
+ 	log_err(_("%s: can't exec %s: %m"), options.tty, login_argv[0]);
+@@ -534,7 +552,7 @@ static void parse_args(int argc, char **
+ 		{  "init-string",    required_argument,  0,  'I'  },
+ 		{  "noclear",	     no_argument,	 0,  'J'  },
+ 		{  "login-program",  required_argument,  0,  'l'  },
+-		{  "local-line",     no_argument,	 0,  'L'  },
++		{  "local-line",     optional_argument,	 0,  'L'  },
+ 		{  "extract-baud",   no_argument,	 0,  'm'  },
+ 		{  "skip-login",     no_argument,	 0,  'n'  },
+ 		{  "nonewline",	     no_argument,	 0,  'N'  },
+@@ -603,7 +621,18 @@ static void parse_args(int argc, char **
+ 			op->login = optarg;
+ 			break;
+ 		case 'L':
+-			op->flags |= F_LOCAL;
++			/* -L and -L=always have the same meaning */
++			op->clocal = CLOCAL_MODE_ALWAYS;
++			if (optarg) {
++				if (strcmp(optarg, "=always") == 0)
++					op->clocal = CLOCAL_MODE_ALWAYS;
++				else if (strcmp(optarg, "=never") == 0)
++					op->clocal = CLOCAL_MODE_NEVER;
++				else if (strcmp(optarg, "=auto") == 0)
++					op->clocal = CLOCAL_MODE_AUTO;
++				else
++					log_err(_("unssuported --local-line mode argument"));
++			}
+ 			break;
+ 		case 'm':
+ 			op->flags |= F_PARSE;
+@@ -1090,8 +1119,19 @@ static void termio_init(struct options *
+ 	cfsetispeed(tp, ispeed);
+ 	cfsetospeed(tp, ospeed);
+ 
+-	if (op->flags & F_LOCAL)
+-		tp->c_cflag |= CLOCAL;
++	/* The default is to follow setting from kernel, but it's possible
++	 * to explicitly remove/add CLOCAL flag by -L[=<mode>]*/
++	switch (op->clocal) {
++	case CLOCAL_MODE_ALWAYS:
++		tp->c_cflag |= CLOCAL;		/* -L or -L=always */
++		break;
++	case CLOCAL_MODE_NEVER:
++		tp->c_cflag &= ~CLOCAL;		/* -L=never */
++		break;
++	case CLOCAL_MODE_AUTO:			/* -L=auto */
++		break;
++	}
++
+ #ifdef HAVE_STRUCT_TERMIOS_C_LINE
+ 	tp->c_line = 0;
+ #endif
+@@ -1412,9 +1452,10 @@ static char *get_logname(struct options
+ 
+ 			if (read(STDIN_FILENO, &c, 1) < 1) {
+ 
+-				/* Do not report trivial like EINTR/EIO errors. */
++				/* The terminal could be open with O_NONBLOCK when
++				 * -L (force CLOCAL) is specified...  */
+ 				if (errno == EINTR || errno == EAGAIN) {
+-					usleep(1000);
++					usleep(250000);
+ 					continue;
+ 				}
+ 				switch (errno) {
+@@ -1648,7 +1689,7 @@ static void __attribute__ ((__noreturn__
+ 	fputs(_(" -i, --noissue              do not display issue file\n"), out);
+ 	fputs(_(" -I, --init-string <string> set init string\n"), out);
+ 	fputs(_(" -l, --login-program <file> specify login program\n"), out);
+-	fputs(_(" -L, --local-line           force local line\n"), out);
++	fputs(_(" -L, --local-line[=<mode>]  cotrol local line flag\n"), out);
+ 	fputs(_(" -m, --extract-baud         extract baud rate during connect\n"), out);
+ 	fputs(_(" -n, --skip-login           do not prompt for login\n"), out);
+ 	fputs(_(" -o, --login-options <opts> options that are passed to login\n"), out);
diff --git a/SOURCES/2.24-agetty-etc-os-release.patch b/SOURCES/2.24-agetty-etc-os-release.patch
new file mode 100644
index 0000000..43b901a
--- /dev/null
+++ b/SOURCES/2.24-agetty-etc-os-release.patch
@@ -0,0 +1,176 @@
+diff -up util-linux-2.23.2/include/pathnames.h.kzak util-linux-2.23.2/include/pathnames.h
+--- util-linux-2.23.2/include/pathnames.h.kzak	2013-07-30 10:39:26.201738190 +0200
++++ util-linux-2.23.2/include/pathnames.h	2013-09-12 13:05:35.928359383 +0200
+@@ -63,6 +63,7 @@
+ 
+ /* used in term-utils/agetty.c */
+ #define _PATH_ISSUE		"/etc/issue"
++#define _PATH_OS_RELEASE	"/etc/os-release"
+ #define _PATH_NUMLOCK_ON	_PATH_LOCALSTATEDIR "/numlock-on"
+ 
+ #define _PATH_LOGINDEFS		"/etc/login.defs"
+diff -up util-linux-2.23.2/term-utils/agetty.8.kzak util-linux-2.23.2/term-utils/agetty.8
+--- util-linux-2.23.2/term-utils/agetty.8.kzak	2013-07-30 10:58:20.889261333 +0200
++++ util-linux-2.23.2/term-utils/agetty.8	2013-09-12 13:05:35.928359383 +0200
+@@ -310,6 +310,14 @@ Insert the current date.
+ .TP
+ s
+ Insert the system name, the name of the operating system. Same as `uname \-s'.
++See also \\S escape code.
++.TP
++S or S{VARIABLE}
++Insert the VARIABLE data from \fI/etc/os-release\fP.  If the VARIABLE argument
++is not specified then use PRETTY_NAME from the file or the system name (see \\s).
++This escape code allows to keep \fI/etc/issue\fP distribution and release
++independent.  Note that \\S{ANSI_COLOR} is converted to the real terminal
++escape sequence.
+ .TP
+ l
+ Insert the name of the current tty line.
+@@ -368,11 +376,14 @@ the system status file.
+ .B /etc/issue
+ printed before the login prompt.
+ .TP
++.B /etc/os-release
++operating system identification data.
++.TP
+ .B /dev/console
+ problem reports (if syslog(3) is not used).
+ .TP
+ .B /etc/inittab
+-\fIinit\fP(8) configuration file.
++\fIinit\fP(8) configuration file for SysV-style init daemon.
+ .SH BUGS
+ .ad
+ .fi
+diff -up util-linux-2.23.2/term-utils/agetty.c.kzak util-linux-2.23.2/term-utils/agetty.c
+--- util-linux-2.23.2/term-utils/agetty.c.kzak	2013-09-12 13:05:35.927359379 +0200
++++ util-linux-2.23.2/term-utils/agetty.c	2013-09-12 13:05:35.929359388 +0200
+@@ -129,6 +129,7 @@ struct options {
+ 	char *issue;			/* alternative issue file */
+ 	char *erasechars;		/* string with erase chars */
+ 	char *killchars;		/* string with kill chars */
++	char *osrelease;		/* /etc/os-release data */
+ 	int delay;			/* Sleep seconds before prompt */
+ 	int nice;			/* Run login with this priority */
+ 	int numspeed;			/* number of baud rates to try */
+@@ -431,7 +432,8 @@ int main(int argc, char **argv)
+ 			log_warn(_("%s: can't change process priority: %m"),
+ 				options.tty);
+ 	}
+-
++	if (options.osrelease)
++		free(options.osrelease);
+ #ifdef DEBUGGING
+ 	fprintf(dbf, "read %c\n", ch);
+ 	if (close_stream(dbf) != 0)
+@@ -1279,6 +1281,84 @@ static char *xgetdomainname(void)
+ 	return NULL;
+ }
+ 
++static char *read_os_release(struct options *op, const char *varname)
++{
++	int fd = -1;
++	struct stat st;
++	size_t varsz = strlen(varname);
++	char *p, *buf = NULL, *ret = NULL;
++
++	/* read the file only once */
++	if (!op->osrelease) {
++		fd = open(_PATH_OS_RELEASE, O_RDONLY);
++		if (fd == -1) {
++			log_warn(_("cannot open: %s: %m"), _PATH_OS_RELEASE);
++			return NULL;
++		}
++
++		if (fstat(fd, &st) < 0 || st.st_size > 4 * 1024 * 1024)
++			goto done;
++
++		op->osrelease = malloc(st.st_size + 1);
++		if (!op->osrelease)
++			log_err(_("failed to allocate memory: %m"));
++		if (read_all(fd, op->osrelease, st.st_size) != (ssize_t) st.st_size) {
++			free(op->osrelease);
++			op->osrelease = NULL;
++			goto done;
++		}
++		op->osrelease[st.st_size] = 0;
++	}
++	buf = strdup(op->osrelease);
++	if (!buf)
++		log_err(_("failed to allocate memory: %m"));
++	p = buf;
++
++	for (;;) {
++		char *eol, *eon;
++
++		p += strspn(p, "\n\r");
++		p += strspn(p, " \t\n\r");
++		if (!*p)
++			break;
++		if (strspn(p, "#;\n") != 0) {
++			p += strcspn(p, "\n\r");
++			continue;
++		}
++		if (strncmp(p, varname, varsz) != 0) {
++			p += strcspn(p, "\n\r");
++			continue;
++		}
++		p += varsz;
++		p += strspn(p, " \t\n\r=\"");
++		eol = p + strcspn(p, "\n\r");
++		*eol = '\0';
++		eon = eol-1;
++		while (eon > p) {
++			if (*eon == '\t' || *eon == ' ') {
++				eon--;
++				continue;
++			}
++			if (*eon == '"') {
++				*eon = '\0';
++				break;
++			}
++			break;
++		}
++		if (ret)
++			free(ret);
++		ret = strdup(p);
++		if (!ret)
++			log_err(_("failed to allocate memory: %m"));
++		p = eol + 1;
++	}
++done:
++	free(buf);
++	if (fd >= 0)
++		close(fd);
++	return ret;
++}
++
+ /* Show login prompt, optionally preceded by /etc/issue contents. */
+ static void do_prompt(struct options *op, struct termios *tp)
+ {
+@@ -1968,6 +2048,24 @@ static void output_special_char(unsigned
+ 		}
+ 		break;
+ 	}
++	case 'S':
++	{
++		char *var = NULL, varname[64];
++
++		if (get_escape_argument(fp, varname, sizeof(varname)))
++			var = read_os_release(op, varname);
++		else if (!(var = read_os_release(op, "PRETTY_NAME")))
++			var = uts.sysname;
++		if (var) {
++			if (strcmp(varname, "ANSI_COLOR") == 0)
++				printf("\033[%sm", var);
++			else
++				printf("%s", var);
++			if (var != uts.sysname)
++				free(var);
++		}
++		break;
++	}
+ 	case 'u':
+ 	case 'U':
+ 	{
diff --git a/SOURCES/2.24-blockdev-setbsz-hint.patch b/SOURCES/2.24-blockdev-setbsz-hint.patch
new file mode 100644
index 0000000..6bb5957
--- /dev/null
+++ b/SOURCES/2.24-blockdev-setbsz-hint.patch
@@ -0,0 +1,42 @@
+From 7ab32ae64d05f018c171ba1525bc337805d84391 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Fri, 11 Oct 2013 11:16:23 +0200
+Subject: [PATCH] blockdev: add note about --setbsz usability
+
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ disk-utils/blockdev.8 | 4 +++-
+ disk-utils/blockdev.c | 2 +-
+ 2 files changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/disk-utils/blockdev.8 b/disk-utils/blockdev.8
+index 2b3d64c..f4282da 100644
+--- a/disk-utils/blockdev.8
++++ b/disk-utils/blockdev.8
+@@ -68,7 +68,9 @@ Get size in 512-byte sectors.
+ .IP "\fB\-\-rereadpt\fP"
+ Reread partition table
+ .IP "\fB\-\-setbsz\fP \fIbytes\fP"
+-Set blocksize.
++Set blocksize. Note that the block size is specific to the current file
++descriptor opening the block device, so the change of block size only persists
++for as long as blockdev has the device open, and is lost once blockdev exits.
+ .IP "\fB\-\-setfra\fP \fIsectors\fP"
+ Set filesystem readahead (same like --setra on 2.6 kernels).
+ .IP "\fB\-\-setra\fP \fIsectors\fP"
+diff --git a/disk-utils/blockdev.c b/disk-utils/blockdev.c
+index 4543818..d030217 100644
+--- a/disk-utils/blockdev.c
++++ b/disk-utils/blockdev.c
+@@ -127,7 +127,7 @@ static const struct bdc bdcms[] =
+ 		.argname = "<bytes>",
+ 		.argtype = ARG_INT,
+ 		.flags = FL_NORESULT,
+-	        .help = N_("set blocksize")
++	        .help = N_("set blocksize on file descriptor opening the block device")
+ 	},{
+ 		IOCTL_ENTRY(BLKGETSIZE),
+ 		.name = "--getsize",
+-- 
+1.8.3.1
+
diff --git a/SOURCES/2.24-fsck-fstab.patch b/SOURCES/2.24-fsck-fstab.patch
new file mode 100644
index 0000000..113c52b
--- /dev/null
+++ b/SOURCES/2.24-fsck-fstab.patch
@@ -0,0 +1,22 @@
+diff -up util-linux-2.23.2/disk-utils/fsck.c.kzak util-linux-2.23.2/disk-utils/fsck.c
+--- util-linux-2.23.2/disk-utils/fsck.c.kzak	2013-06-13 09:46:10.377650254 +0200
++++ util-linux-2.23.2/disk-utils/fsck.c	2014-03-25 12:46:59.525939425 +0100
+@@ -437,10 +437,14 @@ static void load_fs_info(void)
+ 	if (mnt_table_parse_fstab(fstab, path)) {
+ 		if (!path)
+ 			path = mnt_get_fstab_path();
+-		if (errno)
+-			warn(_("%s: failed to parse fstab"), path);
+-		else
+-			warnx(_("%s: failed to parse fstab"), path);
++
++		/* don't print error when there is no fstab at all */
++		if (access(path, F_OK) == 0) {
++			if (errno)
++				warn(_("%s: failed to parse fstab"), path);
++			else
++				warnx(_("%s: failed to parse fstab"), path);
++		}
+ 	}
+ }
+ 
diff --git a/SOURCES/2.24-libfdisk-fix-SIGFPE.patch b/SOURCES/2.24-libfdisk-fix-SIGFPE.patch
new file mode 100644
index 0000000..bb8e872
--- /dev/null
+++ b/SOURCES/2.24-libfdisk-fix-SIGFPE.patch
@@ -0,0 +1,40 @@
+From 44baaedaffee029dca76796b933412d97a19dff6 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Mon, 9 Sep 2013 10:57:50 +0200
+Subject: [PATCH] libfdisk: fix SIGFPE
+
+ #0 recount_geometry at libfdisk/src/alignment.c:143
+ #1 fdisk_discover_geometry at libfdisk/src/alignment.c:205
+ #2 fdisk_context_assign_device at libfdisk/src/context.c:173
+ #3 print_partition_table_from_option at fdisks/fdisk.c:924
+
+References: https://bugzilla.redhat.com/show_bug.cgi?id=1005566
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libfdisk/src/alignment.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/libfdisk/src/alignment.c b/libfdisk/src/alignment.c
+index ac44e73..4d4ab48 100644
+--- a/libfdisk/src/alignment.c
++++ b/libfdisk/src/alignment.c
+@@ -193,11 +193,12 @@ int fdisk_discover_geometry(struct fdisk_context *cxt)
+ 
+ 	/* what the kernel/bios thinks the geometry is */
+ 	blkdev_get_geometry(cxt->dev_fd, &h, &s);
+-	if (!h && !s) {
+-		/* unable to discover geometry, use default values */
+-		s = 63;
++
++	/* defaults */
++	if (!h)
+ 		h = 255;
+-	}
++	if (!s)
++		s = 63;
+ 
+ 	/* obtained heads and sectors */
+ 	cxt->geom.heads = h;
+-- 
+1.8.1.4
+
diff --git a/SOURCES/2.24-libmount-3.14.patch b/SOURCES/2.24-libmount-3.14.patch
new file mode 100644
index 0000000..64de1a9
--- /dev/null
+++ b/SOURCES/2.24-libmount-3.14.patch
@@ -0,0 +1,80 @@
+diff -up util-linux-2.23.2/libmount/src/tab.c.kzak util-linux-2.23.2/libmount/src/tab.c
+--- util-linux-2.23.2/libmount/src/tab.c.kzak	2013-07-30 10:39:26.218738358 +0200
++++ util-linux-2.23.2/libmount/src/tab.c	2014-09-25 10:53:43.525269554 +0200
+@@ -47,6 +47,8 @@
+ #include "strutils.h"
+ #include "loopdev.h"
+ 
++static int is_mountinfo(struct libmnt_table *tb);
++
+ /**
+  * mnt_new_table:
+  *
+@@ -233,7 +235,7 @@ int mnt_table_get_root_fs(struct libmnt_
+ 	assert(tb);
+ 	assert(root);
+ 
+-	if (!tb || !root)
++	if (!tb || !root || !is_mountinfo(tb))
+ 		return -EINVAL;
+ 
+ 	DBG(TAB, mnt_debug_h(tb, "lookup root fs"));
+@@ -241,8 +243,6 @@ int mnt_table_get_root_fs(struct libmnt_
+ 	mnt_reset_iter(&itr, MNT_ITER_FORWARD);
+ 	while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
+ 		int id = mnt_fs_get_parent_id(fs);
+-		if (!id)
+-			break;		/* @tab is not mountinfo file? */
+ 
+ 		if (!*root || id < root_id) {
+ 			*root = fs;
+@@ -250,7 +250,7 @@ int mnt_table_get_root_fs(struct libmnt_
+ 		}
+ 	}
+ 
+-	return root_id ? 0 : -EINVAL;
++	return *root ? 0 : -EINVAL;
+ }
+ 
+ /**
+@@ -271,15 +271,13 @@ int mnt_table_next_child_fs(struct libmn
+ 	struct libmnt_fs *fs;
+ 	int parent_id, lastchld_id = 0, chld_id = 0;
+ 
+-	if (!tb || !itr || !parent)
++	if (!tb || !itr || !parent || !is_mountinfo(tb))
+ 		return -EINVAL;
+ 
+ 	DBG(TAB, mnt_debug_h(tb, "lookup next child of '%s'",
+ 				mnt_fs_get_target(parent)));
+ 
+ 	parent_id = mnt_fs_get_id(parent);
+-	if (!parent_id)
+-		return -EINVAL;
+ 
+ 	/* get ID of the previously returned child */
+ 	if (itr->head && itr->p != itr->head) {
+@@ -310,7 +308,7 @@ int mnt_table_next_child_fs(struct libmn
+ 		}
+ 	}
+ 
+-	if (!chld_id)
++	if (!*chld)
+ 		return 1;	/* end of iterator */
+ 
+ 	/* set the iterator to the @chld for the next call */
+diff -up util-linux-2.23.2/misc-utils/findmnt.c.kzak util-linux-2.23.2/misc-utils/findmnt.c
+--- util-linux-2.23.2/misc-utils/findmnt.c.kzak	2013-07-30 11:07:35.138395654 +0200
++++ util-linux-2.23.2/misc-utils/findmnt.c	2014-09-25 10:49:50.953050560 +0200
+@@ -826,8 +826,9 @@ static int tab_is_tree(struct libmnt_tab
+ 	if (!itr)
+ 		return 0;
+ 
+-	if (mnt_table_next_fs(tb, itr, &fs) == 0)
+-		rc = mnt_fs_get_id(fs) > 0 && mnt_fs_get_parent_id(fs) > 0;
++	rc = (mnt_table_next_fs(tb, itr, &fs) == 0 &&
++	      mnt_fs_is_kernel(fs) &&
++	      mnt_fs_get_root(fs));
+ 
+ 	mnt_free_iter(itr);
+ 	return rc;
diff --git a/SOURCES/2.24-libmount-canonicalize-for-conversion-from-loopdev.patch b/SOURCES/2.24-libmount-canonicalize-for-conversion-from-loopdev.patch
new file mode 100644
index 0000000..d1e2341
--- /dev/null
+++ b/SOURCES/2.24-libmount-canonicalize-for-conversion-from-loopdev.patch
@@ -0,0 +1,40 @@
+From 3f420a49dd4d0c413b635dd621aa34eebce2d3d2 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Mon, 5 Aug 2013 13:58:01 +0200
+Subject: [PATCH] libmount: canonicalize for conversion from loopdev backing
+ file
+
+  # mount foo.img /mnt
+  # umount foo.img
+  umount: foo.img: not mounted
+
+The loopdev code (and sysfs backing_file) uses absolute paths, but
+libmount does not canonicalize the path before lookup for the backing file.
+
+References: https://bugzilla.redhat.com/show_bug.cgi?id=950497
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libmount/src/context_umount.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/libmount/src/context_umount.c b/libmount/src/context_umount.c
+index 2b791c4..b02902c 100644
+--- a/libmount/src/context_umount.c
++++ b/libmount/src/context_umount.c
+@@ -161,7 +161,12 @@ try_loopdev:
+ 		struct stat st;
+ 
+ 		if (stat(tgt, &st) == 0 && S_ISREG(st.st_mode)) {
+-			int count = loopdev_count_by_backing_file(tgt, &loopdev);
++			int count;
++
++			cn_tgt = mnt_resolve_path(tgt, cache);
++			count = loopdev_count_by_backing_file(cn_tgt, &loopdev);
++			if (!cache)
++				free(cn_tgt);
+ 			if (count == 1) {
+ 				DBG(CXT, mnt_debug_h(cxt,
+ 					"umount: %s --> %s (retry)", tgt, loopdev));
+-- 
+1.8.1.4
+
diff --git a/SOURCES/2.24-libmount-mem.patch b/SOURCES/2.24-libmount-mem.patch
new file mode 100644
index 0000000..64926a0
--- /dev/null
+++ b/SOURCES/2.24-libmount-mem.patch
@@ -0,0 +1,24 @@
+diff -up util-linux-2.23.2/libmount/src/context_umount.c.kzak util-linux-2.23.2/libmount/src/context_umount.c
+--- util-linux-2.23.2/libmount/src/context_umount.c.kzak	2013-10-07 11:43:10.990598629 +0200
++++ util-linux-2.23.2/libmount/src/context_umount.c	2013-10-07 11:46:01.051031431 +0200
+@@ -423,6 +423,8 @@ static int evaluate_permissions(struct l
+ 		if (optstr && !mnt_optstr_get_option(optstr,
+ 					"user", &mtab_user, &sz) && sz)
+ 			ok = !strncmp(curr_user, mtab_user, sz);
++
++		free(curr_user);
+ 	}
+ 
+ 	if (ok) {
+diff -up util-linux-2.23.2/libmount/src/utils.c.kzak util-linux-2.23.2/libmount/src/utils.c
+--- util-linux-2.23.2/libmount/src/utils.c.kzak	2013-07-30 11:15:27.391515623 +0200
++++ util-linux-2.23.2/libmount/src/utils.c	2013-10-07 11:43:27.209924834 +0200
+@@ -159,7 +159,7 @@ int mnt_chdir_to_parent(const char *targ
+ 		if (!last || !*last)
+ 			memcpy(*filename, ".", 2);
+ 		else
+-			memcpy(*filename, last, strlen(last) + 1);
++			memmove(*filename, last, strlen(last) + 1);
+ 	} else
+ 		free(buf);
+ 	return 0;
diff --git a/SOURCES/2.24-losetup-add-device.patch b/SOURCES/2.24-losetup-add-device.patch
new file mode 100644
index 0000000..680d616
--- /dev/null
+++ b/SOURCES/2.24-losetup-add-device.patch
@@ -0,0 +1,63 @@
+diff -up util-linux-2.23.2/include/loopdev.h.kzak util-linux-2.23.2/include/loopdev.h
+--- util-linux-2.23.2/include/loopdev.h.kzak	2013-06-13 09:46:10.397650425 +0200
++++ util-linux-2.23.2/include/loopdev.h	2014-01-14 11:11:48.427643690 +0100
+@@ -149,6 +149,7 @@ extern void loopcxt_enable_debug(struct
+ extern int loopcxt_set_device(struct loopdev_cxt *lc, const char *device)
+ 				__attribute__ ((warn_unused_result));
+ extern int loopcxt_has_device(struct loopdev_cxt *lc);
++extern int loopcxt_add_device(struct loopdev_cxt *lc);
+ extern char *loopcxt_strdup_device(struct loopdev_cxt *lc);
+ extern const char *loopcxt_get_device(struct loopdev_cxt *lc);
+ extern struct sysfs_cxt *loopcxt_get_sysfs(struct loopdev_cxt *lc);
+diff -up util-linux-2.23.2/lib/loopdev.c.kzak util-linux-2.23.2/lib/loopdev.c
+--- util-linux-2.23.2/lib/loopdev.c.kzak	2013-07-30 11:19:20.143600300 +0200
++++ util-linux-2.23.2/lib/loopdev.c	2014-01-14 11:11:48.428643700 +0100
+@@ -1298,6 +1298,36 @@ int loopcxt_delete_device(struct loopdev
+ 	return 0;
+ }
+ 
++int loopcxt_add_device(struct loopdev_cxt *lc)
++{
++	int rc = -EINVAL;
++	int ctl, nr = -1;
++	const char *p, *dev = loopcxt_get_device(lc);
++
++	if (!dev)
++		goto done;
++
++	if (!(lc->flags & LOOPDEV_FL_CONTROL)) {
++		rc = -ENOSYS;
++		goto done;
++	}
++
++	p = strrchr(dev, '/');
++	if (!p || (sscanf(p, "/loop%d", &nr) != 1 && sscanf(p, "/%d", &nr) != 1)
++	       || nr < 0)
++		goto done;
++
++	ctl = open(_PATH_DEV_LOOPCTL, O_RDWR|O_CLOEXEC);
++	if (ctl >= 0) {
++		DBG(lc, loopdev_debug("add_device %d", nr));
++		rc = ioctl(ctl, LOOP_CTL_ADD, nr);
++		close(ctl);
++	}
++done:
++	DBG(lc, loopdev_debug("add_device done [rc=%d]", rc));
++	return rc;
++}
++
+ /*
+  * Note that LOOP_CTL_GET_FREE ioctl is supported since kernel 3.1. In older
+  * kernels we have to check all loop devices to found unused one.
+diff -up util-linux-2.23.2/sys-utils/losetup.c.kzak util-linux-2.23.2/sys-utils/losetup.c
+--- util-linux-2.23.2/sys-utils/losetup.c.kzak	2013-07-30 11:20:16.987117853 +0200
++++ util-linux-2.23.2/sys-utils/losetup.c	2014-01-14 11:11:48.428643700 +0100
+@@ -600,6 +600,8 @@ int main(int argc, char **argv)
+ 	{
+ 		int hasdev = loopcxt_has_device(&lc);
+ 
++		if (hasdev && !is_loopdev(loopcxt_get_device(&lc)))
++			loopcxt_add_device(&lc);
+ 		do {
+ 			const char *errpre;
+ 
diff --git a/SOURCES/2.24-losetup-offset.patch b/SOURCES/2.24-losetup-offset.patch
new file mode 100644
index 0000000..a93cc55
--- /dev/null
+++ b/SOURCES/2.24-losetup-offset.patch
@@ -0,0 +1,32 @@
+diff -up util-linux-2.23.2/lib/loopdev.c.kzak util-linux-2.23.2/lib/loopdev.c
+--- util-linux-2.23.2/lib/loopdev.c.kzak	2014-09-25 10:16:23.521897462 +0200
++++ util-linux-2.23.2/lib/loopdev.c	2014-09-25 10:23:38.852050990 +0200
+@@ -1129,6 +1129,12 @@ static int loopcxt_check_size(struct loo
+ 		return -errno;
+ 	}
+ 
++	/* It's block device, so, align to 512-byte sectors */
++	if (expected_size % 512) {
++		DBG(lc, loopdev_debug("expected size misaligned to 512-byte sectors"));
++		expected_size = (expected_size >> 9) << 9;
++	}
++
+ 	if (expected_size != size) {
+ 		DBG(lc, loopdev_debug("warning: loopdev and expected "
+ 				      "size dismatch (%ju/%ju)",
+diff -up util-linux-2.23.2/sys-utils/losetup.c.kzak util-linux-2.23.2/sys-utils/losetup.c
+--- util-linux-2.23.2/sys-utils/losetup.c.kzak	2014-09-25 10:16:23.521897462 +0200
++++ util-linux-2.23.2/sys-utils/losetup.c	2014-09-25 10:23:38.852050990 +0200
+@@ -632,11 +632,7 @@ int main(int argc, char **argv)
+ 			/* errors */
+ 			errpre = hasdev && loopcxt_get_fd(&lc) < 0 ?
+ 					 loopcxt_get_device(&lc) : file;
+-			if (errno == ERANGE && offset && offset % 512)
+-				warnx(_("%s: failed to set up loop device, "
+-					"offset is not 512-byte aligned."), errpre);
+-			else
+-				warn(_("%s: failed to set up loop device"), errpre);
++			warn(_("%s: failed to set up loop device"), errpre);
+ 			break;
+ 		} while (hasdev == 0);
+ 
diff --git a/SOURCES/2.24-partx-update.patch b/SOURCES/2.24-partx-update.patch
new file mode 100644
index 0000000..f1dc8e7
--- /dev/null
+++ b/SOURCES/2.24-partx-update.patch
@@ -0,0 +1,131 @@
+From 5cc378e4cdeb957b405e0264a09295eda7d75ff7 Mon Sep 17 00:00:00 2001
+From: Scott Moser <smoser@ubuntu.com>
+Date: Mon, 13 Jan 2014 15:32:49 -0500
+Subject: [PATCH] partx: fix --update ranges and out of order tables
+
+partx --update DEVICE NUMBER
+was broken in 2 cases:
+ * if NUMBER != 1
+ * if the partition table was "out of order".
+   Ie, where sda2 came after sda3.
+
+References: https://bugs.launchpad.net/ubuntu/+source/cloud-utils/+bug/1244662
+Signed-off-by: Scott Moser <smoser@ubuntu.com>
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ disk-utils/partx.c | 75 ++++++++++++++++++++++++++++++++++++------------------
+ 1 file changed, 50 insertions(+), 25 deletions(-)
+
+diff --git a/disk-utils/partx.c b/disk-utils/partx.c
+index 880d779..df03e59 100644
+--- a/disk-utils/partx.c
++++ b/disk-utils/partx.c
+@@ -412,10 +412,41 @@ static void upd_parts_warnx(const char *device, int first, int last)
+ 				device, first, last);
+ }
+ 
++/**
++ * get_partition_by_partno:
++ * @ls: partitions list
++ * @n: the partition number (e.g. 'N' from sda'N')
++ *
++ * This does not assume any order of the input blkid_partlist.
++ * And correctly handles "out of order" partition tables.
++ * partition N is located after partition N+1 on the disk.
++ *
++ * Returns: partition object or NULL in case or error.
++ */
++blkid_partition get_partition_by_partno(blkid_partlist ls, int n)
++{
++	int i, nparts;
++	blkid_partition par;
++	if (!ls)
++		return NULL;
++
++	nparts = blkid_partlist_numof_partitions(ls);
++	if (nparts < 0)
++		return NULL;
++
++	for (i = 0; i < nparts; i++) {
++		par = blkid_partlist_get_partition(ls, i);
++		if (n == blkid_partition_get_partno(par)) {
++			return par;
++		}
++	}
++	return NULL;
++}
++
+ static int upd_parts(int fd, const char *device, dev_t devno,
+ 		     blkid_partlist ls, int lower, int upper)
+ {
+-	int i, n, an, nparts, rc = 0, errfirst = 0, errlast = 0, err;
++	int n, nparts, rc = 0, errfirst = 0, errlast = 0, err;
+ 	blkid_partition par;
+ 	uintmax_t start, size;
+ 
+@@ -441,18 +472,16 @@ static int upd_parts(int fd, const char *device, dev_t devno,
+ 		return -1;
+ 	}
+ 
+-	for (i = 0, n = lower; n <= upper; n++) {
+-		par = blkid_partlist_get_partition(ls, i);
+-		an = blkid_partition_get_partno(par);
+-
+-		if (lower && n < lower)
+-			continue;
+-		if (upper && n > upper)
++	for (n = lower; n <= upper; n++) {
++		par = get_partition_by_partno(ls, n);
++		if (!par) {
++			if (verbose)
++				warn(_("%s: no partition #%d"), device, n);
+ 			continue;
++		}
+ 
+ 		start = blkid_partition_get_start(par);
+ 		size =  blkid_partition_get_size(par);
+-
+ 		if (blkid_partition_is_extended(par))
+ 			/*
+ 			 * Let's follow the Linux kernel and reduce
+@@ -463,25 +492,21 @@ static int upd_parts(int fd, const char *device, dev_t devno,
+ 		err = partx_del_partition(fd, n);
+ 		if (err == -1 && errno == ENXIO)
+ 			err = 0; /* good, it already doesn't exist */
+-		if (an == n)
++		if (err == -1 && errno == EBUSY)
+ 		{
+-			if (i < nparts)
+-				i++;
+-			if (err == -1 && errno == EBUSY)
+-			{
+-				/* try to resize */
+-				err = partx_resize_partition(fd, n, start, size);
+-				if (verbose)
+-					printf(_("%s: partition #%d resized\n"), device, n);
+-				if (err == 0)
+-					continue;
+-			}
+-			if (err == 0 && partx_add_partition(fd, n, start, size) == 0) {
+-				if (verbose)
+-					printf(_("%s: partition #%d added\n"), device, n);
++			/* try to resize */
++			err = partx_resize_partition(fd, n, start, size);
++			if (verbose)
++				printf(_("%s: partition #%d resized\n"), device, n);
++			if (err == 0)
+ 				continue;
+-			}
+ 		}
++		if (err == 0 && partx_add_partition(fd, n, start, size) == 0) {
++			if (verbose)
++				printf(_("%s: partition #%d added\n"), device, n);
++			continue;
++		}
++
+ 		if (err == 0)
+ 			continue;
+ 		rc = -1;
+-- 
+1.9.3
+
diff --git a/SOURCES/2.24-sfdisk-y-n-miscmatch.patch b/SOURCES/2.24-sfdisk-y-n-miscmatch.patch
new file mode 100644
index 0000000..68ef91b
--- /dev/null
+++ b/SOURCES/2.24-sfdisk-y-n-miscmatch.patch
@@ -0,0 +1,15 @@
+diff -up util-linux-2.23.2/fdisks/sfdisk.c.kzak util-linux-2.23.2/fdisks/sfdisk.c
+--- util-linux-2.23.2/fdisks/sfdisk.c.kzak	2013-07-30 10:39:26.200738180 +0200
++++ util-linux-2.23.2/fdisks/sfdisk.c	2013-10-07 11:52:10.701445115 +0200
+@@ -3201,9 +3201,9 @@ do_fdisk(char *dev) {
+ 	    ignore_result( fgets(answer, sizeof(answer), stdin) );
+ 	    if (answer[0] == 'q' || answer[0] == 'Q') {
+ 		errx(EXIT_FAILURE, _("Quitting - nothing changed"));
+-	    } else if (rpmatch(answer) == 1) {
+-		continue;
+ 	    } else if (rpmatch(answer) == 0) {
++		continue;
++	    } else if (rpmatch(answer) == 1) {
+ 		break;
+ 	    } else {
+ 		printf(_("Please answer one of y,n,q\n"));
diff --git a/SOURCES/2.24-su-fix-lastlog-and-btmp-logging.patch b/SOURCES/2.24-su-fix-lastlog-and-btmp-logging.patch
new file mode 100644
index 0000000..40c6081
--- /dev/null
+++ b/SOURCES/2.24-su-fix-lastlog-and-btmp-logging.patch
@@ -0,0 +1,48 @@
+From 9b5dc4cb8d5d82c31c0cda898832998c21afc303 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Mon, 9 Sep 2013 12:24:01 +0200
+Subject: [PATCH] su: fix lastlog and btmp logging
+
+The su(1) logging code mix ups "old" and "new" passwd structs. The
+result is things like
+
+	Sep  9 11:50:45 x2 su: (to kzak) kzak on none
+
+in /var/log/messages. The right log entry is
+
+	Sep  9 11:50:45 x2 su: (to root) kzak on pts/3
+
+The bug has been introduced by commit c74a7af17c7a176c358dfaa8e1814786c89ebc14.
+
+References: https://bugzilla.redhat.com/show_bug.cgi?id=1005194
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ login-utils/su-common.c | 5 +----
+ 1 file changed, 1 insertion(+), 4 deletions(-)
+
+diff --git a/login-utils/su-common.c b/login-utils/su-common.c
+index ade5c92..858af01 100644
+--- a/login-utils/su-common.c
++++ b/login-utils/su-common.c
+@@ -161,7 +161,7 @@ log_syslog(struct passwd const *pw, bool successful)
+       old_user = pwd ? pwd->pw_name : "";
+     }
+ 
+-  if (get_terminal_name(STDERR_FILENO, NULL, &tty, NULL) == 0 && tty)
++  if (get_terminal_name(STDERR_FILENO, NULL, &tty, NULL) != 0 || !tty)
+     tty = "none";
+ 
+   openlog (program_invocation_short_name, 0 , LOG_AUTH);
+@@ -483,9 +483,6 @@ authenticate (const struct passwd *pw)
+ 
+ done:
+ 
+-  if (lpw && lpw->pw_name)
+-     pw = lpw;
+-
+   log_syslog(pw, !is_pam_failure(retval));
+ 
+   if (is_pam_failure(retval))
+-- 
+1.8.1.4
+
diff --git a/SOURCES/2.24-su-suppress-PAM-info-messages.patch b/SOURCES/2.24-su-suppress-PAM-info-messages.patch
new file mode 100644
index 0000000..3b54521
--- /dev/null
+++ b/SOURCES/2.24-su-suppress-PAM-info-messages.patch
@@ -0,0 +1,48 @@
+diff -up util-linux-2.23.2/login-utils/su-common.c.kzak util-linux-2.23.2/login-utils/su-common.c
+--- util-linux-2.23.2/login-utils/su-common.c.kzak	2013-07-30 10:39:26.223738407 +0200
++++ util-linux-2.23.2/login-utils/su-common.c	2013-09-09 09:32:05.497238691 +0200
+@@ -111,6 +111,9 @@ static int same_session = 0;
+ /* SU_MODE_{RUNUSER,SU} */
+ static int su_mode;
+
++/* Don't print PAM info messages (Last login, etc.). */
++static int suppress_pam_info;
++
+ static bool _pam_session_opened;
+ static bool _pam_cred_established;
+ static sig_atomic_t volatile caught_signal = false;
+@@ -208,10 +211,23 @@ static void log_btmp(struct passwd const
+	updwtmp(_PATH_BTMP, &ut);
+ }
+
++
++static int su_pam_conv(int num_msg, const struct pam_message **msg,
++                       struct pam_response **resp, void *appdata_ptr)
++{
++	if (suppress_pam_info
++	    && num_msg == 1
++	    && msg
++	    && msg[0]->msg_style == PAM_TEXT_INFO)
++		return PAM_SUCCESS;
++
++	return misc_conv(num_msg, msg, resp, appdata_ptr);
++}
++
+ static struct pam_conv conv =
+ {
+-  misc_conv,
+-  NULL
++	su_pam_conv,
++	NULL
+ };
+
+ static void
+@@ -902,6 +918,9 @@ su_main (int argc, char **argv, int mode
+
+   init_groups (pw, groups, num_supp_groups);
+
++  if (!simulate_login || command)
++    suppress_pam_info = 1;		/* don't print PAM info messages */
++
+   create_watching_parent ();
+   /* Now we're in the child.  */
diff --git a/SOURCES/2.24-tests-portability.patch b/SOURCES/2.24-tests-portability.patch
new file mode 100644
index 0000000..be6f0b1
--- /dev/null
+++ b/SOURCES/2.24-tests-portability.patch
@@ -0,0 +1,37 @@
+diff -up util-linux-2.23.2/tests/functions.sh.kzak util-linux-2.23.2/tests/functions.sh
+--- util-linux-2.23.2/tests/functions.sh.kzak	2013-06-13 09:46:10.554651768 +0200
++++ util-linux-2.23.2/tests/functions.sh	2013-09-09 10:01:23.355469268 +0200
+@@ -483,7 +483,7 @@ function ts_scsi_debug_init {
+ 	modprobe scsi_debug $*
+ 	[ "$?" == 0 ] || ts_die "Cannot init device"
+ 
+-	DEVNAME=$(grep scsi_debug /sys/block/*/device/model | awk -F '/' '{print $4}')
++	DEVNAME=$(grep --with-filename scsi_debug /sys/block/*/device/model | awk -F '/' '{print $4}')
+ 	[ "x${DEVNAME}" == "x" ] && ts_die "Cannot find device"
+ 
+ 	DEVICE="/dev/${DEVNAME}"
+diff -up util-linux-2.23.2/tests/ts/cramfs/mkfs.kzak util-linux-2.23.2/tests/ts/cramfs/mkfs
+--- util-linux-2.23.2/tests/ts/cramfs/mkfs.kzak	2013-06-13 09:46:10.557651793 +0200
++++ util-linux-2.23.2/tests/ts/cramfs/mkfs	2013-09-09 10:01:23.355469268 +0200
+@@ -80,7 +80,7 @@ cd $TS_MOUNTPOINT
+ 
+ ts_log "list the image"
+ export TZ='GMT-1'
+-ls -laR --time-style=long-iso . >> $TS_OUTPUT
++ls -laR --time-style=long-iso . | sed 's:\. : :g' >> $TS_OUTPUT
+ echo >> $TS_OUTPUT
+ 
+ ts_log "list checksums from new data"
+diff -up util-linux-2.23.2/tests/ts/libmount/context-utab.kzak util-linux-2.23.2/tests/ts/libmount/context-utab
+--- util-linux-2.23.2/tests/ts/libmount/context-utab.kzak	2013-06-13 09:46:10.561651827 +0200
++++ util-linux-2.23.2/tests/ts/libmount/context-utab	2013-09-09 10:01:23.355469268 +0200
+@@ -85,7 +85,9 @@ grep -q $DEVICE $LIBMOUNT_UTAB && \
+ 	echo "umount (mountpoint) failed: found $DEVICE in $LIBMOUNT_UTAB" >> $TS_OUTPUT 2>&1
+ ts_finalize_subtest
+ 
++
+ if [ -x "/sbin/mkfs.btrfs" ]; then
++	$TS_CMD_WIPEFS -a  $DEVICE &> /dev/null
+ 	ts_log "Create filesystem [btrfs]"
+ 	/sbin/mkfs.btrfs -L "$LABEL" $DEVICE &> /dev/null
+ 	udevadm settle
diff --git a/SOURCES/2.24-unshare-mount-fork.patch b/SOURCES/2.24-unshare-mount-fork.patch
new file mode 100644
index 0000000..1f2d816
--- /dev/null
+++ b/SOURCES/2.24-unshare-mount-fork.patch
@@ -0,0 +1,248 @@
+diff -up util-linux-2.23.2/sys-utils/Makemodule.am.kzak util-linux-2.23.2/sys-utils/Makemodule.am
+--- util-linux-2.23.2/sys-utils/Makemodule.am.kzak	2014-09-25 14:16:33.526384729 +0200
++++ util-linux-2.23.2/sys-utils/Makemodule.am	2014-09-25 14:15:34.861825005 +0200
+@@ -290,6 +290,7 @@ usrbin_exec_PROGRAMS += unshare
+ dist_man_MANS += sys-utils/unshare.1
+ unshare_SOURCES = sys-utils/unshare.c
+ unshare_LDADD = $(LDADD) libcommon.la
++unshare_CFLAGS = $(AM_CFLAGS) -I$(ul_libmount_incdir)
+ endif
+ 
+ if BUILD_NSENTER
+diff -up util-linux-2.23.2/sys-utils/unshare.1.kzak util-linux-2.23.2/sys-utils/unshare.1
+--- util-linux-2.23.2/sys-utils/unshare.1.kzak	2014-09-25 14:14:30.194208005 +0200
++++ util-linux-2.23.2/sys-utils/unshare.1	2014-09-25 14:15:17.617660476 +0200
+@@ -1,63 +1,82 @@
+ .\" Process this file with
+ .\" groff -man -Tascii lscpu.1
+ .\"
+-.TH UNSHARE 1 "January 2013" "util-linux" "User Commands"
++.TH UNSHARE 1 "July 2013" "util-linux" "User Commands"
+ .SH NAME
+ unshare \- run program with some namespaces unshared from parent
+ .SH SYNOPSIS
+ .B unshare
+ .RI [ options ]
+-program
++.I program
+ .RI [ arguments ]
+ .SH DESCRIPTION
+-Unshares specified namespaces from parent process and then executes specified
+-program. Unshareable namespaces are:
++Unshares the indicated namespaces from the parent process and then executes
++the specified program.  The namespaces to be unshared are indicated via
++options.  Unshareable namespaces are:
+ .TP
+ .BR "mount namespace"
+-mounting and unmounting filesystems will not affect rest of the system
++Mounting and unmounting filesystems will not affect the rest of the system
+ (\fBCLONE_NEWNS\fP flag), except for filesystems which are explicitly marked as
+-shared (by mount --make-shared). See /proc/self/mountinfo for the shared flags.
++shared (with \fBmount --make-shared\fP; see \fI/proc/self/mountinfo\fP for the
++\fBshared\fP flags).
++
++It's recommended to use \fBmount --make-rprivate\fP or \fBmount --make-rslave\fP
++after \fBunshare --mount\fP to make sure that mountpoints in the new namespace
++are really unshared from parental namespace.
+ .TP
+ .BR "UTS namespace"
+-setting hostname, domainname will not affect rest of the system
+-(\fBCLONE_NEWUTS\fP flag).
++Setting hostname or domainname will not affect the rest of the system.
++(\fBCLONE_NEWUTS\fP flag)
+ .TP
+ .BR "IPC namespace"
+-process will have independent namespace for System V message queues, semaphore
+-sets and shared memory segments (\fBCLONE_NEWIPC\fP flag).
++The process will have an independent namespace for System V message queues,
++semaphore sets and shared memory segments.  (\fBCLONE_NEWIPC\fP flag)
+ .TP
+ .BR "network namespace"
+-process will have independent IPv4 and IPv6 stacks, IP routing tables, firewall
+-rules, the \fI/proc/net\fP and \fI/sys/class/net\fP directory trees, sockets
+-etc. (\fBCLONE_NEWNET\fP flag).
++The process will have independent IPv4 and IPv6 stacks, IP routing tables,
++firewall rules, the \fI/proc/net\fP and \fI/sys/class/net\fP directory trees,
++sockets, etc.  (\fBCLONE_NEWNET\fP flag)
+ .TP
+ .BR "pid namespace"
+-children will have a distinct set of pid to process mappings than their parent.
+-(\fBCLONE_NEWPID\fP flag).
++Children will have a distinct set of PID to process mappings from their parent.
++(\fBCLONE_NEWPID\fP flag)
+ .PP
+-See the \fBclone\fR(2) for exact semantics of the flags.
++See \fBclone\fR(2) for the exact semantics of the flags.
+ .SH OPTIONS
+ .TP
+ .BR \-h , " \-\-help"
+-Print a help message,
+-.TP
+-.BR \-m , " \-\-mount"
+-Unshare the mount namespace,
+-.TP
+-.BR \-u , " \-\-uts"
+-Unshare the UTS namespace,
++Display help text and exit.
+ .TP
+ .BR \-i , " \-\-ipc"
+-Unshare the IPC namespace,
++Unshare the IPC namespace.
++.TP
++.BR \-m , " \-\-mount"
++Unshare the mount namespace.
+ .TP
+ .BR \-n , " \-\-net"
+ Unshare the network namespace.
+ .TP
+ .BR \-p , " \-\-pid"
+ Unshare the pid namespace.
++See also the \fB--fork\fP and \fB--mount-proc\fP options.
++.TP
++.BR \-u , " \-\-uts"
++Unshare the UTS namespace.
++.TP
++.BR \-f , " \-\-fork"
++Fork the specified \fIprogram\fR as a child process of \fBunshare\fR rather than
++running it directly.  This is useful when creating a new pid namespace.
++.TP
++.BR \-\-mount-proc "[=\fImountpoint\fP]"
++Just before running the program, mount the proc filesystem at the \fImountpoint\fP
++(default is /proc).  This is useful when creating a new pid namespace.  It also
++implies creating a new mount namespace since the /proc mount would otherwise
++mess up existing programs on the system. The new proc filesystem is explicitly
++mounted as private (by MS_PRIVATE|MS_REC).
+ .SH SEE ALSO
+ .BR unshare (2),
+-.BR clone (2)
++.BR clone (2),
++.BR mount (8)
+ .SH BUGS
+ None known so far.
+ .SH AUTHOR
+diff -up util-linux-2.23.2/sys-utils/unshare.c.kzak util-linux-2.23.2/sys-utils/unshare.c
+--- util-linux-2.23.2/sys-utils/unshare.c.kzak	2014-09-25 14:14:30.194208005 +0200
++++ util-linux-2.23.2/sys-utils/unshare.c	2014-09-25 14:15:34.861825005 +0200
+@@ -24,12 +24,19 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <unistd.h>
++#include <sys/wait.h>
++#include <sys/mount.h>
++
++/* we only need some defines missing in sys/mount.h, no libmount linkage */
++#include <libmount.h>
+ 
+ #include "nls.h"
+ #include "c.h"
+-#include "closestream.h"
+ #include "namespace.h"
+ #include "exec_shell.h"
++#include "xalloc.h"
++#include "pathnames.h"
++
+ 
+ static void usage(int status)
+ {
+@@ -40,11 +47,13 @@ static void usage(int status)
+ 	      _(" %s [options] <program> [args...]\n"),	program_invocation_short_name);
+ 
+ 	fputs(USAGE_OPTIONS, out);
+-	fputs(_(" -m, --mount       unshare mounts namespace\n"), out);
+-	fputs(_(" -u, --uts         unshare UTS namespace (hostname etc)\n"), out);
+-	fputs(_(" -i, --ipc         unshare System V IPC namespace\n"), out);
+-	fputs(_(" -n, --net         unshare network namespace\n"), out);
+-	fputs(_(" -p, --pid         unshare pid namespace\n"), out);
++	fputs(_(" -m, --mount               unshare mounts namespace\n"), out);
++	fputs(_(" -u, --uts                 unshare UTS namespace (hostname etc)\n"), out);
++	fputs(_(" -i, --ipc                 unshare System V IPC namespace\n"), out);
++	fputs(_(" -n, --net                 unshare network namespace\n"), out);
++	fputs(_(" -p, --pid                 unshare pid namespace\n"), out);
++	fputs(_(" -f, --fork                fork before launching <program>\n"), out);
++	fputs(_("     --mount-proc[=<dir>]  mount proc filesystem first (implies --mount)\n"), out);
+ 
+ 	fputs(USAGE_SEPARATOR, out);
+ 	fputs(USAGE_HELP, out);
+@@ -56,6 +65,9 @@ static void usage(int status)
+ 
+ int main(int argc, char *argv[])
+ {
++	enum {
++		OPT_MOUNTPROC = CHAR_MAX + 1
++	};
+ 	static const struct option longopts[] = {
+ 		{ "help", no_argument, 0, 'h' },
+ 		{ "version", no_argument, 0, 'V'},
+@@ -64,20 +76,24 @@ int main(int argc, char *argv[])
+ 		{ "ipc", no_argument, 0, 'i' },
+ 		{ "net", no_argument, 0, 'n' },
+ 		{ "pid", no_argument, 0, 'p' },
++		{ "fork", no_argument, 0, 'f' },
++		{ "mount-proc", optional_argument, 0, OPT_MOUNTPROC },
+ 		{ NULL, 0, 0, 0 }
+ 	};
+ 
+ 	int unshare_flags = 0;
++	int c, forkit = 0;
++	const char *procmnt = NULL;
+ 
+-	int c;
+-
+-	setlocale(LC_MESSAGES, "");
++	setlocale(LC_ALL, "");
+ 	bindtextdomain(PACKAGE, LOCALEDIR);
+ 	textdomain(PACKAGE);
+-	atexit(close_stdout);
+ 
+-	while ((c = getopt_long(argc, argv, "hVmuinp", longopts, NULL)) != -1) {
++	while ((c = getopt_long(argc, argv, "+fhVmuinp", longopts, NULL)) != -1) {
+ 		switch (c) {
++		case 'f':
++			forkit = 1;
++			break;
+ 		case 'h':
+ 			usage(EXIT_SUCCESS);
+ 		case 'V':
+@@ -98,6 +114,10 @@ int main(int argc, char *argv[])
+ 		case 'p':
+ 			unshare_flags |= CLONE_NEWPID;
+ 			break;
++		case OPT_MOUNTPROC:
++			unshare_flags |= CLONE_NEWNS;
++			procmnt = optarg ? optarg : "/proc";
++			break;
+ 		default:
+ 			usage(EXIT_FAILURE);
+ 		}
+@@ -106,6 +126,31 @@ int main(int argc, char *argv[])
+ 	if (-1 == unshare(unshare_flags))
+ 		err(EXIT_FAILURE, _("unshare failed"));
+ 
++	if (forkit) {
++		int status;
++		pid_t pid = fork();
++
++		switch(pid) {
++		case -1:
++			err(EXIT_FAILURE, _("fork failed"));
++		case 0:	/* child */
++			break;
++		default: /* parent */
++			if (waitpid(pid, &status, 0) == -1)
++				err(EXIT_FAILURE, _("waitpid failed"));
++			if (WIFEXITED(status))
++				return WEXITSTATUS(status);
++			else if (WIFSIGNALED(status))
++				kill(getpid(), WTERMSIG(status));
++			err(EXIT_FAILURE, _("child exit failed"));
++		}
++	}
++
++	if (procmnt &&
++	    (mount("none", procmnt, NULL, MS_PRIVATE|MS_REC, NULL) != 0 ||
++	     mount("proc", procmnt, "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL) != 0))
++			err(EXIT_FAILURE, _("mount %s failed"), procmnt);
++
+ 	if (optind < argc) {
+ 		execvp(argv[optind], argv + optind);
+ 		err(EXIT_FAILURE, _("failed to execute %s"), argv[optind]);
diff --git a/SOURCES/2.24-utmpdump-ipv6.patch b/SOURCES/2.24-utmpdump-ipv6.patch
new file mode 100644
index 0000000..562892a
--- /dev/null
+++ b/SOURCES/2.24-utmpdump-ipv6.patch
@@ -0,0 +1,56 @@
+diff -up util-linux-2.23.2/login-utils/utmpdump.c.kzak util-linux-2.23.2/login-utils/utmpdump.c
+--- util-linux-2.23.2/login-utils/utmpdump.c.kzak	2013-10-07 11:56:02.030191040 +0200
++++ util-linux-2.23.2/login-utils/utmpdump.c	2013-10-07 12:05:08.671171091 +0200
+@@ -85,11 +85,14 @@ static void xcleanse(char *s, int len)
+ 
+ static void print_utline(struct utmp ut)
+ {
+-	char *addr_string, *time_string;
+-	struct in_addr in;
++	const char *addr_string, *time_string;
++	char buffer[INET6_ADDRSTRLEN];
++
++	if (ut.ut_addr_v6[1] || ut.ut_addr_v6[2] || ut.ut_addr_v6[3])
++		addr_string = inet_ntop(AF_INET6, &(ut.ut_addr_v6), buffer, sizeof(buffer));
++	else
++		addr_string = inet_ntop(AF_INET, &(ut.ut_addr_v6), buffer, sizeof(buffer));
+ 
+-	in.s_addr = ut.ut_addr;
+-	addr_string = inet_ntoa(in);
+ 	time_string = timetostr(ut.ut_time);
+ 	cleanse(ut.ut_id);
+ 	cleanse(ut.ut_user);
+@@ -97,7 +100,7 @@ static void print_utline(struct utmp ut)
+ 	cleanse(ut.ut_host);
+ 
+ 	/*            pid    id       user     line     host     addr       time */
+-	printf("[%d] [%05d] [%-4.4s] [%-*.*s] [%-*.*s] [%-*.*s] [%-15.15s] [%-28.28s]\n",
++	printf("[%d] [%05d] [%-4.4s] [%-*.*s] [%-*.*s] [%-*.*s] [%-15s] [%-28.28s]\n",
+ 	       ut.ut_type, ut.ut_pid, ut.ut_id, 8, UT_NAMESIZE, ut.ut_user,
+ 	       12, UT_LINESIZE, ut.ut_line, 20, UT_HOSTSIZE, ut.ut_host,
+ 	       addr_string, time_string);
+@@ -248,11 +251,10 @@ static int gettok(char *line, char *dest
+ static void undump(FILE *fp)
+ {
+ 	struct utmp ut;
+-	char s_addr[16], s_time[29], *linestart, *line;
++	char s_addr[INET6_ADDRSTRLEN + 1], s_time[29], *linestart, *line;
+ 	int count = 0;
+ 
+ 	line = linestart = xmalloc(1024 * sizeof(*linestart));
+-	s_addr[15] = 0;
+ 	s_time[28] = 0;
+ 
+ 	while (fgets(linestart, 1023, fp)) {
+@@ -267,7 +269,10 @@ static void undump(FILE *fp)
+ 		line += gettok(line, s_addr, sizeof(s_addr) - 1, 1);
+ 		line += gettok(line, s_time, sizeof(s_time) - 1, 0);
+ 
+-		ut.ut_addr = inet_addr(s_addr);
++		if (strchr(s_addr, '.'))
++			inet_pton(AF_INET, s_addr, &(ut.ut_addr_v6));
++		else
++			inet_pton(AF_INET6, s_addr, &(ut.ut_addr_v6));
+ 		ut.ut_time = strtotime(s_time);
+ 
+ 		ignore_result( fwrite(&ut, sizeof(ut), 1, stdout) );
diff --git a/SOURCES/2.25-blockdev-geom.patch b/SOURCES/2.25-blockdev-geom.patch
new file mode 100644
index 0000000..4bf6b61
--- /dev/null
+++ b/SOURCES/2.25-blockdev-geom.patch
@@ -0,0 +1,95 @@
+diff -up util-linux-2.23.2/disk-utils/blockdev.c.kzak util-linux-2.23.2/disk-utils/blockdev.c
+--- util-linux-2.23.2/disk-utils/blockdev.c.kzak	2015-06-23 11:29:27.818001654 +0200
++++ util-linux-2.23.2/disk-utils/blockdev.c	2015-06-23 11:29:43.752884860 +0200
+@@ -16,6 +16,7 @@
+ #include "blkdev.h"
+ #include "pathnames.h"
+ #include "closestream.h"
++#include "sysfs.h"
+ 
+ struct bdc {
+ 	long		ioc;		/* ioctl code */
+@@ -364,7 +365,7 @@ static void do_commands(int fd, char **a
+ 		}
+ 
+ 		if (res == -1) {
+-			perror(bdcms[j].iocname);
++			warn(_("ioctl error on %s"), bdcms[j].iocname);
+ 			if (verbose)
+ 				printf(_("%s failed.\n"), _(bdcms[j].help));
+ 			exit(EXIT_FAILURE);
+@@ -436,7 +437,8 @@ static void report_device(char *device,
+ 	int ro, ssz, bsz;
+ 	long ra;
+ 	unsigned long long bytes;
+-	struct hd_geometry g;
++	uint64_t start = 0;
++	struct stat st;
+ 
+ 	fd = open(device, O_RDONLY | O_NONBLOCK);
+ 	if (fd < 0) {
+@@ -446,15 +448,27 @@ static void report_device(char *device,
+ 	}
+ 
+ 	ro = ssz = bsz = 0;
+-	g.start = ra = 0;
++	ra = 0;
++	if (fstat(fd, &st) == 0 && !sysfs_devno_is_wholedisk(st.st_rdev)) {
++		struct sysfs_cxt cxt;
++
++		if (sysfs_init(&cxt, st.st_rdev, NULL))
++			err(EXIT_FAILURE,
++				_("%s: failed to initialize sysfs handler"),
++				device);
++		if (sysfs_read_u64(&cxt, "start", &start))
++			err(EXIT_FAILURE,
++				_("%s: failed to read partition start from sysfs"),
++				device);
++		sysfs_deinit(&cxt);
++	}
+ 	if (ioctl(fd, BLKROGET, &ro) == 0 &&
+ 	    ioctl(fd, BLKRAGET, &ra) == 0 &&
+ 	    ioctl(fd, BLKSSZGET, &ssz) == 0 &&
+ 	    ioctl(fd, BLKBSZGET, &bsz) == 0 &&
+-	    ioctl(fd, HDIO_GETGEO, &g) == 0 &&
+ 	    blkdev_get_size(fd, &bytes) == 0) {
+-		printf("%s %5ld %5d %5d %10ld %15lld   %s\n",
+-		       ro ? "ro" : "rw", ra, ssz, bsz, g.start, bytes, device);
++		printf("%s %5ld %5d %5d %10ju %15lld   %s\n",
++		       ro ? "ro" : "rw", ra, ssz, bsz, start, bytes, device);
+ 	} else {
+ 		if (!quiet)
+ 			warnx(_("ioctl error on %s"), device);
+diff -up util-linux-2.23.2/include/sysfs.h.kzak util-linux-2.23.2/include/sysfs.h
+--- util-linux-2.23.2/include/sysfs.h.kzak	2015-06-23 11:32:12.709793086 +0200
++++ util-linux-2.23.2/include/sysfs.h	2015-06-23 11:32:31.909652361 +0200
+@@ -72,6 +72,7 @@ extern int sysfs_is_partition_dirent(DIR
+ 
+ extern int sysfs_devno_to_wholedisk(dev_t dev, char *diskname,
+             size_t len, dev_t *diskdevno);
++extern int sysfs_devno_is_wholedisk(dev_t devno);
+ 
+ extern int sysfs_scsi_get_hctl(struct sysfs_cxt *cxt, int *h,
+ 			       int *c, int *t, int *l);
+diff -up util-linux-2.23.2/lib/sysfs.c.kzak util-linux-2.23.2/lib/sysfs.c
+--- util-linux-2.23.2/lib/sysfs.c.kzak	2015-06-23 11:31:32.166090250 +0200
++++ util-linux-2.23.2/lib/sysfs.c	2015-06-23 11:31:59.684888551 +0200
+@@ -638,6 +638,18 @@ err:
+     return -1;
+ }
+ 
++/*
++ * Return 0 or 1, or < 0 in case of error
++ */
++int sysfs_devno_is_wholedisk(dev_t devno)
++{
++	dev_t disk;
++
++	if (sysfs_devno_to_wholedisk(devno, NULL, 0, &disk) != 0)
++		return -1;
++
++	return devno == disk;
++}
+ 
+ int sysfs_scsi_get_hctl(struct sysfs_cxt *cxt, int *h, int *c, int *t, int *l)
+ {
diff --git a/SOURCES/2.25-dmesg-w.patch b/SOURCES/2.25-dmesg-w.patch
new file mode 100644
index 0000000..c01449c
--- /dev/null
+++ b/SOURCES/2.25-dmesg-w.patch
@@ -0,0 +1,12 @@
+diff -up util-linux-2.23.2/sys-utils/dmesg.c.kzak util-linux-2.23.2/sys-utils/dmesg.c
+--- util-linux-2.23.2/sys-utils/dmesg.c.kzak	2013-07-30 11:22:47.213494455 +0200
++++ util-linux-2.23.2/sys-utils/dmesg.c	2014-09-24 10:24:49.179371108 +0200
+@@ -991,6 +991,8 @@ static int init_kmsg(struct dmesg_contro
+ 
+ 	if (!ctl->follow)
+ 		mode |= O_NONBLOCK;
++	else
++		setlinebuf(stdout);
+ 
+ 	ctl->kmsg = open("/dev/kmsg", mode);
+ 	if (ctl->kmsg < 0)
diff --git a/SOURCES/2.25-flock-nfs4.patch b/SOURCES/2.25-flock-nfs4.patch
new file mode 100644
index 0000000..7a01332
--- /dev/null
+++ b/SOURCES/2.25-flock-nfs4.patch
@@ -0,0 +1,11 @@
+diff -up util-linux-2.23.2/sys-utils/flock.c.kzak util-linux-2.23.2/sys-utils/flock.c
+--- util-linux-2.23.2/sys-utils/flock.c.kzak	2014-03-25 12:00:53.735361387 +0100
++++ util-linux-2.23.2/sys-utils/flock.c	2014-03-25 12:01:44.534886083 +0100
+@@ -250,6 +250,7 @@ int main(int argc, char *argv[])
+ 			/* otherwise try again */
+ 			continue;
+ 		case EIO:
++		case EBADF:		/* since Linux 3.4 (commit 55725513) */
+ 			/* Probably NFSv4 where flock() is emulated by fcntl().
+ 			 * Let's try to reopen in read-write mode.
+ 			 */
diff --git a/SOURCES/2.25-fsck-nohelper.patch b/SOURCES/2.25-fsck-nohelper.patch
new file mode 100644
index 0000000..b8dc8fa
--- /dev/null
+++ b/SOURCES/2.25-fsck-nohelper.patch
@@ -0,0 +1,173 @@
+diff -up util-linux-2.23.2/disk-utils/fsck.c.kzak util-linux-2.23.2/disk-utils/fsck.c
+--- util-linux-2.23.2/disk-utils/fsck.c.kzak	2014-03-25 12:52:33.429389852 +0100
++++ util-linux-2.23.2/disk-utils/fsck.c	2014-03-25 12:56:27.126804792 +0100
+@@ -79,9 +79,7 @@ static const char *really_wanted[] = {
+ 	"ext4dev",
+ 	"jfs",
+ 	"reiserfs",
+-	"xiafs",
+-	"xfs",
+-	NULL
++	"xiafs"
+ };
+ 
+ /*
+@@ -167,6 +165,19 @@ static int string_to_int(const char *s)
+ 		return (int) l;
+ }
+ 
++/* Do we really really want to check this fs? */
++static int fs_check_required(const char *type)
++{
++	size_t i;
++
++	for(i = 0; i < ARRAY_SIZE(really_wanted); i++) {
++		if (strcmp(type, really_wanted[i]) == 0)
++			return 1;
++	}
++
++	return 0;
++}
++
+ static int is_mounted(struct libmnt_fs *fs)
+ {
+ 	int rc;
+@@ -546,17 +557,17 @@ static void print_stats(struct fsck_inst
+  * Execute a particular fsck program, and link it into the list of
+  * child processes we are waiting for.
+  */
+-static int execute(const char *type, struct libmnt_fs *fs, int interactive)
++static int execute(const char *progname, const char *progpath,
++		   const char *type, struct libmnt_fs *fs, int interactive)
+ {
+-	char *s, *argv[80], prog[80];
++	char *argv[80];
+ 	int  argc, i;
+ 	struct fsck_instance *inst, *p;
+ 	pid_t	pid;
+ 
+ 	inst = xcalloc(1, sizeof(*inst));
+ 
+-	sprintf(prog, "fsck.%s", type);
+-	argv[0] = xstrdup(prog);
++	argv[0] = xstrdup(progname);
+ 	argc = 1;
+ 
+ 	for (i=0; i <num_args; i++)
+@@ -583,19 +594,12 @@ static int execute(const char *type, str
+ 	argv[argc++] = xstrdup(fs_get_device(fs));
+ 	argv[argc] = 0;
+ 
+-	s = find_fsck(prog);
+-	if (s == NULL) {
+-		warnx(_("%s: not found"), prog);
+-		free(inst);
+-		return ENOENT;
+-	}
+-
+ 	if (verbose || noexecute) {
+ 		const char *tgt = mnt_fs_get_target(fs);
+ 
+ 		if (!tgt)
+ 			tgt = fs_get_device(fs);
+-		printf("[%s (%d) -- %s] ", s, num_running, tgt);
++		printf("[%s (%d) -- %s] ", progpath, num_running, tgt);
+ 		for (i=0; i < argc; i++)
+ 			printf("%s ", argv[i]);
+ 		printf("\n");
+@@ -617,15 +621,15 @@ static int execute(const char *type, str
+ 	} else if (pid == 0) {
+ 		if (!interactive)
+ 			close(0);
+-		execv(s, argv);
+-		err(FSCK_EX_ERROR, _("%s: execute failed"), s);
++		execv(progpath, argv);
++		err(FSCK_EX_ERROR, _("%s: execute failed"), progpath);
+ 	}
+ 
+ 	for (i=0; i < argc; i++)
+ 		free(argv[i]);
+ 
+ 	inst->pid = pid;
+-	inst->prog = xstrdup(prog);
++	inst->prog = xstrdup(progname);
+ 	inst->type = xstrdup(type);
+ 	gettimeofday(&inst->start_time, NULL);
+ 	inst->next = NULL;
+@@ -822,6 +826,7 @@ static int wait_many(int flags)
+  */
+ static int fsck_device(struct libmnt_fs *fs, int interactive)
+ {
++	char progname[80], *progpath;
+ 	const char *type;
+ 	int retval;
+ 
+@@ -838,15 +843,27 @@ static int fsck_device(struct libmnt_fs
+ 	else
+ 		type = DEFAULT_FSTYPE;
+ 
++	sprintf(progname, "fsck.%s", type);
++	progpath = find_fsck(progname);
++	if (progpath == NULL) {
++		if (fs_check_required(type)) {
++			retval = ENOENT;
++			goto err;
++		}
++		return 0;
++	}
++
+ 	num_running++;
+-	retval = execute(type, fs, interactive);
++	retval = execute(progname, progpath, type, fs, interactive);
+ 	if (retval) {
+-		warnx(_("error %d while executing fsck.%s for %s"),
+-			retval, type, fs_get_device(fs));
+ 		num_running--;
+-		return FSCK_EX_ERROR;
++		goto err;
+ 	}
+ 	return 0;
++err:
++	warnx(_("error %d (%m) while executing fsck.%s for %s"),
++			retval, type, fs_get_device(fs));
++	return FSCK_EX_ERROR;
+ }
+ 
+ 
+@@ -1014,8 +1031,7 @@ static int fs_ignored_type(struct libmnt
+ /* Check if we should ignore this filesystem. */
+ static int ignore(struct libmnt_fs *fs)
+ {
+-	const char **ip, *type;
+-	int wanted = 0;
++	const char *type;
+ 
+ 	/*
+ 	 * If the pass number is 0, ignore it.
+@@ -1070,16 +1086,11 @@ static int ignore(struct libmnt_fs *fs)
+ 	if (fs_ignored_type(fs))
+ 		return 1;
+ 
+-	/* Do we really really want to check this fs? */
+-	for(ip = really_wanted; *ip; ip++)
+-		if (strcmp(type, *ip) == 0) {
+-			wanted = 1;
+-			break;
+-		}
++
+ 
+ 	/* See if the <fsck.fs> program is available. */
+ 	if (find_fsck(type) == NULL) {
+-		if (wanted)
++		if (fs_check_required(type))
+ 			warnx(_("cannot check %s: fsck.%s not found"),
+ 				fs_get_device(fs), type);
+ 		return 1;
+@@ -1557,7 +1568,6 @@ int main(int argc, char *argv[])
+ 			fs = add_dummy_fs(devices[i]);
+ 		else if (fs_ignored_type(fs))
+ 			continue;
+-
+ 		if (ignore_mounted && is_mounted(fs))
+ 			continue;
+ 		status |= fsck_device(fs, interactive);
diff --git a/SOURCES/2.25-fstrim-all.patch b/SOURCES/2.25-fstrim-all.patch
new file mode 100644
index 0000000..233e2ec
--- /dev/null
+++ b/SOURCES/2.25-fstrim-all.patch
@@ -0,0 +1,496 @@
+diff -up util-linux-2.23.2/libmount/src/libmount.h.in.kzak util-linux-2.23.2/libmount/src/libmount.h.in
+--- util-linux-2.23.2/libmount/src/libmount.h.in.kzak	2015-06-23 11:54:00.510210784 +0200
++++ util-linux-2.23.2/libmount/src/libmount.h.in	2015-06-23 11:54:58.592785482 +0200
+@@ -420,6 +420,15 @@ extern int mnt_table_get_root_fs(struct
+ extern int mnt_table_set_iter(struct libmnt_table *tb, struct libmnt_iter *itr,
+ 			      struct libmnt_fs *fs);
+ 
++enum {
++	MNT_UNIQ_FORWARD  = (1 << 1),	/* default is backward */
++	MNT_UNIQ_KEEPTREE = (1 << 2)
++};
++extern int mnt_table_uniq_fs(struct libmnt_table *tb, int flags,
++				int (*cmp)(struct libmnt_table *,
++					   struct libmnt_fs *,
++					   struct libmnt_fs *));
++
+ extern struct libmnt_fs *mnt_table_find_mountpoint(struct libmnt_table *tb,
+ 				const char *path, int direction);
+ extern struct libmnt_fs *mnt_table_find_target(struct libmnt_table *tb,
+diff -up util-linux-2.23.2/libmount/src/libmount.sym.kzak util-linux-2.23.2/libmount/src/libmount.sym
+--- util-linux-2.23.2/libmount/src/libmount.sym.kzak	2015-06-23 11:56:47.259989779 +0200
++++ util-linux-2.23.2/libmount/src/libmount.sym	2015-06-23 11:56:17.681206366 +0200
+@@ -256,3 +256,9 @@ global:
+ 	mnt_context_find_umount_fs;
+ 	mnt_table_find_mountpoint;
+ } MOUNT_2.22;
++
++/* backport from v2.25 to RHEL7 */
++MOUNT_2.25 {
++	mnt_table_uniq_fs;
++} MOUNT_2.23;
++
+diff -up util-linux-2.23.2/libmount/src/tab.c.kzak util-linux-2.23.2/libmount/src/tab.c
+--- util-linux-2.23.2/libmount/src/tab.c.kzak	2015-06-23 11:52:04.750058424 +0200
++++ util-linux-2.23.2/libmount/src/tab.c	2015-06-23 11:53:26.109462680 +0200
+@@ -398,6 +398,93 @@ int mnt_table_find_next_fs(struct libmnt
+ 	return 1;
+ }
+ 
++static int mnt_table_move_parent(struct libmnt_table *tb, int oldid, int newid)
++{
++	struct libmnt_iter itr;
++	struct libmnt_fs *fs;
++
++	if (!tb)
++		return -EINVAL;
++	if (list_empty(&tb->ents))
++		return 0;
++
++
++	mnt_reset_iter(&itr, MNT_ITER_FORWARD);
++
++	while (mnt_table_next_fs(tb, &itr, &fs) == 0) {
++		if (fs->parent == oldid)
++			fs->parent = newid;
++	}
++	return 0;
++}
++
++/**
++ * mnt_table_uniq_fs:
++ * @tb: table
++ * @flags: MNT_UNIQ_*
++ * @cmp: function to compare filesystems
++ *
++ * This function de-duplicate the @tb, but does not change order of the
++ * filesystems. The @cmp function has to return 0 if the filesystems are
++ * equal, otherwise non-zero.
++ *
++ * The default is to keep in the table later mounted filesystems (function uses
++ * backward mode iterator).
++ *
++ * @MNT_UNIQ_FORWARD:  remove later mounted filesystems
++ * @MNT_UNIQ_KEEPTREE: keep parent->id relation ship stil valid
++ *
++ * Returns: negative number in case of error, or 0 o success.
++ */
++int mnt_table_uniq_fs(struct libmnt_table *tb, int flags,
++				int (*cmp)(struct libmnt_table *,
++					   struct libmnt_fs *,
++					   struct libmnt_fs *))
++{
++	struct libmnt_iter itr;
++	struct libmnt_fs *fs;
++	int direction = MNT_ITER_BACKWARD;
++
++	if (!tb || !cmp)
++		return -EINVAL;
++	if (list_empty(&tb->ents))
++		return 0;
++
++	if (flags & MNT_UNIQ_FORWARD)
++		direction = MNT_ITER_FORWARD;
++
++
++	mnt_reset_iter(&itr, direction);
++
++	if ((flags & MNT_UNIQ_KEEPTREE) && !is_mountinfo(tb))
++		flags &= ~MNT_UNIQ_KEEPTREE;
++
++	while (mnt_table_next_fs(tb, &itr, &fs) == 0) {
++		int want = 1;
++		struct libmnt_iter xtr;
++		struct libmnt_fs *x;
++
++		mnt_reset_iter(&xtr, direction);
++		while (want && mnt_table_next_fs(tb, &xtr, &x) == 0) {
++			if (fs == x)
++				break;
++			want = cmp(tb, x, fs) != 0;
++		}
++
++		if (!want) {
++			if (flags & MNT_UNIQ_KEEPTREE)
++				mnt_table_move_parent(tb, mnt_fs_get_id(fs),
++							  mnt_fs_get_parent_id(fs));
++
++
++
++			mnt_table_remove_fs(tb, fs);
++		}
++	}
++
++	return 0;
++}
++
+ /**
+  * mnt_table_set_iter:
+  * @tb: tab pointer
+diff -up util-linux-2.23.2/sys-utils/fstrim.c.kzak util-linux-2.23.2/sys-utils/fstrim.c
+--- util-linux-2.23.2/sys-utils/fstrim.c.kzak	2013-06-13 09:46:10.535651605 +0200
++++ util-linux-2.23.2/sys-utils/fstrim.c	2015-06-23 11:57:59.435461283 +0200
+@@ -41,6 +41,11 @@
+ #include "strutils.h"
+ #include "c.h"
+ #include "closestream.h"
++#include "pathnames.h"
++#include "sysfs.h"
++#include "exitcodes.h"
++
++#include <libmount.h>
+ 
+ #ifndef FITRIM
+ struct fstrim_range {
+@@ -51,16 +56,216 @@ struct fstrim_range {
+ #define FITRIM		_IOWR('X', 121, struct fstrim_range)
+ #endif
+ 
++/* returns: 0 = success, 1 = unsupported, < 0 = error */
++static int fstrim_filesystem(const char *path, struct fstrim_range *rangetpl,
++			    int verbose)
++{
++	int fd;
++	struct stat sb;
++	struct fstrim_range range;
++
++	/* kernel modifies the range */
++	memcpy(&range, rangetpl, sizeof(range));
++
++	fd = open(path, O_RDONLY);
++	if (fd < 0) {
++		warn(_("cannot open %s"), path);
++		return -1;
++	}
++	if (fstat(fd, &sb) == -1) {
++		warn(_("stat of %s failed"), path);
++		return -1;
++	}
++	if (!S_ISDIR(sb.st_mode)) {
++		warnx(_("%s: not a directory"), path);
++		return -1;
++	}
++	errno = 0;
++	if (ioctl(fd, FITRIM, &range)) {
++		int rc = errno == EOPNOTSUPP || errno == ENOTTY ? 1 : -1;
++
++		if (rc != 1)
++			warn(_("%s: FITRIM ioctl failed"), path);
++		close(fd);
++		return rc;
++	}
++
++	if (verbose) {
++		char *str = size_to_human_string(
++				SIZE_SUFFIX_3LETTER | SIZE_SUFFIX_SPACE,
++				(uint64_t) range.len);
++		/* TRANSLATORS: The standard value here is a very large number. */
++		printf(_("%s: %s (%" PRIu64 " bytes) trimmed\n"),
++				path, str, (uint64_t) range.len);
++		free(str);
++	}
++	close(fd);
++	return 0;
++}
++
++static int has_discard(const char *devname, struct sysfs_cxt *wholedisk)
++{
++	struct sysfs_cxt cxt, *parent = NULL;
++	uint64_t dg = 0;
++	dev_t disk = 0, dev;
++	int rc;
++
++	dev = sysfs_devname_to_devno(devname, NULL);
++	if (!dev)
++		return 1;
++	/*
++	 * This is tricky to read the info from sys/, because the queue
++	 * atrributes are provided for whole devices (disk) only. We're trying
++	 * to reuse the whole-disk sysfs context to optimize this stuff (as
++	 * system usually have just one disk only).
++	 */
++	if (sysfs_devno_to_wholedisk(dev, NULL, 0, &disk) || !disk)
++		return 1;
++	if (dev != disk) {
++		if (wholedisk->devno != disk) {
++			sysfs_deinit(wholedisk);
++			if (sysfs_init(wholedisk, disk, NULL))
++				return 1;
++		}
++		parent = wholedisk;
++	}
++
++	rc = sysfs_init(&cxt, dev, parent);
++	if (!rc)
++		rc = sysfs_read_u64(&cxt, "queue/discard_granularity", &dg);
++
++	sysfs_deinit(&cxt);
++	return rc == 0 && dg > 0;
++}
++
++
++static int uniq_fs_target_cmp(
++		struct libmnt_table *tb __attribute__((__unused__)),
++		struct libmnt_fs *a,
++		struct libmnt_fs *b)
++{
++	return !mnt_fs_streq_target(a, mnt_fs_get_target(b));
++}
++
++static int uniq_fs_source_cmp(
++		struct libmnt_table *tb __attribute__((__unused__)),
++		struct libmnt_fs *a,
++		struct libmnt_fs *b)
++{
++	int eq;
++
++	if (mnt_fs_is_pseudofs(a) || mnt_fs_is_netfs(a) ||
++	    mnt_fs_is_pseudofs(b) || mnt_fs_is_netfs(b))
++		return 1;
++
++	eq = mnt_fs_streq_srcpath(a, mnt_fs_get_srcpath(b));
++	if (eq) {
++		const char *aroot = mnt_fs_get_root(a),
++			   *broot = mnt_fs_get_root(b);
++		if (!aroot || !broot)
++			eq = 0;
++		else if (strcmp(aroot, broot) != 0)
++			eq = 0;
++	}
++
++	return !eq;
++}
++
++/*
++ * fstrim --all follows "mount -a" return codes:
++ *
++ * 0  = all success
++ * 32 = all failed
++ * 64 = some failed, some success
++ */
++static int fstrim_all(struct fstrim_range *rangetpl, int verbose)
++{
++	struct libmnt_fs *fs;
++	struct libmnt_iter *itr;
++	struct libmnt_table *tab;
++	struct sysfs_cxt wholedisk = UL_SYSFSCXT_EMPTY;
++	int cnt = 0, cnt_err = 0;
++
++	mnt_init_debug(0);
++
++	itr = mnt_new_iter(MNT_ITER_BACKWARD);
++	if (!itr)
++		err(MOUNT_EX_FAIL, _("failed to initialize libmount iterator"));
++
++	tab = mnt_new_table_from_file(_PATH_PROC_MOUNTINFO);
++	if (!tab)
++		err(MOUNT_EX_FAIL, _("failed to parse %s"), _PATH_PROC_MOUNTINFO);
++
++	/* de-duplicate by mountpoints */
++	mnt_table_uniq_fs(tab, 0, uniq_fs_target_cmp);
++
++	/* de-duplicate by source and root */
++	mnt_table_uniq_fs(tab, 0, uniq_fs_source_cmp);
++
++	while (mnt_table_next_fs(tab, itr, &fs) == 0) {
++		const char *src = mnt_fs_get_srcpath(fs),
++			   *tgt = mnt_fs_get_target(fs);
++		char *path;
++		int rc = 1;
++
++		if (!src || !tgt || *src != '/' ||
++		    mnt_fs_is_pseudofs(fs) ||
++		    mnt_fs_is_netfs(fs))
++			continue;
++
++		/* Is it really accessible mountpoint? Not all mountpoints are
++		 * accessible (maybe over mounted by another fylesystem) */
++		path = mnt_get_mountpoint(tgt);
++		if (path && strcmp(path, tgt) == 0)
++			rc = 0;
++		free(path);
++		if (rc)
++			continue;	/* overlaying mount */
++
++		if (!has_discard(src, &wholedisk))
++			continue;
++		cnt++;
++
++		/*
++		 * We're able to detect that the device supports discard, but
++		 * things also depend on filesystem or device mapping, for
++		 * example vfat or LUKS (by default) does not support FSTRIM.
++		 *
++		 * This is reason why we ignore EOPNOTSUPP and ENOTTY errors
++		 * from discard ioctl.
++		 */
++		if (fstrim_filesystem(tgt, rangetpl, verbose) < 0)
++		       cnt_err++;
++	}
++
++	sysfs_deinit(&wholedisk);
++	mnt_free_table(tab);
++	mnt_free_iter(itr);
++
++	if (cnt && cnt == cnt_err)
++		return MOUNT_EX_FAIL;		/* all failed */
++	if (cnt && cnt_err)
++		return MOUNT_EX_SOMEOK;		/* some ok */
++
++	return EXIT_SUCCESS;
++}
++
+ static void __attribute__((__noreturn__)) usage(FILE *out)
+ {
+ 	fputs(USAGE_HEADER, out);
+ 	fprintf(out,
+ 	      _(" %s [options] <mount point>\n"), program_invocation_short_name);
++
++	fputs(USAGE_SEPARATOR, out);
++	fputs(_("Discard unused blocks on a mounted filesystem.\n"), out);
++
+ 	fputs(USAGE_OPTIONS, out);
+-	fputs(_(" -o, --offset <num>  offset in bytes to discard from\n"
+-		" -l, --length <num>  length of bytes to discard from the offset\n"
+-		" -m, --minimum <num> minimum extent length to discard\n"
+-		" -v, --verbose       print number of discarded bytes\n"), out);
++	fputs(_(" -a, --all           trim all mounted filesystems that are supported\n"), out);
++	fputs(_(" -o, --offset <num>  the offset in bytes to start discarding from\n"), out);
++	fputs(_(" -l, --length <num>  the number of bytes to discard\n"), out);
++	fputs(_(" -m, --minimum <num> the minimum extent length to discard\n"), out);
++	fputs(_(" -v, --verbose       print number of discarded bytes\n"), out);
++
+ 	fputs(USAGE_SEPARATOR, out);
+ 	fputs(USAGE_HELP, out);
+ 	fputs(USAGE_VERSION, out);
+@@ -70,12 +275,12 @@ static void __attribute__((__noreturn__)
+ 
+ int main(int argc, char **argv)
+ {
+-	char *path;
+-	int c, fd, verbose = 0;
++	char *path = NULL;
++	int c, rc, verbose = 0, all = 0;
+ 	struct fstrim_range range;
+-	struct stat sb;
+ 
+ 	static const struct option longopts[] = {
++	    { "all",       0, 0, 'a' },
+ 	    { "help",      0, 0, 'h' },
+ 	    { "version",   0, 0, 'V' },
+ 	    { "offset",    1, 0, 'o' },
+@@ -93,8 +298,11 @@ int main(int argc, char **argv)
+ 	memset(&range, 0, sizeof(range));
+ 	range.len = ULLONG_MAX;
+ 
+-	while ((c = getopt_long(argc, argv, "hVo:l:m:v", longopts, NULL)) != -1) {
++	while ((c = getopt_long(argc, argv, "ahVo:l:m:v", longopts, NULL)) != -1) {
+ 		switch(c) {
++		case 'a':
++			all = 1;
++			break;
+ 		case 'h':
+ 			usage(stdout);
+ 			break;
+@@ -122,38 +330,26 @@ int main(int argc, char **argv)
+ 		}
+ 	}
+ 
+-	if (optind == argc)
+-		errx(EXIT_FAILURE, _("no mountpoint specified"));
+-
+-	path = argv[optind++];
++	if (!all) {
++		if (optind == argc)
++			errx(EXIT_FAILURE, _("no mountpoint specified"));
++		path = argv[optind++];
++	}
+ 
+ 	if (optind != argc) {
+ 		warnx(_("unexpected number of arguments"));
+ 		usage(stderr);
+ 	}
+ 
+-	if (stat(path, &sb) == -1)
+-		err(EXIT_FAILURE, _("stat failed %s"), path);
+-	if (!S_ISDIR(sb.st_mode))
+-		errx(EXIT_FAILURE, _("%s: not a directory"), path);
+-
+-	fd = open(path, O_RDONLY);
+-	if (fd < 0)
+-		err(EXIT_FAILURE, _("cannot open %s"), path);
+-
+-	if (ioctl(fd, FITRIM, &range))
+-		err(EXIT_FAILURE, _("%s: FITRIM ioctl failed"), path);
+-
+-	if (verbose) {
+-		char *str = size_to_human_string(SIZE_SUFFIX_3LETTER |
+-						 SIZE_SUFFIX_SPACE,
+-						 (uint64_t) range.len);
+-		/* TRANSLATORS: The standard value here is a very large number. */
+-		printf(_("%s: %s (%" PRIu64 " bytes) trimmed\n"),
+-						path, str,
+-						(uint64_t) range.len);
+-		free(str);
++	if (all)
++		rc = fstrim_all(&range, verbose);
++	else {
++		rc = fstrim_filesystem(path, &range, verbose);
++		if (rc == 1) {
++			warnx(_("%s: the discard operation is not supported"), path);
++			rc = EXIT_FAILURE;
++		}
+ 	}
+-	close(fd);
+-	return EXIT_SUCCESS;
++
++	return rc;
+ }
+diff -up util-linux-2.23.2/sys-utils/fstrim.service.in.kzak util-linux-2.23.2/sys-utils/fstrim.service
+--- util-linux-2.23.2/sys-utils/fstrim.service.in.kzak	2015-06-23 12:02:18.505564273 +0200
++++ util-linux-2.23.2/sys-utils/fstrim.service.in	2015-06-23 12:02:05.049662802 +0200
+@@ -0,0 +1,6 @@
++[Unit]
++Description=Discard unused blocks
++
++[Service]
++Type=oneshot
++ExecStart=@sbindir@/fstrim -a
+diff -up util-linux-2.23.2/sys-utils/fstrim.timer.kzak util-linux-2.23.2/sys-utils/fstrim.timer
+--- util-linux-2.23.2/sys-utils/fstrim.timer.kzak	2015-06-23 12:02:18.505564273 +0200
++++ util-linux-2.23.2/sys-utils/fstrim.timer	2015-06-23 12:02:05.049662802 +0200
+@@ -0,0 +1,11 @@
++[Unit]
++Description=Discard unused blocks once a week
++Documentation=man:fstrim
++
++[Timer]
++OnCalendar=weekly
++AccuracySec=1h
++Persistent=true
++
++[Install]
++WantedBy=multi-user.target
+diff -up util-linux-2.23.2/sys-utils/Makemodule.am.kzak util-linux-2.23.2/sys-utils/Makemodule.am
+--- util-linux-2.23.2/sys-utils/Makemodule.am.kzak	2015-06-23 11:59:05.803975307 +0200
++++ util-linux-2.23.2/sys-utils/Makemodule.am	2015-06-23 12:01:18.682002323 +0200
+@@ -68,7 +68,18 @@ fsfreeze_SOURCES = sys-utils/fsfreeze.c
+ sbin_PROGRAMS += fstrim
+ dist_man_MANS += sys-utils/fstrim.8
+ fstrim_SOURCES = sys-utils/fstrim.c
+-fstrim_LDADD = $(LDADD) libcommon.la
++fstrim_LDADD = $(LDADD) libcommon.la libmount.la
++fstrim_CFLAGS = $(AM_CFLAGS) -I$(ul_libmount_incdir)
++
++if HAVE_SYSTEMD
++systemdsystemunit_DATA += \
++		sys-utils/fstrim.service \
++		sys-utils/fstrim.timer
++endif
++
++PATHFILES += sys-utils/fstrim.service
++EXTRA_DIST += sys-utils/fstrim.timer
++
+ 
+ sbin_PROGRAMS += blkdiscard
+ dist_man_MANS += sys-utils/blkdiscard.8
diff --git a/SOURCES/2.25-hwclock-hang.patch b/SOURCES/2.25-hwclock-hang.patch
new file mode 100644
index 0000000..de7df17
--- /dev/null
+++ b/SOURCES/2.25-hwclock-hang.patch
@@ -0,0 +1,255 @@
+From 4a44a54b3caf77923f0e3f1d5bdf5eda6ef07f62 Mon Sep 17 00:00:00 2001
+From: Chris MacGregor <chrismacgregor@google.com>
+Date: Thu, 27 Feb 2014 10:40:59 -0800
+Subject: [PATCH] hwclock: fix possible hang and other
+ set_hardware_clock_exact() issues
+
+In sys-utils/hwclock.c, set_hardware_clock_exact() has some problems when the
+process gets pre-empted (for more than 100ms) before reaching the time for
+which it waits:
+
+1. The "continue" statement causes execution to skip the final tdiff
+assignment at the end of the do...while loop, leading to the while condition
+using the wrong value of tdiff, and thus always exiting the loop once
+newhwtime != sethwtime (e.g., after 1 second).  This masks bug # 2, below.
+
+2. The previously-existing bug is that because it starts over waiting for the
+desired time whenever two successive calls to gettimeofday() return values >
+100ms apart, the loop will never terminate unless the process holds the CPU
+(without losing it for more than 100ms) for at least 500ms.  This can happen
+on a heavily loaded machine or on a virtual machine (or on a heavily loaded
+virtual machine).  This has been observed to occur, preventing a machine from
+completing the shutdown or reboot process due to a "hwclock --systohc" call in
+a shutdown script.
+
+The new implementation presented in this patch takes a somewhat different
+approach, intended to accomplish the same goals:
+
+It computes the desired target system time (at which the requested hardware
+clock time will be applied to the hardware clock), and waits for that time to
+arrive.  If it misses the time (such as due to being pre-empted for too long),
+it recalculates the target time, and increases the tolerance (how late it can
+be relative to the target time, and still be "close enough".  Thus, if all is
+well, the time will be set *very* precisely.  On a machine where the hwclock
+process is repeatedly pre-empted, it will set the time as precisely as is
+possible under the conditions present on that particular machine.  In any
+case, it will always terminate eventually (and pretty quickly); it will never
+hang forever.
+
+[kzak@redhat.com: - tiny coding style changes]
+
+Signed-off-by: Chris MacGregor <chrismacgregor@google.com>
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ sys-utils/hwclock.c | 170 ++++++++++++++++++++++++++++++++++++++++------------
+ 1 file changed, 131 insertions(+), 39 deletions(-)
+
+diff --git a/sys-utils/hwclock.c b/sys-utils/hwclock.c
+index 30660d4..395b5c3 100644
+--- a/sys-utils/hwclock.c
++++ b/sys-utils/hwclock.c
+@@ -125,7 +125,7 @@ struct adjtime {
+  * We are running in debug mode, wherein we put a lot of information about
+  * what we're doing to standard output.
+  */
+-bool debug;
++int debug;
+ 
+ /* Workaround for Award 4.50g BIOS bug: keep the year in a file. */
+ bool badyear;
+@@ -526,43 +526,141 @@ set_hardware_clock_exact(const time_t sethwtime,
+ 			 const struct timeval refsystime,
+ 			 const bool universal, const bool testing)
+ {
+-	time_t newhwtime = sethwtime;
+-	struct timeval beginsystime, nowsystime;
+-	double tdiff;
+-	int time_resync = 1;
+-
+ 	/*
+-	 * Now delay some more until Hardware Clock time newhwtime arrives.
+-	 * The 0.5 s is because the Hardware Clock always sets to your set
+-	 * time plus 500 ms (because it is designed to update to the next
+-	 * second precisely 500 ms after you finish the setting).
++	 * The Hardware Clock can only be set to any integer time plus one
++	 * half second.	 The integer time is required because there is no
++	 * interface to set or get a fractional second.	 The additional half
++	 * second is because the Hardware Clock updates to the following
++	 * second precisely 500 ms (not 1 second!) after you release the
++	 * divider reset (after setting the new time) - see description of
++	 * DV2, DV1, DV0 in Register A in the MC146818A data sheet (and note
++	 * that although that document doesn't say so, real-world code seems
++	 * to expect that the SET bit in Register B functions the same way).
++	 * That means that, e.g., when you set the clock to 1:02:03, it
++	 * effectively really sets it to 1:02:03.5, because it will update to
++	 * 1:02:04 only half a second later.  Our caller passes the desired
++	 * integer Hardware Clock time in sethwtime, and the corresponding
++	 * system time (which may have a fractional part, and which may or may
++	 * not be the same!) in refsystime.  In an ideal situation, we would
++	 * then apply sethwtime to the Hardware Clock at refsystime+500ms, so
++	 * that when the Hardware Clock ticks forward to sethwtime+1s half a
++	 * second later at refsystime+1000ms, everything is in sync.  So we
++	 * spin, waiting for gettimeofday() to return a time at or after that
++	 * time (refsystime+500ms) up to a tolerance value, initially 1ms.  If
++	 * we miss that time due to being preempted for some other process,
++	 * then we increase the margin a little bit (initially 1ms, doubling
++	 * each time), add 1 second (or more, if needed to get a time that is
++	 * in the future) to both the time for which we are waiting and the
++	 * time that we will apply to the Hardware Clock, and start waiting
++	 * again.
++	 * 
++	 * For example, the caller requests that we set the Hardware Clock to
++	 * 1:02:03, with reference time (current system time) = 6:07:08.250.
++	 * We want the Hardware Clock to update to 1:02:04 at 6:07:09.250 on
++	 * the system clock, and the first such update will occur 0.500
++	 * seconds after we write to the Hardware Clock, so we spin until the
++	 * system clock reads 6:07:08.750.  If we get there, great, but let's
++	 * imagine the system is so heavily loaded that our process is
++	 * preempted and by the time we get to run again, the system clock
++	 * reads 6:07:11.990.  We now want to wait until the next xx:xx:xx.750
++	 * time, which is 6:07:12.750 (4.5 seconds after the reference time),
++	 * at which point we will set the Hardware Clock to 1:02:07 (4 seconds
++	 * after the originally requested time).  If we do that successfully,
++	 * then at 6:07:13.250 (5 seconds after the reference time), the
++	 * Hardware Clock will update to 1:02:08 (5 seconds after the
++	 * originally requested time), and all is well thereafter.
+ 	 */
+-	do {
+-		if (time_resync) {
+-			gettimeofday(&beginsystime, NULL);
+-			tdiff = time_diff(beginsystime, refsystime);
+-			newhwtime = sethwtime + (int)(tdiff + 0.5);
+-			if (debug)
+-				printf(_
+-				       ("Time elapsed since reference time has been %.6f seconds.\n"
+-					"Delaying further to reach the new time.\n"),
+-				       tdiff);
+-			time_resync = 0;
++
++	time_t newhwtime = sethwtime;
++	double target_time_tolerance_secs = 0.001;  /* initial value */
++	double tolerance_incr_secs = 0.001;	    /* initial value */
++	const double RTC_SET_DELAY_SECS = 0.5;	    /* 500 ms */
++	const struct timeval RTC_SET_DELAY_TV = { 0, RTC_SET_DELAY_SECS * 1E6 };
++
++	struct timeval targetsystime;
++	struct timeval nowsystime;
++	struct timeval prevsystime = refsystime;
++	double deltavstarget;
++
++	timeradd(&refsystime, &RTC_SET_DELAY_TV, &targetsystime);
++
++	while (1) {
++		double ticksize;
++
++		/* FOR TESTING ONLY: inject random delays of up to 1000ms */
++		if (debug >= 10) {
++			int usec = random() % 1000000;
++			printf(_("sleeping ~%d usec\n"), usec);
++			usleep(usec);
+ 		}
+ 
+ 		gettimeofday(&nowsystime, NULL);
+-		tdiff = time_diff(nowsystime, beginsystime);
+-		if (tdiff < 0) {
+-			time_resync = 1;	/* probably backward time reset */
+-			continue;
+-		}
+-		if (tdiff > 0.1) {
+-			time_resync = 1;	/* probably forward time reset */
+-			continue;
++		deltavstarget = time_diff(nowsystime, targetsystime);
++		ticksize = time_diff(nowsystime, prevsystime);
++		prevsystime = nowsystime;
++
++		if (ticksize < 0) {
++			if (debug)
++				printf(_("time jumped backward %.6f seconds "
++					 "to %ld.%06d - retargeting\n"),
++				       ticksize, (long)nowsystime.tv_sec,
++				       (int)nowsystime.tv_usec);
++			/* The retarget is handled at the end of the loop. */
++		} else if (deltavstarget < 0) {
++			/* deltavstarget < 0 if current time < target time */
++			if (debug >= 2)
++				printf(_("%ld.%06d < %ld.%06d (%.6f)\n"),
++				       (long)nowsystime.tv_sec,
++				       (int)nowsystime.tv_usec,
++				       (long)targetsystime.tv_sec,
++				       (int)targetsystime.tv_usec,
++				       deltavstarget);
++			continue;  /* not there yet - keep spinning */
++		} else if (deltavstarget <= target_time_tolerance_secs) {
++			/* Close enough to the target time; done waiting. */
++			break;
++		} else /* (deltavstarget > target_time_tolerance_secs) */ {
++			/*
++			 * We missed our window.  Increase the tolerance and
++			 * aim for the next opportunity.
++			 */
++			if (debug)
++				printf(_("missed it - %ld.%06d is too far "
++					 "past %ld.%06d (%.6f > %.6f)\n"),
++				       (long)nowsystime.tv_sec,
++				       (int)nowsystime.tv_usec,
++				       (long)targetsystime.tv_sec,
++				       (int)targetsystime.tv_usec,
++				       deltavstarget,
++				       target_time_tolerance_secs);
++			target_time_tolerance_secs += tolerance_incr_secs;
++			tolerance_incr_secs *= 2;
+ 		}
+-		beginsystime = nowsystime;
+-		tdiff = time_diff(nowsystime, refsystime);
+-	} while (newhwtime == sethwtime + (int)(tdiff + 0.5));
++
++		/*
++		 * Aim for the same offset (tv_usec) within the second in
++		 * either the current second (if that offset hasn't arrived
++		 * yet), or the next second.
++		 */
++		if (nowsystime.tv_usec < targetsystime.tv_usec)
++			targetsystime.tv_sec = nowsystime.tv_sec;
++		else
++			targetsystime.tv_sec = nowsystime.tv_sec + 1;
++	}
++
++	newhwtime = sethwtime
++		    + (int)(time_diff(nowsystime, refsystime)
++			    - RTC_SET_DELAY_SECS /* don't count this */
++			    + 0.5 /* for rounding */);
++	if (debug)
++		printf(_("%ld.%06d is close enough to %ld.%06d (%.6f < %.6f)\n"
++			 "Set RTC to %ld (%ld + %d; refsystime = %ld.%06d)\n"),
++		       (long)nowsystime.tv_sec, (int)nowsystime.tv_usec,
++		       (long)targetsystime.tv_sec, (int)targetsystime.tv_usec,
++		       deltavstarget, target_time_tolerance_secs,
++		       (long)newhwtime, (long)sethwtime,
++		       (int)(newhwtime - sethwtime),
++		       (long)refsystime.tv_sec, (int)refsystime.tv_usec);
+ 
+ 	set_hardware_clock(newhwtime, universal, testing);
+ }
+@@ -1636,7 +1734,7 @@ int main(int argc, char **argv)
+ 
+ 		switch (c) {
+ 		case 'D':
+-			debug = TRUE;
++			++debug;
+ 			break;
+ 		case 'a':
+ 			adjust = TRUE;
+@@ -1953,10 +2051,4 @@ void __attribute__((__noreturn__)) hwaudit_exit(int status)
+  *
+  * hwclock uses this method, and considers the Hardware Clock to have
+  * infinite precision.
+- *
+- * TODO: Enhancements needed:
+- *
+- *  - When waiting for whole second boundary in set_hardware_clock_exact,
+- *    fail if we miss the goal by more than .1 second, as could happen if we
+- *    get pre-empted (by the kernel dispatcher).
+  */
+-- 
+1.9.3
+
diff --git a/SOURCES/2.25-lib-add-path_strdup.patch b/SOURCES/2.25-lib-add-path_strdup.patch
new file mode 100644
index 0000000..e3a9cc3
--- /dev/null
+++ b/SOURCES/2.25-lib-add-path_strdup.patch
@@ -0,0 +1,51 @@
+From dd3bc51a539ffdd5c6c6b7d0b20acd1f61bdd337 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Mon, 6 Jan 2014 16:48:13 +0100
+Subject: [PATCH] lib/path: add path_strdup()
+
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ include/path.h |  2 ++
+ lib/path.c     | 13 +++++++++++++
+ 2 files changed, 15 insertions(+)
+
+diff --git a/include/path.h b/include/path.h
+index 615d284..45da692 100644
+--- a/include/path.h
++++ b/include/path.h
+@@ -4,6 +4,8 @@
+ #include <stdio.h>
+ #include <stdint.h>
+ 
++extern char *path_strdup(const char *path, ...)
++			__attribute__ ((__format__ (__printf__, 1, 2)));
+ extern FILE *path_fopen(const char *mode, int exit_on_err, const char *path, ...)
+ 			__attribute__ ((__format__ (__printf__, 3, 4)));
+ extern void path_read_str(char *result, size_t len, const char *path, ...)
+diff --git a/lib/path.c b/lib/path.c
+index 1f7e258..42d321c 100644
+--- a/lib/path.c
++++ b/lib/path.c
+@@ -49,6 +49,19 @@ path_vcreate(const char *path, va_list ap)
+ 	return pathbuf;
+ }
+ 
++char *
++path_strdup(const char *path, ...)
++{
++	const char *p;
++	va_list ap;
++
++	va_start(ap, path);
++	p = path_vcreate(path, ap);
++	va_end(ap);
++
++	return p ? strdup(p) : NULL;
++}
++
+ static FILE *
+ path_vfopen(const char *mode, int exit_on_error, const char *path, va_list ap)
+ {
+-- 
+1.8.4.2
+
diff --git a/SOURCES/2.25-libblkid-Identify-extN-file-system-properly.patch b/SOURCES/2.25-libblkid-Identify-extN-file-system-properly.patch
new file mode 100644
index 0000000..da4bcb3
--- /dev/null
+++ b/SOURCES/2.25-libblkid-Identify-extN-file-system-properly.patch
@@ -0,0 +1,240 @@
+diff -up util-linux-2.23.2/libblkid/src/superblocks/ext.c.kzak util-linux-2.23.2/libblkid/src/superblocks/ext.c
+--- util-linux-2.23.2/libblkid/src/superblocks/ext.c.kzak	2013-06-13 09:46:10.422650639 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/ext.c	2014-01-23 10:28:51.175358545 +0100
+@@ -18,7 +18,6 @@
+ #endif
+ #include <time.h>
+ 
+-#include "linux_version.h"
+ #include "superblocks.h"
+ 
+ struct ext2_super_block {
+@@ -132,140 +131,11 @@ struct ext2_super_block {
+ #define EXT3_FEATURE_RO_COMPAT_UNSUPPORTED	~EXT3_FEATURE_RO_COMPAT_SUPP
+ 
+ /*
+- * Check to see if a filesystem is in /proc/filesystems.
+- * Returns 1 if found, 0 if not
+- */
+-static int fs_proc_check(const char *fs_name)
+-{
+-	FILE	*f;
+-	char	buf[80], *cp, *t;
+-
+-	f = fopen("/proc/filesystems", "r" UL_CLOEXECSTR);
+-	if (!f)
+-		return 0;
+-	while (!feof(f)) {
+-		if (!fgets(buf, sizeof(buf), f))
+-			break;
+-		cp = buf;
+-		if (!isspace(*cp)) {
+-			while (*cp && !isspace(*cp))
+-				cp++;
+-		}
+-		while (*cp && isspace(*cp))
+-			cp++;
+-		if ((t = strchr(cp, '\n')) != NULL)
+-			*t = 0;
+-		if ((t = strchr(cp, '\t')) != NULL)
+-			*t = 0;
+-		if ((t = strchr(cp, ' ')) != NULL)
+-			*t = 0;
+-		if (!strcmp(fs_name, cp)) {
+-			fclose(f);
+-			return 1;
+-		}
+-	}
+-	fclose(f);
+-	return (0);
+-}
+-
+-/*
+- * Check to see if a filesystem is available as a module
+- * Returns 1 if found, 0 if not
+- */
+-static int check_for_modules(const char *fs_name)
+-{
+-#ifdef __linux__
+-	struct utsname	uts;
+-	FILE		*f;
+-	char		buf[1024], *cp;
+-	int		namesz;
+-
+-	if (uname(&uts))
+-		return 0;
+-	snprintf(buf, sizeof(buf), "/lib/modules/%s/modules.dep", uts.release);
+-
+-	f = fopen(buf, "r" UL_CLOEXECSTR);
+-	if (!f)
+-		return 0;
+-
+-	namesz = strlen(fs_name);
+-
+-	while (!feof(f)) {
+-		if (!fgets(buf, sizeof(buf), f))
+-			break;
+-		if ((cp = strchr(buf, ':')) != NULL)
+-			*cp = 0;
+-		else
+-			continue;
+-		if ((cp = strrchr(buf, '/')) == NULL)
+-			continue;
+-		cp++;
+-
+-		if (!strncmp(cp, fs_name, namesz) &&
+-		    (!strcmp(cp + namesz, ".ko") ||
+-		     !strcmp(cp + namesz, ".ko.gz"))) {
+-			fclose(f);
+-			return 1;
+-		}
+-	}
+-	fclose(f);
+-#endif /* __linux__ */
+-	return 0;
+-}
+-
+-/*
+  * Starting in 2.6.29, ext4 can be used to support filesystems
+  * without a journal.
+  */
+ #define EXT4_SUPPORTS_EXT2 KERNEL_VERSION(2, 6, 29)
+ 
+-static int system_supports_ext2(void)
+-{
+-	static time_t	last_check = 0;
+-	static int	ret = -1;
+-	time_t		now = time(0);
+-
+-	if (ret != -1 || (now - last_check) < 5)
+-		return ret;
+-	last_check = now;
+-	ret = (fs_proc_check("ext2") || check_for_modules("ext2"));
+-	return ret;
+-}
+-
+-static int system_supports_ext4(void)
+-{
+-	static time_t	last_check = 0;
+-	static int	ret = -1;
+-	time_t		now = time(0);
+-
+-	if (ret != -1 || (now - last_check) < 5)
+-		return ret;
+-	last_check = now;
+-	ret = (fs_proc_check("ext4") || check_for_modules("ext4"));
+-	return ret;
+-}
+-
+-static int system_supports_ext4dev(void)
+-{
+-	static time_t	last_check = 0;
+-	static int	ret = -1;
+-	time_t		now = time(0);
+-
+-	if (ret != -1 || (now - last_check) < 5)
+-		return ret;
+-	last_check = now;
+-	ret = (fs_proc_check("ext4dev") || check_for_modules("ext4dev"));
+-	return ret;
+-}
+-
+-static int system_supports_ext4_ext2(void)
+-{
+-#ifdef __linux__
+-	return get_linux_version() >= EXT4_SUPPORTS_EXT2;
+-#else
+-	return 0;
+-#endif
+-}
+ /*
+  * reads superblock and returns:
+  *	fc = feature_compat
+@@ -355,15 +225,6 @@ static int probe_ext2(blkid_probe pr,
+ 	    (fi  & EXT2_FEATURE_INCOMPAT_UNSUPPORTED))
+ 		return -BLKID_ERR_PARAM;
+ 
+-	/*
+-	 * If ext2 is not present, but ext4 or ext4dev are, then
+-	 * disclaim we are ext2
+-	 */
+-	if (!system_supports_ext2() &&
+-	    (system_supports_ext4() || system_supports_ext4dev()) &&
+-	    system_supports_ext4_ext2())
+-		return -BLKID_ERR_PARAM;
+-
+ 	ext_get_info(pr, 2, es);
+ 	return 0;
+ }
+@@ -406,34 +267,9 @@ static int probe_ext4dev(blkid_probe pr,
+ 	if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
+ 		return -BLKID_ERR_PARAM;
+ 
+-	/*
+-	 * If the filesystem does not have a journal and ext2 and ext4
+-	 * is not present, then force this to be detected as an
+-	 * ext4dev filesystem.
+-	 */
+-	if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
+-	    !system_supports_ext2() && !system_supports_ext4() &&
+-	    system_supports_ext4dev() &&
+-	    system_supports_ext4_ext2())
+-		goto force_ext4dev;
+-
+-	/*
+-	 * If the filesystem is marked as OK for use by in-development
+-	 * filesystem code, but ext4dev is not supported, and ext4 is,
+-	 * then don't call ourselves ext4dev, since we should be
+-	 * detected as ext4 in that case.
+-	 *
+-	 * If the filesystem is marked as in use by production
+-	 * filesystem, then it can only be used by ext4 and NOT by
+-	 * ext4dev, so always disclaim we are ext4dev in that case.
+-	 */
+-	if (le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) {
+-		if (!system_supports_ext4dev() && system_supports_ext4())
+-			return -BLKID_ERR_PARAM;
+-	} else
++	if (!(le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS))
+ 		return -BLKID_ERR_PARAM;
+ 
+-force_ext4dev:
+ 	ext_get_info(pr, 4, es);
+ 	return 0;
+ }
+@@ -452,22 +288,11 @@ static int probe_ext4(blkid_probe pr,
+ 	if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
+ 		return -BLKID_ERR_PARAM;
+ 
+-	/*
+-	 * If the filesystem does not have a journal and ext2 is not
+-	 * present, then force this to be detected as an ext2
+-	 * filesystem.
+-	 */
+-	if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
+-	    !system_supports_ext2() && system_supports_ext4() &&
+-	    system_supports_ext4_ext2())
+-		goto force_ext4;
+-
+ 	/* Ext4 has at least one feature which ext3 doesn't understand */
+ 	if (!(frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) &&
+ 	    !(fi  & EXT3_FEATURE_INCOMPAT_UNSUPPORTED))
+ 		return -BLKID_ERR_PARAM;
+ 
+-force_ext4:
+ 	/*
+ 	 * If the filesystem is a OK for use by in-development
+ 	 * filesystem code, and ext4dev is supported or ext4 is not
+@@ -478,10 +303,8 @@ force_ext4:
+ 	 * filesystem, then it can only be used by ext4 and NOT by
+ 	 * ext4dev.
+ 	 */
+-	if (le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) {
+-		if (system_supports_ext4dev() || !system_supports_ext4())
+-			return -BLKID_ERR_PARAM;
+-	}
++	if (le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS)
++		return -BLKID_ERR_PARAM;
+ 
+ 	ext_get_info(pr, 4, es);
+ 	return 0;
diff --git a/SOURCES/2.25-libblkid-detect-alone-PMBR.patch b/SOURCES/2.25-libblkid-detect-alone-PMBR.patch
new file mode 100644
index 0000000..fe06167
--- /dev/null
+++ b/SOURCES/2.25-libblkid-detect-alone-PMBR.patch
@@ -0,0 +1,100 @@
+diff -up util-linux-2.23.2/libblkid/src/partitions/gpt.c.kzak util-linux-2.23.2/libblkid/src/partitions/gpt.c
+--- util-linux-2.23.2/libblkid/src/partitions/gpt.c.kzak	2013-07-30 10:39:26.206738239 +0200
++++ util-linux-2.23.2/libblkid/src/partitions/gpt.c	2014-01-23 11:06:17.364011293 +0100
+@@ -156,13 +156,15 @@ static int last_lba(blkid_probe pr, uint
+  * Note that the PMBR detection is optional (enabled by default) and could be
+  * disabled by BLKID_PARTS_FOPCE_GPT flag (see also blkid_paertitions_set_flags()).
+  */
+-static int is_pmbr_valid(blkid_probe pr)
++static int is_pmbr_valid(blkid_probe pr, int *has)
+ {
+ 	int flags = blkid_partitions_get_flags(pr);
+ 	unsigned char *data;
+ 	struct dos_partition *p;
+ 	int i;
+ 
++	if (has)
++		*has = 0;
+ 	if (flags & BLKID_PARTS_FORCE_GPT)
+ 		goto ok;			/* skip PMBR check */
+ 
+@@ -182,6 +184,8 @@ static int is_pmbr_valid(blkid_probe pr)
+ failed:
+ 	return 0;
+ ok:
++	if (has)
++		*has = 1;
+ 	return 1;
+ }
+ 
+@@ -305,7 +309,7 @@ static int probe_gpt_pt(blkid_probe pr,
+ 	if (last_lba(pr, &lastlba))
+ 		goto nothing;
+ 
+-	if (!is_pmbr_valid(pr))
++	if (!is_pmbr_valid(pr, NULL))
+ 		goto nothing;
+ 
+ 	h = get_gpt_header(pr, &hdr, &e, (lba = GPT_PRIMARY_LBA), lastlba);
+@@ -410,3 +414,39 @@ const struct blkid_idinfo gpt_pt_idinfo
+ 	.magics		= BLKID_NONE_MAGIC
+ };
+ 
++
++
++/* probe for *alone* protective MBR */
++static int probe_pmbr_pt(blkid_probe pr,
++		const struct blkid_idmag *mag __attribute__((__unused__)))
++{
++	int has = 0;
++	struct gpt_entry *e;
++	uint64_t lastlba = 0;
++	struct gpt_header hdr;
++
++	if (last_lba(pr, &lastlba))
++		goto nothing;
++
++	is_pmbr_valid(pr, &has);
++	if (!has)
++		goto nothing;
++
++	if (!get_gpt_header(pr, &hdr, &e, GPT_PRIMARY_LBA, lastlba) &&
++	    !get_gpt_header(pr, &hdr, &e, lastlba, lastlba))
++		return 0;
++nothing:
++	return 1;
++}
++
++const struct blkid_idinfo pmbr_pt_idinfo =
++{
++	.name		= "PMBR",
++	.probefunc	= probe_pmbr_pt,
++	.magics		=
++	{
++		{ .magic = "\x55\xAA", .len = 2, .sboff = 510 },
++		{ NULL }
++	}
++};
++
+diff -up util-linux-2.23.2/libblkid/src/partitions/partitions.c.kzak util-linux-2.23.2/libblkid/src/partitions/partitions.c
+--- util-linux-2.23.2/libblkid/src/partitions/partitions.c.kzak	2013-07-30 10:39:26.207738249 +0200
++++ util-linux-2.23.2/libblkid/src/partitions/partitions.c	2014-01-23 11:06:17.364011293 +0100
+@@ -125,6 +125,7 @@ static const struct blkid_idinfo *idinfo
+ 	&sun_pt_idinfo,
+ 	&dos_pt_idinfo,
+ 	&gpt_pt_idinfo,
++	&pmbr_pt_idinfo,	/* always after GPT */
+ 	&mac_pt_idinfo,
+ 	&ultrix_pt_idinfo,
+ 	&bsd_pt_idinfo,
+diff -up util-linux-2.23.2/libblkid/src/partitions/partitions.h.kzak util-linux-2.23.2/libblkid/src/partitions/partitions.h
+--- util-linux-2.23.2/libblkid/src/partitions/partitions.h.kzak	2013-07-30 10:39:26.208738259 +0200
++++ util-linux-2.23.2/libblkid/src/partitions/partitions.h	2014-01-23 11:06:17.364011293 +0100
+@@ -59,6 +59,7 @@ extern const struct blkid_idinfo mac_pt_
+ extern const struct blkid_idinfo dos_pt_idinfo;
+ extern const struct blkid_idinfo minix_pt_idinfo;
+ extern const struct blkid_idinfo gpt_pt_idinfo;
++extern const struct blkid_idinfo pmbr_pt_idinfo;
+ extern const struct blkid_idinfo ultrix_pt_idinfo;
+ 
+ #endif /* BLKID_PARTITIONS_H */
diff --git a/SOURCES/2.25-libblkid-gpt-512.patch b/SOURCES/2.25-libblkid-gpt-512.patch
new file mode 100644
index 0000000..3e711ce
--- /dev/null
+++ b/SOURCES/2.25-libblkid-gpt-512.patch
@@ -0,0 +1,22 @@
+diff -up util-linux-2.23.2/libblkid/src/partitions/gpt.c.kzak util-linux-2.23.2/libblkid/src/partitions/gpt.c
+--- util-linux-2.23.2/libblkid/src/partitions/gpt.c.kzak	2014-09-25 10:36:26.761377688 +0200
++++ util-linux-2.23.2/libblkid/src/partitions/gpt.c	2014-09-25 10:36:56.912665364 +0200
+@@ -332,7 +332,7 @@ static int probe_gpt_pt(blkid_probe pr,
+ 
+ 	blkid_probe_use_wiper(pr, lba * blkid_probe_get_size(pr), 8);
+ 
+-	if (blkid_probe_set_magic(pr, lba << 9,
++	if (blkid_probe_set_magic(pr, blkid_probe_get_sectorsize(pr) * lba,
+ 			      sizeof(GPT_HEADER_SIGNATURE_STR) - 1,
+ 			      (unsigned char *) GPT_HEADER_SIGNATURE_STR))
+ 		goto err;
+@@ -345,7 +345,8 @@ static int probe_gpt_pt(blkid_probe pr,
+ 	if (!ls)
+ 		goto err;
+ 
+-	tab = blkid_partlist_new_parttable(ls, "gpt", lba << 9);
++	tab = blkid_partlist_new_parttable(ls, "gpt",
++				blkid_probe_get_sectorsize(pr) * lba);
+ 	if (!tab)
+ 		goto err;
+ 
diff --git a/SOURCES/2.25-libblkid-io-errors.patch b/SOURCES/2.25-libblkid-io-errors.patch
new file mode 100644
index 0000000..4392cf5
--- /dev/null
+++ b/SOURCES/2.25-libblkid-io-errors.patch
@@ -0,0 +1,2590 @@
+diff -up util-linux-2.23.2/libblkid/src/blkidP.h.kzak util-linux-2.23.2/libblkid/src/blkidP.h
+--- util-linux-2.23.2/libblkid/src/blkidP.h.kzak	2014-03-28 15:11:18.334283704 +0100
++++ util-linux-2.23.2/libblkid/src/blkidP.h	2014-03-28 15:11:44.676551975 +0100
+@@ -297,6 +297,9 @@ struct blkid_struct_cache
+ /* old systems */
+ #define BLKID_CACHE_FILE_OLD	"/etc/blkid.tab"
+ 
++#define BLKID_PROBE_OK	 0
++#define BLKID_PROBE_NONE 1
++
+ #define BLKID_ERR_IO	 5
+ #define BLKID_ERR_PROC	 9
+ #define BLKID_ERR_MEM	12
+diff -up util-linux-2.23.2/libblkid/src/partitions/aix.c.kzak util-linux-2.23.2/libblkid/src/partitions/aix.c
+--- util-linux-2.23.2/libblkid/src/partitions/aix.c.kzak	2013-05-30 15:21:43.120591308 +0200
++++ util-linux-2.23.2/libblkid/src/partitions/aix.c	2014-03-28 15:11:44.676551975 +0100
+@@ -22,19 +22,17 @@ static int probe_aix_pt(blkid_probe pr,
+ 
+ 	if (blkid_partitions_need_typeonly(pr))
+ 		/* caller does not ask for details about partitions */
+-		return 0;
++		return BLKID_PROBE_OK;
+ 
+ 	ls = blkid_probe_get_partlist(pr);
+ 	if (!ls)
+-		goto err;
++		return BLKID_PROBE_NONE;
+ 
+ 	tab = blkid_partlist_new_parttable(ls, "aix", 0);
+ 	if (!tab)
+-		goto err;
++		return -ENOMEM;
+ 
+-	return 0;
+-err:
+-	return -1;
++	return BLKID_PROBE_OK;
+ }
+ 
+ /*
+diff -up util-linux-2.23.2/libblkid/src/partitions/bsd.c.kzak util-linux-2.23.2/libblkid/src/partitions/bsd.c
+--- util-linux-2.23.2/libblkid/src/partitions/bsd.c.kzak	2013-07-15 10:25:46.283049056 +0200
++++ util-linux-2.23.2/libblkid/src/partitions/bsd.c	2014-03-28 15:11:44.677551986 +0100
+@@ -113,20 +113,24 @@ static int probe_bsd_pt(blkid_probe pr,
+ 	blkid_partlist ls;
+ 	int i, nparts = BSD_MAXPARTITIONS;
+ 	unsigned char *data;
++	int rc = BLKID_PROBE_NONE;
+ 
+ 	if (blkid_partitions_need_typeonly(pr))
+ 		/* caller does not ask for details about partitions */
+-		return 0;
++		return rc;
+ 
+ 	data = blkid_probe_get_sector(pr, BLKID_MAG_SECTOR(mag));
+-	if (!data)
++	if (!data) {
++		if (errno)
++			rc = -errno;
+ 		goto nothing;
++	}
+ 
+ 	l = (struct bsd_disklabel *) data + BLKID_MAG_LASTOFFSET(mag);
+ 
+ 	ls = blkid_probe_get_partlist(pr);
+ 	if (!ls)
+-		goto err;
++		goto nothing;
+ 
+ 	/* try to determine the real type of BSD system according to
+ 	 * (parental) primary partition */
+@@ -152,8 +156,10 @@ static int probe_bsd_pt(blkid_probe pr,
+ 	}
+ 
+ 	tab = blkid_partlist_new_parttable(ls, name, BLKID_MAG_OFFSET(mag));
+-	if (!tab)
+-		goto err;
++	if (!tab) {
++		rc = -ENOMEM;
++		goto nothing;
++	}
+ 
+ 	if (le16_to_cpu(l->d_npartitions) < BSD_MAXPARTITIONS)
+ 		nparts = le16_to_cpu(l->d_npartitions);
+@@ -189,18 +195,18 @@ static int probe_bsd_pt(blkid_probe pr,
+ 		}
+ 
+ 		par = blkid_partlist_add_partition(ls, tab, start, size);
+-		if (!par)
+-			goto err;
++		if (!par) {
++			rc = -ENOMEM;
++			goto nothing;
++		}
+ 
+ 		blkid_partition_set_type(par, p->p_fstype);
+ 	}
+ 
+-	return 0;
++	return BLKID_PROBE_OK;
+ 
+ nothing:
+-	return 1;
+-err:
+-	return -1;
++	return rc;
+ }
+ 
+ 
+diff -up util-linux-2.23.2/libblkid/src/partitions/dos.c.kzak util-linux-2.23.2/libblkid/src/partitions/dos.c
+--- util-linux-2.23.2/libblkid/src/partitions/dos.c.kzak	2013-07-30 10:39:26.205738229 +0200
++++ util-linux-2.23.2/libblkid/src/partitions/dos.c	2014-03-28 15:13:23.220555797 +0100
+@@ -53,10 +53,13 @@ static int parse_dos_extended(blkid_prob
+ 		uint32_t start, size;
+ 
+ 		if (++ct_nodata > 100)
+-			return 0;
++			return BLKID_PROBE_OK;
+ 		data = blkid_probe_get_sector(pr, cur_start);
+-		if (!data)
++		if (!data) {
++			if (errno)
++				return -errno;
+ 			goto leave;	/* malformed partition? */
++		}
+ 
+ 		if (!is_valid_mbr_signature(data))
+ 			goto leave;
+@@ -99,7 +102,7 @@ static int parse_dos_extended(blkid_prob
+ 
+ 			par = blkid_partlist_add_partition(ls, tab, abs_start, size);
+ 			if (!par)
+-				goto err;
++				return -ENOMEM;
+ 
+ 			blkid_partition_set_type(par, p->sys_type);
+ 			blkid_partition_set_flags(par, p->boot_ind);
+@@ -123,9 +126,7 @@ static int parse_dos_extended(blkid_prob
+ 		cur_size = size;
+ 	}
+ leave:
+-	return 0;
+-err:
+-	return -1;
++	return BLKID_PROBE_OK;
+ }
+ 
+ static int probe_dos_pt(blkid_probe pr,
+@@ -140,8 +141,11 @@ static int probe_dos_pt(blkid_probe pr,
+ 	uint32_t start, size, id;
+ 
+ 	data = blkid_probe_get_sector(pr, 0);
+-	if (!data)
++	if (!data) {
++		if (errno)
++			return -errno;
+ 		goto nothing;
++	}
+ 
+ 	/* ignore disks with AIX magic number -- for more details see aix.c */
+ 	if (memcmp(data, BLKID_AIX_MAGIC_STRING, BLKID_AIX_MAGIC_STRLEN) == 0)
+@@ -152,7 +156,7 @@ static int probe_dos_pt(blkid_probe pr,
+ 	 * either the boot sector of a FAT filesystem or a DOS-type
+ 	 * partition table.
+ 	 */
+-	if (blkid_probe_is_vfat(pr)) {
++	if (blkid_probe_is_vfat(pr) == 1) {
+ 		DBG(LOWPROBE, blkid_debug("probably FAT -- ignore"));
+ 		goto nothing;
+ 	}
+@@ -189,6 +193,8 @@ static int probe_dos_pt(blkid_probe pr,
+ 		return 0;
+ 
+ 	ls = blkid_probe_get_partlist(pr);
++	if (!ls)
++		goto nothing;
+ 
+ 	/* sector size factor (the start and size are in the real sectors, but
+ 	 * we need to convert all sizes to 512 logical sectors
+@@ -198,7 +204,7 @@ static int probe_dos_pt(blkid_probe pr,
+ 	/* allocate a new partition table */
+ 	tab = blkid_partlist_new_parttable(ls, "dos", BLKID_MSDOS_PT_OFFSET);
+ 	if (!tab)
+-		goto err;
++		return -ENOMEM;
+ 
+ 	id = dos_parttable_id(data);
+ 	if (id) {
+@@ -224,7 +230,7 @@ static int probe_dos_pt(blkid_probe pr,
+ 		}
+ 		par = blkid_partlist_add_partition(ls, tab, start, size);
+ 		if (!par)
+-			goto err;
++			return -ENOMEM;
+ 
+ 		blkid_partition_set_type(par, p->sys_type);
+ 		blkid_partition_set_flags(par, p->boot_ind);
+@@ -244,13 +250,14 @@ static int probe_dos_pt(blkid_probe pr,
+ 			continue;
+ 		if (is_extended(p) &&
+ 		    parse_dos_extended(pr, tab, start, size, ssf) == -1)
+-			goto err;
++			goto nothing;
+ 	}
+ 
+ 	/* Parse subtypes (nested partitions) on large disks */
+ 	if (!blkid_probe_is_tiny(pr)) {
+ 		for (p = p0, i = 0; i < 4; i++, p++) {
+ 			size_t n;
++			int rc;
+ 
+ 			if (!dos_partition_size(p) || is_extended(p))
+ 				continue;
+@@ -259,20 +266,19 @@ static int probe_dos_pt(blkid_probe pr,
+ 				if (dos_nested[n].type != p->sys_type)
+ 					continue;
+ 
+-				if (blkid_partitions_do_subprobe(pr,
++				rc = blkid_partitions_do_subprobe(pr,
+ 						blkid_partlist_get_partition(ls, i),
+-						dos_nested[n].id) == -1)
+-					goto err;
++						dos_nested[n].id);
++				if (rc < 0)
++					return rc;
+ 				break;
+ 			}
+ 		}
+ 	}
+-	return 0;
++	return BLKID_PROBE_OK;
+ 
+ nothing:
+-	return 1;
+-err:
+-	return -1;
++	return BLKID_PROBE_NONE;
+ }
+ 
+ 
+diff -up util-linux-2.23.2/libblkid/src/partitions/gpt.c.kzak util-linux-2.23.2/libblkid/src/partitions/gpt.c
+--- util-linux-2.23.2/libblkid/src/partitions/gpt.c.kzak	2014-03-28 15:11:18.336283724 +0100
++++ util-linux-2.23.2/libblkid/src/partitions/gpt.c	2014-03-28 15:11:44.677551986 +0100
+@@ -169,8 +169,11 @@ static int is_pmbr_valid(blkid_probe pr,
+ 		goto ok;			/* skip PMBR check */
+ 
+ 	data = blkid_probe_get_sector(pr, 0);
+-	if (!data)
++	if (!data) {
++		if (errno)
++			return -errno;
+ 		goto failed;
++	}
+ 
+ 	if (!is_valid_mbr_signature(data))
+ 		goto failed;
+@@ -305,19 +308,27 @@ static int probe_gpt_pt(blkid_probe pr,
+ 	uint64_t fu, lu;
+ 	uint32_t ssf, i;
+ 	efi_guid_t guid;
++	int ret;
+ 
+ 	if (last_lba(pr, &lastlba))
+ 		goto nothing;
+ 
+-	if (!is_pmbr_valid(pr, NULL))
++	ret = is_pmbr_valid(pr, NULL);
++	if (ret < 0)
++		return ret;
++	else if (ret == 0)
+ 		goto nothing;
+ 
++	errno = 0;
+ 	h = get_gpt_header(pr, &hdr, &e, (lba = GPT_PRIMARY_LBA), lastlba);
+-	if (!h)
++	if (!h && !errno)
+ 		h = get_gpt_header(pr, &hdr, &e, (lba = lastlba), lastlba);
+ 
+-	if (!h)
++	if (!h) {
++		if (errno)
++			return -errno;
+ 		goto nothing;
++	}
+ 
+ 	blkid_probe_use_wiper(pr, lba * blkid_probe_get_size(pr), 8);
+ 
+@@ -388,12 +399,13 @@ static int probe_gpt_pt(blkid_probe pr,
+ 		blkid_partition_set_flags(par, e->attributes);
+ 	}
+ 
+-	return 0;
++	return BLKID_PROBE_OK;
+ 
+ nothing:
+-	return 1;
++	return BLKID_PROBE_NONE;
++
+ err:
+-	return -1;
++	return -ENOMEM;
+ }
+ 
+ 
+diff -up util-linux-2.23.2/libblkid/src/partitions/mac.c.kzak util-linux-2.23.2/libblkid/src/partitions/mac.c
+--- util-linux-2.23.2/libblkid/src/partitions/mac.c.kzak	2013-06-13 09:46:10.418650605 +0200
++++ util-linux-2.23.2/libblkid/src/partitions/mac.c	2014-03-28 15:11:44.677551986 +0100
+@@ -87,8 +87,11 @@ static int probe_mac_pt(blkid_probe pr,
+ 	 * the first block on the disk.
+ 	 */
+ 	md = (struct mac_driver_desc *) blkid_probe_get_sector(pr, 0);
+-	if (!md)
++	if (!md) {
++		if (errno)
++			return -errno;
+ 		goto nothing;
++	}
+ 
+ 	block_size = be16_to_cpu(md->block_size);
+ 
+@@ -96,8 +99,11 @@ static int probe_mac_pt(blkid_probe pr,
+ 	 * the second block on the disk.
+ 	 */
+ 	p = (struct mac_partition *) get_mac_block(pr, block_size, 1);
+-	if (!p)
++	if (!p) {
++		if (errno)
++			return -errno;
+ 		goto nothing;
++	}
+ 
+ 	/* check the first partition signature */
+ 	if (!has_part_signature(p))
+@@ -109,7 +115,7 @@ static int probe_mac_pt(blkid_probe pr,
+ 
+ 	ls = blkid_probe_get_partlist(pr);
+ 	if (!ls)
+-		goto err;
++		goto nothing;
+ 
+ 	tab = blkid_partlist_new_parttable(ls, "mac", 0);
+ 	if (!tab)
+@@ -124,15 +130,18 @@ static int probe_mac_pt(blkid_probe pr,
+ 		uint32_t size;
+ 
+ 		p = (struct mac_partition *) get_mac_block(pr, block_size, i);
+-		if (!p)
++		if (!p) {
++			if (errno)
++				return -errno;
+ 			goto nothing;
++		}
+ 		if (!has_part_signature(p))
+ 			goto nothing;
+ 
+ 		if (be32_to_cpu(p->map_count) != nblks) {
+ 			DBG(LOWPROBE, blkid_debug(
+ 				"mac: inconsisten map_count in partition map, "
+-			        "entry[0]: %d, entry[%d]: %d",
++				"entry[0]: %d, entry[%d]: %d",
+ 				nblks, i - 1,
+ 				be32_to_cpu(p->map_count)));
+ 		}
+@@ -157,12 +166,12 @@ static int probe_mac_pt(blkid_probe pr,
+ 						sizeof(p->type));
+ 	}
+ 
+-	return 0;
++	return BLKID_PROBE_OK;
+ 
+ nothing:
+-	return 1;
++	return BLKID_PROBE_NONE;
+ err:
+-	return -1;
++	return -ENOMEM;
+ }
+ 
+ /*
+diff -up util-linux-2.23.2/libblkid/src/partitions/minix.c.kzak util-linux-2.23.2/libblkid/src/partitions/minix.c
+--- util-linux-2.23.2/libblkid/src/partitions/minix.c.kzak	2013-07-15 10:25:46.284049064 +0200
++++ util-linux-2.23.2/libblkid/src/partitions/minix.c	2014-03-28 15:36:23.866715100 +0100
+@@ -26,12 +26,15 @@ static int probe_minix_pt(blkid_probe pr
+ 	int i;
+ 
+ 	data = blkid_probe_get_sector(pr, 0);
+-	if (!data)
++	if (!data) {
++		if (errno)
++			return -errno;
+ 		goto nothing;
++	}
+ 
+ 	ls = blkid_probe_get_partlist(pr);
+ 	if (!ls)
+-		goto err;
++		goto nothing;
+ 
+ 	/* Parent is required, because Minix uses the same PT as DOS and
+ 	 * difference is only in primary partition (parent) type.
+@@ -78,12 +81,12 @@ static int probe_minix_pt(blkid_probe pr
+ 		blkid_partition_set_flags(par, p->boot_ind);
+ 	}
+ 
+-	return 0;
++	return BLKID_PROBE_OK;
+ 
+ nothing:
+-	return 1;
++	return BLKID_PROBE_NONE;
+ err:
+-	return -1;
++	return -ENOMEM;
+ }
+ 
+ /* same as DOS */
+diff -up util-linux-2.23.2/libblkid/src/partitions/partitions.c.kzak util-linux-2.23.2/libblkid/src/partitions/partitions.c
+--- util-linux-2.23.2/libblkid/src/partitions/partitions.c.kzak	2014-03-28 15:11:18.336283724 +0100
++++ util-linux-2.23.2/libblkid/src/partitions/partitions.c	2014-03-28 15:12:28.036993622 +0100
+@@ -533,12 +533,13 @@ static int idinfo_probe(blkid_probe pr,
+ {
+ 	const struct blkid_idmag *mag = NULL;
+ 	blkid_loff_t off;
+-	int rc = 1;		/* = nothing detected */
++	int rc = BLKID_PROBE_NONE;		/* = nothing detected */
+ 
+ 	if (pr->size <= 0 || (id->minsz && id->minsz > pr->size))
+ 		goto nothing;	/* the device is too small */
+ 
+-	if (blkid_probe_get_idmag(pr, id, &off, &mag))
++	rc = blkid_probe_get_idmag(pr, id, &off, &mag);
++	if (rc != BLKID_PROBE_OK)
+ 		goto nothing;
+ 
+ 	/* final check by probing function */
+@@ -546,14 +547,15 @@ static int idinfo_probe(blkid_probe pr,
+ 		DBG(LOWPROBE, blkid_debug(
+ 			"%s: ---> call probefunc()", id->name));
+ 		rc = id->probefunc(pr, mag);
+-	        if (rc == -1) {
++		if (rc < 0) {
+ 			/* reset after error */
+ 			reset_partlist(blkid_probe_get_partlist(pr));
+ 			if (chn && !chn->binary)
+ 				blkid_probe_chain_reset_vals(pr, chn);
+-			DBG(LOWPROBE, blkid_debug("%s probefunc failed", id->name));
++			DBG(LOWPROBE, blkid_debug("%s probefunc failed, rc %d",
++						  id->name, rc));
+ 		}
+-		if (rc == 0 && mag && chn && !chn->binary)
++		if (rc == BLKID_PROBE_OK && mag && chn && !chn->binary)
+ 			rc = blkid_probe_set_magic(pr, off, mag->len,
+ 					(unsigned char *) mag->magic);
+ 
+@@ -569,11 +571,11 @@ nothing:
+  */
+ static int partitions_probe(blkid_probe pr, struct blkid_chain *chn)
+ {
+-	int rc = 1;
++	int rc = BLKID_PROBE_NONE;
+ 	size_t i;
+ 
+ 	if (!pr || chn->idx < -1)
+-		return -1;
++		return -EINVAL;
+ 	blkid_probe_chain_reset_vals(pr, chn);
+ 
+ 	if (chn->binary)
+@@ -597,7 +599,10 @@ static int partitions_probe(blkid_probe
+ 			continue;
+ 
+ 		/* apply checks from idinfo */
+-		if (idinfo_probe(pr, idinfos[i], chn) != 0)
++		rc = idinfo_probe(pr, idinfos[i], chn);
++		if (rc < 0)
++			break;
++		if (rc != BLKID_PROBE_OK)
+ 			continue;
+ 
+ 		name = idinfos[i]->name;
+@@ -613,20 +618,21 @@ static int partitions_probe(blkid_probe
+ 		break;
+ 	}
+ 
+-	if (rc == 1) {
+-		DBG(LOWPROBE, blkid_debug("<-- leaving probing loop (failed) [PARTS idx=%d]",
+-			chn->idx));
++	if (rc != BLKID_PROBE_OK) {
++		DBG(LOWPROBE, blkid_debug("<-- leaving probing loop (failed=%d) [PARTS idx=%d]",
++			rc, chn->idx));
+ 	}
+ 
+ details_only:
+ 	/*
+ 	 * Gather PART_ENTRY_* values if the current device is a partition.
+ 	 */
+-	if (!chn->binary &&
++	if ((rc == BLKID_PROBE_OK || rc == BLKID_PROBE_NONE) && !chn->binary &&
+ 	    (blkid_partitions_get_flags(pr) & BLKID_PARTS_ENTRY_DETAILS)) {
+ 
+-		if (!blkid_partitions_probe_partition(pr))
+-			rc = 0;
++		int xrc = blkid_partitions_probe_partition(pr);
++		if (xrc < 0)
++			rc = xrc;	/* optional, care about errors only */
+ 	}
+ 
+ 	return rc;
+@@ -637,7 +643,7 @@ int blkid_partitions_do_subprobe(blkid_p
+ 		const struct blkid_idinfo *id)
+ {
+ 	blkid_probe prc;
+-	int rc = 1;
++	int rc;
+ 	blkid_partlist ls;
+ 	blkid_loff_t sz, off;
+ 
+@@ -646,7 +652,7 @@ int blkid_partitions_do_subprobe(blkid_p
+ 		id->name, parent));
+ 
+ 	if (!pr || !parent || !parent->size)
+-		return -1;
++		return -EINVAL;
+ 
+ 	/* range defined by parent */
+ 	sz = ((blkid_loff_t) parent->size) << 9;
+@@ -656,13 +662,13 @@ int blkid_partitions_do_subprobe(blkid_p
+ 		DBG(LOWPROBE, blkid_debug(
+ 			"ERROR: parts: <---- '%s' subprobe: overflow detected.",
+ 			id->name));
+-		return -1;
++		return -ENOSPC;
+ 	}
+ 
+ 	/* create private prober */
+ 	prc = blkid_clone_probe(pr);
+ 	if (!prc)
+-		return -1;
++		return -ENOMEM;
+ 
+ 	blkid_probe_set_dimension(prc, off, sz);
+ 
+@@ -695,7 +701,7 @@ int blkid_partitions_do_subprobe(blkid_p
+ 
+ static int blkid_partitions_probe_partition(blkid_probe pr)
+ {
+-	int rc = 1;
++	int rc = BLKID_PROBE_NONE;
+ 	blkid_probe disk_pr = NULL;
+ 	blkid_partlist ls;
+ 	blkid_partition par;
+@@ -761,7 +767,7 @@ static int blkid_partitions_probe_partit
+ 		blkid_probe_sprintf_value(pr, "PART_ENTRY_DISK", "%u:%u",
+ 				major(disk), minor(disk));
+ 	}
+-	rc = 0;
++	rc = BLKID_PROBE_OK;
+ nothing:
+ 	return rc;
+ }
+diff -up util-linux-2.23.2/libblkid/src/partitions/sgi.c.kzak util-linux-2.23.2/libblkid/src/partitions/sgi.c
+--- util-linux-2.23.2/libblkid/src/partitions/sgi.c.kzak	2013-07-15 10:25:46.285049072 +0200
++++ util-linux-2.23.2/libblkid/src/partitions/sgi.c	2014-03-28 15:11:44.677551986 +0100
+@@ -99,8 +99,11 @@ static int probe_sgi_pt(blkid_probe pr,
+ 	int i;
+ 
+ 	l = (struct sgi_disklabel *) blkid_probe_get_sector(pr, 0);
+-	if (!l)
++	if (!l) {
++		if (errno)
++			return -errno;
+ 		goto nothing;
++	}
+ 
+ 	if (count_checksum(l)) {
+ 		DBG(LOWPROBE, blkid_debug(
+@@ -110,11 +113,11 @@ static int probe_sgi_pt(blkid_probe pr,
+ 
+ 	if (blkid_partitions_need_typeonly(pr))
+ 		/* caller does not ask for details about partitions */
+-		return 0;
++		return BLKID_PROBE_OK;
+ 
+ 	ls = blkid_probe_get_partlist(pr);
+ 	if (!ls)
+-		goto err;
++		goto nothing;
+ 
+ 	tab = blkid_partlist_new_parttable(ls, "sgi", 0);
+ 	if (!tab)
+@@ -138,12 +141,12 @@ static int probe_sgi_pt(blkid_probe pr,
+ 		blkid_partition_set_type(par, type);
+ 	}
+ 
+-	return 0;
++	return BLKID_PROBE_OK;
+ 
+ nothing:
+-	return 1;
++	return BLKID_PROBE_NONE;
+ err:
+-	return -1;
++	return -ENOMEM;
+ }
+ 
+ const struct blkid_idinfo sgi_pt_idinfo =
+diff -up util-linux-2.23.2/libblkid/src/partitions/solaris_x86.c.kzak util-linux-2.23.2/libblkid/src/partitions/solaris_x86.c
+--- util-linux-2.23.2/libblkid/src/partitions/solaris_x86.c.kzak	2013-06-13 09:46:10.418650605 +0200
++++ util-linux-2.23.2/libblkid/src/partitions/solaris_x86.c	2014-03-28 15:11:44.677551986 +0100
+@@ -69,8 +69,11 @@ static int probe_solaris_pt(blkid_probe
+ 	uint16_t nparts;
+ 
+ 	l = (struct solaris_vtoc *) blkid_probe_get_sector(pr, SOLARIS_SECTOR);
+-	if (!l)
++	if (!l) {
++		if (errno)
++			return -errno;
+ 		goto nothing;
++	}
+ 
+ 	if (le32_to_cpu(l->v_version) != 1) {
+ 		DBG(LOWPROBE, blkid_debug(
+@@ -81,11 +84,11 @@ static int probe_solaris_pt(blkid_probe
+ 
+ 	if (blkid_partitions_need_typeonly(pr))
+ 		/* caller does not ask for details about partitions */
+-		return 0;
++		return BLKID_PROBE_OK;
+ 
+ 	ls = blkid_probe_get_partlist(pr);
+ 	if (!ls)
+-		goto err;
++		goto nothing;
+ 
+ 	parent = blkid_partlist_get_parent(ls);
+ 
+@@ -126,12 +129,12 @@ static int probe_solaris_pt(blkid_probe
+ 		blkid_partition_set_flags(par, le16_to_cpu(p->s_flag));
+ 	}
+ 
+-	return 0;
++	return BLKID_PROBE_OK;
+ 
+ nothing:
+-	return 1;
++	return BLKID_PROBE_NONE;
+ err:
+-	return -1;
++	return -ENOMEM;
+ }
+ 
+ const struct blkid_idinfo solaris_x86_pt_idinfo =
+diff -up util-linux-2.23.2/libblkid/src/partitions/sun.c.kzak util-linux-2.23.2/libblkid/src/partitions/sun.c
+--- util-linux-2.23.2/libblkid/src/partitions/sun.c.kzak	2013-06-13 09:46:10.419650613 +0200
++++ util-linux-2.23.2/libblkid/src/partitions/sun.c	2014-03-28 15:11:44.678551996 +0100
+@@ -27,8 +27,11 @@ static int probe_sun_pt(blkid_probe pr,
+ 	int i, use_vtoc;
+ 
+ 	l = (struct sun_disklabel *) blkid_probe_get_sector(pr, 0);
+-	if (!l)
++	if (!l) {
++		if (errno)
++			return -errno;
+ 		goto nothing;
++	}
+ 
+ 	if (sun_pt_checksum(l)) {
+ 		DBG(LOWPROBE, blkid_debug(
+@@ -38,11 +41,11 @@ static int probe_sun_pt(blkid_probe pr,
+ 
+ 	if (blkid_partitions_need_typeonly(pr))
+ 		/* caller does not ask for details about partitions */
+-		return 0;
++		return BLKID_PROBE_OK;
+ 
+ 	ls = blkid_probe_get_partlist(pr);
+ 	if (!ls)
+-		goto err;
++		goto nothing;
+ 
+ 	tab = blkid_partlist_new_parttable(ls, "sun", 0);
+ 	if (!tab)
+@@ -76,7 +79,7 @@ static int probe_sun_pt(blkid_probe pr,
+ 		uint16_t type = 0, flags = 0;
+ 		blkid_partition par;
+ 
+-                start = be32_to_cpu(p->start_cylinder) * spc;
++		start = be32_to_cpu(p->start_cylinder) * spc;
+ 		size = be32_to_cpu(p->num_sectors);
+ 		if (use_vtoc) {
+ 			type = be16_to_cpu(l->vtoc.infos[i].id);
+@@ -96,12 +99,12 @@ static int probe_sun_pt(blkid_probe pr,
+ 		if (flags)
+ 			blkid_partition_set_flags(par, flags);
+ 	}
+-	return 0;
++	return BLKID_PROBE_OK;
+ 
+ nothing:
+-	return 1;
++	return BLKID_PROBE_NONE;
+ err:
+-	return -1;
++	return -ENOMEM;
+ }
+ 
+ 
+diff -up util-linux-2.23.2/libblkid/src/partitions/ultrix.c.kzak util-linux-2.23.2/libblkid/src/partitions/ultrix.c
+--- util-linux-2.23.2/libblkid/src/partitions/ultrix.c.kzak	2013-05-30 15:21:43.127591380 +0200
++++ util-linux-2.23.2/libblkid/src/partitions/ultrix.c	2014-03-28 15:11:44.678551996 +0100
+@@ -44,8 +44,11 @@ static int probe_ultrix_pt(blkid_probe p
+ 	int i;
+ 
+ 	data = blkid_probe_get_sector(pr, ULTRIX_SECTOR);
+-	if (!data)
++	if (!data) {
++		if (errno)
++			return -errno;
+ 		goto nothing;
++	}
+ 
+ 	l = (struct ultrix_disklabel *) (data + ULTRIX_OFFSET);
+ 
+@@ -59,11 +62,11 @@ static int probe_ultrix_pt(blkid_probe p
+ 
+ 	if (blkid_partitions_need_typeonly(pr))
+ 		/* caller does not ask for details about partitions */
+-		return 0;
++		return BLKID_PROBE_OK;
+ 
+ 	ls = blkid_probe_get_partlist(pr);
+ 	if (!ls)
+-		goto err;
++		goto nothing;
+ 
+ 	tab = blkid_partlist_new_parttable(ls, "ultrix", 0);
+ 	if (!tab)
+@@ -80,11 +83,11 @@ static int probe_ultrix_pt(blkid_probe p
+ 		}
+ 	}
+ 
+-	return 0;
++	return BLKID_PROBE_OK;
+ nothing:
+-	return 1;
++	return BLKID_PROBE_NONE;
+ err:
+-	return -1;
++	return -ENOMEM;
+ }
+ 
+ const struct blkid_idinfo ultrix_pt_idinfo =
+diff -up util-linux-2.23.2/libblkid/src/partitions/unixware.c.kzak util-linux-2.23.2/libblkid/src/partitions/unixware.c
+--- util-linux-2.23.2/libblkid/src/partitions/unixware.c.kzak	2013-06-13 09:46:10.419650613 +0200
++++ util-linux-2.23.2/libblkid/src/partitions/unixware.c	2014-03-28 15:11:44.678551996 +0100
+@@ -106,19 +106,22 @@ static int probe_unixware_pt(blkid_probe
+ 
+ 	l = (struct unixware_disklabel *)
+ 			blkid_probe_get_sector(pr, UNIXWARE_SECTOR);
+-	if (!l)
++	if (!l) {
++		if (errno)
++			return -errno;
+ 		goto nothing;
++	}
+ 
+ 	if (le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_VTOCMAGIC)
+ 		goto nothing;
+ 
+ 	if (blkid_partitions_need_typeonly(pr))
+ 		/* caller does not ask for details about partitions */
+-		return 0;
++		return BLKID_PROBE_OK;
+ 
+ 	ls = blkid_probe_get_partlist(pr);
+ 	if (!ls)
+-		goto err;
++		goto nothing;
+ 
+ 	parent = blkid_partlist_get_parent(ls);
+ 
+@@ -161,12 +164,12 @@ static int probe_unixware_pt(blkid_probe
+ 		blkid_partition_set_flags(par, flg);
+ 	}
+ 
+-	return 0;
++	return BLKID_PROBE_OK;
+ 
+ nothing:
+-	return 1;
++	return BLKID_PROBE_NONE;
+ err:
+-	return -1;
++	return -ENOMEM;
+ }
+ 
+ 
+diff -up util-linux-2.23.2/libblkid/src/probe.c.kzak util-linux-2.23.2/libblkid/src/probe.c
+--- util-linux-2.23.2/libblkid/src/probe.c.kzak	2014-03-28 15:11:18.334283704 +0100
++++ util-linux-2.23.2/libblkid/src/probe.c	2014-03-28 15:11:44.678551996 +0100
+@@ -559,13 +559,17 @@ unsigned char *blkid_probe_get_buffer(bl
+ 	if (!bf) {
+ 		ssize_t ret;
+ 
+-		if (blkid_llseek(pr->fd, pr->off + off, SEEK_SET) < 0)
++		if (blkid_llseek(pr->fd, pr->off + off, SEEK_SET) < 0) {
++			errno = 0;
+ 			return NULL;
++		}
+ 
+ 		/* allocate info and space for data by why call */
+ 		bf = calloc(1, sizeof(struct blkid_bufinfo) + len);
+-		if (!bf)
++		if (!bf) {
++			errno = ENOMEM;
+ 			return NULL;
++		}
+ 
+ 		bf->data = ((unsigned char *) bf) + sizeof(struct blkid_bufinfo);
+ 		bf->len = len;
+@@ -577,7 +581,10 @@ unsigned char *blkid_probe_get_buffer(bl
+ 
+ 		ret = read(pr->fd, bf->data, len);
+ 		if (ret != (ssize_t) len) {
++			DBG(LOWPROBE, blkid_debug("\tbuffer read: return %zd error %m", ret));
+ 			free(bf);
++			if (ret >= 0)
++				errno = 0;
+ 			return NULL;
+ 		}
+ 		list_add_tail(&bf->bufs, &pr->buffers);
+@@ -766,6 +773,17 @@ int blkid_probe_set_dimension(blkid_prob
+ 	return 0;
+ }
+ 
++/**
++ * blkid_probe_get_idmag:
++ * @pr: probe
++ * @id: id information
++ * @offset: begin of probing area
++ * @res: found id information
++ *
++ * Check for matching magic value.
++ * Returns BLKID_PROBE_OK if found, BLKID_PROBE_NONE if not found
++ * or no magic present, or negative value on error.
++ */
+ int blkid_probe_get_idmag(blkid_probe pr, const struct blkid_idinfo *id,
+ 			blkid_loff_t *offset, const struct blkid_idmag **res)
+ {
+@@ -784,6 +802,8 @@ int blkid_probe_get_idmag(blkid_probe pr
+ 		off = (mag->kboff + (mag->sboff >> 10)) << 10;
+ 		buf = blkid_probe_get_buffer(pr, off, 1024);
+ 
++		if (!buf && errno)
++			return -errno;
+ 		if (buf && !memcmp(mag->magic,
+ 				buf + (mag->sboff & 0x3ff), mag->len)) {
+ 			DBG(LOWPROBE, blkid_debug("\tmagic sboff=%u, kboff=%ld",
+@@ -792,16 +812,16 @@ int blkid_probe_get_idmag(blkid_probe pr
+ 				*offset = off + (mag->sboff & 0x3ff);
+ 			if (res)
+ 				*res = mag;
+-			return 0;
++			return BLKID_PROBE_OK;
+ 		}
+ 		mag++;
+ 	}
+ 
+ 	if (id && id->magics[0].magic)
+ 		/* magic string(s) defined, but not found */
+-		return 1;
++		return BLKID_PROBE_NONE;
+ 
+-	return 0;
++	return BLKID_PROBE_OK;
+ }
+ 
+ static inline void blkid_probe_start(blkid_probe pr)
+diff -up util-linux-2.23.2/libblkid/src/superblocks/adaptec_raid.c.kzak util-linux-2.23.2/libblkid/src/superblocks/adaptec_raid.c
+--- util-linux-2.23.2/libblkid/src/superblocks/adaptec_raid.c.kzak	2013-04-08 17:55:40.232855970 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/adaptec_raid.c	2014-03-28 15:11:44.678551996 +0100
+@@ -80,10 +80,10 @@ static int probe_adraid(blkid_probe pr,
+ 	struct adaptec_metadata *ad;
+ 
+ 	if (pr->size < 0x10000)
+-		return -1;
++		return BLKID_PROBE_NONE;
+ 
+ 	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+-		return -1;
++		return BLKID_PROBE_NONE;
+ 
+ 	off = ((pr->size / 0x200)-1) * 0x200;
+ 	ad = (struct adaptec_metadata *)
+@@ -91,17 +91,19 @@ static int probe_adraid(blkid_probe pr,
+ 					off,
+ 					sizeof(struct adaptec_metadata));
+ 	if (!ad)
+-		return -1;
++		return errno ? -errno : BLKID_PROBE_NONE;;
++
+ 	if (ad->smagic != be32_to_cpu(AD_SIGNATURE))
+-		return -1;
++		return BLKID_PROBE_NONE;
+ 	if (ad->b0idcode != be32_to_cpu(AD_MAGIC))
+-		return -1;
++		return BLKID_PROBE_NONE;
+ 	if (blkid_probe_sprintf_version(pr, "%u", ad->resver) != 0)
+-		return -1;
++		return BLKID_PROBE_NONE;
+ 	if (blkid_probe_set_magic(pr, off, sizeof(ad->b0idcode),
+ 				(unsigned char *) &ad->b0idcode))
+-		return -1;
+-	return 0;
++		return BLKID_PROBE_NONE;
++
++	return BLKID_PROBE_OK;
+ }
+ 
+ const struct blkid_idinfo adraid_idinfo = {
+diff -up util-linux-2.23.2/libblkid/src/superblocks/befs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/befs.c
+--- util-linux-2.23.2/libblkid/src/superblocks/befs.c.kzak	2013-04-08 17:55:40.237856017 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/befs.c	2014-03-28 15:11:44.679552006 +0100
+@@ -261,21 +261,23 @@ static int64_t get_key_value(blkid_probe
+ 	int64_t node_pointer;
+ 	int32_t first, last, mid, cmp;
+ 
++	errno = 0;
+ 	bh = (struct bplustree_header *) get_tree_node(pr, bs, &bi->data, 0,
+ 					sizeof(struct bplustree_header), fs_le);
+ 	if (!bh)
+-		return -1;
++		return errno ? -errno : -ENOENT;
+ 
+ 	if ((int32_t) FS32_TO_CPU(bh->magic, fs_le) != BPLUSTREE_MAGIC)
+-		return -1;
++		return -ENOENT;
+ 
+ 	node_pointer = FS64_TO_CPU(bh->root_node_pointer, fs_le);
+ 
+ 	do {
++		errno = 0;
+ 		bn = (struct bplustree_node *) get_tree_node(pr, bs, &bi->data,
+ 			node_pointer, FS32_TO_CPU(bh->node_size, fs_le), fs_le);
+ 		if (!bn)
+-			return -1;
++			return errno ? -errno : -ENOENT;
+ 
+ 		keylengths = (uint16_t *) ((uint8_t *) bn
+ 				+ ((sizeof(struct bplustree_node)
+@@ -336,10 +338,10 @@ static int get_uuid(blkid_probe pr, cons
+ 
+ 	bi = (struct befs_inode *) get_block_run(pr, bs, &bs->root_dir, fs_le);
+ 	if (!bi)
+-		return -1;
++		return errno ? -errno : BLKID_PROBE_NONE;
+ 
+ 	if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1)
+-		return -1;
++		return BLKID_PROBE_NONE;
+ 
+ 	sd = (struct small_data *) bi->small_data;
+ 
+@@ -376,24 +378,24 @@ static int get_uuid(blkid_probe pr, cons
+ 		bi = (struct befs_inode *) get_block_run(pr, bs,
+ 							&bi->attributes, fs_le);
+ 		if (!bi)
+-			return -1;
++			return errno ? -errno : BLKID_PROBE_NONE;
+ 
+ 		if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1)
+-			return -1;
++			return BLKID_PROBE_NONE;
+ 
+ 		value = get_key_value(pr, bs, bi, KEY_NAME, fs_le);
+-
+ 		if (value < 0)
+-			return value;
++			return value == -ENOENT ? BLKID_PROBE_NONE : value;
++
+ 		else if (value > 0) {
+ 			bi = (struct befs_inode *) blkid_probe_get_buffer(pr,
+ 				value << FS32_TO_CPU(bs->block_shift, fs_le),
+ 				FS32_TO_CPU(bs->block_size, fs_le));
+ 			if (!bi)
+-				return -1;
++				return errno ? -errno : BLKID_PROBE_NONE;
+ 
+ 			if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1)
+-				return -1;
++				return 1;
+ 
+ 			if (FS32_TO_CPU(bi->type, fs_le) == B_UINT64_TYPE
+ 				&& FS64_TO_CPU(bi->data.size, fs_le) == KEY_SIZE
+@@ -404,7 +406,7 @@ static int get_uuid(blkid_probe pr, cons
+ 				attr_data = (uint64_t *) get_block_run(pr, bs,
+ 						&bi->data.direct[0], fs_le);
+ 				if (!attr_data)
+-					return -1;
++					return errno ? -errno : BLKID_PROBE_NONE;
+ 
+ 				*uuid = *attr_data;
+ 			}
+@@ -424,7 +426,7 @@ static int probe_befs(blkid_probe pr, co
+ 					mag->sboff - B_OS_NAME_LENGTH,
+ 					sizeof(struct befs_super_block));
+ 	if (!bs)
+-		return -1;
++		return errno ? -errno : BLKID_PROBE_NONE;
+ 
+ 	if (le32_to_cpu(bs->magic1) == SUPER_BLOCK_MAGIC1
+ 		&& le32_to_cpu(bs->magic2) == SUPER_BLOCK_MAGIC2
+@@ -439,11 +441,11 @@ static int probe_befs(blkid_probe pr, co
+ 		fs_le = 0;
+ 		version = "big-endian";
+ 	} else
+-		return -1;
++		return BLKID_PROBE_NONE;
+ 
+ 	ret = get_uuid(pr, bs, &volume_id, fs_le);
+ 
+-	if (ret < 0)
++	if (ret != 0)
+ 		return ret;
+ 
+ 	/*
+@@ -459,7 +461,7 @@ static int probe_befs(blkid_probe pr, co
+ 		blkid_probe_sprintf_uuid(pr, (unsigned char *) &volume_id,
+ 					sizeof(volume_id), "%016" PRIx64,
+ 					FS64_TO_CPU(volume_id, fs_le));
+-	return 0;
++	return BLKID_PROBE_OK;
+ }
+ 
+ const struct blkid_idinfo befs_idinfo =
+diff -up util-linux-2.23.2/libblkid/src/superblocks/btrfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/btrfs.c
+--- util-linux-2.23.2/libblkid/src/superblocks/btrfs.c.kzak	2014-03-28 15:11:18.335283714 +0100
++++ util-linux-2.23.2/libblkid/src/superblocks/btrfs.c	2014-03-28 15:11:44.679552006 +0100
+@@ -65,7 +65,7 @@ static int probe_btrfs(blkid_probe pr, c
+ 
+ 	bfs = blkid_probe_get_sb(pr, mag, struct btrfs_super_block);
+ 	if (!bfs)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	if (*bfs->label)
+ 		blkid_probe_set_label(pr,
+diff -up util-linux-2.23.2/libblkid/src/superblocks/cramfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/cramfs.c
+--- util-linux-2.23.2/libblkid/src/superblocks/cramfs.c.kzak	2013-04-08 17:55:40.240856046 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/cramfs.c	2014-03-28 15:11:44.679552006 +0100
+@@ -40,7 +40,7 @@ static int probe_cramfs(blkid_probe pr,
+ 
+ 	cs = blkid_probe_get_sb(pr, mag, struct cramfs_super);
+ 	if (!cs)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	blkid_probe_set_label(pr, cs->name, sizeof(cs->name));
+ 	return 0;
+diff -up util-linux-2.23.2/libblkid/src/superblocks/ddf_raid.c.kzak util-linux-2.23.2/libblkid/src/superblocks/ddf_raid.c
+--- util-linux-2.23.2/libblkid/src/superblocks/ddf_raid.c.kzak	2013-04-08 17:55:40.241856056 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/ddf_raid.c	2014-03-28 15:11:44.679552006 +0100
+@@ -81,7 +81,7 @@ static int probe_ddf(blkid_probe pr,
+ 	uint64_t off, lba;
+ 
+ 	if (pr->size < 0x30000)
+-		return -1;
++		return 1;
+ 
+ 	for (i = 0; i < ARRAY_SIZE(hdrs); i++) {
+ 		off = ((pr->size / 0x200) - hdrs[i]) * 0x200;
+@@ -90,8 +90,7 @@ static int probe_ddf(blkid_probe pr,
+ 					off,
+ 					sizeof(struct ddf_header));
+ 		if (!ddf)
+-			return -1;
+-
++			return errno ? -errno : 1;
+ 		if (ddf->signature == cpu_to_be32(DDF_MAGIC) ||
+ 		    ddf->signature == cpu_to_le32(DDF_MAGIC))
+ 			break;
+@@ -99,7 +98,7 @@ static int probe_ddf(blkid_probe pr,
+ 	}
+ 
+ 	if (!ddf)
+-		return -1;
++		return 1;
+ 
+ 	lba = ddf->signature == cpu_to_be32(DDF_MAGIC) ?
+ 			be64_to_cpu(ddf->primary_lba) :
+@@ -111,8 +110,12 @@ static int probe_ddf(blkid_probe pr,
+ 
+ 		buf = blkid_probe_get_buffer(pr,
+ 					lba << 9, sizeof(ddf->signature));
+-		if (!buf || memcmp(buf, &ddf->signature, 4))
+-			return -1;
++		if (!buf) {
++			if (errno)
++				return -errno;
++			if (memcmp(buf, &ddf->signature, 4))
++				return 1;
++		}
+ 	}
+ 
+ 	blkid_probe_strncpy_uuid(pr, ddf->guid, sizeof(ddf->guid));
+@@ -121,11 +124,11 @@ static int probe_ddf(blkid_probe pr,
+ 	*(version + sizeof(ddf->ddf_rev)) = '\0';
+ 
+ 	if (blkid_probe_set_version(pr, version) != 0)
+-		return -1;
++		return 1;
+ 	if (blkid_probe_set_magic(pr, off,
+ 			sizeof(ddf->signature),
+ 			(unsigned char *) &ddf->signature))
+-		return -1;
++		return 1;
+ 	return 0;
+ }
+ 
+diff -up util-linux-2.23.2/libblkid/src/superblocks/drbd.c.kzak util-linux-2.23.2/libblkid/src/superblocks/drbd.c
+--- util-linux-2.23.2/libblkid/src/superblocks/drbd.c.kzak	2013-04-08 17:55:40.243856074 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/drbd.c	2014-03-28 15:11:44.679552006 +0100
+@@ -75,18 +75,18 @@ static int probe_drbd(blkid_probe pr,
+ 
+ 	/* Small devices cannot be drbd (?) */
+ 	if (pr->size < 0x10000)
+-		return -1;
++		return 1;
+ 
+ 	md = (struct md_on_disk_08 *)
+ 			blkid_probe_get_buffer(pr,
+ 					off,
+ 					sizeof(struct md_on_disk_08));
+ 	if (!md)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	if (be32_to_cpu(md->magic) != DRBD_MD_MAGIC_08 &&
+ 			be32_to_cpu(md->magic) != DRBD_MD_MAGIC_84_UNCLEAN)
+-		return -1;
++		return 1;
+ 
+ 	/*
+ 	 * DRBD does not have "real" uuids; the following resembles DRBD's
+@@ -102,7 +102,7 @@ static int probe_drbd(blkid_probe pr,
+ 				off + offsetof(struct md_on_disk_08, magic),
+ 				sizeof(md->magic),
+ 				(unsigned char *) &md->magic))
+-		return -1;
++		return 1;
+ 
+ 	return 0;
+ }
+diff -up util-linux-2.23.2/libblkid/src/superblocks/drbdproxy_datalog.c.kzak util-linux-2.23.2/libblkid/src/superblocks/drbdproxy_datalog.c
+--- util-linux-2.23.2/libblkid/src/superblocks/drbdproxy_datalog.c.kzak	2013-04-08 17:55:40.244856084 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/drbdproxy_datalog.c	2014-03-28 15:11:44.679552006 +0100
+@@ -33,7 +33,7 @@ static int probe_drbdproxy_datalog(blkid
+ 
+ 	lh = (struct log_header_t *) blkid_probe_get_buffer(pr, 0, sizeof(*lh));
+ 	if (!lh)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	blkid_probe_set_uuid(pr, lh->uuid);
+ 	blkid_probe_sprintf_version(pr, "v%jd", le64_to_cpu(lh->version));
+diff -up util-linux-2.23.2/libblkid/src/superblocks/exfat.c.kzak util-linux-2.23.2/libblkid/src/superblocks/exfat.c
+--- util-linux-2.23.2/libblkid/src/superblocks/exfat.c.kzak	2013-04-08 17:55:40.245856093 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/exfat.c	2014-03-28 15:11:44.680552016 +0100
+@@ -115,12 +115,14 @@ static int probe_exfat(blkid_probe pr, c
+ 
+ 	sb = blkid_probe_get_sb(pr, mag, struct exfat_super_block);
+ 	if (!sb)
+-		return -1;
++		return errno ? -errno : BLKID_PROBE_NONE;
+ 
+ 	label = find_label(pr, sb);
+ 	if (label)
+ 		blkid_probe_set_utf8label(pr, label->name,
+ 				min(label->length * 2, 30), BLKID_ENC_UTF16LE);
++	else if (errno)
++		return -errno;
+ 
+ 	blkid_probe_sprintf_uuid(pr, sb->volume_serial, 4,
+ 			"%02hhX%02hhX-%02hhX%02hhX",
+@@ -130,7 +132,7 @@ static int probe_exfat(blkid_probe pr, c
+ 	blkid_probe_sprintf_version(pr, "%u.%u",
+ 			sb->version.major, sb->version.minor);
+ 
+-	return 0;
++	return BLKID_PROBE_OK;
+ }
+ 
+ const struct blkid_idinfo exfat_idinfo =
+diff -up util-linux-2.23.2/libblkid/src/superblocks/ext.c.kzak util-linux-2.23.2/libblkid/src/superblocks/ext.c
+--- util-linux-2.23.2/libblkid/src/superblocks/ext.c.kzak	2014-03-28 15:11:18.333283694 +0100
++++ util-linux-2.23.2/libblkid/src/superblocks/ext.c	2014-03-28 15:11:44.680552016 +0100
+@@ -198,9 +198,9 @@ static int probe_jbd(blkid_probe pr,
+ 
+ 	es = ext_get_super(pr, NULL, &fi, NULL);
+ 	if (!es)
+-		return -BLKID_ERR_PARAM;
++		return errno ? -errno : 1;
+ 	if (!(fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV))
+-		return -BLKID_ERR_PARAM;
++		return 1;
+ 
+ 	ext_get_info(pr, 2, es);
+ 	return 0;
+@@ -214,16 +214,16 @@ static int probe_ext2(blkid_probe pr,
+ 
+ 	es = ext_get_super(pr, &fc, &fi, &frc);
+ 	if (!es)
+-		return -BLKID_ERR_PARAM;
++		return errno ? -errno : 1;
+ 
+ 	/* Distinguish between ext3 and ext2 */
+ 	if (fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL)
+-		return -BLKID_ERR_PARAM;
++		return 1;
+ 
+ 	/* Any features which ext2 doesn't understand */
+ 	if ((frc & EXT2_FEATURE_RO_COMPAT_UNSUPPORTED) ||
+ 	    (fi  & EXT2_FEATURE_INCOMPAT_UNSUPPORTED))
+-		return -BLKID_ERR_PARAM;
++		return 1;
+ 
+ 	ext_get_info(pr, 2, es);
+ 	return 0;
+@@ -237,16 +237,16 @@ static int probe_ext3(blkid_probe pr,
+ 
+ 	es = ext_get_super(pr, &fc, &fi, &frc);
+ 	if (!es)
+-		return -BLKID_ERR_PARAM;
++		return errno ? -errno : 1;
+ 
+ 	/* ext3 requires journal */
+ 	if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL))
+-		return -BLKID_ERR_PARAM;
++		return 1;
+ 
+ 	/* Any features which ext3 doesn't understand */
+ 	if ((frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) ||
+ 	    (fi  & EXT3_FEATURE_INCOMPAT_UNSUPPORTED))
+-		return -BLKID_ERR_PARAM;
++		return 1;
+ 
+ 	ext_get_info(pr, 3, es);
+ 	return 0;
+@@ -261,14 +261,14 @@ static int probe_ext4dev(blkid_probe pr,
+ 
+ 	es = ext_get_super(pr, &fc, &fi, &frc);
+ 	if (!es)
+-		return -BLKID_ERR_PARAM;
++		return errno ? -errno : 1;
+ 
+ 	/* Distinguish from jbd */
+ 	if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
+-		return -BLKID_ERR_PARAM;
++		return 1;
+ 
+ 	if (!(le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS))
+-		return -BLKID_ERR_PARAM;
++		return 1;
+ 
+ 	ext_get_info(pr, 4, es);
+ 	return 0;
+@@ -282,16 +282,16 @@ static int probe_ext4(blkid_probe pr,
+ 
+ 	es = ext_get_super(pr, &fc, &fi, &frc);
+ 	if (!es)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	/* Distinguish from jbd */
+ 	if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
+-		return -BLKID_ERR_PARAM;
++		return 1;
+ 
+ 	/* Ext4 has at least one feature which ext3 doesn't understand */
+ 	if (!(frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) &&
+ 	    !(fi  & EXT3_FEATURE_INCOMPAT_UNSUPPORTED))
+-		return -BLKID_ERR_PARAM;
++		return 1;
+ 
+ 	/*
+ 	 * If the filesystem is a OK for use by in-development
+@@ -304,7 +304,7 @@ static int probe_ext4(blkid_probe pr,
+ 	 * ext4dev.
+ 	 */
+ 	if (le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS)
+-		return -BLKID_ERR_PARAM;
++		return 1;
+ 
+ 	ext_get_info(pr, 4, es);
+ 	return 0;
+diff -up util-linux-2.23.2/libblkid/src/superblocks/f2fs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/f2fs.c
+--- util-linux-2.23.2/libblkid/src/superblocks/f2fs.c.kzak	2013-06-13 09:46:10.422650639 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/f2fs.c	2014-03-28 15:11:44.680552016 +0100
+@@ -62,7 +62,7 @@ static int probe_f2fs(blkid_probe pr, co
+ 
+ 	sb = blkid_probe_get_sb(pr, mag, struct f2fs_super_block);
+ 	if (!sb)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	major = le16_to_cpu(sb->major_ver);
+ 	minor = le16_to_cpu(sb->minor_ver);
+diff -up util-linux-2.23.2/libblkid/src/superblocks/gfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/gfs.c
+--- util-linux-2.23.2/libblkid/src/superblocks/gfs.c.kzak	2013-04-08 17:55:40.250856141 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/gfs.c	2014-03-28 15:11:44.680552016 +0100
+@@ -64,7 +64,7 @@ static int probe_gfs(blkid_probe pr, con
+ 
+ 	sbd = blkid_probe_get_sb(pr, mag, struct gfs2_sb);
+ 	if (!sbd)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	if (be32_to_cpu(sbd->sb_fs_format) == GFS_FORMAT_FS &&
+ 	    be32_to_cpu(sbd->sb_multihost_format) == GFS_FORMAT_MULTI)
+@@ -78,7 +78,7 @@ static int probe_gfs(blkid_probe pr, con
+ 		return 0;
+ 	}
+ 
+-	return -1;
++	return 1;
+ }
+ 
+ static int probe_gfs2(blkid_probe pr, const struct blkid_idmag *mag)
+@@ -87,7 +87,7 @@ static int probe_gfs2(blkid_probe pr, co
+ 
+ 	sbd = blkid_probe_get_sb(pr, mag, struct gfs2_sb);
+ 	if (!sbd)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	if (be32_to_cpu(sbd->sb_fs_format) == GFS2_FORMAT_FS &&
+ 	    be32_to_cpu(sbd->sb_multihost_format) == GFS2_FORMAT_MULTI)
+@@ -100,7 +100,7 @@ static int probe_gfs2(blkid_probe pr, co
+ 		blkid_probe_set_version(pr, "1");
+ 		return 0;
+ 	}
+-	return -1;
++	return 1;
+ }
+ 
+ const struct blkid_idinfo gfs_idinfo =
+diff -up util-linux-2.23.2/libblkid/src/superblocks/hfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/hfs.c
+--- util-linux-2.23.2/libblkid/src/superblocks/hfs.c.kzak	2013-04-08 17:55:40.251856150 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/hfs.c	2014-03-28 15:11:44.680552016 +0100
+@@ -154,7 +154,7 @@ static int probe_hfs(blkid_probe pr, con
+ 
+ 	hfs = blkid_probe_get_sb(pr, mag, struct hfs_mdb);
+ 	if (!hfs)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	if ((memcmp(hfs->embed_sig, "H+", 2) == 0) ||
+ 	    (memcmp(hfs->embed_sig, "HX", 2) == 0))
+@@ -193,7 +193,7 @@ static int probe_hfsplus(blkid_probe pr,
+ 
+ 	sbd = blkid_probe_get_sb(pr, mag, struct hfs_mdb);
+ 	if (!sbd)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	/* Check for a HFS+ volume embedded in a HFS volume */
+ 	if (memcmp(sbd->signature, "BD", 2) == 0) {
+@@ -218,7 +218,7 @@ static int probe_hfsplus(blkid_probe pr,
+ 				struct hfsplus_vol_header);
+ 
+ 	if (!hfsplus)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	if ((memcmp(hfsplus->signature, "H+", 2) != 0) &&
+ 	    (memcmp(hfsplus->signature, "HX", 2) != 0))
+@@ -228,7 +228,7 @@ static int probe_hfsplus(blkid_probe pr,
+ 
+ 	blocksize = be32_to_cpu(hfsplus->blocksize);
+ 	if (blocksize < HFSPLUS_SECTOR_SIZE)
+-		return -1;
++		return 1;
+ 
+ 	memcpy(extents, hfsplus->cat_file.extents, sizeof(extents));
+ 	cat_block = be32_to_cpu(extents[0].start_block);
+@@ -236,7 +236,7 @@ static int probe_hfsplus(blkid_probe pr,
+ 	buf = blkid_probe_get_buffer(pr,
+ 			off + ((blkid_loff_t) cat_block * blocksize), 0x2000);
+ 	if (!buf)
+-		return 0;
++		return errno ? -errno : 0;
+ 
+ 	bnode = (struct hfsplus_bheader_record *)
+ 		&buf[sizeof(struct hfsplus_bnode_descriptor)];
+@@ -271,7 +271,7 @@ static int probe_hfsplus(blkid_probe pr,
+ 				(blkid_loff_t) off + leaf_off,
+ 				leaf_node_size);
+ 	if (!buf)
+-		return 0;
++		return errno ? -errno : 0;
+ 
+ 	descr = (struct hfsplus_bnode_descriptor *) buf;
+ 	record_count = be16_to_cpu(descr->num_recs);
+diff -up util-linux-2.23.2/libblkid/src/superblocks/highpoint_raid.c.kzak util-linux-2.23.2/libblkid/src/superblocks/highpoint_raid.c
+--- util-linux-2.23.2/libblkid/src/superblocks/highpoint_raid.c.kzak	2013-04-08 17:55:40.251856150 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/highpoint_raid.c	2014-03-28 15:11:44.680552016 +0100
+@@ -30,9 +30,9 @@ static int probe_highpoint45x(blkid_prob
+ 	uint32_t magic;
+ 
+ 	if (pr->size < 0x10000)
+-		return -1;
++		return 1;
+ 	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+-		return -1;
++		return 1;
+ 
+ 	off = ((pr->size / 0x200) - 11) * 0x200;
+ 	hpt = (struct hpt45x_metadata *)
+@@ -40,13 +40,13 @@ static int probe_highpoint45x(blkid_prob
+ 					off,
+ 					sizeof(struct hpt45x_metadata));
+ 	if (!hpt)
+-		return -1;
++		return errno ? -errno : 1;
+ 	magic = le32_to_cpu(hpt->magic);
+ 	if (magic != HPT45X_MAGIC_OK && magic != HPT45X_MAGIC_BAD)
+-		return -1;
++		return 1;
+ 	if (blkid_probe_set_magic(pr, off, sizeof(hpt->magic),
+ 				(unsigned char *) &hpt->magic))
+-		return -1;
++		return 1;
+ 	return 0;
+ }
+ 
+@@ -54,7 +54,7 @@ static int probe_highpoint37x(blkid_prob
+ 		const struct blkid_idmag *mag __attribute__((__unused__)))
+ {
+ 	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+-		return -1;
++		return 1;
+ 	return 0;
+ }
+ 
+diff -up util-linux-2.23.2/libblkid/src/superblocks/hpfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/hpfs.c
+--- util-linux-2.23.2/libblkid/src/superblocks/hpfs.c.kzak	2013-04-08 17:55:40.252856159 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/hpfs.c	2014-03-28 15:11:44.680552016 +0100
+@@ -68,7 +68,7 @@ static int probe_hpfs(blkid_probe pr, co
+ 	/* super block */
+ 	hs = blkid_probe_get_sb(pr, mag, struct hpfs_super_block);
+ 	if (!hs)
+-		return -1;
++		return errno ? -errno : 1;
+ 	version = hs->version;
+ 
+ 	/* spare super block */
+@@ -77,9 +77,9 @@ static int probe_hpfs(blkid_probe pr, co
+ 				HPFS_SBSPARE_OFFSET,
+ 				sizeof(struct hpfs_spare_super));
+ 	if (!hss)
+-		return -1;
++		return errno ? -errno : 1;
+ 	if (memcmp(hss->magic, "\x49\x18\x91\xf9", 4) != 0)
+-		return -1;
++		return 1;
+ 
+ 	/* boot block (with UUID and LABEL) */
+ 	hbb = (struct hpfs_boot_block *)
+@@ -87,7 +87,7 @@ static int probe_hpfs(blkid_probe pr, co
+ 				0,
+ 				sizeof(struct hpfs_boot_block));
+ 	if (!hbb)
+-		return -1;
++		return errno ? -errno : 1;
+ 	if (memcmp(hbb->magic, "\x55\xaa", 2) == 0 &&
+ 	    memcmp(hbb->sig_hpfs, "HPFS", 4) == 0 &&
+ 	    hbb->sig_28h == 0x28) {
+diff -up util-linux-2.23.2/libblkid/src/superblocks/iso9660.c.kzak util-linux-2.23.2/libblkid/src/superblocks/iso9660.c
+--- util-linux-2.23.2/libblkid/src/superblocks/iso9660.c.kzak	2013-06-13 09:46:10.422650639 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/iso9660.c	2014-03-28 15:11:44.680552016 +0100
+@@ -100,7 +100,7 @@ static int probe_iso9660_hsfs(blkid_prob
+ 
+ 	iso = blkid_probe_get_sb(pr, mag, struct high_sierra_volume_descriptor);
+ 	if (!iso)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	blkid_probe_set_version(pr, "High Sierra");
+ 	blkid_probe_set_label(pr, iso->volume_id, sizeof(iso->volume_id));
+@@ -178,7 +178,7 @@ int probe_iso9660(blkid_probe pr, const
+ 
+ 	iso = blkid_probe_get_sb(pr, mag, struct iso_volume_descriptor);
+ 	if (!iso)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	memcpy(label, iso->volume_id, sizeof(label));
+ 
+diff -up util-linux-2.23.2/libblkid/src/superblocks/isw_raid.c.kzak util-linux-2.23.2/libblkid/src/superblocks/isw_raid.c
+--- util-linux-2.23.2/libblkid/src/superblocks/isw_raid.c.kzak	2013-04-08 17:55:40.252856159 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/isw_raid.c	2014-03-28 15:11:44.680552016 +0100
+@@ -33,9 +33,9 @@ static int probe_iswraid(blkid_probe pr,
+ 	struct isw_metadata *isw;
+ 
+ 	if (pr->size < 0x10000)
+-		return -1;
++		return 1;
+ 	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+-		return -1;
++		return 1;
+ 
+ 	off = ((pr->size / 0x200) - 2) * 0x200;
+ 	isw = (struct isw_metadata *)
+@@ -43,15 +43,16 @@ static int probe_iswraid(blkid_probe pr,
+ 					off,
+ 					sizeof(struct isw_metadata));
+ 	if (!isw)
+-		return -1;
++		return errno ? -errno : 1;
++
+ 	if (memcmp(isw->sig, ISW_SIGNATURE, sizeof(ISW_SIGNATURE)-1) != 0)
+-		return -1;
++		return 1;
+ 	if (blkid_probe_sprintf_version(pr, "%6s",
+ 			&isw->sig[sizeof(ISW_SIGNATURE)-1]) != 0)
+-		return -1;
++		return 1;
+ 	if (blkid_probe_set_magic(pr, off, sizeof(isw->sig),
+ 				(unsigned char *) isw->sig))
+-		return -1;
++		return 1;
+ 	return 0;
+ }
+ 
+diff -up util-linux-2.23.2/libblkid/src/superblocks/jfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/jfs.c
+--- util-linux-2.23.2/libblkid/src/superblocks/jfs.c.kzak	2013-04-08 17:55:40.253856169 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/jfs.c	2014-03-28 15:11:44.681552026 +0100
+@@ -40,7 +40,7 @@ static int probe_jfs(blkid_probe pr, con
+ 
+ 	js = blkid_probe_get_sb(pr, mag, struct jfs_super_block);
+ 	if (!js)
+-		return -1;
++		return errno ? -errno : 1;
+ 	if (le32_to_cpu(js->js_bsize) != (1U << le16_to_cpu(js->js_l2bsize)))
+ 		return 1;
+ 	if (le32_to_cpu(js->js_pbsize) != (1U << le16_to_cpu(js->js_l2pbsize)))
+diff -up util-linux-2.23.2/libblkid/src/superblocks/jmicron_raid.c.kzak util-linux-2.23.2/libblkid/src/superblocks/jmicron_raid.c
+--- util-linux-2.23.2/libblkid/src/superblocks/jmicron_raid.c.kzak	2013-04-08 17:55:40.253856169 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/jmicron_raid.c	2014-03-28 15:11:44.681552026 +0100
+@@ -32,9 +32,9 @@ static int probe_jmraid(blkid_probe pr,
+ 	struct jm_metadata *jm;
+ 
+ 	if (pr->size < 0x10000)
+-		return -1;
++		return 1;
+ 	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+-		return -1;
++		return 1;
+ 
+ 	off = ((pr->size / 0x200) - 1) * 0x200;
+ 	jm = (struct jm_metadata *)
+@@ -42,15 +42,16 @@ static int probe_jmraid(blkid_probe pr,
+ 				off,
+ 				sizeof(struct jm_metadata));
+ 	if (!jm)
+-		return -1;
++		return errno ? -errno : 1;
++
+ 	if (memcmp(jm->signature, JM_SIGNATURE, sizeof(JM_SIGNATURE) - 1) != 0)
+-		return -1;
++		return 1;
+ 	if (blkid_probe_sprintf_version(pr, "%u.%u",
+ 				jm->major_version, jm->minor_version) != 0)
+-		return -1;
++		return 1;
+ 	if (blkid_probe_set_magic(pr, off, sizeof(jm->signature),
+ 				(unsigned char *) jm->signature))
+-		return -1;
++		return 1;
+ 	return 0;
+ }
+ 
+diff -up util-linux-2.23.2/libblkid/src/superblocks/linux_raid.c.kzak util-linux-2.23.2/libblkid/src/superblocks/linux_raid.c
+--- util-linux-2.23.2/libblkid/src/superblocks/linux_raid.c.kzak	2013-04-08 17:55:40.253856169 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/linux_raid.c	2014-03-28 15:11:44.681552026 +0100
+@@ -110,13 +110,13 @@ static int probe_raid0(blkid_probe pr, b
+ 	uint64_t size;
+ 
+ 	if (pr->size < MD_RESERVED_BYTES)
+-		return -1;
++		return 1;
+ 	mdp0 = (struct mdp0_super_block *)
+ 			blkid_probe_get_buffer(pr,
+ 				off,
+ 				sizeof(struct mdp0_super_block));
+ 	if (!mdp0)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	memset(uuid.ints, 0, sizeof(uuid.ints));
+ 
+@@ -173,12 +173,12 @@ static int probe_raid0(blkid_probe pr, b
+ 	}
+ 
+ 	if (blkid_probe_sprintf_version(pr, "%u.%u.%u", ma, mi, pa) != 0)
+-		return -1;
++		return 1;
+ 	if (blkid_probe_set_uuid(pr, (unsigned char *) uuid.bytes) != 0)
+-		return -1;
++		return 1;
+ 	if (blkid_probe_set_magic(pr, off, sizeof(mdp0->md_magic),
+ 				(unsigned char *) &mdp0->md_magic))
+-		return -1;
++		return 1;
+ 	return 0;
+ }
+ 
+@@ -191,24 +191,24 @@ static int probe_raid1(blkid_probe pr, o
+ 				off,
+ 				sizeof(struct mdp1_super_block));
+ 	if (!mdp1)
+-		return -1;
++		return errno ? -errno : 1;
+ 	if (le32_to_cpu(mdp1->magic) != MD_SB_MAGIC)
+-		return -1;
++		return 1;
+ 	if (le32_to_cpu(mdp1->major_version) != 1U)
+-		return -1;
++		return 1;
+ 	if (le64_to_cpu(mdp1->super_offset) != (uint64_t) off >> 9)
+-		return -1;
++		return 1;
+ 	if (blkid_probe_set_uuid(pr, (unsigned char *) mdp1->set_uuid) != 0)
+-		return -1;
++		return 1;
+ 	if (blkid_probe_set_uuid_as(pr,
+ 			(unsigned char *) mdp1->device_uuid, "UUID_SUB") != 0)
+-		return -1;
++		return 1;
+ 	if (blkid_probe_set_label(pr, mdp1->set_name,
+ 				sizeof(mdp1->set_name)) != 0)
+-		return -1;
++		return 1;
+ 	if (blkid_probe_set_magic(pr, off, sizeof(mdp1->magic),
+ 				(unsigned char *) &mdp1->magic))
+-		return -1;
++		return 1;
+ 	return 0;
+ }
+ 
+@@ -216,35 +216,44 @@ int probe_raid(blkid_probe pr,
+ 		const struct blkid_idmag *mag __attribute__((__unused__)))
+ {
+ 	const char *ver = NULL;
++	int ret = BLKID_PROBE_NONE;
+ 
+ 	if (pr->size > MD_RESERVED_BYTES) {
+ 		/* version 0 at the end of the device */
+ 		uint64_t sboff = (pr->size & ~(MD_RESERVED_BYTES - 1))
+-			         - MD_RESERVED_BYTES;
+-		if (probe_raid0(pr, sboff) == 0)
+-			return 0;
++			- MD_RESERVED_BYTES;
++		ret = probe_raid0(pr, sboff);
++		if (ret < 1)
++			return ret;	/* error */
+ 
+ 		/* version 1.0 at the end of the device */
+ 		sboff = (pr->size & ~(0x1000 - 1)) - 0x2000;
+-		if (probe_raid1(pr, sboff) == 0)
++		ret = probe_raid1(pr, sboff);
++		if (ret < 0)
++			return ret;	/* error */
++		if (ret == 0)
+ 			ver = "1.0";
+ 	}
+ 
+ 	if (!ver) {
+ 		/* version 1.1 at the start of the device */
+-		if (probe_raid1(pr, 0) == 0)
++		ret = probe_raid1(pr, 0);
++		if (ret == 0)
+ 			ver = "1.1";
+ 
+ 		/* version 1.2 at 4k offset from the start */
+-		else if (probe_raid1(pr, 0x1000) == 0)
+-			ver = "1.2";
++		else if (ret == BLKID_PROBE_NONE) {
++			ret = probe_raid1(pr, 0x1000);
++			if (ret == 0)
++				ver = "1.2";
++		}
+ 	}
+ 
+ 	if (ver) {
+ 		blkid_probe_set_version(pr, ver);
+-		return 0;
++		return BLKID_PROBE_OK;
+ 	}
+-	return -1;
++	return ret;
+ }
+ 
+ 
+diff -up util-linux-2.23.2/libblkid/src/superblocks/lsi_raid.c.kzak util-linux-2.23.2/libblkid/src/superblocks/lsi_raid.c
+--- util-linux-2.23.2/libblkid/src/superblocks/lsi_raid.c.kzak	2013-04-08 17:55:40.254856179 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/lsi_raid.c	2014-03-28 15:11:44.681552026 +0100
+@@ -30,9 +30,9 @@ static int probe_lsiraid(blkid_probe pr,
+ 	struct lsi_metadata *lsi;
+ 
+ 	if (pr->size < 0x10000)
+-		return -1;
++		return 1;
+ 	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+-		return -1;
++		return 1;
+ 
+ 	off = ((pr->size / 0x200) - 1) * 0x200;
+ 	lsi = (struct lsi_metadata *)
+@@ -40,13 +40,13 @@ static int probe_lsiraid(blkid_probe pr,
+ 				off,
+ 				sizeof(struct lsi_metadata));
+ 	if (!lsi)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	if (memcmp(lsi->sig, LSI_SIGNATURE, sizeof(LSI_SIGNATURE)-1) != 0)
+-		return -1;
++		return 1;
+ 	if (blkid_probe_set_magic(pr, off, sizeof(lsi->sig),
+ 				(unsigned char *) lsi->sig))
+-		return -1;
++		return 1;
+ 	return 0;
+ }
+ 
+diff -up util-linux-2.23.2/libblkid/src/superblocks/luks.c.kzak util-linux-2.23.2/libblkid/src/superblocks/luks.c
+--- util-linux-2.23.2/libblkid/src/superblocks/luks.c.kzak	2013-04-08 17:55:40.254856179 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/luks.c	2014-03-28 15:11:44.681552026 +0100
+@@ -45,7 +45,7 @@ static int probe_luks(blkid_probe pr, co
+ 
+ 	header = blkid_probe_get_sb(pr, mag, struct luks_phdr);
+ 	if (header == NULL)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	blkid_probe_strncpy_uuid(pr, (unsigned char *) header->uuid,
+ 			sizeof(header->uuid));
+diff -up util-linux-2.23.2/libblkid/src/superblocks/lvm.c.kzak util-linux-2.23.2/libblkid/src/superblocks/lvm.c
+--- util-linux-2.23.2/libblkid/src/superblocks/lvm.c.kzak	2013-06-13 09:46:10.422650639 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/lvm.c	2014-03-28 15:11:44.681552026 +0100
+@@ -82,7 +82,7 @@ static int probe_lvm2(blkid_probe pr, co
+ 			mag->kboff << 10,
+ 			512 + sizeof(struct lvm2_pv_label_header));
+ 	if (!buf)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	/* buf is at 0k or 1k offset; find label inside */
+ 	if (memcmp(buf, "LABELONE", 8) == 0) {
+@@ -129,7 +129,7 @@ static int probe_lvm1(blkid_probe pr, co
+ 
+ 	label = blkid_probe_get_sb(pr, mag, struct lvm1_pv_label_header);
+ 	if (!label)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	version = le16_to_cpu(label->version);
+ 	if (version != 1 && version != 2)
+@@ -164,7 +164,7 @@ static int probe_verity(blkid_probe pr,
+ 
+ 	sb = blkid_probe_get_sb(pr, mag, struct verity_sb);
+ 	if (sb == NULL)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	version = le32_to_cpu(sb->version);
+ 	if (version != 1)
+diff -up util-linux-2.23.2/libblkid/src/superblocks/minix.c.kzak util-linux-2.23.2/libblkid/src/superblocks/minix.c
+--- util-linux-2.23.2/libblkid/src/superblocks/minix.c.kzak	2013-06-13 09:46:10.423650647 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/minix.c	2014-03-28 15:11:44.681552026 +0100
+@@ -80,17 +80,17 @@ static int probe_minix(blkid_probe pr, c
+ 			max(sizeof(struct minix_super_block),
+ 			    sizeof(struct minix3_super_block)));
+ 	if (!data)
+-		return -1;
++		return errno ? -errno : 1;
+ 	version = get_minix_version(data, &swabme);
+ 	if (version < 1)
+-		return -1;
++		return 1;
+ 
+ 	if (version <= 2) {
+ 		struct minix_super_block *sb = (struct minix_super_block *) data;
+ 		int zones, ninodes, imaps, zmaps, firstz;
+ 
+ 		if (sb->s_imap_blocks == 0 || sb->s_zmap_blocks == 0)
+-			return -1;
++			return 1;
+ 
+ 		zones = version == 2 ? minix_swab32(swabme, sb->s_zones) :
+ 				       minix_swab16(swabme, sb->s_nzones);
+@@ -101,15 +101,15 @@ static int probe_minix(blkid_probe pr, c
+ 
+ 		/* sanity checks to be sure that the FS is really minix */
+ 		if (imaps * MINIX_BLOCK_SIZE * 8 < ninodes + 1)
+-			return -1;
++			return 1;
+ 		if (zmaps * MINIX_BLOCK_SIZE * 8 < zones - firstz + 1)
+-			return -1;
++			return 1;
+ 
+ 	} else if (version == 3) {
+ 		struct minix3_super_block *sb = (struct minix3_super_block *) data;
+ 
+ 		if (sb->s_imap_blocks == 0 || sb->s_zmap_blocks == 0)
+-			return -1;
++			return 1;
+ 	}
+ 
+ 	/* unfortunately, some parts of ext3 is sometimes possible to
+@@ -117,8 +117,10 @@ static int probe_minix(blkid_probe pr, c
+ 	 * string. (For extN magic string and offsets see ext.c.)
+ 	 */
+ 	ext = blkid_probe_get_buffer(pr, 0x400 + 0x38, 2);
+-	if (ext && memcmp(ext, "\123\357", 2) == 0)
+-		return -1;
++	if (!ext)
++		return errno ? -errno : 1;
++	else if (memcmp(ext, "\123\357", 2) == 0)
++		return 1;
+ 
+ 	blkid_probe_sprintf_version(pr, "%d", version);
+ 	return 0;
+diff -up util-linux-2.23.2/libblkid/src/superblocks/netware.c.kzak util-linux-2.23.2/libblkid/src/superblocks/netware.c
+--- util-linux-2.23.2/libblkid/src/superblocks/netware.c.kzak	2013-04-08 17:55:40.255856188 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/netware.c	2014-03-28 15:11:44.681552026 +0100
+@@ -71,7 +71,7 @@ static int probe_netware(blkid_probe pr,
+ 
+ 	nw = blkid_probe_get_sb(pr, mag, struct netware_super_block);
+ 	if (!nw)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	blkid_probe_set_uuid(pr, nw->SBH_PoolID);
+ 
+diff -up util-linux-2.23.2/libblkid/src/superblocks/nilfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/nilfs.c
+--- util-linux-2.23.2/libblkid/src/superblocks/nilfs.c.kzak	2013-04-08 17:55:40.256856198 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/nilfs.c	2014-03-28 15:11:44.681552026 +0100
+@@ -82,7 +82,7 @@ static int probe_nilfs2(blkid_probe pr,
+ 
+ 	sb = blkid_probe_get_sb(pr, mag, struct nilfs_super_block);
+ 	if (!sb)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	bytes = le16_to_cpu(sb->s_bytes);
+ 	crc = crc32(le32_to_cpu(sb->s_crc_seed), (unsigned char *)sb, sumoff);
+@@ -90,7 +90,7 @@ static int probe_nilfs2(blkid_probe pr,
+ 	crc = crc32(crc, (unsigned char *)sb + sumoff + 4, bytes - sumoff - 4);
+ 
+ 	if (crc != le32_to_cpu(sb->s_sum))
+-		return -1;
++		return 1;
+ 
+ 	if (strlen(sb->s_volume_name))
+ 		blkid_probe_set_label(pr, (unsigned char *) sb->s_volume_name,
+diff -up util-linux-2.23.2/libblkid/src/superblocks/ntfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/ntfs.c
+--- util-linux-2.23.2/libblkid/src/superblocks/ntfs.c.kzak	2013-06-13 09:46:10.423650647 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/ntfs.c	2014-03-28 15:11:44.681552026 +0100
+@@ -91,7 +91,7 @@ static int probe_ntfs(blkid_probe pr, co
+ 
+ 	ns = blkid_probe_get_sb(pr, mag, struct ntfs_super_block);
+ 	if (!ns)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	/*
+ 	 * Check bios parameters block
+@@ -158,7 +158,7 @@ static int probe_ntfs(blkid_probe pr, co
+ 
+ 	buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size);
+ 	if (!buf_mft)
+-		return 1;
++		return errno ? -errno : 1;
+ 
+ 	if (memcmp(buf_mft, "FILE", 4))
+ 		return 1;
+@@ -167,7 +167,7 @@ static int probe_ntfs(blkid_probe pr, co
+ 
+ 	buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size);
+ 	if (!buf_mft)
+-		return 1;
++		return errno ? -errno : 1;
+ 
+ 	if (memcmp(buf_mft, "FILE", 4))
+ 		return 1;
+diff -up util-linux-2.23.2/libblkid/src/superblocks/nvidia_raid.c.kzak util-linux-2.23.2/libblkid/src/superblocks/nvidia_raid.c
+--- util-linux-2.23.2/libblkid/src/superblocks/nvidia_raid.c.kzak	2013-04-08 17:55:40.257856207 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/nvidia_raid.c	2014-03-28 15:11:44.682552036 +0100
+@@ -32,9 +32,9 @@ static int probe_nvraid(blkid_probe pr,
+ 	struct nv_metadata *nv;
+ 
+ 	if (pr->size < 0x10000)
+-		return -1;
++		return 1;
+ 	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+-		return -1;
++		return 1;
+ 
+ 	off = ((pr->size / 0x200) - 2) * 0x200;
+ 	nv = (struct nv_metadata *)
+@@ -42,15 +42,15 @@ static int probe_nvraid(blkid_probe pr,
+ 				off,
+ 				sizeof(struct nv_metadata));
+ 	if (!nv)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	if (memcmp(nv->vendor, NVIDIA_SIGNATURE, sizeof(NVIDIA_SIGNATURE)-1) != 0)
+-		return -1;
++		return 1;
+ 	if (blkid_probe_sprintf_version(pr, "%u", le16_to_cpu(nv->version)) != 0)
+-		return -1;
++		return 1;
+ 	if (blkid_probe_set_magic(pr, off, sizeof(nv->vendor),
+ 				(unsigned char *) nv->vendor))
+-		return -1;
++		return 1;
+ 	return 0;
+ }
+ 
+diff -up util-linux-2.23.2/libblkid/src/superblocks/ocfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/ocfs.c
+--- util-linux-2.23.2/libblkid/src/superblocks/ocfs.c.kzak	2013-04-08 17:55:40.257856207 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/ocfs.c	2014-03-28 15:11:44.682552036 +0100
+@@ -109,14 +109,14 @@ static int probe_ocfs(blkid_probe pr, co
+ 	buf = blkid_probe_get_buffer(pr, mag->kboff << 10,
+ 			sizeof(struct ocfs_volume_header));
+ 	if (!buf)
+-		return -1;
++		return errno ? -errno : 1;
+ 	memcpy(&ovh, buf, sizeof(ovh));
+ 
+ 	/* label */
+ 	buf = blkid_probe_get_buffer(pr, (mag->kboff << 10) + 512,
+ 			sizeof(struct ocfs_volume_label));
+ 	if (!buf)
+-		return -1;
++		return errno ? -errno : 1;
+ 	memcpy(&ovl, buf, sizeof(ovl));
+ 
+ 	maj = ocfsmajor(ovh);
+@@ -144,7 +144,7 @@ static int probe_ocfs2(blkid_probe pr, c
+ 
+ 	osb = blkid_probe_get_sb(pr, mag, struct ocfs2_super_block);
+ 	if (!osb)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	blkid_probe_set_label(pr, (unsigned char *) osb->s_label, sizeof(osb->s_label));
+ 	blkid_probe_set_uuid(pr, osb->s_uuid);
+@@ -162,7 +162,7 @@ static int probe_oracleasm(blkid_probe p
+ 
+ 	dl = blkid_probe_get_sb(pr, mag, struct oracle_asm_disk_label);
+ 	if (!dl)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	blkid_probe_set_label(pr, (unsigned char *) dl->dl_id, sizeof(dl->dl_id));
+ 	return 0;
+diff -up util-linux-2.23.2/libblkid/src/superblocks/promise_raid.c.kzak util-linux-2.23.2/libblkid/src/superblocks/promise_raid.c
+--- util-linux-2.23.2/libblkid/src/superblocks/promise_raid.c.kzak	2013-06-13 09:46:10.423650647 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/promise_raid.c	2014-03-28 15:11:44.682552036 +0100
+@@ -33,9 +33,9 @@ static int probe_pdcraid(blkid_probe pr,
+ 	};
+ 
+ 	if (pr->size < 0x40000)
+-		return -1;
++		return 1;
+ 	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+-		return -1;
++		return 1;
+ 
+ 	for (i = 0; sectors[i] != 0; i++) {
+ 		uint64_t off;
+@@ -47,18 +47,18 @@ static int probe_pdcraid(blkid_probe pr,
+ 					off,
+ 					sizeof(struct promise_metadata));
+ 		if (!pdc)
+-			return -1;
++			return errno ? -errno : 1;
+ 
+ 		if (memcmp(pdc->sig, PDC_SIGNATURE,
+ 				sizeof(PDC_SIGNATURE) - 1) == 0) {
+ 
+ 			if (blkid_probe_set_magic(pr, off, sizeof(pdc->sig),
+ 						(unsigned char *) pdc->sig))
+-				return -1;
++				return 1;
+ 			return 0;
+ 		}
+ 	}
+-	return -1;
++	return 1;
+ }
+ 
+ const struct blkid_idinfo pdcraid_idinfo = {
+diff -up util-linux-2.23.2/libblkid/src/superblocks/reiserfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/reiserfs.c
+--- util-linux-2.23.2/libblkid/src/superblocks/reiserfs.c.kzak	2013-04-08 17:55:40.258856216 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/reiserfs.c	2014-03-28 15:11:44.682552036 +0100
+@@ -45,17 +45,17 @@ static int probe_reiser(blkid_probe pr,
+ 
+ 	rs = blkid_probe_get_sb(pr, mag, struct reiserfs_super_block);
+ 	if (!rs)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	blocksize = le16_to_cpu(rs->rs_blocksize);
+ 
+ 	/* The blocksize must be at least 512B */
+ 	if ((blocksize >> 9) == 0)
+-		return -BLKID_ERR_PARAM;
++		return 1;
+ 
+ 	/* If the superblock is inside the journal, we have the wrong one */
+ 	if (mag->kboff / (blocksize >> 9) > le32_to_cpu(rs->rs_journal_block) / 2)
+-		return -BLKID_ERR_BIG;
++		return 1;
+ 
+ 	/* LABEL/UUID are only valid for later versions of Reiserfs v3.6. */
+ 	if (mag->magic[6] == '2' || mag->magic[6] == '3') {
+@@ -82,7 +82,7 @@ static int probe_reiser4(blkid_probe pr,
+ 
+ 	rs4 = blkid_probe_get_sb(pr, mag, struct reiser4_super_block);
+ 	if (!rs4)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	if (*rs4->rs4_label)
+ 		blkid_probe_set_label(pr, rs4->rs4_label, sizeof(rs4->rs4_label));
+diff -up util-linux-2.23.2/libblkid/src/superblocks/romfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/romfs.c
+--- util-linux-2.23.2/libblkid/src/superblocks/romfs.c.kzak	2013-04-08 17:55:40.258856216 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/romfs.c	2014-03-28 15:11:44.682552036 +0100
+@@ -29,7 +29,7 @@ static int probe_romfs(blkid_probe pr, c
+ 
+ 	ros = blkid_probe_get_sb(pr, mag, struct romfs_super_block);
+ 	if (!ros)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	if (strlen((char *) ros->ros_volume))
+ 		blkid_probe_set_label(pr, ros->ros_volume,
+diff -up util-linux-2.23.2/libblkid/src/superblocks/silicon_raid.c.kzak util-linux-2.23.2/libblkid/src/superblocks/silicon_raid.c
+--- util-linux-2.23.2/libblkid/src/superblocks/silicon_raid.c.kzak	2013-06-13 09:46:10.424650656 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/silicon_raid.c	2014-03-28 15:11:44.682552036 +0100
+@@ -88,9 +88,9 @@ static int probe_silraid(blkid_probe pr,
+ 	struct silicon_metadata *sil;
+ 
+ 	if (pr->size < 0x10000)
+-		return -1;
++		return 1;
+ 	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+-		return -1;
++		return 1;
+ 
+ 	off = ((pr->size / 0x200) - 1) * 0x200;
+ 
+@@ -98,27 +98,27 @@ static int probe_silraid(blkid_probe pr,
+ 			blkid_probe_get_buffer(pr, off,
+ 				sizeof(struct silicon_metadata));
+ 	if (!sil)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	if (le32_to_cpu(sil->magic) != SILICON_MAGIC)
+-		return -1;
++		return 1;
+ 	if (sil->disk_number >= 8)
+-		return -1;
++		return 1;
+ 	if (!checksum(sil)) {
+ 		DBG(LOWPROBE, blkid_debug("silicon raid: incorrect checksum"));
+-		return -1;
++		return 1;
+ 	}
+ 
+ 	if (blkid_probe_sprintf_version(pr, "%u.%u",
+ 				le16_to_cpu(sil->major_ver),
+ 				le16_to_cpu(sil->minor_ver)) != 0)
+-		return -1;
++		return 1;
+ 
+ 	if (blkid_probe_set_magic(pr,
+ 			off + offsetof(struct silicon_metadata, magic),
+ 			sizeof(sil->magic),
+ 			(unsigned char *) &sil->magic))
+-		return -1;
++		return 1;
+ 	return 0;
+ }
+ 
+diff -up util-linux-2.23.2/libblkid/src/superblocks/squashfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/squashfs.c
+--- util-linux-2.23.2/libblkid/src/superblocks/squashfs.c.kzak	2013-04-08 17:55:40.258856216 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/squashfs.c	2014-03-28 15:11:44.682552036 +0100
+@@ -34,7 +34,7 @@ static int probe_squashfs(blkid_probe pr
+ 
+ 	sq = blkid_probe_get_sb(pr, mag, struct sqsh_super_block);
+ 	if (!sq)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	if (strcmp(mag->magic, "sqsh") == 0 ||
+ 	    strcmp(mag->magic, "qshs") == 0)
+diff -up util-linux-2.23.2/libblkid/src/superblocks/superblocks.c.kzak util-linux-2.23.2/libblkid/src/superblocks/superblocks.c
+--- util-linux-2.23.2/libblkid/src/superblocks/superblocks.c.kzak	2013-07-30 10:39:26.209738269 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/superblocks.c	2014-03-28 15:11:44.682552036 +0100
+@@ -331,9 +331,10 @@ int blkid_superblocks_get_name(size_t id
+ static int superblocks_probe(blkid_probe pr, struct blkid_chain *chn)
+ {
+ 	size_t i;
++	int rc = BLKID_PROBE_NONE;
+ 
+ 	if (!pr || chn->idx < -1)
+-		return -1;
++		return -EINVAL;
+ 	blkid_probe_chain_reset_vals(pr, chn);
+ 
+ 	DBG(LOWPROBE, blkid_debug("--> starting probing loop [SUBLKS idx=%d]",
+@@ -351,38 +352,50 @@ static int superblocks_probe(blkid_probe
+ 		const struct blkid_idinfo *id;
+ 		const struct blkid_idmag *mag = NULL;
+ 		blkid_loff_t off = 0;
+-		int rc = 0;
+ 
+ 		chn->idx = i;
+ 		id = idinfos[i];
+ 
+ 		if (chn->fltr && blkid_bmp_get_item(chn->fltr, i)) {
+ 			DBG(LOWPROBE, blkid_debug("filter out: %s", id->name));
++			rc = BLKID_PROBE_NONE;
+ 			continue;
+ 		}
+ 
+-		if (id->minsz && id->minsz > pr->size)
++		if (id->minsz && id->minsz > pr->size) {
++			rc = BLKID_PROBE_NONE;
+ 			continue;	/* the device is too small */
++		}
+ 
+ 		/* don't probe for RAIDs, swap or journal on CD/DVDs */
+ 		if ((id->usage & (BLKID_USAGE_RAID | BLKID_USAGE_OTHER)) &&
+-		    blkid_probe_is_cdrom(pr))
++		    blkid_probe_is_cdrom(pr)) {
++			rc = BLKID_PROBE_NONE;
+ 			continue;
++		}
+ 
+ 		/* don't probe for RAIDs on floppies */
+-		if ((id->usage & BLKID_USAGE_RAID) && blkid_probe_is_tiny(pr))
++		if ((id->usage & BLKID_USAGE_RAID) && blkid_probe_is_tiny(pr)) {
++			rc = BLKID_PROBE_NONE;
+ 			continue;
++		}
+ 
+ 		DBG(LOWPROBE, blkid_debug("[%zd] %s:", i, id->name));
+ 
+-		if (blkid_probe_get_idmag(pr, id, &off, &mag))
++		rc = blkid_probe_get_idmag(pr, id, &off, &mag);
++		if (rc < 0)
++			break;
++		if (rc != BLKID_PROBE_OK)
+ 			continue;
+ 
+ 		/* final check by probing function */
+ 		if (id->probefunc) {
+ 			DBG(LOWPROBE, blkid_debug("\tcall probefunc()"));
+-			if (id->probefunc(pr, mag) != 0) {
++			rc = id->probefunc(pr, mag);
++			if (rc != BLKID_PROBE_OK) {
+ 				blkid_probe_chain_reset_vals(pr, chn);
++				if (rc < 0)
++					break;
+ 				continue;
+ 			}
+ 		}
+@@ -407,13 +420,13 @@ static int superblocks_probe(blkid_probe
+ 
+ 		DBG(LOWPROBE, blkid_debug("<-- leaving probing loop (type=%s) [SUBLKS idx=%d]",
+ 			id->name, chn->idx));
+-		return 0;
++		return BLKID_PROBE_OK;
+ 	}
+ 
+ nothing:
+-	DBG(LOWPROBE, blkid_debug("<-- leaving probing loop (failed) [SUBLKS idx=%d]",
+-		chn->idx));
+-	return 1;
++	DBG(LOWPROBE, blkid_debug("<-- leaving probing loop (failed=%d) [SUBLKS idx=%d]",
++			rc, chn->idx));
++	return rc;
+ }
+ 
+ /*
+diff -up util-linux-2.23.2/libblkid/src/superblocks/swap.c.kzak util-linux-2.23.2/libblkid/src/superblocks/swap.c
+--- util-linux-2.23.2/libblkid/src/superblocks/swap.c.kzak	2013-06-13 09:46:10.425650665 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/swap.c	2014-03-28 15:11:44.682552036 +0100
+@@ -44,17 +44,17 @@ static int swap_set_info(blkid_probe pr,
+ 	hdr = (struct swap_header_v1_2 *) blkid_probe_get_buffer(pr, 1024,
+ 				sizeof(struct swap_header_v1_2));
+ 	if (!hdr)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	/* SWAPSPACE2 - check for wrong version or zeroed pagecount */
+         if (strcmp(version, "2") == 0) {
+ 		if (hdr->version != 1 && swab32(hdr->version) != 1) {
+ 			DBG(LOWPROBE, blkid_debug("incorrect swap version"));
+-			return -1;
++			return 1;
+ 		}
+ 		if (hdr->lastpage == 0) {
+ 			DBG(LOWPROBE, blkid_debug("not set last swap page"));
+-			return -1;
++			return 1;
+ 		}
+         }
+ 
+@@ -62,9 +62,9 @@ static int swap_set_info(blkid_probe pr,
+ 	if (hdr->padding[32] == 0 && hdr->padding[33] == 0) {
+ 		if (hdr->volume[0] && blkid_probe_set_label(pr, hdr->volume,
+ 				sizeof(hdr->volume)) < 0)
+-			return -1;
++			return 1;
+ 		if (blkid_probe_set_uuid(pr, hdr->uuid) < 0)
+-			return -1;
++			return 1;
+ 	}
+ 
+ 	blkid_probe_set_version(pr, version);
+@@ -76,12 +76,12 @@ static int probe_swap(blkid_probe pr, co
+ 	unsigned char *buf;
+ 
+ 	if (!mag)
+-		return -1;
++		return 1;
+ 
+ 	/* TuxOnIce keeps valid swap header at the end of the 1st page */
+ 	buf = blkid_probe_get_buffer(pr, 0, TOI_MAGIC_STRLEN);
+ 	if (!buf)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	if (memcmp(buf, TOI_MAGIC_STRING, TOI_MAGIC_STRLEN) == 0)
+ 		return 1;	/* Ignore swap signature, it's TuxOnIce */
+@@ -94,13 +94,13 @@ static int probe_swap(blkid_probe pr, co
+ 	} else if (!memcmp(mag->magic, "SWAPSPACE2", mag->len))
+ 		return swap_set_info(pr, "2");
+ 
+-	return -1;
++	return 1;
+ }
+ 
+ static int probe_swsuspend(blkid_probe pr, const struct blkid_idmag *mag)
+ {
+ 	if (!mag)
+-		return -1;
++		return 1;
+ 	if (!memcmp(mag->magic, "S1SUSPEND", mag->len))
+ 		return swap_set_info(pr, "s1suspend");
+ 	if (!memcmp(mag->magic, "S2SUSPEND", mag->len))
+@@ -112,7 +112,7 @@ static int probe_swsuspend(blkid_probe p
+ 	if (!memcmp(mag->magic, "LINHIB0001", mag->len))
+ 		return swap_set_info(pr, "linhib0001");
+ 
+-	return -1;	/* no signature detected */
++	return 1;	/* no signature detected */
+ }
+ 
+ const struct blkid_idinfo swap_idinfo =
+diff -up util-linux-2.23.2/libblkid/src/superblocks/sysv.c.kzak util-linux-2.23.2/libblkid/src/superblocks/sysv.c
+--- util-linux-2.23.2/libblkid/src/superblocks/sysv.c.kzak	2013-04-08 17:55:40.261856245 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/sysv.c	2014-03-28 15:11:44.683552047 +0100
+@@ -80,7 +80,7 @@ static int probe_xenix(blkid_probe pr, c
+ 
+ 	sb = blkid_probe_get_sb(pr, mag, struct xenix_super_block);
+ 	if (!sb)
+-		return -1;
++		return errno ? -errno : 1;
+ 	blkid_probe_set_label(pr, sb->s_fname, sizeof(sb->s_fname));
+ 	return 0;
+ }
+@@ -105,21 +105,21 @@ static int probe_sysv(blkid_probe pr,
+ 					off,
+ 					sizeof(struct sysv_super_block));
+ 		if (!sb)
+-			return -1;
++			return errno ? -errno : 1;
+ 
+ 		if (sb->s_magic == cpu_to_le32(0xfd187e20) ||
+ 		    sb->s_magic == cpu_to_be32(0xfd187e20)) {
+ 
+ 			if (blkid_probe_set_label(pr, sb->s_fname,
+ 						sizeof(sb->s_fname)))
+-				return -1;
++				return 1;
+ 
+ 			if (blkid_probe_set_magic(pr,
+ 					off + offsetof(struct sysv_super_block,
+ 								s_magic),
+ 					sizeof(sb->s_magic),
+ 					(unsigned char *) &sb->s_magic))
+-				return -1;
++				return 1;
+ 
+ 			return 0;
+ 		}
+diff -up util-linux-2.23.2/libblkid/src/superblocks/ubifs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/ubifs.c
+--- util-linux-2.23.2/libblkid/src/superblocks/ubifs.c.kzak	2013-06-13 09:46:10.426650673 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/ubifs.c	2014-03-28 15:11:44.683552047 +0100
+@@ -99,7 +99,7 @@ static int probe_ubifs(blkid_probe pr, c
+ 
+ 	sb = blkid_probe_get_sb(pr, mag, struct ubifs_sb_node);
+ 	if (!sb)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	blkid_probe_set_uuid(pr, sb->uuid);
+ 	blkid_probe_sprintf_version(pr, "w%dr%d",
+diff -up util-linux-2.23.2/libblkid/src/superblocks/udf.c.kzak util-linux-2.23.2/libblkid/src/superblocks/udf.c
+--- util-linux-2.23.2/libblkid/src/superblocks/udf.c.kzak	2013-06-13 09:46:10.426650673 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/udf.c	2014-03-28 15:11:44.683552047 +0100
+@@ -85,11 +85,11 @@ static int probe_udf(blkid_probe pr,
+ 					UDF_VSD_OFFSET + b,
+ 					sizeof(*vsd));
+ 		if (!vsd)
+-			return 1;
++			return errno ? -errno : 1;
+ 		if (vsd->id[0] != '\0')
+ 			goto nsr;
+ 	}
+-	return -1;
++	return 1;
+ 
+ nsr:
+ 	/* search the list of VSDs for a NSR descriptor */
+@@ -99,15 +99,15 @@ nsr:
+ 					UDF_VSD_OFFSET + ((blkid_loff_t) b * 0x800),
+ 					sizeof(*vsd));
+ 		if (!vsd)
+-			return -1;
++			return errno ? -errno : 1;
+ 		if (vsd->id[0] == '\0')
+-			return -1;
++			return 1;
+ 		if (memcmp(vsd->id, "NSR02", 5) == 0)
+ 			goto anchor;
+ 		if (memcmp(vsd->id, "NSR03", 5) == 0)
+ 			goto anchor;
+ 	}
+-	return -1;
++	return 1;
+ 
+ anchor:
+ 	/* read Anchor Volume Descriptor (AVDP), checking block size */
+@@ -115,7 +115,7 @@ anchor:
+ 		vd = (struct volume_descriptor *)
+ 			blkid_probe_get_buffer(pr, 256 * pbs[i], sizeof(*vd));
+ 		if (!vd)
+-			return -1;
++			return errno ? -errno : 1;
+ 
+ 		type = le16_to_cpu(vd->tag.id);
+ 		if (type == 2) /* TAG_ID_AVDP */
+@@ -138,7 +138,7 @@ real_blksz:
+ 					(blkid_loff_t) (loc + b) * bs,
+ 					sizeof(*vd));
+ 		if (!vd)
+-			return -1;
++			return errno ? -errno : 1;
+ 	}
+ 
+ 	/* Try extract all possible ISO9660 information -- if there is
+@@ -155,7 +155,7 @@ real_blksz:
+ 					(blkid_loff_t) (loc + b) * bs,
+ 					sizeof(*vd));
+ 		if (!vd)
+-			return -1;
++			return errno ? -errno : 1;
+ 		type = le16_to_cpu(vd->tag.id);
+ 		if (type == 0)
+ 			break;
+diff -up util-linux-2.23.2/libblkid/src/superblocks/ufs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/ufs.c
+--- util-linux-2.23.2/libblkid/src/superblocks/ufs.c.kzak	2013-04-08 17:55:40.263856264 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/ufs.c	2014-03-28 15:11:44.683552047 +0100
+@@ -185,7 +185,7 @@ static int probe_ufs(blkid_probe pr,
+ 					offsets[i] * 1024,
+ 					sizeof(struct ufs_super_block));
+ 		if (!ufs)
+-			return -1;
++			return errno ? -errno : 1;
+ 
+ 		magBE = be32_to_cpu(ufs->fs_magic);
+ 		magLE = le32_to_cpu(ufs->fs_magic);
+@@ -231,7 +231,7 @@ found:
+ 				offsetof(struct ufs_super_block, fs_magic),
+ 			sizeof(ufs->fs_magic),
+ 			(unsigned char *) &ufs->fs_magic))
+-		return -1;
++		return 1;
+ 
+ 	return 0;
+ }
+diff -up util-linux-2.23.2/libblkid/src/superblocks/vfat.c.kzak util-linux-2.23.2/libblkid/src/superblocks/vfat.c
+--- util-linux-2.23.2/libblkid/src/superblocks/vfat.c.kzak	2013-06-13 09:46:10.426650673 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/vfat.c	2014-03-28 15:12:28.036993622 +0100
+@@ -255,16 +255,20 @@ int blkid_probe_is_vfat(blkid_probe pr)
+ 	struct vfat_super_block *vs;
+ 	struct msdos_super_block *ms;
+ 	const struct blkid_idmag *mag = NULL;
++	int rc;
+ 
+-	if (blkid_probe_get_idmag(pr, &vfat_idinfo, NULL, &mag) || !mag)
++	rc = blkid_probe_get_idmag(pr, &vfat_idinfo, NULL, &mag);
++	if (rc < 0)
++		return rc;	/* error */
++	if (rc != BLKID_PROBE_OK || !mag)
+ 		return 0;
+ 
+ 	ms = blkid_probe_get_sb(pr, mag, struct msdos_super_block);
+ 	if (!ms)
+-		return 0;
++		return errno ? -errno : 0;
+ 	vs = blkid_probe_get_sb(pr, mag, struct vfat_super_block);
+ 	if (!vs)
+-		return 0;
++		return errno ? -errno : 0;
+ 
+ 	return fat_valid_superblock(mag, ms, vs, NULL, NULL);
+ }
+@@ -283,10 +287,12 @@ static int probe_vfat(blkid_probe pr, co
+ 
+ 	ms = blkid_probe_get_sb(pr, mag, struct msdos_super_block);
+ 	if (!ms)
+-		return 0;
++		return errno ? -errno : 1;
++
+ 	vs = blkid_probe_get_sb(pr, mag, struct vfat_super_block);
+ 	if (!vs)
+-		return 0;
++		return errno ? -errno : 1;
++
+ 	if (!fat_valid_superblock(mag, ms, vs, &cluster_count, &fat_size))
+ 		return 1;
+ 
+@@ -376,16 +382,16 @@ static int probe_vfat(blkid_probe pr, co
+ 					(blkid_loff_t) fsinfo_sect * sector_size,
+ 					sizeof(struct fat32_fsinfo));
+ 			if (buf == NULL)
+-				return -1;
++				return errno ? -errno : 1;
+ 
+ 			fsinfo = (struct fat32_fsinfo *) buf;
+ 			if (memcmp(fsinfo->signature1, "\x52\x52\x61\x41", 4) != 0 &&
+ 			    memcmp(fsinfo->signature1, "\x52\x52\x64\x41", 4) != 0 &&
+ 			    memcmp(fsinfo->signature1, "\x00\x00\x00\x00", 4) != 0)
+-				return -1;
++				return 1;
+ 			if (memcmp(fsinfo->signature2, "\x72\x72\x41\x61", 4) != 0 &&
+ 			    memcmp(fsinfo->signature2, "\x00\x00\x00\x00", 4) != 0)
+-				return -1;
++				return 1;
+ 		}
+ 	}
+ 
+diff -up util-linux-2.23.2/libblkid/src/superblocks/via_raid.c.kzak util-linux-2.23.2/libblkid/src/superblocks/via_raid.c
+--- util-linux-2.23.2/libblkid/src/superblocks/via_raid.c.kzak	2013-04-08 17:55:40.264856273 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/via_raid.c	2014-03-28 15:11:44.683552047 +0100
+@@ -52,9 +52,9 @@ static int probe_viaraid(blkid_probe pr,
+ 	struct via_metadata *v;
+ 
+ 	if (pr->size < 0x10000)
+-		return -1;
++		return 1;
+ 	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+-		return -1;
++		return 1;
+ 
+ 	off = ((pr->size / 0x200)-1) * 0x200;
+ 
+@@ -63,19 +63,19 @@ static int probe_viaraid(blkid_probe pr,
+ 				off,
+ 				sizeof(struct via_metadata));
+ 	if (!v)
+-		return -1;
++		return errno ? -errno : 1;
+ 	if (le16_to_cpu(v->signature) != VIA_SIGNATURE)
+-		return -1;
++		return 1;
+ 	if (v->version_number > 2)
+-		return -1;
++		return 1;
+ 	if (!via_checksum(v))
+-		return -1;
++		return 1;
+ 	if (blkid_probe_sprintf_version(pr, "%u", v->version_number) != 0)
+-		return -1;
++		return 1;
+ 	if (blkid_probe_set_magic(pr, off,
+ 				sizeof(v->signature),
+ 				(unsigned char *) &v->signature))
+-		return -1;
++		return 1;
+ 	return 0;
+ }
+ 
+diff -up util-linux-2.23.2/libblkid/src/superblocks/vmfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/vmfs.c
+--- util-linux-2.23.2/libblkid/src/superblocks/vmfs.c.kzak	2013-04-08 17:55:40.264856273 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/vmfs.c	2014-03-28 15:11:44.683552047 +0100
+@@ -28,7 +28,7 @@ static int probe_vmfs_fs(blkid_probe pr,
+ 
+ 	header = blkid_probe_get_sb(pr, mag, struct vmfs_fs_info);
+ 	if (header == NULL)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	blkid_probe_sprintf_uuid(pr, (unsigned char *) header->uuid, 16,
+ 		"%02x%02x%02x%02x-%02x%02x%02x%02x-"
+@@ -53,7 +53,7 @@ static int probe_vmfs_volume(blkid_probe
+ 
+ 	header = blkid_probe_get_sb(pr, mag, struct vmfs_volume_info);
+ 	if (header == NULL)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	blkid_probe_sprintf_value(pr, "UUID_SUB",
+ 		"%02x%02x%02x%02x-%02x%02x%02x%02x-"
+diff -up util-linux-2.23.2/libblkid/src/superblocks/vxfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/vxfs.c
+--- util-linux-2.23.2/libblkid/src/superblocks/vxfs.c.kzak	2013-04-08 17:55:40.264856273 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/vxfs.c	2014-03-28 15:11:44.683552047 +0100
+@@ -20,7 +20,7 @@ static int probe_vxfs(blkid_probe pr, co
+ 
+ 	vxs = blkid_probe_get_sb(pr, mag, struct vxfs_super_block);
+ 	if (!vxs)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	blkid_probe_sprintf_version(pr, "%u", (unsigned int) vxs->vs_version);
+ 	return 0;
+diff -up util-linux-2.23.2/libblkid/src/superblocks/xfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/xfs.c
+--- util-linux-2.23.2/libblkid/src/superblocks/xfs.c.kzak	2013-04-08 17:55:40.265856283 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/xfs.c	2014-03-28 15:11:44.683552047 +0100
+@@ -40,7 +40,7 @@ static int probe_xfs(blkid_probe pr, con
+ 
+ 	xs = blkid_probe_get_sb(pr, mag, struct xfs_super_block);
+ 	if (!xs)
+-		return -1;
++		return errno ? -errno : 1;
+ 
+ 	if (strlen(xs->xs_fname))
+ 		blkid_probe_set_label(pr, (unsigned char *) xs->xs_fname,
+diff -up util-linux-2.23.2/libblkid/src/superblocks/zfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/zfs.c
+--- util-linux-2.23.2/libblkid/src/superblocks/zfs.c.kzak	2013-06-13 09:46:10.427650682 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/zfs.c	2014-03-28 15:11:44.683552047 +0100
+@@ -185,7 +185,7 @@ static int probe_zfs(blkid_probe pr,
+ 			blkid_probe_get_buffer(pr, offset,
+ 					       sizeof(struct zfs_uberblock));
+ 		if (ub == NULL)
+-			return -1;
++			return errno ? -errno : 1;
+ 
+ 		if (ub->ub_magic == UBERBLOCK_MAGIC) {
+ 			ub_offset = offset;
+@@ -202,7 +202,7 @@ static int probe_zfs(blkid_probe pr,
+ 	}
+ 
+ 	if (found < 4)
+-		return -1;
++		return 1;
+ 
+ 	/* If we found the 4th uberblock, then we will have exited from the
+ 	 * scanning loop immediately, and ub will be a valid uberblock. */
+@@ -214,7 +214,7 @@ static int probe_zfs(blkid_probe pr,
+ 	if (blkid_probe_set_magic(pr, ub_offset,
+ 				sizeof(ub->ub_magic),
+ 				(unsigned char *) &ub->ub_magic))
+-		return -1;
++		return 1;
+ 
+ 	return 0;
+ }
diff --git a/SOURCES/2.25-libblkid-no-more-probe-for-btrfs-backup-superblock.patch b/SOURCES/2.25-libblkid-no-more-probe-for-btrfs-backup-superblock.patch
new file mode 100644
index 0000000..5083b38
--- /dev/null
+++ b/SOURCES/2.25-libblkid-no-more-probe-for-btrfs-backup-superblock.patch
@@ -0,0 +1,68 @@
+diff -up util-linux-2.23.2/libblkid/src/blkidP.h.kzak util-linux-2.23.2/libblkid/src/blkidP.h
+--- util-linux-2.23.2/libblkid/src/blkidP.h.kzak	2013-07-30 10:39:26.205738229 +0200
++++ util-linux-2.23.2/libblkid/src/blkidP.h	2014-01-23 10:51:10.109593273 +0100
+@@ -224,9 +224,6 @@ struct blkid_struct_probe
+ 
+ /* private per-probing flags */
+ #define BLKID_PROBE_FL_IGNORE_PT (1 << 1)	/* ignore partition table */
+-#define BLKID_PROBE_FL_IGNORE_BACKUP (1 << 2)	/* ignore backup superblocks or PT */
+-
+-extern int blkid_probe_ignore_backup(blkid_probe pr);
+ 
+ extern blkid_probe blkid_clone_probe(blkid_probe parent);
+ extern blkid_probe blkid_probe_get_wholedisk_probe(blkid_probe pr);
+diff -up util-linux-2.23.2/libblkid/src/probe.c.kzak util-linux-2.23.2/libblkid/src/probe.c
+--- util-linux-2.23.2/libblkid/src/probe.c.kzak	2013-07-30 10:39:26.208738259 +0200
++++ util-linux-2.23.2/libblkid/src/probe.c	2014-01-23 10:51:10.109593273 +0100
+@@ -924,7 +924,8 @@ int blkid_do_probe(blkid_probe pr)
+  *
+  * This function erases the current signature detected by @pr. The @pr has to
+  * be open in O_RDWR mode, BLKID_SUBLKS_MAGIC or/and BLKID_PARTS_MAGIC flags
+- * has to be enabled.
++ * has to be enabled (if you want to errase also superblock with broken check
++ * sums then use BLKID_SUBLKS_BADCSUM too).
+  *
+  * After successful signature removing the @pr prober will be moved one step
+  * back and the next blkid_do_probe() call will again call previously called
+@@ -1125,8 +1126,6 @@ int blkid_do_safeprobe(blkid_probe pr)
+ 
+ 	blkid_probe_start(pr);
+ 
+-	pr->prob_flags |= BLKID_PROBE_FL_IGNORE_BACKUP;
+-
+ 	for (i = 0; i < BLKID_NCHAINS; i++) {
+ 		struct blkid_chain *chn;
+ 
+@@ -1764,8 +1763,3 @@ void blkid_probe_use_wiper(blkid_probe p
+ 		blkid_probe_chain_reset_vals(pr, chn);
+ 	}
+ }
+-
+-int blkid_probe_ignore_backup(blkid_probe pr)
+-{
+-	return pr && (pr->prob_flags & BLKID_PROBE_FL_IGNORE_BACKUP);
+-}
+diff -up util-linux-2.23.2/libblkid/src/superblocks/btrfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/btrfs.c
+--- util-linux-2.23.2/libblkid/src/superblocks/btrfs.c.kzak	2013-06-13 09:46:10.421650630 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/btrfs.c	2014-01-23 10:51:10.109593273 +0100
+@@ -63,11 +63,6 @@ static int probe_btrfs(blkid_probe pr, c
+ {
+ 	struct btrfs_super_block *bfs;
+ 
+-	if (mag->kboff > 64 && blkid_probe_ignore_backup(pr)) {
+-		DBG(LOWPROBE, blkid_debug("btrfs: found backup superblock, ignore"));
+-		return 1;
+-	}
+-
+ 	bfs = blkid_probe_get_sb(pr, mag, struct btrfs_super_block);
+ 	if (!bfs)
+ 		return -1;
+@@ -92,8 +87,6 @@ const struct blkid_idinfo btrfs_idinfo =
+ 	.magics		=
+ 	{
+ 	  { .magic = "_BHRfS_M", .len = 8, .sboff = 0x40, .kboff = 64 },
+-	  { .magic = "_BHRfS_M", .len = 8, .sboff = 0x40, .kboff = 64 * 1024 },
+-	  { .magic = "_BHRfS_M", .len = 8, .sboff = 0x40, .kboff = 256 * 1024 * 1024 },
+ 	  { NULL }
+ 	}
+ };
diff --git a/SOURCES/2.25-libblkid-return-codes.patch b/SOURCES/2.25-libblkid-return-codes.patch
new file mode 100644
index 0000000..6462359
--- /dev/null
+++ b/SOURCES/2.25-libblkid-return-codes.patch
@@ -0,0 +1,204 @@
+diff -up util-linux-2.23.2/libblkid/src/partitions/partitions.c.kzak util-linux-2.23.2/libblkid/src/partitions/partitions.c
+--- util-linux-2.23.2/libblkid/src/partitions/partitions.c.kzak	2015-08-11 14:00:27.930573965 +0200
++++ util-linux-2.23.2/libblkid/src/partitions/partitions.c	2015-08-11 14:13:11.213087814 +0200
+@@ -533,7 +533,7 @@ static int idinfo_probe(blkid_probe pr,
+ {
+ 	const struct blkid_idmag *mag = NULL;
+ 	blkid_loff_t off;
+-	int rc = BLKID_PROBE_NONE;		/* = nothing detected */
++	int rc = BLKID_PROBE_NONE;		/* default is nothing */
+ 
+ 	if (pr->size <= 0 || (id->minsz && id->minsz > pr->size))
+ 		goto nothing;	/* the device is too small */
+@@ -564,8 +564,10 @@ static int idinfo_probe(blkid_probe pr,
+ 		DBG(LOWPROBE, blkid_debug("%s: <--- (rc = %d)", id->name, rc));
+ 	}
+ 
+-nothing:
+ 	return rc;
++
++nothing:
++	return BLKID_PROBE_NONE;
+ }
+ 
+ /*
+@@ -620,7 +622,7 @@ static int partitions_probe(blkid_probe
+ 						strlen(name) + 1);
+ 		DBG(LOWPROBE, blkid_debug("<-- leaving probing loop (type=%s) [PARTS idx=%d]",
+ 			name, chn->idx));
+-		rc = 0;
++		rc = BLKID_PROBE_OK;
+ 		break;
+ 	}
+ 
+@@ -637,10 +639,16 @@ details_only:
+ 	    (blkid_partitions_get_flags(pr) & BLKID_PARTS_ENTRY_DETAILS)) {
+ 
+ 		int xrc = blkid_partitions_probe_partition(pr);
++
++		/* partition entry probing is optional, and "not-found" from
++		 * this sub-probing must not to overwrite previous success. */
+ 		if (xrc < 0)
+-			rc = xrc;	/* optional, care about errors only */
++			rc = xrc;			/* always propagate errors */
++		else if (rc == BLKID_PROBE_NONE)
++			rc = xrc;
+ 	}
+ 
++	DBG(LOWPROBE, blkid_debug("partitions probe done [rc=%d]", rc));
+ 	return rc;
+ }
+ 
+@@ -709,7 +717,6 @@ int blkid_partitions_do_subprobe(blkid_p
+ 
+ static int blkid_partitions_probe_partition(blkid_probe pr)
+ {
+-	int rc = BLKID_PROBE_NONE;
+ 	blkid_probe disk_pr = NULL;
+ 	blkid_partlist ls;
+ 	blkid_partition par;
+@@ -732,7 +739,9 @@ static int blkid_partitions_probe_partit
+ 		goto nothing;
+ 
+ 	par = blkid_partlist_devno_to_partition(ls, devno);
+-	if (par) {
++	if (!par)
++		goto nothing;
++	else {
+ 		const char *v;
+ 		blkid_parttable tab = blkid_partition_get_table(par);
+ 		dev_t disk = blkid_probe_get_devno(disk_pr);
+@@ -778,9 +787,13 @@ static int blkid_partitions_probe_partit
+ 		blkid_probe_sprintf_value(pr, "PART_ENTRY_DISK", "%u:%u",
+ 				major(disk), minor(disk));
+ 	}
+-	rc = BLKID_PROBE_OK;
++
++	DBG(LOWPROBE, blkid_debug("parts: end probing for partition entry [success]"));
++	return BLKID_PROBE_OK;
++
+ nothing:
+-	return rc;
++	DBG(LOWPROBE, blkid_debug("parts: end probing for partition entry [nothing]"));
++	return BLKID_PROBE_NONE;
+ }
+ 
+ /*
+diff -up util-linux-2.23.2/libblkid/src/superblocks/superblocks.c.kzak util-linux-2.23.2/libblkid/src/superblocks/superblocks.c
+--- util-linux-2.23.2/libblkid/src/superblocks/superblocks.c.kzak	2015-07-03 10:35:05.456153560 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/superblocks.c	2015-08-11 14:08:42.572674469 +0200
+@@ -335,19 +335,24 @@ static int superblocks_probe(blkid_probe
+ 
+ 	if (!pr || chn->idx < -1)
+ 		return -EINVAL;
+-	if (pr->flags & BLKID_FL_NOSCAN_DEV)
+-		goto nothing;
+ 
+ 	blkid_probe_chain_reset_vals(pr, chn);
+ 
+ 	DBG(LOWPROBE, blkid_debug("--> starting probing loop [SUBLKS idx=%d]",
+ 		chn->idx));
+ 
++	if (pr->flags & BLKID_FL_NOSCAN_DEV)
++		return BLKID_PROBE_NONE;
++
+ 	if (pr->size <= 0 || (pr->size <= 1024 && !S_ISCHR(pr->mode)))
+ 		/* Ignore very very small block devices or regular files (e.g.
+ 		 * extended partitions). Note that size of the UBI char devices
+ 		 * is 1 byte */
+-		goto nothing;
++		return BLKID_PROBE_NONE;
++
++
++	DBG(LOWPROBE, blkid_debug("--> starting probing loop [SUBLKS idx=%d]",
++		chn->idx));
+ 
+ 	i = chn->idx < 0 ? 0 : chn->idx + 1U;
+ 
+@@ -417,7 +422,7 @@ static int superblocks_probe(blkid_probe
+ 					(unsigned char *) mag->magic);
+ 		if (rc) {
+ 			blkid_probe_chain_reset_vals(pr, chn);
+-			DBG(LOWPROBE, blkid_debug("failed to set result -- ingnore"));
++			DBG(LOWPROBE, blkid_debug("failed to set result -- ignore"));
+ 			continue;
+ 		}
+ 
+@@ -426,7 +431,6 @@ static int superblocks_probe(blkid_probe
+ 		return BLKID_PROBE_OK;
+ 	}
+ 
+-nothing:
+ 	DBG(LOWPROBE, blkid_debug("<-- leaving probing loop (failed=%d) [SUBLKS idx=%d]",
+ 			rc, chn->idx));
+ 	return rc;
+@@ -454,13 +458,12 @@ static int superblocks_safeprobe(blkid_p
+ 	int rc;
+ 
+ 	if (pr->flags & BLKID_FL_NOSCAN_DEV)
+-		return 1;				/* nothing */
++		return BLKID_PROBE_NONE;
+ 
+ 	while ((rc = superblocks_probe(pr, chn)) == 0) {
+ 
+ 		if (blkid_probe_is_tiny(pr) && !count)
+-			/* floppy or so -- returns the first result. */
+-			return 0;
++			return BLKID_PROBE_OK;	/* floppy or so -- returns the first result. */
+ 
+ 		count++;
+ 
+@@ -489,7 +492,7 @@ static int superblocks_safeprobe(blkid_p
+ 		return -2;		/* error, ambivalent result (more FS) */
+ 	}
+ 	if (!count)
+-		return 1;		/* nothing detected */
++		return BLKID_PROBE_NONE;
+ 
+ 	if (idx != -1) {
+ 		/* restore the first result */
+@@ -506,7 +509,7 @@ static int superblocks_safeprobe(blkid_p
+ 	if (chn->idx >= 0 && idinfos[chn->idx]->usage & BLKID_USAGE_RAID)
+ 		pr->prob_flags |= BLKID_PROBE_FL_IGNORE_PT;
+ 
+-	return 0;
++	return BLKID_PROBE_OK;
+ }
+ 
+ int blkid_probe_set_version(blkid_probe pr, const char *version)
+diff -up util-linux-2.23.2/libblkid/src/topology/topology.c.kzak util-linux-2.23.2/libblkid/src/topology/topology.c
+--- util-linux-2.23.2/libblkid/src/topology/topology.c.kzak	2013-06-13 09:46:10.429650699 +0200
++++ util-linux-2.23.2/libblkid/src/topology/topology.c	2015-08-11 14:09:35.623361499 +0200
+@@ -150,7 +150,7 @@ static int topology_probe(blkid_probe pr
+ 		return -1;
+ 
+ 	if (!S_ISBLK(pr->mode))
+-		return -1;	/* nothing, works with block devices only */
++		return -EINVAL;	/* nothing, works with block devices only */
+ 
+ 	if (chn->binary) {
+ 		DBG(LOWPROBE, blkid_debug("initialize topology binary data"));
+@@ -163,7 +163,7 @@ static int topology_probe(blkid_probe pr
+ 			chn->data = calloc(1,
+ 					sizeof(struct blkid_struct_topology));
+ 			if (!chn->data)
+-				return -1;
++				return -ENOMEM;
+ 		}
+ 	}
+ 
+@@ -193,12 +193,12 @@ static int topology_probe(blkid_probe pr
+ 
+ 		DBG(LOWPROBE, blkid_debug("<-- leaving probing loop (type=%s) [TOPOLOGY idx=%d]",
+ 			id->name, chn->idx));
+-		return 0;
++		return BLKID_PROBE_OK;
+ 	}
+ 
+ 	DBG(LOWPROBE, blkid_debug("<-- leaving probing loop (failed) [TOPOLOGY idx=%d]",
+ 		chn->idx));
+-	return 1;
++	return BLKID_PROBE_NONE;
+ }
+ 
+ static void topology_free(blkid_probe pr __attribute__((__unused__)),
diff --git a/SOURCES/2.25-libblkid-thinpool.patch b/SOURCES/2.25-libblkid-thinpool.patch
new file mode 100644
index 0000000..b17b98c
--- /dev/null
+++ b/SOURCES/2.25-libblkid-thinpool.patch
@@ -0,0 +1,237 @@
+diff -up util-linux-2.23.2/fdisks/fdisk.c.kzak util-linux-2.23.2/fdisks/fdisk.c
+--- util-linux-2.23.2/fdisks/fdisk.c.kzak	2015-07-02 12:37:24.465906322 +0200
++++ util-linux-2.23.2/fdisks/fdisk.c	2015-07-02 12:37:57.870673753 +0200
+@@ -34,6 +34,7 @@
+ #include "canonicalize.h"
+ #include "strutils.h"
+ #include "closestream.h"
++#include "sysfs.h"
+ 
+ #include "fdisksunlabel.h"
+ #include "fdisksgilabel.h"
+diff -up util-linux-2.23.2/include/sysfs.h.kzak util-linux-2.23.2/include/sysfs.h
+--- util-linux-2.23.2/include/sysfs.h.kzak	2015-07-02 12:12:50.408196320 +0200
++++ util-linux-2.23.2/include/sysfs.h	2015-07-02 12:13:09.708061372 +0200
+@@ -74,6 +74,8 @@ extern int sysfs_devno_to_wholedisk(dev_
+             size_t len, dev_t *diskdevno);
+ extern int sysfs_devno_is_wholedisk(dev_t devno);
+ 
++extern int sysfs_devno_is_lvm_private(dev_t devno);
++
+ extern int sysfs_scsi_get_hctl(struct sysfs_cxt *cxt, int *h,
+ 			       int *c, int *t, int *l);
+ extern char *sysfs_scsi_host_strdup_attribute(struct sysfs_cxt *cxt,
+diff -up util-linux-2.23.2/libblkid/src/blkidP.h.kzak util-linux-2.23.2/libblkid/src/blkidP.h
+--- util-linux-2.23.2/libblkid/src/blkidP.h.kzak	2015-07-02 12:18:27.349840375 +0200
++++ util-linux-2.23.2/libblkid/src/blkidP.h	2015-07-02 12:19:07.797557558 +0200
+@@ -221,6 +221,7 @@ struct blkid_struct_probe
+ #define BLKID_FL_PRIVATE_FD	(1 << 1)	/* see blkid_new_probe_from_filename() */
+ #define BLKID_FL_TINY_DEV	(1 << 2)	/* <= 1.47MiB (floppy or so) */
+ #define BLKID_FL_CDROM_DEV	(1 << 3)	/* is a CD/DVD drive */
++#define BLKID_FL_NOSCAN_DEV	(1 << 4)        /* do not scan this device */
+ 
+ /* private per-probing flags */
+ #define BLKID_PROBE_FL_IGNORE_PT (1 << 1)	/* ignore partition table */
+diff -up util-linux-2.23.2/libblkid/src/partitions/partitions.c.kzak util-linux-2.23.2/libblkid/src/partitions/partitions.c
+--- util-linux-2.23.2/libblkid/src/partitions/partitions.c.kzak	2015-07-02 12:19:11.669530485 +0200
++++ util-linux-2.23.2/libblkid/src/partitions/partitions.c	2015-07-02 12:28:24.166667964 +0200
+@@ -537,6 +537,8 @@ static int idinfo_probe(blkid_probe pr,
+ 
+ 	if (pr->size <= 0 || (id->minsz && id->minsz > pr->size))
+ 		goto nothing;	/* the device is too small */
++	if (pr->flags & BLKID_FL_NOSCAN_DEV)
++		goto nothing;
+ 
+ 	rc = blkid_probe_get_idmag(pr, id, &off, &mag);
+ 	if (rc != BLKID_PROBE_OK)
+@@ -576,8 +578,12 @@ static int partitions_probe(blkid_probe
+ 
+ 	if (!pr || chn->idx < -1)
+ 		return -EINVAL;
++
+ 	blkid_probe_chain_reset_vals(pr, chn);
+ 
++	if (pr->flags & BLKID_FL_NOSCAN_DEV)
++		return BLKID_PROBE_NONE;
++
+ 	if (chn->binary)
+ 		partitions_init_data(chn);
+ 
+@@ -653,6 +659,8 @@ int blkid_partitions_do_subprobe(blkid_p
+ 
+ 	if (!pr || !parent || !parent->size)
+ 		return -EINVAL;
++	if (pr->flags & BLKID_FL_NOSCAN_DEV)
++		return BLKID_PROBE_NONE;
+ 
+ 	/* range defined by parent */
+ 	sz = ((blkid_loff_t) parent->size) << 9;
+@@ -707,6 +715,9 @@ static int blkid_partitions_probe_partit
+ 	blkid_partition par;
+ 	dev_t devno;
+ 
++	if (pr->flags & BLKID_FL_NOSCAN_DEV)
++		goto nothing;
++
+ 	devno = blkid_probe_get_devno(pr);
+ 	if (!devno)
+ 		goto nothing;
+@@ -779,7 +790,7 @@ nothing:
+ int blkid_probe_is_covered_by_pt(blkid_probe pr,
+ 				 blkid_loff_t offset, blkid_loff_t size)
+ {
+-	blkid_probe prc;
++	blkid_probe prc = NULL;
+ 	blkid_partlist ls = NULL;
+ 	blkid_loff_t start, end;
+ 	int nparts, i, rc = 0;
+@@ -788,6 +799,9 @@ int blkid_probe_is_covered_by_pt(blkid_p
+ 		"=> checking if off=%jd size=%jd covered by PT",
+ 		offset, size));
+ 
++	if (pr->flags & BLKID_FL_NOSCAN_DEV)
++		goto done;
++
+ 	prc = blkid_clone_probe(pr);
+ 	if (!prc)
+ 		goto done;
+diff -up util-linux-2.23.2/libblkid/src/probe.c.kzak util-linux-2.23.2/libblkid/src/probe.c
+--- util-linux-2.23.2/libblkid/src/probe.c.kzak	2015-07-02 12:13:48.823787869 +0200
++++ util-linux-2.23.2/libblkid/src/probe.c	2015-07-02 12:38:20.110518915 +0200
+@@ -110,6 +110,7 @@
+ 
+ #include "blkidP.h"
+ #include "all-io.h"
++#include "sysfs.h"
+ 
+ /* chains */
+ extern const struct blkid_chaindrv superblocks_drv;
+@@ -714,8 +715,13 @@ int blkid_probe_set_device(blkid_probe p
+ 	if (pr->size <= 1440 * 1024 && !S_ISCHR(sb.st_mode))
+ 		pr->flags |= BLKID_FL_TINY_DEV;
+ 
++	if (S_ISBLK(sb.st_mode) && sysfs_devno_is_lvm_private(sb.st_rdev)) {
++		DBG(LOWPROBE, blkid_debug("ignore private LVM device"));
++		pr->flags |= BLKID_FL_NOSCAN_DEV;
++        }
++
+ #ifdef CDROM_GET_CAPABILITY
+-	if (S_ISBLK(sb.st_mode) &&
++	else if (S_ISBLK(sb.st_mode) &&
+ 	    !blkid_probe_is_tiny(pr) &&
+ 	    blkid_probe_is_wholedisk(pr) &&
+ 	    ioctl(fd, CDROM_GET_CAPABILITY, NULL) >= 0)
+@@ -892,6 +898,9 @@ int blkid_do_probe(blkid_probe pr)
+ 	if (!pr)
+ 		return -1;
+ 
++	if (pr->flags & BLKID_FL_NOSCAN_DEV)
++		return 1;
++
+ 	do {
+ 		struct blkid_chain *chn = pr->cur_chain;
+ 
+@@ -1143,6 +1152,8 @@ int blkid_do_safeprobe(blkid_probe pr)
+ 
+ 	if (!pr)
+ 		return -1;
++	if (pr->flags & BLKID_FL_NOSCAN_DEV)
++		return 1;
+ 
+ 	blkid_probe_start(pr);
+ 
+@@ -1197,6 +1208,8 @@ int blkid_do_fullprobe(blkid_probe pr)
+ 
+ 	if (!pr)
+ 		return -1;
++	if (pr->flags & BLKID_FL_NOSCAN_DEV)
++		return 1;
+ 
+ 	blkid_probe_start(pr);
+ 
+diff -up util-linux-2.23.2/libblkid/src/superblocks/superblocks.c.kzak util-linux-2.23.2/libblkid/src/superblocks/superblocks.c
+--- util-linux-2.23.2/libblkid/src/superblocks/superblocks.c.kzak	2015-07-02 12:29:32.370193121 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/superblocks.c	2015-07-02 12:31:06.897535008 +0200
+@@ -338,6 +338,9 @@ static int superblocks_probe(blkid_probe
+ 
+ 	if (!pr || chn->idx < -1)
+ 		return -EINVAL;
++	if (pr->flags & BLKID_FL_NOSCAN_DEV)
++		goto nothing;
++
+ 	blkid_probe_chain_reset_vals(pr, chn);
+ 
+ 	DBG(LOWPROBE, blkid_debug("--> starting probing loop [SUBLKS idx=%d]",
+@@ -453,6 +456,9 @@ static int superblocks_safeprobe(blkid_p
+ 	int intol = 0;
+ 	int rc;
+ 
++	if (pr->flags & BLKID_FL_NOSCAN_DEV)
++		return 1;				/* nothing */
++
+ 	while ((rc = superblocks_probe(pr, chn)) == 0) {
+ 
+ 		if (blkid_probe_is_tiny(pr) && !count)
+diff -up util-linux-2.23.2/libblkid/src/verify.c.kzak util-linux-2.23.2/libblkid/src/verify.c
+--- util-linux-2.23.2/libblkid/src/verify.c.kzak	2015-07-02 12:15:51.782928121 +0200
++++ util-linux-2.23.2/libblkid/src/verify.c	2015-07-02 12:16:45.078555470 +0200
+@@ -112,6 +112,10 @@ blkid_dev blkid_verify(blkid_cache cache
+ 		   (unsigned long)diff));
+ #endif
+ 
++	if (sysfs_devno_is_lvm_private(st.st_rdev)) {
++		blkid_free_dev(dev);
++		return NULL;
++	}
+ 	if (!cache->probe) {
+ 		cache->probe = blkid_new_probe();
+ 		if (!cache->probe) {
+diff -up util-linux-2.23.2/lib/sysfs.c.kzak util-linux-2.23.2/lib/sysfs.c
+--- util-linux-2.23.2/lib/sysfs.c.kzak	2015-07-02 12:12:29.193344657 +0200
++++ util-linux-2.23.2/lib/sysfs.c	2015-07-02 12:12:13.565453930 +0200
+@@ -639,6 +639,35 @@ err:
+ }
+ 
+ /*
++ * Returns 1 if the device is private LVM device.
++ */
++int sysfs_devno_is_lvm_private(dev_t devno)
++{
++	struct sysfs_cxt cxt = UL_SYSFSCXT_EMPTY;
++	char *uuid = NULL;
++	int rc = 0;
++
++	if (sysfs_init(&cxt, devno, NULL) != 0)
++		return 0;
++
++	uuid = sysfs_strdup(&cxt, "dm/uuid");
++
++	/* Private LVM devices use "LVM-<uuid>-<name>" uuid format (important
++	 * is the "LVM" prefix and "-<name>" postfix).
++	 */
++	if (uuid && strncmp(uuid, "LVM-", 4) == 0) {
++		char *p = strrchr(uuid + 4, '-');
++
++		if (p && *(p + 1))
++			rc = 1;
++	}
++
++	sysfs_deinit(&cxt);
++	free(uuid);
++	return rc;
++}
++
++/*
+  * Return 0 or 1, or < 0 in case of error
+  */
+ int sysfs_devno_is_wholedisk(dev_t devno)
+@@ -651,6 +680,9 @@ int sysfs_devno_is_wholedisk(dev_t devno
+ 	return devno == disk;
+ }
+ 
++
++
++
+ int sysfs_scsi_get_hctl(struct sysfs_cxt *cxt, int *h, int *c, int *t, int *l)
+ {
+ 	char buf[PATH_MAX], *hctl;
diff --git a/SOURCES/2.25-libblkid-xfs-log.patch b/SOURCES/2.25-libblkid-xfs-log.patch
new file mode 100644
index 0000000..41f1ec8
--- /dev/null
+++ b/SOURCES/2.25-libblkid-xfs-log.patch
@@ -0,0 +1,133 @@
+diff -up util-linux-2.23.2/libblkid/src/superblocks/superblocks.c.kzak util-linux-2.23.2/libblkid/src/superblocks/superblocks.c
+--- util-linux-2.23.2/libblkid/src/superblocks/superblocks.c.kzak	2015-06-24 12:58:20.790115492 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/superblocks.c	2015-06-24 12:57:57.961286166 +0200
+@@ -49,6 +49,8 @@
+  *
+  * @UUID_SUB: subvolume uuid (e.g. btrfs)
+  *
++ * @LOGUUID: external log UUID (e.g. xfs)
++ *
+  * @UUID_RAW: raw UUID from FS superblock
+  *
+  * @EXT_JOURNAL: external journal UUID
+@@ -113,6 +115,7 @@ static const struct blkid_idinfo *idinfo
+ 	&swsuspend_idinfo,
+ 	&swap_idinfo,
+ 	&xfs_idinfo,
++	&xfs_log_idinfo,
+ 	&ext4dev_idinfo,
+ 	&ext4_idinfo,
+ 	&ext3_idinfo,
+diff -up util-linux-2.23.2/libblkid/src/superblocks/superblocks.h.kzak util-linux-2.23.2/libblkid/src/superblocks/superblocks.h
+--- util-linux-2.23.2/libblkid/src/superblocks/superblocks.h.kzak	2015-06-24 12:58:48.533908071 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/superblocks.h	2015-06-24 12:59:00.098821476 +0200
+@@ -29,6 +29,7 @@ extern const struct blkid_idinfo ext2_id
+ extern const struct blkid_idinfo jbd_idinfo;
+ extern const struct blkid_idinfo jfs_idinfo;
+ extern const struct blkid_idinfo xfs_idinfo;
++extern const struct blkid_idinfo xfs_log_idinfo;
+ extern const struct blkid_idinfo gfs_idinfo;
+ extern const struct blkid_idinfo gfs2_idinfo;
+ extern const struct blkid_idinfo romfs_idinfo;
+diff -up util-linux-2.23.2/libblkid/src/superblocks/xfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/xfs.c
+--- util-linux-2.23.2/libblkid/src/superblocks/xfs.c.kzak	2015-06-24 12:39:34.300507071 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/xfs.c	2015-06-24 12:39:45.389427015 +0200
+@@ -4,6 +4,7 @@
+  * Copyright (C) 2001 by Andreas Dilger
+  * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+  * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
++ * Copyright (C) 2013 Eric Sandeen <sandeen@redhat.com>
+  *
+  * This file may be redistributed under the terms of the
+  * GNU Lesser General Public License.
+@@ -187,3 +188,90 @@ const struct blkid_idinfo xfs_idinfo =
+ 	}
+ };
+ 
++struct xlog_rec_header {
++	uint32_t	h_magicno;
++	uint32_t	h_dummy1[1];
++	uint32_t	h_version;
++	uint32_t	h_len;
++	uint32_t	h_dummy2[71];
++	uint32_t	h_fmt;
++	unsigned char	h_uuid[16];
++} __attribute__((packed));
++
++#define XLOG_HEADER_MAGIC_NUM 0xFEEDbabe
++
++/*
++ * For very small filesystems, the minimum log size
++ * can be smaller, but that seems vanishingly unlikely
++ * when used with an external log (which is used for
++ * performance reasons; tiny conflicts with that goal).
++ */
++#define XFS_MIN_LOG_BYTES	(10 * 1024 * 1024)
++
++#define XLOG_FMT_LINUX_LE	1
++#define XLOG_FMT_LINUX_BE	2
++#define XLOG_FMT_IRIX_BE	3
++
++#define XLOG_VERSION_1		1
++#define XLOG_VERSION_2		2	/* Large IClogs, Log sunit */
++#define XLOG_VERSION_OKBITS	(XLOG_VERSION_1 | XLOG_VERSION_2)
++
++static int xlog_valid_rec_header(struct xlog_rec_header *rhead)
++{
++	uint32_t hlen;
++
++	if (rhead->h_magicno != cpu_to_be32(XLOG_HEADER_MAGIC_NUM))
++		return 0;
++
++	if (!rhead->h_version ||
++            (be32_to_cpu(rhead->h_version) & (~XLOG_VERSION_OKBITS)))
++		return 0;
++
++	/* LR body must have data or it wouldn't have been written */
++	hlen = be32_to_cpu(rhead->h_len);
++	if (hlen <= 0 || hlen > INT_MAX)
++		return 0;
++
++	if (rhead->h_fmt != cpu_to_be32(XLOG_FMT_LINUX_LE) &&
++	    rhead->h_fmt != cpu_to_be32(XLOG_FMT_LINUX_BE) &&
++	    rhead->h_fmt != cpu_to_be32(XLOG_FMT_IRIX_BE))
++		return 0;
++
++	return 1;
++}
++
++/* xlog record header will be in some sector in the first 256k */
++static int probe_xfs_log(blkid_probe pr, const struct blkid_idmag *mag)
++{
++	int i;
++	struct xlog_rec_header *rhead;
++	unsigned char *buf;
++
++	buf = blkid_probe_get_buffer(pr, 0, 256*1024);
++	if (!buf)
++		return errno ? -errno : 1;
++
++	if (memcmp(buf, "XFSB", 4) == 0)
++		return 1;			/* this is regular XFS, ignore */
++
++	/* check the first 512 512-byte sectors */
++	for (i = 0; i < 512; i++) {
++		rhead = (struct xlog_rec_header *)&buf[i*512];
++
++		if (xlog_valid_rec_header(rhead)) {
++			blkid_probe_set_uuid_as(pr, rhead->h_uuid, "LOGUUID");
++			return 0;
++		}
++	}
++
++	return 1;
++}
++
++const struct blkid_idinfo xfs_log_idinfo =
++{
++	.name		= "xfs_external_log",
++	.usage		= BLKID_USAGE_OTHER,
++	.probefunc	= probe_xfs_log,
++	.magics		= BLKID_NONE_MAGIC,
++	.minsz		= XFS_MIN_LOG_BYTES,
++};
diff --git a/SOURCES/2.25-libblkid-xfs.patch b/SOURCES/2.25-libblkid-xfs.patch
new file mode 100644
index 0000000..adc717b
--- /dev/null
+++ b/SOURCES/2.25-libblkid-xfs.patch
@@ -0,0 +1,177 @@
+diff -up util-linux-2.23.2/libblkid/src/superblocks/xfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/xfs.c
+--- util-linux-2.23.2/libblkid/src/superblocks/xfs.c.kzak	2014-09-24 10:59:39.548315524 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/xfs.c	2014-09-24 11:02:55.595186026 +0200
+@@ -20,20 +20,143 @@
+ #include "superblocks.h"
+ 
+ struct xfs_super_block {
+-	unsigned char	xs_magic[4];
+-	uint32_t	xs_blocksize;
+-	uint64_t	xs_dblocks;
+-	uint64_t	xs_rblocks;
+-	uint32_t	xs_dummy1[2];
+-	unsigned char	xs_uuid[16];
+-	uint32_t	xs_dummy2[15];
+-	char		xs_fname[12];
+-	uint32_t	xs_dummy3[2];
+-	uint64_t	xs_icount;
+-	uint64_t	xs_ifree;
+-	uint64_t	xs_fdblocks;
++	uint32_t	sb_magicnum;	/* magic number == XFS_SB_MAGIC */
++	uint32_t	sb_blocksize;	/* logical block size, bytes */
++	uint64_t	sb_dblocks;	/* number of data blocks */
++	uint64_t	sb_rblocks;	/* number of realtime blocks */
++	uint64_t	sb_rextents;	/* number of realtime extents */
++	unsigned char	sb_uuid[16];	/* file system unique id */
++	uint64_t	sb_logstart;	/* starting block of log if internal */
++	uint64_t	sb_rootino;	/* root inode number */
++	uint64_t	sb_rbmino;	/* bitmap inode for realtime extents */
++	uint64_t	sb_rsumino;	/* summary inode for rt bitmap */
++	uint32_t	sb_rextsize;	/* realtime extent size, blocks */
++	uint32_t	sb_agblocks;	/* size of an allocation group */
++	uint32_t	sb_agcount;	/* number of allocation groups */
++	uint32_t	sb_rbmblocks;	/* number of rt bitmap blocks */
++	uint32_t	sb_logblocks;	/* number of log blocks */
++
++	uint16_t	sb_versionnum;	/* header version == XFS_SB_VERSION */
++	uint16_t	sb_sectsize;	/* volume sector size, bytes */
++	uint16_t	sb_inodesize;	/* inode size, bytes */
++	uint16_t	sb_inopblock;	/* inodes per block */
++	char		sb_fname[12];	/* file system name */
++	uint8_t		sb_blocklog;	/* log2 of sb_blocksize */
++	uint8_t		sb_sectlog;	/* log2 of sb_sectsize */
++	uint8_t		sb_inodelog;	/* log2 of sb_inodesize */
++	uint8_t		sb_inopblog;	/* log2 of sb_inopblock */
++	uint8_t		sb_agblklog;	/* log2 of sb_agblocks (rounded up) */
++	uint8_t		sb_rextslog;	/* log2 of sb_rextents */
++	uint8_t		sb_inprogress;	/* mkfs is in progress, don't mount */
++	uint8_t		sb_imax_pct;	/* max % of fs for inode space */
++					/* statistics */
++	uint64_t	sb_icount;	/* allocated inodes */
++	uint64_t	sb_ifree;	/* free inodes */
++	uint64_t	sb_fdblocks;	/* free data blocks */
++	uint64_t	sb_frextents;	/* free realtime extents */
++
++	/* this is not all... but enough for libblkid */
++
+ } __attribute__((packed));
+ 
++#define XFS_MIN_BLOCKSIZE_LOG	9	/* i.e. 512 bytes */
++#define XFS_MAX_BLOCKSIZE_LOG	16	/* i.e. 65536 bytes */
++#define XFS_MIN_BLOCKSIZE	(1 << XFS_MIN_BLOCKSIZE_LOG)
++#define XFS_MAX_BLOCKSIZE	(1 << XFS_MAX_BLOCKSIZE_LOG)
++#define XFS_MIN_SECTORSIZE_LOG	9	/* i.e. 512 bytes */
++#define XFS_MAX_SECTORSIZE_LOG	15	/* i.e. 32768 bytes */
++#define XFS_MIN_SECTORSIZE	(1 << XFS_MIN_SECTORSIZE_LOG)
++#define XFS_MAX_SECTORSIZE	(1 << XFS_MAX_SECTORSIZE_LOG)
++
++#define	XFS_DINODE_MIN_LOG	8
++#define	XFS_DINODE_MAX_LOG	11
++#define	XFS_DINODE_MIN_SIZE	(1 << XFS_DINODE_MIN_LOG)
++#define	XFS_DINODE_MAX_SIZE	(1 << XFS_DINODE_MAX_LOG)
++
++#define	XFS_MAX_RTEXTSIZE	(1024 * 1024 * 1024)	/* 1GB */
++#define	XFS_DFL_RTEXTSIZE	(64 * 1024)	        /* 64kB */
++#define	XFS_MIN_RTEXTSIZE	(4 * 1024)		/* 4kB */
++
++#define XFS_MIN_AG_BLOCKS	64
++#define XFS_MAX_DBLOCKS(s) ((uint64_t)(s)->sb_agcount * (s)->sb_agblocks)
++#define XFS_MIN_DBLOCKS(s) ((uint64_t)((s)->sb_agcount - 1) *	\
++			 (s)->sb_agblocks + XFS_MIN_AG_BLOCKS)
++
++
++static void sb_from_disk(struct xfs_super_block *from,
++			 struct xfs_super_block *to)
++{
++
++	to->sb_magicnum = be32_to_cpu(from->sb_magicnum);
++	to->sb_blocksize = be32_to_cpu(from->sb_blocksize);
++	to->sb_dblocks = be64_to_cpu(from->sb_dblocks);
++	to->sb_rblocks = be64_to_cpu(from->sb_rblocks);
++	to->sb_rextents = be64_to_cpu(from->sb_rextents);
++	to->sb_logstart = be64_to_cpu(from->sb_logstart);
++	to->sb_rootino = be64_to_cpu(from->sb_rootino);
++	to->sb_rbmino = be64_to_cpu(from->sb_rbmino);
++	to->sb_rsumino = be64_to_cpu(from->sb_rsumino);
++	to->sb_rextsize = be32_to_cpu(from->sb_rextsize);
++	to->sb_agblocks = be32_to_cpu(from->sb_agblocks);
++	to->sb_agcount = be32_to_cpu(from->sb_agcount);
++	to->sb_rbmblocks = be32_to_cpu(from->sb_rbmblocks);
++	to->sb_logblocks = be32_to_cpu(from->sb_logblocks);
++	to->sb_versionnum = be16_to_cpu(from->sb_versionnum);
++	to->sb_sectsize = be16_to_cpu(from->sb_sectsize);
++	to->sb_inodesize = be16_to_cpu(from->sb_inodesize);
++	to->sb_inopblock = be16_to_cpu(from->sb_inopblock);
++	to->sb_blocklog = from->sb_blocklog;
++	to->sb_sectlog = from->sb_sectlog;
++	to->sb_inodelog = from->sb_inodelog;
++	to->sb_inopblog = from->sb_inopblog;
++	to->sb_agblklog = from->sb_agblklog;
++	to->sb_rextslog = from->sb_rextslog;
++	to->sb_inprogress = from->sb_inprogress;
++	to->sb_imax_pct = from->sb_imax_pct;
++	to->sb_icount = be64_to_cpu(from->sb_icount);
++	to->sb_ifree = be64_to_cpu(from->sb_ifree);
++	to->sb_fdblocks = be64_to_cpu(from->sb_fdblocks);
++	to->sb_frextents = be64_to_cpu(from->sb_frextents);
++}
++
++static int xfs_verify_sb(struct xfs_super_block *ondisk)
++{
++	struct xfs_super_block sb, *sbp = &sb;
++
++	/* beXX_to_cpu(), but don't convert UUID and fsname! */
++	sb_from_disk(ondisk, sbp);
++
++	/* sanity checks, we don't want to rely on magic string only */
++	if (sbp->sb_agcount <= 0					||
++	    sbp->sb_sectsize < XFS_MIN_SECTORSIZE			||
++	    sbp->sb_sectsize > XFS_MAX_SECTORSIZE			||
++	    sbp->sb_sectlog < XFS_MIN_SECTORSIZE_LOG			||
++	    sbp->sb_sectlog > XFS_MAX_SECTORSIZE_LOG			||
++	    sbp->sb_sectsize != (1 << sbp->sb_sectlog)			||
++	    sbp->sb_blocksize < XFS_MIN_BLOCKSIZE			||
++	    sbp->sb_blocksize > XFS_MAX_BLOCKSIZE			||
++	    sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG			||
++	    sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG			||
++	    sbp->sb_blocksize != (1 << sbp->sb_blocklog)		||
++	    sbp->sb_inodesize < XFS_DINODE_MIN_SIZE			||
++	    sbp->sb_inodesize > XFS_DINODE_MAX_SIZE			||
++	    sbp->sb_inodelog < XFS_DINODE_MIN_LOG			||
++	    sbp->sb_inodelog > XFS_DINODE_MAX_LOG			||
++	    sbp->sb_inodesize != (1 << sbp->sb_inodelog)		||
++	    (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog)	||
++	    (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE)	||
++	    (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE)	||
++	    (sbp->sb_imax_pct > 100 /* zero sb_imax_pct is valid */)	||
++	    sbp->sb_dblocks == 0					||
++	    sbp->sb_dblocks > XFS_MAX_DBLOCKS(sbp)			||
++	    sbp->sb_dblocks < XFS_MIN_DBLOCKS(sbp))
++		return 0;
++
++	/* TODO: version 5 has also checksum CRC32, maybe we can check it too */
++
++	return 1;
++}
++
+ static int probe_xfs(blkid_probe pr, const struct blkid_idmag *mag)
+ {
+ 	struct xfs_super_block *xs;
+@@ -42,10 +165,13 @@ static int probe_xfs(blkid_probe pr, con
+ 	if (!xs)
+ 		return errno ? -errno : 1;
+ 
+-	if (strlen(xs->xs_fname))
+-		blkid_probe_set_label(pr, (unsigned char *) xs->xs_fname,
+-				sizeof(xs->xs_fname));
+-	blkid_probe_set_uuid(pr, xs->xs_uuid);
++	if (!xfs_verify_sb(xs))
++		return 1;
++
++	if (strlen(xs->sb_fname))
++		blkid_probe_set_label(pr, (unsigned char *) xs->sb_fname,
++				sizeof(xs->sb_fname));
++	blkid_probe_set_uuid(pr, xs->sb_uuid);
+ 	return 0;
+ }
+ 
diff --git a/SOURCES/2.25-lscpu-d_type.patch b/SOURCES/2.25-lscpu-d_type.patch
new file mode 100644
index 0000000..b6055af
--- /dev/null
+++ b/SOURCES/2.25-lscpu-d_type.patch
@@ -0,0 +1,12 @@
+diff -up util-linux-2.23.2/sys-utils/lscpu.c.kzak util-linux-2.23.2/sys-utils/lscpu.c
+--- util-linux-2.23.2/sys-utils/lscpu.c.kzak	2014-09-24 10:27:29.410899893 +0200
++++ util-linux-2.23.2/sys-utils/lscpu.c	2014-09-24 10:33:20.960254060 +0200
+@@ -809,7 +809,7 @@ static inline int is_node_dirent(struct
+ 	return
+ 		d &&
+ #ifdef _DIRENT_HAVE_D_TYPE
+-		d->d_type == DT_DIR &&
++		(d->d_type == DT_DIR || d->d_type == DT_UNKNOWN) &&
+ #endif
+ 		strncmp(d->d_name, "node", 4) == 0 &&
+ 		isdigit_string(d->d_name + 4);
diff --git a/SOURCES/2.25-lscpu-discontinuous-NUMA-nodes.patch b/SOURCES/2.25-lscpu-discontinuous-NUMA-nodes.patch
new file mode 100644
index 0000000..6428857
--- /dev/null
+++ b/SOURCES/2.25-lscpu-discontinuous-NUMA-nodes.patch
@@ -0,0 +1,102 @@
+diff -up util-linux-2.23.2/sys-utils/lscpu.c.kzak util-linux-2.23.2/sys-utils/lscpu.c
+--- util-linux-2.23.2/sys-utils/lscpu.c.kzak	2013-07-30 10:39:26.342739583 +0200
++++ util-linux-2.23.2/sys-utils/lscpu.c	2014-01-14 11:21:51.837599200 +0100
+@@ -49,6 +49,7 @@
+ /* /sys paths */
+ #define _PATH_SYS_SYSTEM	"/sys/devices/system"
+ #define _PATH_SYS_CPU		_PATH_SYS_SYSTEM "/cpu"
++#define _PATH_SYS_NODE		_PATH_SYS_SYSTEM "/node"
+ #define _PATH_PROC_XEN		"/proc/xen"
+ #define _PATH_PROC_XENCAP	_PATH_PROC_XEN "/capabilities"
+ #define _PATH_PROC_CPUINFO	"/proc/cpuinfo"
+@@ -157,6 +158,7 @@ struct lscpu_desc {
+ 	cpu_set_t	*online;	/* mask with online CPUs */
+ 
+ 	int		nnodes;		/* number of NUMA modes */
++	int		*idx2nodenum;	/* Support for discontinuous nodes */
+ 	cpu_set_t	**nodemaps;	/* array with NUMA nodes */
+ 
+ 	/* books -- based on book_siblings (internal kernel map of cpuX's
+@@ -802,25 +804,59 @@ read_cache(struct lscpu_desc *desc, int
+ 	}
+ }
+ 
++static inline int is_node_dirent(struct dirent *d)
++{
++	return
++		d &&
++#ifdef _DIRENT_HAVE_D_TYPE
++		d->d_type == DT_DIR &&
++#endif
++		strncmp(d->d_name, "node", 4) == 0 &&
++		isdigit_string(d->d_name + 4);
++}
++
+ static void
+ read_nodes(struct lscpu_desc *desc)
+ {
+-	int i;
++	int i = 0;
++	DIR *dir;
++	struct dirent *d;
++	char *path;
+ 
+ 	/* number of NUMA node */
+-	while (path_exist(_PATH_SYS_SYSTEM "/node/node%d", desc->nnodes))
+-		desc->nnodes++;
++	path = path_strdup(_PATH_SYS_NODE);
++	dir = opendir(path);
++	free(path);
++
++	while (dir && (d = readdir(dir))) {
++		if (is_node_dirent(d))
++			desc->nnodes++;
++	}
+ 
+-	if (!desc->nnodes)
++	if (!desc->nnodes) {
++		if (dir)
++			closedir(dir);
+ 		return;
++	}
+ 
+ 	desc->nodemaps = xcalloc(desc->nnodes, sizeof(cpu_set_t *));
++	desc->idx2nodenum = xmalloc(desc->nnodes * sizeof(int));
++
++	if (dir) {
++		rewinddir(dir);
++		while ((d = readdir(dir)) && i < desc->nnodes) {
++			if (is_node_dirent(d))
++				desc->idx2nodenum[i++] = strtol_or_err(((d->d_name) + 4),
++							_("Failed to extract the node number"));
++		}
++		closedir(dir);
++	}
+ 
+ 	/* information about how nodes share different CPUs */
+ 	for (i = 0; i < desc->nnodes; i++)
+ 		desc->nodemaps[i] = path_read_cpuset(maxcpus,
+ 					_PATH_SYS_SYSTEM "/node/node%d/cpumap",
+-					i);
++					desc->idx2nodenum[i]);
+ }
+ 
+ static char *
+@@ -850,7 +886,7 @@ get_cell_data(struct lscpu_desc *desc, i
+ 	case COL_NODE:
+ 		if (cpuset_ary_isset(cpu, desc->nodemaps,
+ 				     desc->nnodes, setsize, &idx) == 0)
+-			snprintf(buf, bufsz, "%zd", idx);
++			snprintf(buf, bufsz, "%d", desc->idx2nodenum[idx]);
+ 		break;
+ 	case COL_BOOK:
+ 		if (cpuset_ary_isset(cpu, desc->bookmaps,
+@@ -1250,7 +1286,7 @@ print_summary(struct lscpu_desc *desc, s
+ 	}
+ 
+ 	for (i = 0; i < desc->nnodes; i++) {
+-		snprintf(buf, sizeof(buf), _("NUMA node%d CPU(s):"), i);
++		snprintf(buf, sizeof(buf), _("NUMA node%d CPU(s):"), desc->idx2nodenum[i]);
+ 		print_cpuset(buf, desc->nodemaps[i], mod->hex);
+ 	}
+ }
diff --git a/SOURCES/2.25-lscpu-sort-NUMA.patch b/SOURCES/2.25-lscpu-sort-NUMA.patch
new file mode 100644
index 0000000..2055d2d
--- /dev/null
+++ b/SOURCES/2.25-lscpu-sort-NUMA.patch
@@ -0,0 +1,144 @@
+diff -up util-linux-2.23.2/sys-utils/lscpu.c.kzak util-linux-2.23.2/sys-utils/lscpu.c
+--- util-linux-2.23.2/sys-utils/lscpu.c.kzak	2014-01-14 14:02:52.228996385 +0100
++++ util-linux-2.23.2/sys-utils/lscpu.c	2014-01-14 14:04:08.109795733 +0100
+@@ -815,6 +815,13 @@ static inline int is_node_dirent(struct
+ 		isdigit_string(d->d_name + 4);
+ }
+ 
++static int
++nodecmp(const void *ap, const void *bp)
++{
++	int *a = (int *) ap, *b = (int *) bp;
++	return *a - *b;
++}
++
+ static void
+ read_nodes(struct lscpu_desc *desc)
+ {
+@@ -850,6 +857,7 @@ read_nodes(struct lscpu_desc *desc)
+ 							_("Failed to extract the node number"));
+ 		}
+ 		closedir(dir);
++		qsort(desc->idx2nodenum, desc->nnodes, sizeof(int), nodecmp);
+ 	}
+ 
+ 	/* information about how nodes share different CPUs */
+diff -up util-linux-2.23.2/tests/expected/lscpu/lscpu-x86_64-64cpu.kzak util-linux-2.23.2/tests/expected/lscpu/lscpu-x86_64-64cpu
+--- util-linux-2.23.2/tests/expected/lscpu/lscpu-x86_64-64cpu.kzak	2013-06-13 09:46:10.551651742 +0200
++++ util-linux-2.23.2/tests/expected/lscpu/lscpu-x86_64-64cpu	2014-01-14 14:04:29.662022613 +0100
+@@ -4,7 +4,7 @@ On-line CPU(s) list:   0-63
+ Thread(s) per core:    2
+ Core(s) per socket:    8
+ Socket(s):             4
+-NUMA node(s):          1
++NUMA node(s):          3
+ Vendor ID:             GenuineIntel
+ CPU family:            6
+ Model:                 46
+@@ -18,72 +18,74 @@ L1i cache:             32K
+ L2 cache:              256K
+ L3 cache:              18432K
+ NUMA node0 CPU(s):     0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62
++NUMA node2 CPU(s):     1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61
++NUMA node3 CPU(s):     3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63
+ 
+ # The following is the parsable format, which can be fed to other
+ # programs. Each different item in every column has an unique ID
+ # starting from zero.
+ # CPU,Core,Socket,Node,,L1d,L1i,L2,L3
+ 0,0,0,0,,0,0,0,0
+-1,1,1,,,1,1,1,1
++1,1,1,2,,1,1,1,1
+ 2,2,2,0,,2,2,2,2
+-3,3,3,,,3,3,3,3
++3,3,3,3,,3,3,3,3
+ 4,4,0,0,,4,4,4,0
+-5,5,1,,,5,5,5,1
++5,5,1,2,,5,5,5,1
+ 6,6,2,0,,6,6,6,2
+-7,7,3,,,7,7,7,3
++7,7,3,3,,7,7,7,3
+ 8,8,0,0,,8,8,8,0
+-9,9,1,,,9,9,9,1
++9,9,1,2,,9,9,9,1
+ 10,10,2,0,,10,10,10,2
+-11,11,3,,,11,11,11,3
++11,11,3,3,,11,11,11,3
+ 12,12,0,0,,12,12,12,0
+-13,13,1,,,13,13,13,1
++13,13,1,2,,13,13,13,1
+ 14,14,2,0,,14,14,14,2
+-15,15,3,,,15,15,15,3
++15,15,3,3,,15,15,15,3
+ 16,16,0,0,,16,16,16,0
+-17,17,1,,,17,17,17,1
++17,17,1,2,,17,17,17,1
+ 18,18,2,0,,18,18,18,2
+-19,19,3,,,19,19,19,3
++19,19,3,3,,19,19,19,3
+ 20,20,0,0,,20,20,20,0
+-21,21,1,,,21,21,21,1
++21,21,1,2,,21,21,21,1
+ 22,22,2,0,,22,22,22,2
+-23,23,3,,,23,23,23,3
++23,23,3,3,,23,23,23,3
+ 24,24,0,0,,24,24,24,0
+-25,25,1,,,25,25,25,1
++25,25,1,2,,25,25,25,1
+ 26,26,2,0,,26,26,26,2
+-27,27,3,,,27,27,27,3
++27,27,3,3,,27,27,27,3
+ 28,28,0,0,,28,28,28,0
+-29,29,1,,,29,29,29,1
++29,29,1,2,,29,29,29,1
+ 30,30,2,0,,30,30,30,2
+-31,31,3,,,31,31,31,3
++31,31,3,3,,31,31,31,3
+ 32,0,0,0,,0,0,0,0
+-33,1,1,,,1,1,1,1
++33,1,1,2,,1,1,1,1
+ 34,2,2,0,,2,2,2,2
+-35,3,3,,,3,3,3,3
++35,3,3,3,,3,3,3,3
+ 36,4,0,0,,4,4,4,0
+-37,5,1,,,5,5,5,1
++37,5,1,2,,5,5,5,1
+ 38,6,2,0,,6,6,6,2
+-39,7,3,,,7,7,7,3
++39,7,3,3,,7,7,7,3
+ 40,8,0,0,,8,8,8,0
+-41,9,1,,,9,9,9,1
++41,9,1,2,,9,9,9,1
+ 42,10,2,0,,10,10,10,2
+-43,11,3,,,11,11,11,3
++43,11,3,3,,11,11,11,3
+ 44,12,0,0,,12,12,12,0
+-45,13,1,,,13,13,13,1
++45,13,1,2,,13,13,13,1
+ 46,14,2,0,,14,14,14,2
+-47,15,3,,,15,15,15,3
++47,15,3,3,,15,15,15,3
+ 48,16,0,0,,16,16,16,0
+-49,17,1,,,17,17,17,1
++49,17,1,2,,17,17,17,1
+ 50,18,2,0,,18,18,18,2
+-51,19,3,,,19,19,19,3
++51,19,3,3,,19,19,19,3
+ 52,20,0,0,,20,20,20,0
+-53,21,1,,,21,21,21,1
++53,21,1,2,,21,21,21,1
+ 54,22,2,0,,22,22,22,2
+-55,23,3,,,23,23,23,3
++55,23,3,3,,23,23,23,3
+ 56,24,0,0,,24,24,24,0
+-57,25,1,,,25,25,25,1
++57,25,1,2,,25,25,25,1
+ 58,26,2,0,,26,26,26,2
+-59,27,3,,,27,27,27,3
++59,27,3,3,,27,27,27,3
+ 60,28,0,0,,28,28,28,0
+-61,29,1,,,29,29,29,1
++61,29,1,2,,29,29,29,1
+ 62,30,2,0,,30,30,30,2
+-63,31,3,,,31,31,31,3
++63,31,3,3,,31,31,31,3
diff --git a/SOURCES/2.25-mount-man-default.patch b/SOURCES/2.25-mount-man-default.patch
new file mode 100644
index 0000000..f137025
--- /dev/null
+++ b/SOURCES/2.25-mount-man-default.patch
@@ -0,0 +1,27 @@
+diff -up util-linux-2.23.2/sys-utils/mount.8.kzak util-linux-2.23.2/sys-utils/mount.8
+--- util-linux-2.23.2/sys-utils/mount.8.kzak	2015-06-24 10:44:54.888929869 +0200
++++ util-linux-2.23.2/sys-utils/mount.8	2015-06-24 10:48:10.022436703 +0200
+@@ -865,9 +865,10 @@ Some of these options are only useful wh
+ .I /etc/fstab
+ file.
+ 
+-Some of these options could be enabled or disabled by default
+-in the system kernel. To check the current setting see the options
+-in /proc/mounts.
++Some of these  options  could be enabled or disabled by default in the system
++kernel.  To check the current setting see the options in /proc/mounts.  Note
++that filesystems also have per-filesystem specific default mount options (see
++for example tune2fs -l output for extN filesystems).
+ 
+ The following options apply to any filesystem that is being
+ mounted (but not every filesystem actually honors them - e.g., the
+@@ -973,6 +974,9 @@ For more details, see
+ .B defaults
+ Use default options:
+ .BR rw ", " suid ", " dev ", " exec ", " auto ", " nouser ", and " async.
++
++Note that the real set of the all default mount options depends on kernel
++and filesystem type. See the begin of this section for more details.
+ .TP
+ .B dev
+ Interpret character or block special devices on the filesystem.
diff --git a/SOURCES/2.25-mount-man-xfs.patch b/SOURCES/2.25-mount-man-xfs.patch
new file mode 100644
index 0000000..b8973cd
--- /dev/null
+++ b/SOURCES/2.25-mount-man-xfs.patch
@@ -0,0 +1,16 @@
+diff -up util-linux-2.23.2/sys-utils/mount.8.kzak util-linux-2.23.2/sys-utils/mount.8
+--- util-linux-2.23.2/sys-utils/mount.8.kzak	2014-03-12 12:35:46.532369960 +0100
++++ util-linux-2.23.2/sys-utils/mount.8	2014-03-12 12:35:23.041126143 +0100
+@@ -2598,9 +2598,9 @@ None.
+ .TP
+ .BR allocsize=size
+ Sets the buffered I/O end-of-file preallocation size when
+-doing delayed allocation writeout (default size is 64KiB).
+-Valid values for this option are page size (typically 4KiB)
+-through to 1GiB, inclusive, in power-of-2 increments.
++doing delayed allocation writeout. Valid values for this
++option are page size (typically 4KiB) through to 1GiB,
++inclusive, in power-of-2 increments.
+ .sp
+ The default behaviour is for dynamic end-of-file
+ preallocation size, which uses a set of heuristics to
diff --git a/SOURCES/2.25-swapon-discard.patch b/SOURCES/2.25-swapon-discard.patch
new file mode 100644
index 0000000..15277ff
--- /dev/null
+++ b/SOURCES/2.25-swapon-discard.patch
@@ -0,0 +1,200 @@
+diff -up util-linux-2.23.2/sys-utils/swapon.8.kzak util-linux-2.23.2/sys-utils/swapon.8
+--- util-linux-2.23.2/sys-utils/swapon.8.kzak	2013-06-13 09:46:10.544651682 +0200
++++ util-linux-2.23.2/sys-utils/swapon.8	2014-09-24 10:57:45.855230767 +0200
+@@ -112,15 +112,25 @@ All devices marked as ``swap'' in
+ are made available, except for those with the ``noauto'' option.
+ Devices that are already being used as swap are silently skipped.
+ .TP
+-.B "\-d, \-\-discard"
+-Discard freed swap pages before they are reused, if the swap
+-device supports the discard or trim operation.  This may improve
+-performance on some Solid State Devices, but often it does not.
++.B "\-d, \-\-discard\fR [=\fIpolicy\fR]"
++Enable swap discards, if the swap backing device supports the discard or
++trim operation. This may improve performance on some Solid State Devices,
++but often it does not. The option allows one to select between two
++available swap discard policies:
++.BI \-\-discard=once
++to perform a single-time discard operation for the whole swap area at swapon;
++or
++.BI \-\-discard=pages
++to discard freed swap pages before they are reused, while swapping.
++If no policy is selected, the default behavior is to enable both discard types.
+ The
+ .I /etc/fstab
+-mount option
+-.BI discard
+-may be also used to enable discard flag.
++mount options
++.BI discard,
++.BI discard=once,
++or
++.BI discard=pages
++may be also used to enable discard flags.
+ .TP
+ .B "\-e, \-\-ifexists"
+ Silently skip devices that do not exist.
+diff -up util-linux-2.23.2/sys-utils/swapon.c.kzak util-linux-2.23.2/sys-utils/swapon.c
+--- util-linux-2.23.2/sys-utils/swapon.c.kzak	2013-07-30 10:39:26.348739643 +0200
++++ util-linux-2.23.2/sys-utils/swapon.c	2014-09-24 10:57:45.855230767 +0200
+@@ -34,9 +34,20 @@
+ #endif
+ 
+ #ifndef SWAP_FLAG_DISCARD
+-# define SWAP_FLAG_DISCARD	0x10000 /* discard swap cluster after use */
++# define SWAP_FLAG_DISCARD	0x10000 /* enable discard for swap */
+ #endif
+ 
++#ifndef SWAP_FLAG_DISCARD_ONCE
++# define SWAP_FLAG_DISCARD_ONCE 0x20000 /* discard swap area at swapon-time */
++#endif
++
++#ifndef SWAP_FLAG_DISCARD_PAGES
++# define SWAP_FLAG_DISCARD_PAGES 0x40000 /* discard page-clusters after use */
++#endif
++
++#define SWAP_FLAGS_DISCARD_VALID (SWAP_FLAG_DISCARD | SWAP_FLAG_DISCARD_ONCE | \
++				  SWAP_FLAG_DISCARD_PAGES)
++
+ #ifndef SWAP_FLAG_PREFER
+ # define SWAP_FLAG_PREFER	0x8000	/* set if swap priority specified */
+ #endif
+@@ -70,7 +81,7 @@ enum {
+ 
+ static int all;
+ static int priority = -1;	/* non-prioritized swap by default */
+-static int discard;
++static int discard;		/* don't send swap discards by default */
+ 
+ /* If true, don't complain if the device/file doesn't exist */
+ static int ifexists;
+@@ -567,8 +578,22 @@ static int do_swapon(const char *orig_sp
+ 			   << SWAP_FLAG_PRIO_SHIFT);
+ 	}
+ #endif
+-	if (fl_discard)
+-		flags |= SWAP_FLAG_DISCARD;
++	/*
++	 * Validate the discard flags passed and set them
++	 * accordingly before calling sys_swapon.
++	 */
++	if (fl_discard && !(fl_discard & ~SWAP_FLAGS_DISCARD_VALID)) {
++		/*
++		 * If we get here with both discard policy flags set,
++		 * we just need to tell the kernel to enable discards
++		 * and it will do correctly, just as we expect.
++		 */
++		if ((fl_discard & SWAP_FLAG_DISCARD_ONCE) &&
++		    (fl_discard & SWAP_FLAG_DISCARD_PAGES))
++			flags |= SWAP_FLAG_DISCARD;
++		else
++			flags |= fl_discard;
++	}
+ 
+ 	status = swapon(special, flags);
+ 	if (status < 0)
+@@ -608,12 +633,22 @@ static int swapon_all(void)
+ 	while (mnt_table_find_next_fs(tb, itr, match_swap, NULL, &fs) == 0) {
+ 		/* defaults */
+ 		int pri = priority, dsc = discard, nofail = ifexists;
+-		char *p, *src;
++		char *p, *src, *dscarg;
+ 
+ 		if (mnt_fs_get_option(fs, "noauto", NULL, NULL) == 0)
+ 			continue;
+-		if (mnt_fs_get_option(fs, "discard", NULL, NULL) == 0)
+-			dsc = 1;
++		if (mnt_fs_get_option(fs, "discard", &dscarg, NULL) == 0) {
++			dsc |= SWAP_FLAG_DISCARD;
++			if (dscarg) {
++				/* only single-time discards are wanted */
++				if (strcmp(dscarg, "once") == 0)
++					dsc |= SWAP_FLAG_DISCARD_ONCE;
++
++				/* do discard for every released swap page */
++				if (strcmp(dscarg, "pages") == 0)
++					dsc |= SWAP_FLAG_DISCARD_PAGES;
++			}
++		}
+ 		if (mnt_fs_get_option(fs, "nofail", NULL, NULL) == 0)
+ 			nofail = 1;
+ 		if (mnt_fs_get_option(fs, "pri", &p, NULL) == 0 && p)
+@@ -643,17 +678,17 @@ static void __attribute__ ((__noreturn__
+ 	fprintf(out, _(" %s [options] [<spec>]\n"), program_invocation_short_name);
+ 
+ 	fputs(USAGE_OPTIONS, out);
+-	fputs(_(" -a, --all              enable all swaps from /etc/fstab\n"
+-		" -d, --discard          discard freed pages before they are reused\n"
+-		" -e, --ifexists         silently skip devices that do not exist\n"
+-		" -f, --fixpgsz          reinitialize the swap space if necessary\n"
+-		" -p, --priority <prio>  specify the priority of the swap device\n"
+-		" -s, --summary          display summary about used swap devices\n"
+-		"     --show[=<columns>] display summary in definable table\n"
+-		"     --noheadings       don't print headings, use with --show\n"
+-		"     --raw              use the raw output format, use with --show\n"
+-		"     --bytes            display swap size in bytes in --show output\n"
+-		" -v, --verbose          verbose mode\n"), out);
++	fputs(_(" -a, --all                enable all swaps from /etc/fstab\n"
++		" -d, --discard[=<policy>] enable swap discards, if supported by device\n"
++		" -e, --ifexists           silently skip devices that do not exist\n"
++		" -f, --fixpgsz            reinitialize the swap space if necessary\n"
++		" -p, --priority <prio>    specify the priority of the swap device\n"
++		" -s, --summary            display summary about used swap devices\n"
++		"     --show[=<columns>]   display summary in definable table\n"
++		"     --noheadings         don't print headings, use with --show\n"
++		"     --raw                use the raw output format, use with --show\n"
++		"     --bytes              display swap size in bytes in --show output\n"
++		" -v, --verbose            verbose mode\n"), out);
+ 
+ 	fputs(USAGE_SEPARATOR, out);
+ 	fputs(USAGE_HELP, out);
+@@ -669,6 +704,11 @@ static void __attribute__ ((__noreturn__
+ 		" <device>               name of device to be used\n"
+ 		" <file>                 name of file to be used\n"), out);
+ 
++	fputs(_("\nAvailable discard policy types (for --discard):\n"
++		" once	  : only single-time area discards are issued. (swapon)\n"
++		" pages	  : discard freed pages before they are reused.\n"
++		" * if no policy is selected both discard types are enabled. (default)\n"), out);
++
+ 	fputs(_("\nAvailable columns (for --show):\n"), out);
+ 	for (i = 0; i < NCOLS; i++)
+ 		fprintf(out, " %4s  %s\n", infos[i].name, _(infos[i].help));
+@@ -693,7 +733,7 @@ int main(int argc, char *argv[])
+ 
+ 	static const struct option long_opts[] = {
+ 		{ "priority", 1, 0, 'p' },
+-		{ "discard",  0, 0, 'd' },
++		{ "discard",  2, 0, 'd' },
+ 		{ "ifexists", 0, 0, 'e' },
+ 		{ "summary",  0, 0, 's' },
+ 		{ "fixpgsz",  0, 0, 'f' },
+@@ -716,7 +756,7 @@ int main(int argc, char *argv[])
+ 	mnt_init_debug(0);
+ 	mntcache = mnt_new_cache();
+ 
+-	while ((c = getopt_long(argc, argv, "ahdefp:svVL:U:",
++	while ((c = getopt_long(argc, argv, "ahd::efp:svVL:U:",
+ 				long_opts, NULL)) != -1) {
+ 		switch (c) {
+ 		case 'a':		/* all */
+@@ -736,7 +776,18 @@ int main(int argc, char *argv[])
+ 			add_uuid(optarg);
+ 			break;
+ 		case 'd':
+-			discard = 1;
++			discard |= SWAP_FLAG_DISCARD;
++			if (optarg) {
++				if (*optarg == '=')
++					optarg++;
++
++				if (strcmp(optarg, "once") == 0)
++					discard |= SWAP_FLAG_DISCARD_ONCE;
++				else if (strcmp(optarg, "pages") == 0)
++					discard |= SWAP_FLAG_DISCARD_PAGES;
++				else
++					errx(EXIT_FAILURE, _("unsupported discard policy: %s"), optarg);
++			}
+ 			break;
+ 		case 'e':               /* ifexists */
+ 		        ifexists = 1;
diff --git a/SOURCES/2.25-taskset-man-fix-permissions.patch b/SOURCES/2.25-taskset-man-fix-permissions.patch
new file mode 100644
index 0000000..ef97f50
--- /dev/null
+++ b/SOURCES/2.25-taskset-man-fix-permissions.patch
@@ -0,0 +1,36 @@
+From ab0e0fa7a45bccf8304edcb2a904f30a4f3a48b1 Mon Sep 17 00:00:00 2001
+From: Rik van Riel <riel@redhat.com>
+Date: Fri, 6 Dec 2013 16:07:54 -0500
+Subject: [PATCH] taskset: fix PERMISSIONS section of taskset man page
+
+A user is always allowed to change the CPU affinity of his or her
+own processes. CAP_SYS_NICE is only required to change the affinity
+of another user's process.
+
+Signed-off-by: Rik van Riel <riel@redhat.com>
+Reported-by: Joe Mario <jmario@redhat.com>
+---
+ schedutils/taskset.1 | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/schedutils/taskset.1 b/schedutils/taskset.1
+index ade202b..fb5738c 100644
+--- a/schedutils/taskset.1
++++ b/schedutils/taskset.1
+@@ -102,10 +102,11 @@ Or set it:
+ .B taskset \-p
+ .I mask pid
+ .SH PERMISSIONS
++A user can change the CPU affinity of a process belonging to the same user.
+ A user must possess
+ .B CAP_SYS_NICE
+-to change the CPU affinity of a process.  Any user can retrieve the affinity
+-mask.
++to change the CPU affinity of a process belonging to another user.
++A user can retrieve the affinity mask of any process.
+ .SH AUTHOR
+ Written by Robert M. Love.
+ .SH COPYRIGHT
+-- 
+1.8.4.2
+
diff --git a/SOURCES/2.25-uuidd-timeout.patch b/SOURCES/2.25-uuidd-timeout.patch
new file mode 100644
index 0000000..850c688
--- /dev/null
+++ b/SOURCES/2.25-uuidd-timeout.patch
@@ -0,0 +1,12 @@
+diff -up util-linux-2.23.2/misc-utils/uuidd.service.in.kzak util-linux-2.23.2/misc-utils/uuidd.service.in
+--- util-linux-2.23.2/misc-utils/uuidd.service.in.kzak	2013-02-27 17:46:29.903020913 +0100
++++ util-linux-2.23.2/misc-utils/uuidd.service.in	2015-04-20 11:31:44.614013049 +0200
+@@ -3,7 +3,7 @@ Description=Daemon for generating UUIDs
+ Requires=uuidd.socket
+ 
+ [Service]
+-ExecStart=@usrsbin_execdir@/uuidd --socket-activation --timeout 60
++ExecStart=@usrsbin_execdir@/uuidd --socket-activation
+ Restart=no
+ User=uuidd
+ Group=uuidd
diff --git a/SOURCES/2.25-wipefs-call-BLKRRPART-when-erase-partition-table.patch b/SOURCES/2.25-wipefs-call-BLKRRPART-when-erase-partition-table.patch
new file mode 100644
index 0000000..260b1ad
--- /dev/null
+++ b/SOURCES/2.25-wipefs-call-BLKRRPART-when-erase-partition-table.patch
@@ -0,0 +1,140 @@
+diff -up util-linux-2.23.2/misc-utils/wipefs.8.kzak util-linux-2.23.2/misc-utils/wipefs.8
+--- util-linux-2.23.2/misc-utils/wipefs.8.kzak	2013-07-30 10:39:26.232738496 +0200
++++ util-linux-2.23.2/misc-utils/wipefs.8	2014-01-23 11:07:54.390022299 +0100
+@@ -23,6 +23,9 @@ does not erase the filesystem itself nor
+ When used without options \fB-a\fR or \fB-o\fR, it lists all visible filesystems
+ and the offsets of their basic signatures.
+ 
++.B wipefs
++calls BLKRRPART ioctl when erase partition table to inform kernel about the change.
++
+ Note that some filesystems or some partition tables store more magic strings on
+ the devices.  The
+ .B wipefs
+diff -up util-linux-2.23.2/misc-utils/wipefs.c.kzak util-linux-2.23.2/misc-utils/wipefs.c
+--- util-linux-2.23.2/misc-utils/wipefs.c.kzak	2013-07-30 10:39:26.232738496 +0200
++++ util-linux-2.23.2/misc-utils/wipefs.c	2014-01-23 11:12:26.786860550 +0100
+@@ -40,21 +40,24 @@
+ #include "c.h"
+ #include "closestream.h"
+ #include "optutils.h"
++#include "blkdev.h"
+ 
+ struct wipe_desc {
+ 	loff_t		offset;		/* magic string offset */
+ 	size_t		len;		/* length of magic string */
+ 	unsigned char	*magic;		/* magic string */
+ 
+-	int		zap;		/* zap this offset? */
+ 	char		*usage;		/* raid, filesystem, ... */
+ 	char		*type;		/* FS type */
+ 	char		*label;		/* FS label */
+ 	char		*uuid;		/* FS uuid */
+ 
+-	int		on_disk;
+-
+ 	struct wipe_desc	*next;
++
++	unsigned int	zap : 1,
++			on_disk : 1,
++			is_parttable : 1;
++
+ };
+ 
+ enum {
+@@ -72,7 +75,7 @@ print_pretty(struct wipe_desc *wp, int l
+ 		printf("----------------------------------------------------------------\n");
+ 	}
+ 
+-	printf("0x%-17jx  %s   [%s]", wp->offset, wp->type, wp->usage);
++	printf("0x%-17jx  %s   [%s]", wp->offset, wp->type, _(wp->usage));
+ 
+ 	if (wp->label && *wp->label)
+ 		printf("\n%27s %s", "LABEL:", wp->label);
+@@ -141,7 +144,7 @@ add_offset(struct wipe_desc *wp0, loff_t
+ 	wp = xcalloc(1, sizeof(struct wipe_desc));
+ 	wp->offset = offset;
+ 	wp->next = wp0;
+-	wp->zap = zap;
++	wp->zap = zap ? 1 : 0;
+ 	return wp;
+ }
+ 
+@@ -164,7 +167,7 @@ get_desc_for_probe(struct wipe_desc *wp,
+ 	const char *off, *type, *mag, *p, *usage = NULL;
+ 	size_t len;
+ 	loff_t offset;
+-	int rc;
++	int rc, ispt = 0;
+ 
+ 	/* superblocks */
+ 	if (blkid_probe_lookup_value(pr, "TYPE", &type, NULL) == 0) {
+@@ -181,7 +184,8 @@ get_desc_for_probe(struct wipe_desc *wp,
+ 			rc = blkid_probe_lookup_value(pr, "PTMAGIC", &mag, &len);
+ 		if (rc)
+ 			return wp;
+-		usage = "partition table";
++		usage = N_("partition table");
++		ispt = 1;
+ 	} else
+ 		return wp;
+ 
+@@ -199,6 +203,7 @@ get_desc_for_probe(struct wipe_desc *wp,
+ 
+ 	wp->type = xstrdup(type);
+ 	wp->on_disk = 1;
++	wp->is_parttable = ispt ? 1 : 0;
+ 
+ 	wp->magic = xmalloc(len);
+ 	memcpy(wp->magic, mag, len);
+@@ -309,10 +314,25 @@ static void do_wipe_real(blkid_probe pr,
+ 	putchar('\n');
+ }
+ 
++
++static void rereadpt(int fd, const char *devname)
++{
++#ifdef BLKRRPART
++	struct stat st;
++
++	if (fstat(fd, &st) || !S_ISBLK(st.st_mode))
++		return;
++
++	errno = 0;
++	ioctl(fd, BLKRRPART);
++	printf(_("%s: calling ioclt to re-read partition table: %m\n"), devname);
++#endif
++}
++
+ static struct wipe_desc *
+ do_wipe(struct wipe_desc *wp, const char *devname, int noact, int all, int quiet, int force)
+ {
+-	int flags;
++	int flags, reread = 0;
+ 	blkid_probe pr;
+ 	struct wipe_desc *w, *wp0;
+ 	int zap = all ? 1 : wp->zap;
+@@ -345,8 +365,11 @@ do_wipe(struct wipe_desc *wp, const char
+ 		if (!wp->on_disk)
+ 			continue;
+ 
+-		if (zap)
++		if (zap) {
+ 			do_wipe_real(pr, devname, wp, noact, quiet);
++			if (wp->is_parttable)
++				reread = 1;
++		}
+ 	}
+ 
+ 	for (w = wp0; w != NULL; w = w->next) {
+@@ -355,6 +378,10 @@ do_wipe(struct wipe_desc *wp, const char
+ 	}
+ 
+ 	fsync(blkid_probe_get_fd(pr));
++
++	if (reread)
++		rereadpt(blkid_probe_get_fd(pr), devname);
++
+ 	close(blkid_probe_get_fd(pr));
+ 	blkid_free_probe(pr);
+ 	free_wipe(wp0);
diff --git a/SOURCES/2.25-wipefs-nested-pt.patch b/SOURCES/2.25-wipefs-nested-pt.patch
new file mode 100644
index 0000000..a9b97dd
--- /dev/null
+++ b/SOURCES/2.25-wipefs-nested-pt.patch
@@ -0,0 +1,53 @@
+diff -up util-linux-2.23.2/misc-utils/wipefs.8.kzak util-linux-2.23.2/misc-utils/wipefs.8
+--- util-linux-2.23.2/misc-utils/wipefs.8.kzak	2014-09-24 10:41:31.061930168 +0200
++++ util-linux-2.23.2/misc-utils/wipefs.8	2014-09-24 10:46:30.142783728 +0200
+@@ -37,6 +37,11 @@ table will still be visible by another m
+ When used with option \fB-a\fR, all magic strings that are visible for libblkid are
+ erased.
+ 
++Note that by default
++.B wipefs
++does not erase nested partition tables on non-whole disk devices. The option 
++\-\-force is required.
++
+ .SH OPTIONS
+ .TP
+ .BR \-a , " \-\-all"
+diff -up util-linux-2.23.2/misc-utils/wipefs.c.kzak util-linux-2.23.2/misc-utils/wipefs.c
+--- util-linux-2.23.2/misc-utils/wipefs.c.kzak	2014-09-24 10:41:31.061930168 +0200
++++ util-linux-2.23.2/misc-utils/wipefs.c	2014-09-24 10:50:07.728859738 +0200
+@@ -332,7 +332,7 @@ static void rereadpt(int fd, const char
+ static struct wipe_desc *
+ do_wipe(struct wipe_desc *wp, const char *devname, int noact, int all, int quiet, int force)
+ {
+-	int flags, reread = 0;
++	int flags, reread = 0, need_force = 0;
+ 	blkid_probe pr;
+ 	struct wipe_desc *w, *wp0;
+ 	int zap = all ? 1 : wp->zap;
+@@ -365,6 +365,15 @@ do_wipe(struct wipe_desc *wp, const char
+ 		if (!wp->on_disk)
+ 			continue;
+ 
++		if (!force
++		    && wp->is_parttable
++		    && !blkid_probe_is_wholedisk(pr)) {
++			warnx(_("%s: ignore nested \"%s\" partition "
++				"table on non-whole disk device."), devname, wp->type);
++			need_force = 1;
++			continue;
++		}
++
+ 		if (zap) {
+ 			do_wipe_real(pr, devname, wp, noact, quiet);
+ 			if (wp->is_parttable)
+@@ -377,6 +386,9 @@ do_wipe(struct wipe_desc *wp, const char
+ 			warnx(_("%s: offset 0x%jx not found"), devname, w->offset);
+ 	}
+ 
++	if (need_force)
++		warnx(_("Use the --force option to force erase."));
++
+ 	fsync(blkid_probe_get_fd(pr));
+ 
+ 	if (reread)
diff --git a/SOURCES/2.26-blkdiscard.patch b/SOURCES/2.26-blkdiscard.patch
new file mode 100644
index 0000000..91e88d2
--- /dev/null
+++ b/SOURCES/2.26-blkdiscard.patch
@@ -0,0 +1,259 @@
+diff -up util-linux-2.23.2/sys-utils/blkdiscard.8.kzak util-linux-2.23.2/sys-utils/blkdiscard.8
+--- util-linux-2.23.2/sys-utils/blkdiscard.8.kzak	2013-06-13 09:46:10.532651579 +0200
++++ util-linux-2.23.2/sys-utils/blkdiscard.8	2014-10-27 10:03:13.650011708 +0100
+@@ -1,5 +1,5 @@
+ .\" -*- nroff -*-
+-.TH BLKDISCARD 8 "October 2012" "util-linux" "System Administration"
++.TH BLKDISCARD 8 "July 2014" "util-linux" "System Administration"
+ .SH NAME
+ blkdiscard \- discard sectors on a device
+ .SH SYNOPSIS
+@@ -15,7 +15,7 @@ blkdiscard \- discard sectors on a devic
+ .B blkdiscard
+ is used to discard device sectors.  This is useful for solid-state
+ drivers (SSDs) and thinly-provisioned storage.  Unlike
+-.BR fstrim (8)
++.BR fstrim (8) ,
+ this command is used directly on the block device.
+ .PP
+ By default,
+@@ -33,32 +33,44 @@ The
+ .I offset
+ and
+ .I length
+-arguments may be followed by the multiplicative suffixes KiB=1024,
+-MiB=1024*1024, and so on for GiB, TiB, PiB, EiB, ZiB and YiB (the "iB" is
++arguments may be followed by the multiplicative suffixes KiB (=1024),
++MiB (=1024*1024), and so on for GiB, TiB, PiB, EiB, ZiB and YiB (the "iB" is
+ optional, e.g., "K" has the same meaning as "KiB") or the suffixes
+-KB=1000, MB=1000*1000, and so on for GB, TB, PB, EB, ZB and YB.
+-.IP "\fB\-h, \-\-help\fP"
+-Print help and exit.
+-.IP "\fB\-o, \-\-offset\fP \fIoffset\fP"
+-Byte offset in the device from which to discard.  Provided value will be
+-aligned to the device sector size.  Default value is zero.
+-.IP "\fB\-l, \-\-length\fP \fIlength\fP"
+-Number of bytes after starting point to discard.  Provided value will be
+-aligned to the device sector size.  If the specified value extends past
++KB (=1000), MB (=1000*1000), and so on for GB, TB, PB, EB, ZB and YB.
++.TP
++.BR \-o , " \-\-offset \fIoffset"
++Byte offset into the device from which to start discarding.  The provided value
++will be aligned to the device sector size.  The default value is zero.
++.TP
++.BR \-l , " \-\-length \fIlength"
++The number of bytes to discard (counting from the starting point).  The provided value
++will be aligned to the device sector size.  If the specified value extends past
+ the end of the device,
+ .B blkdiscard
+-will stop at the device size boundary.  Default value extends to the end
++will stop at the device size boundary.  The default value extends to the end
+ of the device.
+-.IP "\fB\-s, \-\-secure\fP"
+-Perform secure discard.  Secure discard is the same as regular discard
+-except all copies of the discarded blocks possibly created by garbage
+-collection must also be erased.  It has to be supported by the device.
+-.IP "\fB\-v, \-\-verbose\fP"
+-Print aligned
++.TP
++.BR \-p , " \-\-step \fIlength"
++The number of bytes to discard within one iteration. The default is to discard
++all by one ioctl call.
++.TP
++.BR \-s , " \-\-secure"
++Perform a secure discard.  A secure discard is the same as a regular discard
++except that all copies of the discarded blocks that were possibly created by
++garbage collection must also be erased.  This requires support from the device.
++.TP
++.BR \-v , " \-\-verbose"
++Display the aligned values of
+ .I offset
+ and
+-.I length
+-arguments.
++.IR length .
++If the option \fB\-\-step\fR specified than it prints discard progress every second.
++.TP
++.BR \-V , " \-\-version"
++Display version information and exit.
++.TP
++.BR \-h , " \-\-help"
++Display help text and exit.
+ .SH AUTHOR
+ .MT lczerner@redhat.com
+ Lukas Czerner
+diff -up util-linux-2.23.2/sys-utils/blkdiscard.c.kzak util-linux-2.23.2/sys-utils/blkdiscard.c
+--- util-linux-2.23.2/sys-utils/blkdiscard.c.kzak	2013-07-30 10:39:26.337739534 +0200
++++ util-linux-2.23.2/sys-utils/blkdiscard.c	2014-10-27 10:03:20.981088614 +0100
+@@ -31,9 +31,11 @@
+ #include <fcntl.h>
+ #include <limits.h>
+ #include <getopt.h>
++#include <time.h>
+ 
+ #include <sys/ioctl.h>
+ #include <sys/stat.h>
++#include <sys/time.h>
+ #include <linux/fs.h>
+ 
+ #include "nls.h"
+@@ -49,6 +51,10 @@
+ #define BLKSECDISCARD	_IO(0x12,125)
+ #endif
+ 
++#define print_stats(path, stats) \
++	printf(_("%s: Discarded %" PRIu64 " bytes from the " \
++		 "offset %" PRIu64"\n"), path, stats[1], stats[0]);
++
+ static void __attribute__((__noreturn__)) usage(FILE *out)
+ {
+ 	fputs(USAGE_HEADER, out);
+@@ -57,6 +63,7 @@ static void __attribute__((__noreturn__)
+ 	fputs(USAGE_OPTIONS, out);
+ 	fputs(_(" -o, --offset <num>  offset in bytes to discard from\n"
+ 		" -l, --length <num>  length of bytes to discard from the offset\n"
++		" -p, --step <num>    size of the discard iterations within the offset\n"
+ 		" -s, --secure        perform secure discard\n"
+ 		" -v, --verbose       print aligned length and offset\n"),
+ 		out);
+@@ -70,15 +77,17 @@ static void __attribute__((__noreturn__)
+ int main(int argc, char **argv)
+ {
+ 	char *path;
+-	int c, fd, verbose = 0, secure = 0;
+-	uint64_t end, blksize, secsize, range[2];
++	int c, fd, verbose = 0, secure = 0, secsize;
++	uint64_t end, blksize, step, range[2], stats[2];
+ 	struct stat sb;
++	struct timespec now, last;
+ 
+ 	static const struct option longopts[] = {
+ 	    { "help",      0, 0, 'h' },
+ 	    { "version",   0, 0, 'V' },
+ 	    { "offset",    1, 0, 'o' },
+ 	    { "length",    1, 0, 'l' },
++	    { "step",      1, 0, 'p' },
+ 	    { "secure",    0, 0, 's' },
+ 	    { "verbose",   0, 0, 'v' },
+ 	    { NULL,        0, 0, 0 }
+@@ -91,8 +100,9 @@ int main(int argc, char **argv)
+ 
+ 	range[0] = 0;
+ 	range[1] = ULLONG_MAX;
++	step = 0;
+ 
+-	while ((c = getopt_long(argc, argv, "hVsvo:l:", longopts, NULL)) != -1) {
++	while ((c = getopt_long(argc, argv, "hVsvo:l:p:", longopts, NULL)) != -1) {
+ 		switch(c) {
+ 		case 'h':
+ 			usage(stdout);
+@@ -108,6 +118,10 @@ int main(int argc, char **argv)
+ 			range[0] = strtosize_or_err(optarg,
+ 					_("failed to parse offset"));
+ 			break;
++		case 'p':
++			step = strtosize_or_err(optarg,
++					_("failed to parse step"));
++			break;
+ 		case 's':
+ 			secure = 1;
+ 			break;
+@@ -121,7 +135,7 @@ int main(int argc, char **argv)
+ 	}
+ 
+ 	if (optind == argc)
+-		errx(EXIT_FAILURE, _("no device specified."));
++		errx(EXIT_FAILURE, _("no device specified"));
+ 
+ 	path = argv[optind++];
+ 
+@@ -130,43 +144,69 @@ int main(int argc, char **argv)
+ 		usage(stderr);
+ 	}
+ 
+-	if (stat(path, &sb) == -1)
+-		err(EXIT_FAILURE, _("stat failed %s"), path);
+-	if (!S_ISBLK(sb.st_mode))
+-		errx(EXIT_FAILURE, _("%s: not a block device"), path);
+-
+ 	fd = open(path, O_WRONLY);
+ 	if (fd < 0)
+ 		err(EXIT_FAILURE, _("cannot open %s"), path);
+ 
++	if (fstat(fd, &sb) == -1)
++		err(EXIT_FAILURE, _("stat failed %s"), path);
++	if (!S_ISBLK(sb.st_mode))
++		errx(EXIT_FAILURE, _("%s: not a block device"), path);
++
+ 	if (ioctl(fd, BLKGETSIZE64, &blksize))
+ 		err(EXIT_FAILURE, _("%s: BLKGETSIZE64 ioctl failed"), path);
+-
+ 	if (ioctl(fd, BLKSSZGET, &secsize))
+ 		err(EXIT_FAILURE, _("%s: BLKSSZGET ioctl failed"), path);
+ 
+-	/* align range to the sector size */
+-	range[0] = (range[0] + secsize - 1) & ~(secsize - 1);
+-	range[1] &= ~(secsize - 1);
++	/* check offset alignment to the sector size */
++	if (range[0] % secsize)
++		errx(EXIT_FAILURE, _("%s: offset %" PRIu64 " is not aligned "
++			 "to sector size %i"), path, range[0], secsize);
+ 
+ 	/* is the range end behind the end of the device ?*/
++	if (range[0] > blksize)
++		errx(EXIT_FAILURE, _("%s: offset is greater than device size"), path);
+ 	end = range[0] + range[1];
+ 	if (end < range[0] || end > blksize)
+-		range[1] = blksize - range[0];
++		end = blksize;
++
++	range[1] = (step > 0) ? step : end - range[0];
++
++	/* check length alignment to the sector size */
++	if (range[1] % secsize)
++		errx(EXIT_FAILURE, _("%s: length %" PRIu64 " is not aligned "
++			 "to sector size %i"), path, range[1], secsize);
++
++	stats[0] = range[0], stats[1] = 0;
++	clock_gettime(CLOCK_MONOTONIC, &last);
++
++	for (range[0] = range[0]; range[0] < end; range[0] += range[1]) {
++		if (range[0] + range[1] > end)
++			range[1] = end - range[0];
++
++		if (secure) {
++			if (ioctl(fd, BLKSECDISCARD, &range))
++				err(EXIT_FAILURE, _("%s: BLKSECDISCARD ioctl failed"), path);
++		} else {
++			if (ioctl(fd, BLKDISCARD, &range))
++				err(EXIT_FAILURE, _("%s: BLKDISCARD ioctl failed"), path);
++		}
++
++		/* reporting progress */
++		if (verbose && step) {
++			clock_gettime(CLOCK_MONOTONIC, &now);
++			if (last.tv_sec < now.tv_sec) {
++				print_stats(path, stats);
++				stats[0] = range[0], stats[1] = 0;
++				last = now;
++			}
++		}
+ 
+-	if (secure) {
+-		if (ioctl(fd, BLKSECDISCARD, &range))
+-			err(EXIT_FAILURE, _("%s: BLKSECDISCARD ioctl failed"), path);
+-	} else {
+-		if (ioctl(fd, BLKDISCARD, &range))
+-			err(EXIT_FAILURE, _("%s: BLKDISCARD ioctl failed"), path);
++		stats[1] += range[1];
+ 	}
+ 
+ 	if (verbose)
+-		/* TRANSLATORS: The standard value here is a very large number. */
+-		printf(_("%s: Discarded %" PRIu64 " bytes from the "
+-			 "offset %" PRIu64"\n"), path,
+-			 (uint64_t) range[1], (uint64_t) range[0]);
++		print_stats(path, stats);
+ 
+ 	close(fd);
+ 	return EXIT_SUCCESS;
diff --git a/SOURCES/2.26-libblkid-fat.patch b/SOURCES/2.26-libblkid-fat.patch
new file mode 100644
index 0000000..f6f87ad
--- /dev/null
+++ b/SOURCES/2.26-libblkid-fat.patch
@@ -0,0 +1,113 @@
+diff -up util-linux-2.23.2/libblkid/src/partitions/dos.c.kzak util-linux-2.23.2/libblkid/src/partitions/dos.c
+--- util-linux-2.23.2/libblkid/src/partitions/dos.c.kzak	2015-08-21 10:16:45.244332027 +0200
++++ util-linux-2.23.2/libblkid/src/partitions/dos.c	2015-08-21 10:22:07.181340367 +0200
+@@ -151,16 +151,6 @@ static int probe_dos_pt(blkid_probe pr,
+ 	if (memcmp(data, BLKID_AIX_MAGIC_STRING, BLKID_AIX_MAGIC_STRLEN) == 0)
+ 		goto nothing;
+ 
+-	/*
+-	 * Now that the 55aa signature is present, this is probably
+-	 * either the boot sector of a FAT filesystem or a DOS-type
+-	 * partition table.
+-	 */
+-	if (blkid_probe_is_vfat(pr) == 1) {
+-		DBG(LOWPROBE, blkid_debug("probably FAT -- ignore"));
+-		goto nothing;
+-	}
+-
+ 	p0 = (struct dos_partition *) (data + BLKID_MSDOS_PT_OFFSET);
+ 
+ 	/*
+@@ -182,6 +172,16 @@ static int probe_dos_pt(blkid_probe pr,
+ 		}
+ 	}
+ 
++	/*
++	 * Now that the 55aa signature is present, this is probably
++	 * either the boot sector of a FAT filesystem or a DOS-type
++	 * partition table.
++	 */
++	if (blkid_probe_is_vfat(pr) == 1) {
++		DBG(LOWPROBE, blkid_debug("probably FAT -- ignore"));
++		goto nothing;
++	}
++
+ 	blkid_probe_use_wiper(pr, BLKID_MSDOS_PT_OFFSET,
+ 				  512 - BLKID_MSDOS_PT_OFFSET);
+ 
+diff -up util-linux-2.23.2/libblkid/src/partitions/dos.h.kzak util-linux-2.23.2/libblkid/src/partitions/dos.h
+--- util-linux-2.23.2/libblkid/src/partitions/dos.h.kzak	2015-08-21 10:34:14.919380422 +0200
++++ util-linux-2.23.2/libblkid/src/partitions/dos.h	2015-08-21 10:35:45.221807669 +0200
+@@ -12,6 +12,12 @@ struct dos_partition {
+ 
+ #define BLKID_MSDOS_PT_OFFSET		0x1be
+ 
++static inline struct dos_partition *mbr_get_partition(unsigned char *mbr, int i)
++{
++	return (struct dos_partition *)
++		(mbr + BLKID_MSDOS_PT_OFFSET + (i * sizeof(struct dos_partition)));
++}
++
+ /* assemble badly aligned little endian integer */
+ static inline unsigned int assemble4le(const unsigned char *p)
+ {
+diff -up util-linux-2.23.2/libblkid/src/superblocks/vfat.c.kzak util-linux-2.23.2/libblkid/src/superblocks/vfat.c
+--- util-linux-2.23.2/libblkid/src/superblocks/vfat.c.kzak	2015-08-21 10:10:12.111906711 +0200
++++ util-linux-2.23.2/libblkid/src/superblocks/vfat.c	2015-08-21 10:35:07.733045452 +0200
+@@ -16,6 +16,7 @@
+ #include <ctype.h>
+ #include <stdint.h>
+ 
++#include "partitions/dos.h"
+ #include "superblocks.h"
+ 
+ /* Yucky misaligned values */
+@@ -169,7 +170,8 @@ static unsigned char *search_fat_label(b
+ 	return NULL;
+ }
+ 
+-static int fat_valid_superblock(const struct blkid_idmag *mag,
++static int fat_valid_superblock(blkid_probe pr,
++			const struct blkid_idmag *mag,
+ 			struct msdos_super_block *ms,
+ 			struct vfat_super_block *vs,
+ 			uint32_t *cluster_count, uint32_t *fat_size)
+@@ -243,6 +245,20 @@ static int fat_valid_superblock(const st
+ 	if (cluster_count)
+ 		*cluster_count = __cluster_count;
+ 
++	if (blkid_probe_is_wholedisk(pr)) {
++		/* OK, seems like FAT, but it's possible that we found boot
++		 * sector with crazy FAT-like stuff (magic strings, media,
++		 * etc..) before MBR. Let's make sure that there is no MBR with
++		 * usable partition. */
++		unsigned char *buf = (unsigned char *) ms;
++		if (is_valid_mbr_signature(buf)) {
++			struct dos_partition *p0 = mbr_get_partition(buf, 0);
++			if (dos_partition_size(p0) != 0 &&
++			    (p0->boot_ind == 0 || p0->boot_ind == 0x80))
++				return 0;
++		}
++	}
++
+ 	return 1;	/* valid */
+ }
+ 
+@@ -270,7 +286,7 @@ int blkid_probe_is_vfat(blkid_probe pr)
+ 	if (!vs)
+ 		return errno ? -errno : 0;
+ 
+-	return fat_valid_superblock(mag, ms, vs, NULL, NULL);
++	return fat_valid_superblock(pr, mag, ms, vs, NULL, NULL);
+ }
+ 
+ /* FAT label extraction from the root directory taken from Kay
+@@ -293,7 +309,7 @@ static int probe_vfat(blkid_probe pr, co
+ 	if (!vs)
+ 		return errno ? -errno : 1;
+ 
+-	if (!fat_valid_superblock(mag, ms, vs, &cluster_count, &fat_size))
++	if (!fat_valid_superblock(pr, mag, ms, vs, &cluster_count, &fat_size))
+ 		return 1;
+ 
+ 	sector_size = unaligned_le16(&ms->ms_sector_size);
diff --git a/SOURCES/2.26-libsmartcols.patch b/SOURCES/2.26-libsmartcols.patch
new file mode 100644
index 0000000..edad5fb
--- /dev/null
+++ b/SOURCES/2.26-libsmartcols.patch
@@ -0,0 +1,5242 @@
+diff -up util-linux-2.23.2/configure.ac.kzak util-linux-2.23.2/configure.ac
+--- util-linux-2.23.2/configure.ac.kzak	2013-07-30 10:39:26.188738061 +0200
++++ util-linux-2.23.2/configure.ac	2014-09-25 14:41:48.980843829 +0200
+@@ -46,6 +46,13 @@ LIBMOUNT_LT_MINOR=1
+ LIBMOUNT_LT_MICRO=0
+ LIBMOUNT_VERSION_INFO=`expr $LIBMOUNT_LT_MAJOR + $LIBMOUNT_LT_MINOR`:$LIBMOUNT_LT_MICRO:$LIBMOUNT_LT_MINOR
+ 
++dnl libsmartcols version
++LIBSMARTCOLS_VERSION="$PACKAGE_VERSION_MAJOR.$PACKAGE_VERSION_MINOR.$PACKAGE_VERSION_RELEASE"
++LIBSMARTCOLS_LT_MAJOR=1
++LIBSMARTCOLS_LT_MINOR=1
++LIBSMARTCOLS_LT_MICRO=0
++LIBSMARTCOLS_VERSION_INFO=`expr $LIBSMARTCOLS_LT_MAJOR + $LIBSMARTCOLS_LT_MINOR`:$LIBSMARTCOLS_LT_MICRO:$LIBSMARTCOLS_LT_MINOR
++
+ # Check whether exec_prefix=/usr:
+ case $exec_prefix:$prefix in
+ NONE:NONE | NONE:/usr | /usr:*)
+@@ -765,6 +772,18 @@ AC_DEFINE_UNQUOTED(LIBMOUNT_VERSION, "$L
+ 
+ 
+ dnl
++dnl libsmartcols
++dnl
++UL_BUILD_INIT([libsmartcols], [yes])
++AM_CONDITIONAL([BUILD_LIBSMARTCOLS], [test "x$build_libsmartcols" = xyes])
++AM_CONDITIONAL([BUILD_LIBSMARTCOLS_TESTS], [test "x$build_libsmartcols" = xyes -a "x$enable_static" = xyes])
++
++AC_SUBST([LIBSMARTCOLS_VERSION])
++AC_SUBST([LIBSMARTCOLS_VERSION_INFO])
++AC_DEFINE_UNQUOTED([LIBSMARTCOLS_VERSION], ["$LIBSMARTCOLS_VERSION"], [libsmartcols version string])
++
++
++dnl
+ dnl libfdisk is enabled all time if possible
+ dnl
+ UL_BUILD_INIT([libfdisk], [check])
+@@ -1500,6 +1519,9 @@ libblkid/src/blkid.h
+ libmount/docs/Makefile
+ libmount/docs/version.xml
+ libmount/src/libmount.h
++libsmartcols/docs/Makefile
++libsmartcols/docs/version.xml
++libsmartcols/src/libsmartcols.h
+ po/Makefile.in
+ ])
+ 
+diff -up util-linux-2.23.2/include/carefulputc.h.kzak util-linux-2.23.2/include/carefulputc.h
+--- util-linux-2.23.2/include/carefulputc.h.kzak	2012-11-29 16:18:33.956147961 +0100
++++ util-linux-2.23.2/include/carefulputc.h	2014-09-25 14:41:48.980843829 +0200
+@@ -26,4 +26,39 @@ static inline int carefulputc(int c, FIL
+ 	return (ret < 0) ? EOF : 0;
+ }
+ 
++static inline void fputs_quoted(const char *data, FILE *out)
++{
++	const char *p;
++
++	fputc('"', out);
++	for (p = data; p && *p; p++) {
++		if ((unsigned char) *p == 0x22 ||		/* " */
++		    (unsigned char) *p == 0x5c ||		/* \ */
++		    !isprint((unsigned char) *p) ||
++		    iscntrl((unsigned char) *p)) {
++
++			fprintf(out, "\\x%02x", (unsigned char) *p);
++		} else
++			fputc(*p, out);
++	}
++	fputc('"', out);
++}
++
++static inline void fputs_nonblank(const char *data, FILE *out)
++{
++	const char *p;
++
++	for (p = data; p && *p; p++) {
++		if (isblank((unsigned char) *p) ||
++		    (unsigned char) *p == 0x5c ||		/* \ */
++		    !isprint((unsigned char) *p) ||
++		    iscntrl((unsigned char) *p)) {
++
++			fprintf(out, "\\x%02x", (unsigned char) *p);
++
++		} else
++			fputc(*p, out);
++	}
++}
++
+ #endif  /*  _CAREFUULPUTC_H  */
+diff -up util-linux-2.23.2/include/debug.h.kzak util-linux-2.23.2/include/debug.h
+--- util-linux-2.23.2/include/debug.h.kzak	2014-09-25 14:41:48.981843839 +0200
++++ util-linux-2.23.2/include/debug.h	2014-09-25 14:41:48.981843839 +0200
+@@ -0,0 +1,126 @@
++/*
++ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
++ *
++ * This file may be distributed under the terms of the
++ * GNU Lesser General Public License.
++ */
++#ifndef UTIL_LINUX_DEBUG_H
++#define UTIL_LINUX_DEBUG_H
++
++#include <stdarg.h>
++#include <string.h>
++
++struct dbg_mask { char *mname; int val; };
++#define UL_DEBUG_EMPTY_MASKNAMES {{ NULL, 0 }}
++
++#define UL_DEBUG_DEFINE_MASK(m) int m ## _debug_mask
++#define UL_DEBUG_DECLARE_MASK(m) extern UL_DEBUG_DEFINE_MASK(m)
++#define UL_DEBUG_DEFINE_MASKANEMS(m) static const struct dbg_mask m ## _masknames[]
++
++/* p - flag prefix, m - flag postfix */
++#define UL_DEBUG_DEFINE_FLAG(p, m) p ## m
++
++/* l - library name, p - flag prefix, m - flag postfix, x - function */
++#define __UL_DBG(l, p, m, x) \
++	do { \
++		if ((p ## m) & l ## _debug_mask) { \
++			fprintf(stderr, "%d: %s: %8s: ", getpid(), # l, # m); \
++			x; \
++		} \
++	} while (0)
++
++#define __UL_DBG_CALL(l, p, m, x) \
++	do { \
++		if ((p ## m) & l ## _debug_mask) { \
++			x; \
++		} \
++	} while (0)
++
++#define __UL_DBG_FLUSH(l, p) \
++	do { \
++		if (l ## _debug_mask && \
++		    l ## _debug_mask != p ## INIT) { \
++			fflush(stderr); \
++		} \
++	} while (0)
++
++
++#define __UL_INIT_DEBUG(lib, pref, mask, env) \
++	do { \
++		if (lib ## _debug_mask & pref ## INIT) \
++		; \
++		else if (!mask) { \
++			char *str = getenv(# env); \
++			if (str) \
++				lib ## _debug_mask = parse_envmask(lib ## _masknames, str); \
++		} else \
++			lib ## _debug_mask = mask; \
++		lib ## _debug_mask |= pref ## INIT; \
++		if (lib ## _debug_mask != pref ## INIT) { \
++			__UL_DBG(lib, pref, INIT, ul_debug("library debug mask: 0x%04x", \
++					lib ## _debug_mask)); \
++		} \
++	} while (0)
++
++
++static inline void __attribute__ ((__format__ (__printf__, 1, 2)))
++ul_debug(const char *mesg, ...)
++{
++	va_list ap;
++	va_start(ap, mesg);
++	vfprintf(stderr, mesg, ap);
++	va_end(ap);
++	fputc('\n', stderr);
++}
++
++static inline void __attribute__ ((__format__ (__printf__, 2, 3)))
++ul_debugobj(void *handler, const char *mesg, ...)
++{
++	va_list ap;
++
++	if (handler)
++		fprintf(stderr, "[%p]: ", handler);
++	va_start(ap, mesg);
++	vfprintf(stderr, mesg, ap);
++	va_end(ap);
++	fputc('\n', stderr);
++}
++
++static inline int parse_envmask(const struct dbg_mask const flagnames[],
++				const char *mask)
++{
++	int res;
++	char *ptr;
++
++	/* let's check for a numeric mask first */
++	res = strtoul(mask, &ptr, 0);
++
++	/* perhaps it's a comma-separated string? */
++	if (*ptr != '\0' && flagnames) {
++		char *msbuf, *ms, *name;
++		res = 0;
++
++		ms = msbuf = strdup(mask);
++		if (!ms)
++			return res;
++
++		while ((name = strtok_r(ms, ",", &ptr))) {
++			size_t i = 0;
++			ms = ptr;
++
++			while (flagnames[i].mname) {
++				if (!strcmp(name, flagnames[i].mname)) {
++					res |= flagnames[i].val;
++					break;
++				}
++				++i;
++			}
++			/* nothing else we can do by OR-ing the mask */
++			if (res == 0xffff)
++				break;
++		}
++		free(msbuf);
++	}
++	return res;
++}
++#endif /* UTIL_LINUX_DEBUG_H */
+diff -up util-linux-2.23.2/include/list.h.kzak util-linux-2.23.2/include/list.h
+--- util-linux-2.23.2/include/list.h.kzak	2013-06-13 09:46:10.396650417 +0200
++++ util-linux-2.23.2/include/list.h	2014-09-25 14:41:48.981843839 +0200
+@@ -212,14 +212,16 @@ _INLINE_ void list_splice(struct list_he
+  * sentinel head node, "prev" links not maintained.
+  */
+ _INLINE_ struct list_head *merge(int (*cmp)(struct list_head *a,
+-					  struct list_head *b),
++					  struct list_head *b,
++					  void *data),
++			       void *data,
+ 			       struct list_head *a, struct list_head *b)
+ {
+ 	struct list_head head, *tail = &head;
+ 
+ 	while (a && b) {
+ 		/* if equal, take 'a' -- important for sort stability */
+-		if ((*cmp)(a, b) <= 0) {
++		if ((*cmp)(a, b, data) <= 0) {
+ 			tail->next = a;
+ 			a = a->next;
+ 		} else {
+@@ -240,7 +242,9 @@ _INLINE_ struct list_head *merge(int (*c
+  * throughout.
+  */
+ _INLINE_ void merge_and_restore_back_links(int (*cmp)(struct list_head *a,
+-						    struct list_head *b),
++						    struct list_head *b,
++						    void *data),
++					 void *data,
+ 					 struct list_head *head,
+ 					 struct list_head *a, struct list_head *b)
+ {
+@@ -248,7 +252,7 @@ _INLINE_ void merge_and_restore_back_lin
+ 
+ 	while (a && b) {
+ 		/* if equal, take 'a' -- important for sort stability */
+-		if ((*cmp)(a, b) <= 0) {
++		if ((*cmp)(a, b, data) <= 0) {
+ 			tail->next = a;
+ 			a->prev = tail;
+ 			a = a->next;
+@@ -268,7 +272,7 @@ _INLINE_ void merge_and_restore_back_lin
+ 		 * element comparison is needed, so the client's cmp()
+ 		 * routine can invoke cond_resched() periodically.
+ 		 */
+-		(*cmp)(tail->next, tail->next);
++		(*cmp)(tail->next, tail->next, data);
+ 
+ 		tail->next->prev = tail;
+ 		tail = tail->next;
+@@ -294,7 +298,9 @@ _INLINE_ void merge_and_restore_back_lin
+  */
+ _INLINE_ void list_sort(struct list_head *head,
+ 			int (*cmp)(struct list_head *a,
+-				   struct list_head *b))
++				   struct list_head *b,
++				   void *data),
++			void *data)
+ {
+ 	struct list_head *part[MAX_LIST_LENGTH_BITS+1]; /* sorted partial lists
+ 							   -- last slot is a sentinel */
+@@ -316,7 +322,7 @@ _INLINE_ void list_sort(struct list_head
+ 		cur->next = NULL;
+ 
+ 		for (lev = 0; part[lev]; lev++) {
+-			cur = merge(cmp, part[lev], cur);
++			cur = merge(cmp, data, part[lev], cur);
+ 			part[lev] = NULL;
+ 		}
+ 		if (lev > max_lev) {
+@@ -330,11 +336,12 @@ _INLINE_ void list_sort(struct list_head
+ 
+ 	for (lev = 0; lev < max_lev; lev++)
+ 		if (part[lev])
+-			list = merge(cmp, part[lev], list);
++			list = merge(cmp, data, part[lev], list);
+ 
+-	merge_and_restore_back_links(cmp, head, part[max_lev], list);
++	merge_and_restore_back_links(cmp, data, head, part[max_lev], list);
+ }
+ 
++
+ #undef _INLINE_
+ 
+ #endif /* UTIL_LINUX_LIST_H */
+diff -up util-linux-2.23.2/include/mbsalign.h.kzak util-linux-2.23.2/include/mbsalign.h
+--- util-linux-2.23.2/include/mbsalign.h.kzak	2013-06-13 09:46:10.397650425 +0200
++++ util-linux-2.23.2/include/mbsalign.h	2014-09-25 14:41:48.981843839 +0200
+@@ -1,5 +1,6 @@
+ /* Align/Truncate a string in a given screen width
+    Copyright (C) 2009-2010 Free Software Foundation, Inc.
++   Copyright (C) 2010-2013 Karel Zak <kzak@redhat.com>
+ 
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+@@ -13,8 +14,9 @@
+ 
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+-
+-#include <stddef.h>
++#ifndef UTIL_LINUX_MBSALIGN_H
++# define UTIL_LINUX_MBSALIGN_H
++# include <stddef.h>
+ 
+ typedef enum { MBS_ALIGN_LEFT, MBS_ALIGN_RIGHT, MBS_ALIGN_CENTER } mbs_align_t;
+ 
+@@ -43,3 +45,12 @@ extern size_t mbs_truncate(char *str, si
+ extern size_t mbsalign (const char *src, char *dest,
+ 			size_t dest_size,  size_t *width,
+ 			mbs_align_t align, int flags);
++
++extern size_t mbs_safe_nwidth(const char *buf, size_t bufsz, size_t *sz);
++extern size_t mbs_safe_width(const char *s);
++
++extern char *mbs_safe_encode(const char *s, size_t *width);
++extern char *mbs_safe_encode_to_buffer(const char *s, size_t *width, char *buf);
++extern size_t mbs_safe_encode_size(size_t bytes);
++
++#endif /* UTIL_LINUX_MBSALIGN_H */
+diff -up util-linux-2.23.2/lib/mbsalign.c.kzak util-linux-2.23.2/lib/mbsalign.c
+--- util-linux-2.23.2/lib/mbsalign.c.kzak	2013-07-30 10:39:26.203738210 +0200
++++ util-linux-2.23.2/lib/mbsalign.c	2014-09-25 14:41:48.982843848 +0200
+@@ -23,17 +23,193 @@
+ #include <stdio.h>
+ #include <stdbool.h>
+ #include <limits.h>
++#include <ctype.h>
+ 
+ #include "c.h"
+ #include "mbsalign.h"
+ #include "widechar.h"
+ 
+-
+ #ifdef HAVE_WIDECHAR
+ /* Replace non printable chars.
+    Note \t and \n etc. are non printable.
+    Return 1 if replacement made, 0 otherwise.  */
+ 
++/*
++ * Counts number of cells in multibyte string. For all control and
++ * non-printable chars is the result width enlarged to store \x?? hex
++ * sequence. See mbs_safe_encode().
++ *
++ * Returns: number of cells, @sz returns number of bytes.
++ */
++size_t mbs_safe_nwidth(const char *buf, size_t bufsz, size_t *sz)
++{
++	mbstate_t st;
++	const char *p = buf, *last = buf;
++	size_t width = 0, bytes = 0;
++
++	memset(&st, 0, sizeof(st));
++
++	if (p && *p && bufsz)
++		last = p + (bufsz - 1);
++
++	while (p && *p && p <= last) {
++		if (iscntrl((unsigned char) *p)) {
++			width += 4, bytes += 4;		/* *p encoded to \x?? */
++			p++;
++		}
++#ifdef HAVE_WIDECHAR
++		else {
++			wchar_t wc;
++			size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st);
++
++			if (len == 0)
++				break;
++
++			if (len == (size_t) -1 || len == (size_t) -2) {
++				len = 1;
++				if (isprint((unsigned char) *p))
++					width += 1, bytes += 1;
++				else
++					width += 4, bytes += 4;
++
++			} else if (!iswprint(wc)) {
++				width += len * 4;	/* hex encode whole sequence */
++				bytes += len * 4;
++			} else {
++				width += wcwidth(wc);	/* number of cells */
++				bytes += len;		/* number of bytes */
++			}
++			p += len;
++		}
++#else
++		else if (!isprint((unsigned char) *p)) {
++			width += 4, bytes += 4;		/* *p encoded to \x?? */
++			p++;
++		} else {
++			width++, bytes++;
++			p++;
++		}
++#endif
++	}
++
++	if (sz)
++		*sz = bytes;
++	return width;
++}
++
++size_t mbs_safe_width(const char *s)
++{
++	if (!s || !*s)
++		return 0;
++	return mbs_safe_nwidth(s, strlen(s), NULL);
++}
++
++/*
++ * Copy @s to @buf and replace control and non-printable chars with
++ * \x?? hex sequence. The @width returns number of cells.
++ *
++ * The @buf has to be big enough to store mbs_safe_encode_size(strlen(s)))
++ * bytes.
++ */
++char *mbs_safe_encode_to_buffer(const char *s, size_t *width, char *buf)
++{
++	mbstate_t st;
++	const char *p = s;
++	char *r;
++	size_t sz = s ? strlen(s) : 0;
++
++	if (!sz || !buf)
++		return NULL;
++
++	memset(&st, 0, sizeof(st));
++
++	r = buf;
++	*width = 0;
++
++	while (p && *p) {
++		if (iscntrl((unsigned char) *p)) {
++			sprintf(r, "\\x%02x", (unsigned char) *p);
++			r += 4;
++			*width += 4;
++			p++;
++		}
++#ifdef HAVE_WIDECHAR
++		else {
++			wchar_t wc;
++			size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st);
++
++			if (len == 0)
++				break;		/* end of string */
++
++			if (len == (size_t) -1 || len == (size_t) -2) {
++				len = 1;
++				/*
++				 * Not valid multibyte sequence -- maybe it's
++				 * printable char according to the current locales.
++				 */
++				if (!isprint((unsigned char) *p)) {
++					sprintf(r, "\\x%02x", (unsigned char) *p);
++					r += 4;
++					*width += 4;
++				} else {
++					width++;
++					*r++ = *p;
++				}
++			} else if (!iswprint(wc)) {
++				size_t i;
++				for (i = 0; i < len; i++) {
++					sprintf(r, "\\x%02x", (unsigned char) *p);
++					r += 4;
++					*width += 4;
++				}
++			} else {
++				memcpy(r, p, len);
++				r += len;
++				*width += wcwidth(wc);
++			}
++			p += len;
++		}
++#else
++		else if (!isprint((unsigned char) *p)) {
++			sprintf(r, "\\x%02x", (unsigned char) *p);
++			p++;
++			r += 4;
++			*width += 4;
++		} else {
++			*r++ = *p++;
++			*width++;
++		}
++#endif
++	}
++
++	*r = '\0';
++
++	return buf;
++}
++
++size_t mbs_safe_encode_size(size_t bytes)
++{
++	return (bytes * 4) + 1;
++}
++
++/*
++ * Returns allocated string where all control and non-printable chars are
++ * replaced with \x?? hex sequence.
++ */
++char *mbs_safe_encode(const char *s, size_t *width)
++{
++	size_t sz = s ? strlen(s) : 0;
++	char *buf;
++
++	if (!sz)
++		return NULL;
++	buf = malloc(mbs_safe_encode_size(sz));
++	if (!buf)
++		return NULL;
++
++	return mbs_safe_encode_to_buffer(s, width, buf);
++}
++
+ static bool
+ wc_ensure_printable (wchar_t *wchars)
+ {
+@@ -254,8 +430,8 @@ mbsalign_unibyte:
+   if (dest_size != 0)
+     {
+       char *dest_end = dest + dest_size - 1;
+-      size_t start_spaces = n_spaces / 2 + n_spaces % 2;
+-      size_t end_spaces = n_spaces / 2;
++      size_t start_spaces;
++      size_t end_spaces;
+ 
+       switch (align)
+         {
+diff -up util-linux-2.23.2/libsmartcols/COPYING.kzak util-linux-2.23.2/libsmartcols/COPYING
+--- util-linux-2.23.2/libsmartcols/COPYING.kzak	2014-09-25 14:41:48.983843858 +0200
++++ util-linux-2.23.2/libsmartcols/COPYING	2014-09-25 14:41:48.983843858 +0200
+@@ -0,0 +1,8 @@
++This library is free software; you can redistribute it and/or
++modify it under the terms of the GNU Lesser General Public
++License as published by the Free Software Foundation; either
++version 2.1 of the License, or (at your option) any later
++version.
++
++The complete text of the license is available in the
++../Documentation/licenses/COPYING.LGPLv2.1 file.
+diff -up util-linux-2.23.2/libsmartcols/docs/.gitignore.kzak util-linux-2.23.2/libsmartcols/docs/.gitignore
+--- util-linux-2.23.2/libsmartcols/docs/.gitignore.kzak	2014-09-25 14:41:48.983843858 +0200
++++ util-linux-2.23.2/libsmartcols/docs/.gitignore	2014-09-25 14:41:48.983843858 +0200
+@@ -0,0 +1,18 @@
++*-decl-list.txt
++*-decl.txt
++*-overrides.txt
++*-undeclared.txt
++*-undocumented.txt
++*-unused.txt
++*.args
++*.bak
++*.hierarchy
++*.interfaces
++*.prerequisites
++*.signals
++*.stamp
++*.types
++html/*
++tmpl/*
++version.xml
++xml/*
+diff -up util-linux-2.23.2/libsmartcols/docs/libsmartcols-docs.xml.kzak util-linux-2.23.2/libsmartcols/docs/libsmartcols-docs.xml
+--- util-linux-2.23.2/libsmartcols/docs/libsmartcols-docs.xml.kzak	2014-09-25 14:41:48.984843867 +0200
++++ util-linux-2.23.2/libsmartcols/docs/libsmartcols-docs.xml	2014-09-25 14:41:48.984843867 +0200
+@@ -0,0 +1,52 @@
++<?xml version="1.0"?>
++<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
++               "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
++[
++  <!ENTITY version SYSTEM "version.xml">
++]>
++<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
++  <bookinfo>
++    <title>libsmartcols Reference Manual</title>
++    <releaseinfo>for libsmartcols version &version;</releaseinfo>
++    <copyright>
++      <year>2014</year>
++      <holder>Karel Zak &lt;kzak@redhat.com&gt;</holder>
++    </copyright>
++  </bookinfo>
++
++  <part id="gtk">
++    <title>libsmartcols Overview</title>
++    <partintro>
++    <para>
++The libsmartcols library is used for smart adaptive formatting of tabular data.
++    </para>
++    <para>
++The library is part of the util-linux package since version 2.25 and is
++available from ftp://ftp.kernel.org/pub/linux/utils/util-linux/.
++    </para>
++  </partintro>
++ </part>
++
++  <part>
++    <title>Data manipulation</title>
++    <xi:include href="xml/table.xml"/>
++    <xi:include href="xml/column.xml"/>
++    <xi:include href="xml/line.xml"/>
++    <xi:include href="xml/cell.xml"/>
++    <xi:include href="xml/symbols.xml"/>
++  </part>
++  <part>
++    <title>Printing</title>
++    <xi:include href="xml/table_print.xml"/>
++  </part>
++  <part>
++    <title>Misc</title>
++    <xi:include href="xml/iter.xml"/>
++    <xi:include href="xml/version-utils.xml"/>
++    <xi:include href="xml/init.xml"/>
++  </part>
++  <index id="api-index-full">
++    <title>API Index</title>
++    <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
++  </index>
++</book>
+diff -up util-linux-2.23.2/libsmartcols/docs/libsmartcols-sections.txt.kzak util-linux-2.23.2/libsmartcols/docs/libsmartcols-sections.txt
+--- util-linux-2.23.2/libsmartcols/docs/libsmartcols-sections.txt.kzak	2014-09-25 14:41:48.984843867 +0200
++++ util-linux-2.23.2/libsmartcols/docs/libsmartcols-sections.txt	2014-09-25 14:41:48.984843867 +0200
+@@ -0,0 +1,146 @@
++<SECTION>
++<FILE>cell</FILE>
++libscols_cell
++scols_cell_copy_content
++scols_cell_get_color
++scols_cell_get_data
++scols_cell_get_userdata
++scols_cell_refer_data
++scols_cell_set_color
++scols_cell_set_data
++scols_cell_set_userdata
++scols_cmpstr_cells
++scols_reset_cell
++</SECTION>
++
++<SECTION>
++<FILE>column</FILE>
++libscols_column
++scols_column_get_color
++scols_column_get_flags
++scols_column_get_header
++scols_column_get_whint
++scols_column_is_noextremes
++scols_column_is_right
++scols_column_is_strict_width
++scols_column_is_tree
++scols_column_is_trunc
++scols_column_set_cmpfunc
++scols_column_set_color
++scols_column_set_flags
++scols_column_set_whint
++scols_copy_column
++scols_new_column
++scols_ref_column
++scols_unref_column
++</SECTION>
++
++<SECTION>
++<FILE>iter</FILE>
++libscols_iter
++scols_free_iter
++scols_iter_get_direction
++scols_new_iter
++scols_reset_iter
++</SECTION>
++
++<SECTION>
++<FILE>line</FILE>
++libscols_line
++scols_copy_line
++scols_line_add_child
++scols_line_alloc_cells
++scols_line_free_cells
++scols_line_get_cell
++scols_line_get_color
++scols_line_get_column_cell
++scols_line_get_ncells
++scols_line_get_parent
++scols_line_get_userdata
++scols_line_has_children
++scols_line_next_child
++scols_line_refer_data
++scols_line_remove_child
++scols_line_set_color
++scols_line_set_data
++scols_line_set_userdata
++scols_new_line
++scols_ref_line
++scols_unref_line
++</SECTION>
++
++<SECTION>
++<FILE>symbols</FILE>
++libscols_symbols
++scols_copy_symbols
++scols_new_symbols
++scols_ref_symbols
++scols_symbols_set_branch
++scols_symbols_set_right
++scols_symbols_set_vertical
++scols_unref_symbols
++</SECTION>
++
++<SECTION>
++<FILE>table</FILE>
++libscols_table
++scols_copy_table
++scols_new_table
++scols_ref_table
++scols_table_add_column
++scols_table_add_line
++scols_table_colors_wanted
++scols_table_enable_ascii
++scols_table_enable_colors
++scols_table_enable_export
++scols_table_enable_maxout
++scols_table_enable_noheadings
++scols_table_enable_raw
++scols_table_get_column
++scols_table_get_column_separator
++scols_table_get_line
++scols_table_get_line_separator
++scols_table_get_ncols
++scols_table_get_nlines
++scols_table_get_stream
++scols_table_is_ascii
++scols_table_is_empty
++scols_table_is_export
++scols_table_is_maxout
++scols_table_is_noheadings
++scols_table_is_raw
++scols_table_is_tree
++scols_table_new_column
++scols_table_new_line
++scols_table_next_column
++scols_table_next_line
++scols_table_reduce_termwidth
++scols_table_remove_column
++scols_table_remove_columns
++scols_table_remove_line
++scols_table_remove_lines
++scols_table_set_column_separator
++scols_table_set_line_separator
++scols_table_set_stream
++scols_table_set_symbols
++scols_sort_table
++scols_unref_table
++</SECTION>
++
++<SECTION>
++<FILE>table_print</FILE>
++scols_print_table
++scols_print_table_to_string
++</SECTION>
++
++<SECTION>
++<FILE>version-utils</FILE>
++scols_get_library_version
++scols_parse_version_string
++LIBSMARTCOLS_VERSION
++</SECTION>
++
++<SECTION>
++<FILE>init</FILE>
++scols_init_debug
++</SECTION>
+diff -up util-linux-2.23.2/libsmartcols/docs/Makefile.am.kzak util-linux-2.23.2/libsmartcols/docs/Makefile.am
+--- util-linux-2.23.2/libsmartcols/docs/Makefile.am.kzak	2014-09-25 14:41:48.984843867 +0200
++++ util-linux-2.23.2/libsmartcols/docs/Makefile.am	2014-09-25 14:41:48.984843867 +0200
+@@ -0,0 +1,93 @@
++## Process this file with automake to produce Makefile.in
++
++# We require automake 1.10 at least.
++AUTOMAKE_OPTIONS = 1.10
++
++# This is a blank Makefile.am for using gtk-doc.
++# Copy this to your project's API docs directory and modify the variables to
++# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples
++# of using the various options.
++
++# The name of the module, e.g. 'glib'.
++DOC_MODULE=libsmartcols
++
++# Uncomment for versioned docs and specify the version of the module, e.g. '2'.
++#DOC_MODULE_VERSION=2
++
++# The top-level SGML file. You can change this if you want to.
++DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml
++
++# The directory containing the source code. Relative to $(srcdir).
++# gtk-doc will search all .c & .h files beneath here for inline comments
++# documenting the functions and macros.
++# e.g. DOC_SOURCE_DIR=../../../gtk
++DOC_SOURCE_DIR=../src
++
++# Extra options to pass to gtkdoc-scangobj. Not normally needed.
++SCANGOBJ_OPTIONS=
++
++# Extra options to supply to gtkdoc-scan.
++# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
++SCAN_OPTIONS=
++
++# Extra options to supply to gtkdoc-mkdb.
++# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml
++MKDB_OPTIONS=--sgml-mode --output-format=xml --name-space mnt
++
++# Extra options to supply to gtkdoc-mktmpl
++# e.g. MKTMPL_OPTIONS=--only-section-tmpl
++MKTMPL_OPTIONS=
++
++# Extra options to supply to gtkdoc-mkhtml
++MKHTML_OPTIONS=
++
++# Extra options to supply to gtkdoc-fixref. Not normally needed.
++# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html
++FIXXREF_OPTIONS=
++
++# Used for dependencies. The docs will be rebuilt if any of these change.
++# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h
++# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c
++HFILE_GLOB=$(top_builddir)/libsmartcols/src/libsmartcols.h
++CFILE_GLOB=$(top_srcdir)/libsmartcols/src/*.c
++
++# Extra header to include when scanning, which are not under DOC_SOURCE_DIR
++# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h
++EXTRA_HFILES=
++
++# Header files to ignore when scanning. Use base file name, no paths
++# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h
++IGNORE_HFILES=smartcolsP.h
++
++# Images to copy into HTML directory.
++# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
++HTML_IMAGES=
++
++# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
++# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
++content_files = $(builddir)/version.xml
++
++# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
++# These files must be listed here *and* in content_files
++# e.g. expand_content_files=running.sgml
++expand_content_files=
++
++# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
++# Only needed if you are using gtkdoc-scangobj to dynamically query widget
++# signals and properties.
++# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
++# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
++GTKDOC_CFLAGS=
++GTKDOC_LIBS=
++
++# This includes the standard gtk-doc make rules, copied by gtkdocize.
++include $(top_srcdir)/config/gtk-doc.make
++
++# Other files to distribute
++# e.g. EXTRA_DIST += version.xml.in
++EXTRA_DIST += version.xml.in
++
++# Files not to distribute
++# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
++# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
++DISTCLEANFILES += version.xml
+diff -up util-linux-2.23.2/libsmartcols/docs/version.xml.in.kzak util-linux-2.23.2/libsmartcols/docs/version.xml.in
+--- util-linux-2.23.2/libsmartcols/docs/version.xml.in.kzak	2014-09-25 14:41:48.985843877 +0200
++++ util-linux-2.23.2/libsmartcols/docs/version.xml.in	2014-09-25 14:41:48.984843867 +0200
+@@ -0,0 +1 @@
++@VERSION@
+diff -up util-linux-2.23.2/libsmartcols/Makemodule.am.kzak util-linux-2.23.2/libsmartcols/Makemodule.am
+--- util-linux-2.23.2/libsmartcols/Makemodule.am.kzak	2014-09-25 14:41:48.983843858 +0200
++++ util-linux-2.23.2/libsmartcols/Makemodule.am	2014-09-25 14:41:48.983843858 +0200
+@@ -0,0 +1,14 @@
++if BUILD_LIBSMARTCOLS
++
++include libsmartcols/src/Makemodule.am
++
++if ENABLE_GTK_DOC
++# Docs uses separate Makefiles
++SUBDIRS += libsmartcols/docs
++endif
++
++# noinst for RHEL7: pkgconfig_DATA += libsmartcols/smartcols.pc
++PATHFILES      += libsmartcols/smartcols.pc
++EXTRA_DIST     += libsmartcols/COPYING
++
++endif # BUILD_LIBSMARTCOLS
+diff -up util-linux-2.23.2/libsmartcols/smartcols.pc.in.kzak util-linux-2.23.2/libsmartcols/smartcols.pc.in
+--- util-linux-2.23.2/libsmartcols/smartcols.pc.in.kzak	2014-09-25 14:41:48.985843877 +0200
++++ util-linux-2.23.2/libsmartcols/smartcols.pc.in	2014-09-25 14:41:48.985843877 +0200
+@@ -0,0 +1,10 @@
++prefix=@prefix@
++exec_prefix=@exec_prefix@
++libdir=@usrlib_execdir@
++includedir=@includedir@
++
++Name: smartcols
++Description: table or tree library
++Version: @LIBSMARTCOLS_VERSION@
++Cflags: -I${includedir}/libsmartcols
++Libs: -L${libdir} -lsmartcols
+diff -up util-linux-2.23.2/libsmartcols/src/cell.c.kzak util-linux-2.23.2/libsmartcols/src/cell.c
+--- util-linux-2.23.2/libsmartcols/src/cell.c.kzak	2014-09-25 14:41:48.986843886 +0200
++++ util-linux-2.23.2/libsmartcols/src/cell.c	2014-09-25 14:41:48.986843886 +0200
+@@ -0,0 +1,242 @@
++/*
++ * cell.c - functions for table handling at the cell level
++ *
++ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
++ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
++ *
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ */
++
++/**
++ * SECTION: cell
++ * @title: Cell
++ * @short_description: cell API
++ *
++ * An API to access and modify per-cell data and information. Note that cell is
++ * always part of the line. If you destroy (un-reference) a line than it
++ * destroys all line cells too.
++ */
++
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <ctype.h>
++
++#include "smartcolsP.h"
++
++/*
++ * The cell has no ref-counting, free() and new() functions. All is
++ * handled by libscols_line.
++ */
++
++/**
++ * scols_reset_cell:
++ * @ce: pointer to a struct libscols_cell instance
++ *
++ * Frees the cell's internal data and resets its status.
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_reset_cell(struct libscols_cell *ce)
++{
++	assert(ce);
++
++	if (!ce)
++		return -EINVAL;
++
++	/*DBG(CELL, ul_debugobj(ce, "reset"));*/
++	free(ce->data);
++	free(ce->color);
++	memset(ce, 0, sizeof(*ce));
++	return 0;
++}
++
++/**
++ * scols_cell_set_data:
++ * @ce: a pointer to a struct libscols_cell instance
++ * @str: data (used for scols_printtable())
++ *
++ * Stores a copy of the @str in @ce.
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_cell_set_data(struct libscols_cell *ce, const char *str)
++{
++	char *p = NULL;
++
++	assert(ce);
++
++	if (!ce)
++		return -EINVAL;
++	if (str) {
++		p = strdup(str);
++		if (!p)
++			return -ENOMEM;
++	}
++	free(ce->data);
++	ce->data = p;
++	return 0;
++}
++
++/**
++ * scols_cell_refer_data:
++ * @ce: a pointer to a struct libscols_cell instance
++ * @str: data (used for scols_printtable())
++ *
++ * Adds a reference to @str to @ce. The pointer is deallocated by
++ * scols_reset_cell() or scols_unref_line(). This function is mostly designed
++ * for situations when the data for the cell are already composed in allocated
++ * memory (e.g. asprintf()) to avoid extra unnecessary strdup().
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_cell_refer_data(struct libscols_cell *ce, char *str)
++{
++	assert(ce);
++
++	if (!ce)
++		return -EINVAL;
++	free(ce->data);
++	ce->data = str;
++	return 0;
++}
++
++/**
++ * scols_cell_get_data:
++ * @ce: a pointer to a struct libscols_cell instance
++ *
++ * Returns: data in @ce or NULL.
++ */
++const char *scols_cell_get_data(const struct libscols_cell *ce)
++{
++	assert(ce);
++	return ce ? ce->data : NULL;
++}
++
++/**
++ * scols_cell_set_userdata:
++ * @ce: a pointer to a struct libscols_cell instance
++ * @data: private user data
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_cell_set_userdata(struct libscols_cell *ce, void *data)
++{
++	assert(ce);
++
++	if (!ce)
++		return -EINVAL;
++	ce->userdata = data;
++	return 0;
++}
++
++/**
++ * scols_cell_get_userdata
++ * @ce: a pointer to a struct libscols_cell instance
++ *
++ * Returns: user data
++ */
++void *scols_cell_get_userdata(struct libscols_cell *ce)
++{
++	return ce ? ce->userdata : NULL;
++}
++
++/**
++ * scols_cmpstr_cells:
++ * @a: pointer to cell
++ * @b: pointer to cell
++ * @data: unused pointer to private data (defined by API)
++ *
++ * Compares cells data by strcmp(). The function is designed for
++ * scols_column_set_cmpfunc() and scols_sort_table().
++ *
++ * Returns: follows strcmp() return values.
++ */
++int scols_cmpstr_cells(struct libscols_cell *a,
++		       struct libscols_cell *b,
++		       __attribute__((__unused__)) void *data)
++{
++	const char *adata, *bdata;
++
++	if (a == b)
++		return 0;
++
++	adata = scols_cell_get_data(a);
++	bdata = scols_cell_get_data(b);
++
++	if (adata == NULL && bdata == NULL)
++		return 0;
++	if (adata == NULL)
++		return -1;
++	if (bdata == NULL)
++		return 1;
++	return strcmp(adata, bdata);
++}
++
++/**
++ * scols_cell_set_color:
++ * @ce: a pointer to a struct libscols_cell instance
++ * @color: ESC sequence
++ *
++ * Set the color of @ce to @color.
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_cell_set_color(struct libscols_cell *ce, const char *color)
++{
++	char *p = NULL;
++
++	assert(ce);
++
++	if (!ce)
++		return -EINVAL;
++	if (color) {
++		p = strdup(color);
++		if (!p)
++			return -ENOMEM;
++	}
++	free(ce->color);
++	ce->color = p;
++	return 0;
++}
++
++/**
++ * scols_cell_get_color:
++ * @ce: a pointer to a struct libscols_cell instance
++ *
++ * Returns: the current color of @ce.
++ */
++const char *scols_cell_get_color(const struct libscols_cell *ce)
++{
++	assert(ce);
++	return ce ? ce->color : NULL;
++}
++
++/**
++ * scols_cell_copy_content:
++ * @dest: a pointer to a struct libscols_cell instance
++ * @src: a pointer to an immutable struct libscols_cell instance
++ *
++ * Copy the contents of @src into @dest.
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_cell_copy_content(struct libscols_cell *dest,
++			    const struct libscols_cell *src)
++{
++	int rc;
++
++	assert(dest);
++	assert(src);
++
++	rc = scols_cell_set_data(dest, scols_cell_get_data(src));
++	if (!rc)
++		rc = scols_cell_set_color(dest, scols_cell_get_color(src));
++	if (!rc)
++		dest->userdata = src->userdata;
++
++	DBG(CELL, ul_debugobj((void *) src, "copy into %p", dest));
++	return rc;
++}
+diff -up util-linux-2.23.2/libsmartcols/src/column.c.kzak util-linux-2.23.2/libsmartcols/src/column.c
+--- util-linux-2.23.2/libsmartcols/src/column.c.kzak	2014-09-25 14:41:48.986843886 +0200
++++ util-linux-2.23.2/libsmartcols/src/column.c	2014-09-25 14:41:48.986843886 +0200
+@@ -0,0 +1,337 @@
++/*
++ * column.c - functions for table handling at the column level
++ *
++ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
++ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
++ *
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ */
++
++/**
++ * SECTION: column
++ * @title: Column
++ * @short_description: column API
++ *
++ * An API to access and modify per-column data and information.
++ */
++
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <ctype.h>
++
++#include "smartcolsP.h"
++
++/**
++ * scols_new_column:
++ *
++ * Allocates space for a new column.
++ *
++ * Returns: a pointer to a new struct libscols_cell instance, NULL in case of an ENOMEM error.
++ */
++struct libscols_column *scols_new_column(void)
++{
++	struct libscols_column *cl;
++
++	cl = calloc(1, sizeof(*cl));
++	if (!cl)
++		return NULL;
++	DBG(COL, ul_debugobj(cl, "alloc"));
++	cl->refcount = 1;
++	INIT_LIST_HEAD(&cl->cl_columns);
++	return cl;
++}
++
++/**
++ * scols_ref_column:
++ * @cl: a pointer to a struct libscols_column instance
++ *
++ * Increases the refcount of @cl.
++ */
++void scols_ref_column(struct libscols_column *cl)
++{
++	if (cl)
++		cl->refcount++;
++}
++
++/**
++ * scols_unref_column:
++ * @cl: a pointer to a struct libscols_column instance
++ *
++ * Decreases the refcount of @cl. When the count falls to zero, the instance
++ * is automatically deallocated.
++ */
++void scols_unref_column(struct libscols_column *cl)
++{
++	if (cl && --cl->refcount <= 0) {
++		DBG(COL, ul_debugobj(cl, "dealloc"));
++		list_del(&cl->cl_columns);
++		scols_reset_cell(&cl->header);
++		free(cl->color);
++		free(cl);
++	}
++}
++
++/**
++ * scols_copy_column:
++ * @cl: a pointer to a struct libscols_column instance
++ *
++ * Creates a new column and copies @cl's data over to it.
++ *
++ * Returns: a pointer to a new struct libscols_column instance.
++ */
++struct libscols_column *scols_copy_column(const struct libscols_column *cl)
++{
++	struct libscols_column *ret;
++
++	assert (cl);
++	if (!cl)
++		return NULL;
++	ret = scols_new_column();
++	if (!ret)
++		return NULL;
++
++	DBG(COL, ul_debugobj((void *) cl, "copy to %p", ret));
++
++	if (scols_column_set_color(ret, cl->color))
++		goto err;
++	if (scols_cell_copy_content(&ret->header, &cl->header))
++		goto err;
++
++	ret->width	= cl->width;
++	ret->width_min	= cl->width_min;
++	ret->width_max	= cl->width_max;
++	ret->width_avg	= cl->width_avg;
++	ret->width_hint	= cl->width_hint;
++	ret->flags	= cl->flags;
++	ret->is_extreme = cl->is_extreme;
++
++	return ret;
++err:
++	scols_unref_column(ret);
++	return NULL;
++}
++
++/**
++ * scols_column_set_whint:
++ * @cl: a pointer to a struct libscols_column instance
++ * @whint: a width hint
++ *
++ * Sets the width hint of column @cl to @whint.
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_column_set_whint(struct libscols_column *cl, double whint)
++{
++	assert(cl);
++
++	if (!cl)
++		return -EINVAL;
++
++	cl->width_hint = whint;
++	return 0;
++}
++
++/**
++ * scols_column_get_whint:
++ * @cl: a pointer to a struct libscols_column instance
++ *
++ * Returns: The width hint of column @cl, a negative value in case of an error.
++ */
++double scols_column_get_whint(struct libscols_column *cl)
++{
++	assert(cl);
++	return cl ? cl->width_hint : -EINVAL;
++}
++
++/**
++ * scols_column_set_flags:
++ * @cl: a pointer to a struct libscols_column instance
++ * @flags: a flag mask
++ *
++ * Sets the flags of @cl to @flags.
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_column_set_flags(struct libscols_column *cl, int flags)
++{
++	assert(cl);
++
++	if (!cl)
++		return -EINVAL;
++
++	cl->flags = flags;
++	return 0;
++}
++
++/**
++ * scols_column_get_flags:
++ * @cl: a pointer to a struct libscols_column instance
++ *
++ * Returns: The flag mask of @cl, a negative value in case of an error.
++ */
++int scols_column_get_flags(struct libscols_column *cl)
++{
++	assert(cl);
++	return cl ? cl->flags : -EINVAL;
++}
++
++/**
++ * scols_column_get_header:
++ * @cl: a pointer to a struct libscols_column instance
++ *
++ * Returns: A pointer to a struct libscols_cell instance, representing the
++ * header info of column @cl or NULL in case of an error.
++ */
++struct libscols_cell *scols_column_get_header(struct libscols_column *cl)
++{
++	assert(cl);
++	return cl ? &cl->header : NULL;
++}
++
++/**
++ * scols_column_set_color:
++ * @cl: a pointer to a struct libscols_column instance
++ * @color: ESC sequence
++ *
++ * The default color for data cells and column header.
++ *
++ * If you want to set header specific color then use scols_column_get_header()
++ * and scols_cell_set_color().
++ *
++ * If you want to set data cell specific color the use scols_line_get_cell() +
++ * scols_cell_set_color().
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_column_set_color(struct libscols_column *cl, const char *color)
++{
++	char *p = NULL;
++
++	assert(cl);
++	if (!cl)
++		return -EINVAL;
++	if (color) {
++		p = strdup(color);
++		if (!p)
++			return -ENOMEM;
++	}
++
++	free(cl->color);
++	cl->color = p;
++	return 0;
++}
++
++/**
++ * scols_column_get_color:
++ * @cl: a pointer to a struct libscols_column instance
++ *
++ * Returns: The current color setting of the column @cl.
++ */
++const char *scols_column_get_color(struct libscols_column *cl)
++{
++	assert(cl);
++	return cl ? cl->color : NULL;
++}
++
++
++/**
++ * scols_column_set_cmpfunc:
++ * @cl: column
++ * @cmp: pointer to compare function
++ * @data: private data for cmp function
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_column_set_cmpfunc(struct libscols_column *cl,
++			int (*cmp)(struct libscols_cell *,
++				   struct libscols_cell *,
++				   void *),
++			void *data)
++{
++	assert(cl);
++	if (!cl)
++		return -EINVAL;
++
++	cl->cmpfunc = cmp;
++	cl->cmpfunc_data = data;
++	return 0;
++}
++
++/**
++ * scols_column_is_trunc:
++ * @cl: a pointer to a struct libscols_column instance
++ *
++ * Gets the value of @cl's flag trunc.
++ *
++ * Returns: trunc flag value, negative value in case of an error.
++ */
++int scols_column_is_trunc(struct libscols_column *cl)
++{
++	assert(cl);
++	if (!cl)
++		return -EINVAL;
++	return cl->flags & SCOLS_FL_TRUNC;
++}
++/**
++ * scols_column_is_tree:
++ * @cl: a pointer to a struct libscols_column instance
++ *
++ * Gets the value of @cl's flag tree.
++ *
++ * Returns: tree flag value, negative value in case of an error.
++ */
++int scols_column_is_tree(struct libscols_column *cl)
++{
++	assert(cl);
++	if (!cl)
++		return -EINVAL;
++	return cl->flags & SCOLS_FL_TREE;
++}
++/**
++ * scols_column_is_right:
++ * @cl: a pointer to a struct libscols_column instance
++ *
++ * Gets the value of @cl's flag right.
++ *
++ * Returns: right flag value, negative value in case of an error.
++ */
++int scols_column_is_right(struct libscols_column *cl)
++{
++	assert(cl);
++	if (!cl)
++		return -EINVAL;
++	return cl->flags & SCOLS_FL_RIGHT;
++}
++/**
++ * scols_column_is_strict_width:
++ * @cl: a pointer to a struct libscols_column instance
++ *
++ * Gets the value of @cl's flag strict_width.
++ *
++ * Returns: strict_width flag value, negative value in case of an error.
++ */
++int scols_column_is_strict_width(struct libscols_column *cl)
++{
++	assert(cl);
++	if (!cl)
++		return -EINVAL;
++	return cl->flags & SCOLS_FL_STRICTWIDTH;
++}
++/**
++ * scols_column_is_noextremes:
++ * @cl: a pointer to a struct libscols_column instance
++ *
++ * Gets the value of @cl's flag no_extremes.
++ *
++ * Returns: no_extremes flag value, negative value in case of an error.
++ */
++int scols_column_is_noextremes(struct libscols_column *cl)
++{
++	assert(cl);
++	if (!cl)
++		return -EINVAL;
++	return cl->flags & SCOLS_FL_NOEXTREMES;
++}
+diff -up util-linux-2.23.2/libsmartcols/src/.gitignore.kzak util-linux-2.23.2/libsmartcols/src/.gitignore
+--- util-linux-2.23.2/libsmartcols/src/.gitignore.kzak	2014-09-25 14:41:48.985843877 +0200
++++ util-linux-2.23.2/libsmartcols/src/.gitignore	2014-09-25 14:41:48.985843877 +0200
+@@ -0,0 +1 @@
++libsmartcols.h
+diff -up util-linux-2.23.2/libsmartcols/src/init.c.kzak util-linux-2.23.2/libsmartcols/src/init.c
+--- util-linux-2.23.2/libsmartcols/src/init.c.kzak	2014-09-25 14:41:48.987843896 +0200
++++ util-linux-2.23.2/libsmartcols/src/init.c	2014-09-25 14:41:48.987843896 +0200
+@@ -0,0 +1,52 @@
++/*
++ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
++ *
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ */
++
++/**
++ * SECTION: init
++ * @title: Library initialization
++ * @short_description: initialize debugging
++ *
++ * The library debug stuff.
++ */
++
++#include <stdarg.h>
++
++#include "smartcolsP.h"
++
++UL_DEBUG_DEFINE_MASK(libsmartcols);
++
++static const struct dbg_mask libsmartcols_masknames [] = {
++	{ "all", SCOLS_DEBUG_ALL },
++	{ "cell", SCOLS_DEBUG_CELL },
++	{ "line", SCOLS_DEBUG_LINE },
++	{ "tab", SCOLS_DEBUG_TAB },
++	{ "col", SCOLS_DEBUG_COL },
++	{ "buff", SCOLS_DEBUG_BUFF },
++	{ NULL, 0 }
++};
++/**
++ * scols_init_debug:
++ * @mask: debug mask (0xffff to enable full debugging)
++ *
++ * If the @mask is not specified, then this function reads
++ * the LIBSMARTCOLS_DEBUG environment variable to get the mask.
++ *
++ * Already initialized debugging stuff cannot be changed. Calling
++ * this function twice has no effect.
++ */
++void scols_init_debug(int mask)
++{
++	__UL_INIT_DEBUG(libsmartcols, SCOLS_DEBUG_, mask, LIBSMARTCOLS_DEBUG);
++
++	if (libsmartcols_debug_mask != SCOLS_DEBUG_INIT) {
++		const char *ver = NULL;
++
++		scols_get_library_version(&ver);
++
++		DBG(INIT, ul_debug("library version: %s", ver));
++	}
++}
+diff -up util-linux-2.23.2/libsmartcols/src/iter.c.kzak util-linux-2.23.2/libsmartcols/src/iter.c
+--- util-linux-2.23.2/libsmartcols/src/iter.c.kzak	2014-09-25 14:41:48.987843896 +0200
++++ util-linux-2.23.2/libsmartcols/src/iter.c	2014-09-25 14:41:48.987843896 +0200
+@@ -0,0 +1,74 @@
++/*
++ * Copyright (C) 2009-2014 Karel Zak <kzak@redhat.com>
++ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
++ *
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ */
++
++/**
++ * SECTION: iter
++ * @title: Iterator
++ * @short_description: unified iterator
++ *
++ * The iterator keeps the direction and the last position
++ * for access to the internal library tables/lists.
++ */
++
++#include <string.h>
++#include <stdlib.h>
++
++#include "smartcolsP.h"
++
++/**
++ * scols_new_iter:
++ * @direction: SCOLS_INTER_{FOR,BACK}WARD direction
++ *
++ * Returns: newly allocated generic libmount iterator.
++ */
++struct libscols_iter *scols_new_iter(int direction)
++{
++	struct libscols_iter *itr = calloc(1, sizeof(*itr));
++	if (!itr)
++		return NULL;
++	itr->direction = direction;
++	return itr;
++}
++
++/**
++ * scols_free_iter:
++ * @itr: iterator pointer
++ *
++ * Deallocates the iterator.
++ */
++void scols_free_iter(struct libscols_iter *itr)
++{
++	free(itr);
++}
++
++/**
++ * scols_reset_iter:
++ * @itr: iterator pointer
++ * @direction: SCOLS_INTER_{FOR,BACK}WARD or -1 to keep the direction unchanged
++ *
++ * Resets the iterator.
++ */
++void scols_reset_iter(struct libscols_iter *itr, int direction)
++{
++	if (direction == -1)
++		direction = itr->direction;
++
++	memset(itr, 0, sizeof(*itr));
++	itr->direction = direction;
++}
++
++/**
++ * scols_iter_get_direction:
++ * @itr: iterator pointer
++ *
++ * Returns: SCOLS_INTER_{FOR,BACK}WARD
++ */
++int scols_iter_get_direction(struct libscols_iter *itr)
++{
++	return itr->direction;
++}
+diff -up util-linux-2.23.2/libsmartcols/src/libsmartcols.h.in.kzak util-linux-2.23.2/libsmartcols/src/libsmartcols.h.in
+--- util-linux-2.23.2/libsmartcols/src/libsmartcols.h.in.kzak	2014-09-25 14:41:48.988843905 +0200
++++ util-linux-2.23.2/libsmartcols/src/libsmartcols.h.in	2014-09-25 14:41:48.988843905 +0200
+@@ -0,0 +1,229 @@
++/*
++ * Prints table or tree.
++ *
++ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
++ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
++ *
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ */
++#ifndef _LIBSMARTCOLS_H
++#define _LIBSMARTCOLS_H
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <sys/types.h>
++
++/**
++ * LIBSMARTCOLS_VERSION:
++ *
++ * Library version string
++ */
++#define LIBSMARTCOLS_VERSION   "@LIBSMARTCOLS_VERSION@"
++
++/**
++ * libscols_iter:
++ *
++ * Generic iterator
++ */
++struct libscols_iter;
++
++/**
++ * libscols_symbols:
++ *
++ * Symbol groups for printing tree hierarchies
++ */
++struct libscols_symbols;
++
++/**
++ * libscols_cell:
++ *
++ * A cell - the smallest library object
++ */
++struct libscols_cell;
++
++/**
++ * libscols_line:
++ *
++ * A line - an array of cells
++ */
++struct libscols_line;
++
++/**
++ * libscols_table:
++ *
++ * A table - The most abstract object, encapsulating lines, columns, symbols and cells
++ */
++struct libscols_table;
++
++/**
++ * libscols_column:
++ *
++ * A column - defines the number of columns and column names
++ */
++struct libscols_column;
++
++/* iter.c */
++enum {
++
++	SCOLS_ITER_FORWARD = 0,
++	SCOLS_ITER_BACKWARD
++};
++
++/*
++ * Column flags
++ */
++enum {
++	SCOLS_FL_TRUNC       = (1 << 0),   /* truncate fields data if necessary */
++	SCOLS_FL_TREE        = (1 << 1),   /* use tree "ascii art" */
++	SCOLS_FL_RIGHT	     = (1 << 2),   /* align to the right */
++	SCOLS_FL_STRICTWIDTH = (1 << 3),   /* don't reduce width if column is empty */
++	SCOLS_FL_NOEXTREMES  = (1 << 4),   /* ignore extreme fields when count column width*/
++};
++
++extern struct libscols_iter *scols_new_iter(int direction);
++extern void scols_free_iter(struct libscols_iter *itr);
++extern void scols_reset_iter(struct libscols_iter *itr, int direction);
++extern int scols_iter_get_direction(struct libscols_iter *itr);
++
++/* init.c */
++extern void scols_init_debug(int mask);
++
++/* version.c */
++extern int scols_parse_version_string(const char *ver_string);
++extern int scols_get_library_version(const char **ver_string);
++
++/* symbols.c */
++extern struct libscols_symbols *scols_new_symbols(void);
++extern void scols_ref_symbols(struct libscols_symbols *sy);
++extern void scols_unref_symbols(struct libscols_symbols *sy);
++extern struct libscols_symbols *scols_copy_symbols(const struct libscols_symbols *sb);
++extern int scols_symbols_set_branch(struct libscols_symbols *sb, const char *str);
++extern int scols_symbols_set_vertical(struct libscols_symbols *sb, const char *str);
++extern int scols_symbols_set_right(struct libscols_symbols *sb, const char *str);
++
++/* cell.c */
++extern int scols_reset_cell(struct libscols_cell *ce);
++extern int scols_cell_copy_content(struct libscols_cell *dest,
++				   const struct libscols_cell *src);
++extern int scols_cell_set_data(struct libscols_cell *ce, const char *str);
++extern int scols_cell_refer_data(struct libscols_cell *ce, char *str);
++extern const char *scols_cell_get_data(const struct libscols_cell *ce);
++extern int scols_cell_set_color(struct libscols_cell *ce, const char *color);
++extern const char *scols_cell_get_color(const struct libscols_cell *ce);
++
++extern void *scols_cell_get_userdata(struct libscols_cell *ce);
++extern int scols_cell_set_userdata(struct libscols_cell *ce, void *data);
++
++extern int scols_cmpstr_cells(struct libscols_cell *a,
++			      struct libscols_cell *b, void *data);
++/* column.c */
++extern int scols_column_is_tree(struct libscols_column *cl);
++extern int scols_column_is_trunc(struct libscols_column *cl);
++extern int scols_column_is_right(struct libscols_column *cl);
++extern int scols_column_is_strict_width(struct libscols_column *cl);
++extern int scols_column_is_noextremes(struct libscols_column *cl);
++
++extern int scols_column_set_flags(struct libscols_column *cl, int flags);
++extern int scols_column_get_flags(struct libscols_column *cl);
++extern struct libscols_column *scols_new_column(void);
++extern void scols_ref_column(struct libscols_column *cl);
++extern void scols_unref_column(struct libscols_column *cl);
++extern struct libscols_column *scols_copy_column(const struct libscols_column *cl);
++extern int scols_column_set_whint(struct libscols_column *cl, double whint);
++extern double scols_column_get_whint(struct libscols_column *cl);
++extern struct libscols_cell *scols_column_get_header(struct libscols_column *cl);
++extern int scols_column_set_color(struct libscols_column *cl, const char *color);
++extern const char *scols_column_get_color(struct libscols_column *cl);
++
++extern int scols_column_set_cmpfunc(struct libscols_column *cl,
++			int (*cmp)(struct libscols_cell *a,
++				   struct libscols_cell *b, void *),
++			void *data);
++
++/* line.c */
++extern struct libscols_line *scols_new_line(void);
++extern void scols_ref_line(struct libscols_line *ln);
++extern void scols_unref_line(struct libscols_line *ln);
++extern int scols_line_alloc_cells(struct libscols_line *ln, size_t n);
++extern void scols_line_free_cells(struct libscols_line *ln);
++extern int scols_line_set_userdata(struct libscols_line *ln, void *data);
++extern void *scols_line_get_userdata(struct libscols_line *ln);
++extern int scols_line_remove_child(struct libscols_line *ln, struct libscols_line *child);
++extern int scols_line_add_child(struct libscols_line *ln, struct libscols_line *child);
++extern int scols_line_has_children(struct libscols_line *ln);
++extern int scols_line_next_child(struct libscols_line *ln,
++			  struct libscols_iter *itr, struct libscols_line **chld);
++extern struct libscols_line *scols_line_get_parent(struct libscols_line *ln);
++extern int scols_line_set_color(struct libscols_line *ln, const char *color);
++extern const char *scols_line_get_color(struct libscols_line *ln);
++extern size_t scols_line_get_ncells(struct libscols_line *ln);
++extern struct libscols_cell *scols_line_get_cell(struct libscols_line *ln, size_t n);
++extern struct libscols_cell *scols_line_get_column_cell(
++		                        struct libscols_line *ln,
++		                        struct libscols_column *cl);
++extern int scols_line_set_data(struct libscols_line *ln, size_t n, const char *data);
++extern int scols_line_refer_data(struct libscols_line *ln, size_t n, char *data);
++extern struct libscols_line *scols_copy_line(struct libscols_line *ln);
++
++/* table */
++extern int scols_table_colors_wanted(struct libscols_table *tb);
++extern int scols_table_is_raw(struct libscols_table *tb);
++extern int scols_table_is_ascii(struct libscols_table *tb);
++extern int scols_table_is_noheadings(struct libscols_table *tb);
++extern int scols_table_is_empty(struct libscols_table *tb);
++extern int scols_table_is_export(struct libscols_table *tb);
++extern int scols_table_is_maxout(struct libscols_table *tb);
++extern int scols_table_is_tree(struct libscols_table *tb);
++
++extern int scols_table_enable_colors(struct libscols_table *tb, int enable);
++extern int scols_table_enable_raw(struct libscols_table *tb, int enable);
++extern int scols_table_enable_ascii(struct libscols_table *tb, int enable);
++extern int scols_table_enable_noheadings(struct libscols_table *tb, int enable);
++extern int scols_table_enable_export(struct libscols_table *tb, int enable);
++extern int scols_table_enable_maxout(struct libscols_table *tb, int enable);
++
++extern int scols_table_set_column_separator(struct libscols_table *tb, const char *sep);
++extern int scols_table_set_line_separator(struct libscols_table *tb, const char *sep);
++
++extern struct libscols_table *scols_new_table(void);
++extern void scols_ref_table(struct libscols_table *tb);
++extern void scols_unref_table(struct libscols_table *tb);
++extern int scols_table_add_column(struct libscols_table *tb, struct libscols_column *cl);
++extern int scols_table_remove_column(struct libscols_table *tb, struct libscols_column *cl);
++extern int scols_table_remove_columns(struct libscols_table *tb);
++extern struct libscols_column *scols_table_new_column(struct libscols_table *tb, const char *name, double whint, int flags);
++extern int scols_table_next_column(struct libscols_table *tb, struct libscols_iter *itr, struct libscols_column **cl);
++extern char *scols_table_get_column_separator(struct libscols_table *tb);
++extern char *scols_table_get_line_separator(struct libscols_table *tb);
++extern int scols_table_get_ncols(struct libscols_table *tb);
++extern int scols_table_get_nlines(struct libscols_table *tb);
++extern struct libscols_column *scols_table_get_column(struct libscols_table *tb, size_t n);
++extern int scols_table_add_line(struct libscols_table *tb, struct libscols_line *ln);
++extern int scols_table_remove_line(struct libscols_table *tb, struct libscols_line *ln);
++extern void scols_table_remove_lines(struct libscols_table *tb);
++extern int scols_table_next_line(struct libscols_table *tb, struct libscols_iter *itr, struct libscols_line **ln);
++extern struct libscols_line *scols_table_new_line(struct libscols_table *tb, struct libscols_line *parent);
++extern struct libscols_line *scols_table_get_line(struct libscols_table *tb, size_t n);
++extern struct libscols_table *scols_copy_table(struct libscols_table *tb);
++extern int scols_table_set_symbols(struct libscols_table *tb, struct libscols_symbols *sy);
++
++extern int scols_table_set_stream(struct libscols_table *tb, FILE *stream);
++extern FILE *scols_table_get_stream(struct libscols_table *tb);
++extern int scols_table_reduce_termwidth(struct libscols_table *tb, size_t reduce);
++
++extern int scols_sort_table(struct libscols_table *tb, struct libscols_column *cl);
++
++/* table_print.c */
++extern int scols_print_table(struct libscols_table *tb);
++extern int scols_print_table_to_string(struct libscols_table *tb, char **data);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _LIBSMARTCOLS_H */
+diff -up util-linux-2.23.2/libsmartcols/src/libsmartcols.sym.kzak util-linux-2.23.2/libsmartcols/src/libsmartcols.sym
+--- util-linux-2.23.2/libsmartcols/src/libsmartcols.sym.kzak	2014-09-25 14:41:48.988843905 +0200
++++ util-linux-2.23.2/libsmartcols/src/libsmartcols.sym	2014-09-25 14:41:48.988843905 +0200
+@@ -0,0 +1,112 @@
++/*
++ * symbols since util-linux 2.25
++ */
++SMARTCOLS_2.25 {
++global:
++	scols_cell_copy_content;
++	scols_cell_get_color;
++	scols_cell_get_data;
++	scols_cell_get_userdata;
++	scols_cell_refer_data;
++	scols_cell_set_color;
++	scols_cell_set_data;
++	scols_cell_set_userdata;
++	scols_cmpstr_cells;
++	scols_column_get_color;
++	scols_column_get_flags;
++	scols_column_get_header;
++	scols_column_get_whint;
++	scols_column_is_noextremes;
++	scols_column_is_right;
++	scols_column_is_strict_width;
++	scols_column_is_tree;
++	scols_column_is_trunc;
++	scols_column_set_cmpfunc;
++	scols_column_set_color;
++	scols_column_set_flags;
++	scols_column_set_whint;
++	scols_copy_column;
++	scols_copy_line;
++	scols_copy_symbols;
++	scols_copy_table;
++	scols_free_iter;
++	scols_get_library_version;
++	scols_init_debug;
++	scols_iter_get_direction;
++	scols_line_add_child;
++	scols_line_alloc_cells;
++	scols_line_free_cells;
++	scols_line_get_cell;
++	scols_line_get_color;
++	scols_line_get_column_cell;
++	scols_line_get_ncells;
++	scols_line_get_parent;
++	scols_line_get_userdata;
++	scols_line_has_children;
++	scols_line_next_child;
++	scols_line_refer_data;
++	scols_line_remove_child;
++	scols_line_set_color;
++	scols_line_set_data;
++	scols_line_set_userdata;
++	scols_new_column;
++	scols_new_iter;
++	scols_new_line;
++	scols_new_symbols;
++	scols_new_table;
++	scols_parse_version_string;
++	scols_print_table;
++	scols_print_table_to_string;
++	scols_ref_column;
++	scols_ref_line;
++	scols_ref_symbols;
++	scols_ref_table;
++	scols_reset_cell;
++	scols_reset_iter;
++	scols_sort_table;
++	scols_symbols_set_branch;
++	scols_symbols_set_right;
++	scols_symbols_set_vertical;
++	scols_table_add_column;
++	scols_table_add_line;
++	scols_table_colors_wanted;
++	scols_table_enable_ascii;
++	scols_table_enable_colors;
++	scols_table_enable_export;
++	scols_table_enable_maxout;
++	scols_table_enable_noheadings;
++	scols_table_enable_raw;
++	scols_table_get_column;
++	scols_table_get_column_separator;
++	scols_table_get_line;
++	scols_table_get_line_separator;
++	scols_table_get_ncols;
++	scols_table_get_nlines;
++	scols_table_get_stream;
++	scols_table_is_ascii;
++	scols_table_is_empty;
++	scols_table_is_export;
++	scols_table_is_maxout;
++	scols_table_is_noheadings;
++	scols_table_is_raw;
++	scols_table_is_tree;
++	scols_table_new_column;
++	scols_table_new_line;
++	scols_table_next_column;
++	scols_table_next_line;
++	scols_table_reduce_termwidth;
++	scols_table_remove_column;
++	scols_table_remove_columns;
++	scols_table_remove_line;
++	scols_table_remove_lines;
++	scols_table_set_column_separator;
++	scols_table_set_line_separator;
++	scols_table_set_stream;
++	scols_table_set_symbols;
++	scols_unref_column;
++	scols_unref_line;
++	scols_unref_symbols;
++	scols_unref_table;
++local:
++	*;
++};
+diff -up util-linux-2.23.2/libsmartcols/src/line.c.kzak util-linux-2.23.2/libsmartcols/src/line.c
+--- util-linux-2.23.2/libsmartcols/src/line.c.kzak	2014-09-25 14:41:48.989843915 +0200
++++ util-linux-2.23.2/libsmartcols/src/line.c	2014-09-25 14:41:48.989843915 +0200
+@@ -0,0 +1,456 @@
++/*
++ * line.c - functions for table handling at the line level
++ *
++ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
++ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
++ *
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ */
++
++/**
++ * SECTION: line
++ * @title: Line
++ * @short_description: line API
++ *
++ * An API to access and modify per-line data and information.
++ */
++
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <ctype.h>
++
++#include "smartcolsP.h"
++
++/**
++ * scols_new_line:
++ *
++ * Note that the line is allocated without cells, the cells will be allocated
++ * later when you add the line to the table. If you want to use the line
++ * without table then you have to explicitly allocate the cells by
++ * scols_line_alloc_cells().
++ *
++ * Returns: a pointer to a new struct libscols_line instance.
++ */
++struct libscols_line *scols_new_line(void)
++{
++	struct libscols_line *ln;
++
++	ln = calloc(1, sizeof(*ln));
++	if (!ln)
++		return NULL;
++
++	DBG(LINE, ul_debugobj(ln, "alloc"));
++	ln->refcount = 1;
++	INIT_LIST_HEAD(&ln->ln_lines);
++	INIT_LIST_HEAD(&ln->ln_children);
++	INIT_LIST_HEAD(&ln->ln_branch);
++	return ln;
++}
++
++/**
++ * scols_ref_line:
++ * @ln: a pointer to a struct libscols_line instance
++ *
++ * Increases the refcount of @ln.
++ */
++void scols_ref_line(struct libscols_line *ln)
++{
++	if (ln)
++		ln->refcount++;
++}
++
++/**
++ * scols_unref_line:
++ * @ln: a pointer to a struct libscols_line instance
++ *
++ * Decreases the refcount of @ln. When the count falls to zero, the instance
++ * is automatically deallocated.
++ */
++void scols_unref_line(struct libscols_line *ln)
++{
++
++	if (ln && --ln->refcount <= 0) {
++		DBG(CELL, ul_debugobj(ln, "dealloc"));
++		list_del(&ln->ln_lines);
++		list_del(&ln->ln_children);
++		scols_line_free_cells(ln);
++		free(ln->color);
++		free(ln);
++		return;
++	}
++}
++
++/**
++ * scols_line_free_cells:
++ * @ln: a pointer to a struct libscols_line instance
++ *
++ * Frees the allocated cells referenced to by @ln.
++ */
++void scols_line_free_cells(struct libscols_line *ln)
++{
++	size_t i;
++
++	if (!ln || !ln->cells)
++		return;
++
++	DBG(LINE, ul_debugobj(ln, "free cells"));
++
++	for (i = 0; i < ln->ncells; i++)
++		scols_reset_cell(&ln->cells[i]);
++
++	free(ln->cells);
++	ln->ncells = 0;
++	ln->cells = NULL;
++}
++
++/**
++ * scols_line_alloc_cells:
++ * @ln: a pointer to a struct libscols_line instance
++ * @n: the number of elements
++ *
++ * Allocates space for @n cells. This function is optional,
++ * and libsmartcols automatically allocates necessary cells
++ * according to number of columns in the table when you add
++ * the line to the table. See scols_table_add_line().
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_line_alloc_cells(struct libscols_line *ln, size_t n)
++{
++	struct libscols_cell *ce;
++
++	assert(ln);
++
++	if (!ln)
++		return -EINVAL;
++	if (ln->ncells == n)
++		return 0;
++
++	if (!n) {
++		scols_line_free_cells(ln);
++		return 0;
++	}
++
++	DBG(LINE, ul_debugobj(ln, "alloc %zu cells", n));
++
++	ce = realloc(ln->cells, n * sizeof(struct libscols_cell));
++	if (!ce)
++		return -errno;
++
++	if (n > ln->ncells)
++		memset(ce + ln->ncells, 0,
++		       (n - ln->ncells) * sizeof(struct libscols_cell));
++
++	ln->cells = ce;
++	ln->ncells = n;
++	return 0;
++}
++
++/**
++ * scols_line_set_userdata:
++ * @ln: a pointer to a struct libscols_line instance
++ * @data: user data
++ *
++ * Binds @data to @ln.
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_line_set_userdata(struct libscols_line *ln, void *data)
++{
++	assert(ln);
++	if (!ln)
++		return -EINVAL;
++	ln->userdata = data;
++	return 0;
++}
++
++/**
++ * scols_line_get_userdata:
++ * @ln: a pointer to a struct libscols_line instance
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++void *scols_line_get_userdata(struct libscols_line *ln)
++{
++	assert(ln);
++	return ln ? ln->userdata : NULL;
++}
++
++/**
++ * scols_line_remove_child:
++ * @ln: a pointer to a struct libscols_line instance
++ * @child: a pointer to a struct libscols_line instance
++ *
++ * Removes @child as a child of @ln.
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_line_remove_child(struct libscols_line *ln, struct libscols_line *child)
++{
++	assert(ln);
++	assert(child);
++
++	if (!ln || !child)
++		return -EINVAL;
++
++	DBG(LINE, ul_debugobj(ln, "remove child %p", child));
++
++	list_del_init(&child->ln_children);
++	child->parent = NULL;
++	scols_unref_line(child);
++
++	scols_unref_line(ln);
++	return 0;
++}
++
++/**
++ * scols_line_add_child:
++ * @ln: a pointer to a struct libscols_line instance
++ * @child: a pointer to a struct libscols_line instance
++ *
++ * Sets @child as a child of @ln.
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_line_add_child(struct libscols_line *ln, struct libscols_line *child)
++{
++	assert(ln);
++	assert(child);
++
++	if (!ln || !child)
++		return -EINVAL;
++
++	/* unref old<->parent */
++	if (child->parent)
++		scols_line_remove_child(child->parent, child);
++
++	DBG(LINE, ul_debugobj(ln, "add child %p", child));
++
++	/* new reference from parent to child */
++	list_add_tail(&child->ln_children, &ln->ln_branch);
++	scols_ref_line(child);
++
++	/* new reference from child to parent */
++	child->parent = ln;
++	scols_ref_line(ln);
++
++	return 0;
++}
++
++/**
++ * scols_line_get_parent:
++ * @ln: a pointer to a struct libscols_line instance
++ *
++ * Returns: a pointer to @ln's parent, NULL in case it has no parent or if there was an error.
++ */
++struct libscols_line *scols_line_get_parent(struct libscols_line *ln)
++{
++	assert(ln);
++	return ln ? ln->parent : NULL;
++}
++
++/**
++ * scols_line_has_children:
++ * @ln: a pointer to a struct libscols_line instance
++ *
++ * Returns: 1 if @ln has any children, otherwise 0.
++ */
++int scols_line_has_children(struct libscols_line *ln)
++{
++	assert(ln);
++	return ln ? !list_empty(&ln->ln_branch) : 0;
++}
++
++/**
++ * scols_line_next_child:
++ * @ln: a pointer to a struct libscols_line instance
++ * @itr: a pointer to a struct libscols_iter instance
++ * @chld: a pointer to a pointer to a struct libscols_line instance
++ *
++ * Finds the next child and returns a pointer to it via @chld.
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_line_next_child(struct libscols_line *ln,
++			  struct libscols_iter *itr,
++			  struct libscols_line **chld)
++{
++	int rc = 1;
++
++	if (!ln || !itr || !chld)
++		return -EINVAL;
++	*chld = NULL;
++
++	if (!itr->head)
++		SCOLS_ITER_INIT(itr, &ln->ln_branch);
++	if (itr->p != itr->head) {
++		SCOLS_ITER_ITERATE(itr, *chld, struct libscols_line, ln_children);
++		rc = 0;
++	}
++
++	return rc;
++}
++
++/**
++ * scols_line_set_color:
++ * @ln: a pointer to a struct libscols_line instance
++ * @color: ESC sequence
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_line_set_color(struct libscols_line *ln, const char *color)
++{
++	char *p = NULL;
++
++	assert(ln);
++	if (!ln)
++		return -EINVAL;
++	if (color) {
++		p = strdup(color);
++		if (!p)
++			return -ENOMEM;
++	}
++
++	free(ln->color);
++	ln->color = p;
++	return 0;
++}
++
++/**
++ * scols_line_get_color:
++ * @ln: a pointer to a struct libscols_line instance
++ *
++ * Returns: @ln's color string, NULL in case of an error.
++ */
++const char *scols_line_get_color(struct libscols_line *ln)
++{
++	assert(ln);
++	return ln ? ln->color : NULL;
++}
++
++/**
++ * scols_line_get_ncells:
++ * @ln: a pointer to a struct libscols_line instance
++ *
++ * Returns: @ln's number of cells
++ */
++size_t scols_line_get_ncells(struct libscols_line *ln)
++{
++	assert(ln);
++	return ln ? ln->ncells : 0;
++}
++
++/**
++ * scols_line_get_cell:
++ * @ln: a pointer to a struct libscols_line instance
++ * @n: cell number to retrieve
++ *
++ * Returns: the @n-th cell in @ln, NULL in case of an error.
++ */
++struct libscols_cell *scols_line_get_cell(struct libscols_line *ln,
++					  size_t n)
++{
++	assert(ln);
++
++	if (!ln || n >= ln->ncells)
++		return NULL;
++	return &ln->cells[n];
++}
++
++/**
++ * scols_line_get_column_cell:
++ * @ln: a pointer to a struct libscols_line instance
++ * @cl: pointer to cell
++ *
++ * Like scols_line_get_cell() by cell is referenced by column.
++ *
++ * Returns: the @n-th cell in @ln, NULL in case of an error.
++ */
++struct libscols_cell *scols_line_get_column_cell(
++			struct libscols_line *ln,
++			struct libscols_column *cl)
++{
++	assert(ln);
++	assert(cl);
++
++	return scols_line_get_cell(ln, cl->seqnum);
++}
++
++/**
++ * scols_line_set_data:
++ * @ln: a pointer to a struct libscols_cell instance
++ * @n: number of the cell, whose data is to be set
++ * @data: actual data to set
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_line_set_data(struct libscols_line *ln, size_t n, const char *data)
++{
++	struct libscols_cell *ce = scols_line_get_cell(ln, n);
++
++	if (!ce)
++		return -EINVAL;
++	return scols_cell_set_data(ce, data);
++}
++
++/**
++ * scols_line_refer_data:
++ * @ln: a pointer to a struct libscols_cell instance
++ * @n: number of the cell which will refer to @data
++ * @data: actual data to refer to
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_line_refer_data(struct libscols_line *ln, size_t n, char *data)
++{
++	struct libscols_cell *ce = scols_line_get_cell(ln, n);
++
++	if (!ce)
++		return -EINVAL;
++	return scols_cell_refer_data(ce, data);
++}
++
++/**
++ * scols_copy_line:
++ * @ln: a pointer to a struct libscols_cell instance
++ *
++ * Returns: A newly allocated copy of @ln, NULL in case of an error.
++ */
++struct libscols_line *scols_copy_line(struct libscols_line *ln)
++{
++	struct libscols_line *ret;
++	size_t i;
++
++	assert (ln);
++	if (!ln)
++		return NULL;
++
++	ret = scols_new_line();
++	if (!ret)
++		return NULL;
++	if (scols_line_set_color(ret, ln->color))
++		goto err;
++	if (scols_line_alloc_cells(ret, ln->ncells))
++		goto err;
++
++	ret->userdata = ln->userdata;
++	ret->ncells   = ln->ncells;
++	ret->seqnum   = ln->seqnum;
++
++	DBG(LINE, ul_debugobj(ln, "copy to %p", ret));
++
++	for (i = 0; i < ret->ncells; ++i) {
++		if (scols_cell_copy_content(&ret->cells[i], &ln->cells[i]))
++			goto err;
++	}
++
++	return ret;
++err:
++	scols_unref_line(ret);
++	return NULL;
++}
++
++
+diff -up util-linux-2.23.2/libsmartcols/src/Makemodule.am.kzak util-linux-2.23.2/libsmartcols/src/Makemodule.am
+--- util-linux-2.23.2/libsmartcols/src/Makemodule.am.kzak	2014-09-25 14:41:48.985843877 +0200
++++ util-linux-2.23.2/libsmartcols/src/Makemodule.am	2014-09-25 14:42:10.471048869 +0200
+@@ -0,0 +1,75 @@
++
++
++## smartcols.h is generated, so it's stored in builddir! (no distribute in RHEL7)
++#smartcolsincdir = $(includedir)/libsmartcols
++#nodist_smartcolsinc_HEADERS = $(top_builddir)/libsmartcols/src/libsmartcols.h
++
++noinst_LTLIBRARIES += libsmartcols.la
++libsmartcols_la_SOURCES= \
++	include/list.h \
++	\
++	libsmartcols/src/smartcolsP.h \
++	libsmartcols/src/iter.c \
++	libsmartcols/src/symbols.c \
++	libsmartcols/src/cell.c \
++	libsmartcols/src/column.c \
++	libsmartcols/src/line.c \
++	libsmartcols/src/table.c \
++	libsmartcols/src/table_print.c \
++	libsmartcols/src/version.c \
++	libsmartcols/src/init.c \
++	$(nodist_smartcolsinc_HEADERS)
++
++nodist_libsmartcols_la_SOURCES = libsmartcols/src/smartcolsP.h
++
++libsmartcols_la_LIBADD = libcommon.la
++
++libsmartcols_la_CFLAGS = \
++	$(SOLIB_CFLAGS) \
++	-I$(ul_libsmartcols_incdir) \
++	-I$(top_srcdir)/libsmartcols/src
++
++libsmartcols_la_DEPENDENCIES = \
++	libcommon.la \
++	libsmartcols/src/libsmartcols.sym \
++	libsmartcols/src/libsmartcols.h.in
++
++libsmartcols_la_LDFLAGS = \
++	$(SOLIB_LDFLAGS) \
++	-Wl,--version-script=$(top_srcdir)/libsmartcols/src/libsmartcols.sym \
++	-version-info $(LIBSMARTCOLS_VERSION_INFO)
++
++EXTRA_DIST += \
++	libsmartcols/src/libsmartcols.sym \
++	libsmartcols/src/libsmartcols.h.in
++
++
++if BUILD_LIBSMARTCOLS_TESTS
++check_PROGRAMS += test_smartcols
++
++libsmartcols_tests_cflags = $(libsmartcols_la_CFLAGS)
++libsmartcols_tests_ldadd  = libsmartcols.la libcommon.la
++
++test_smartcols_SOURCES = libsmartcols/src/test.c
++test_smartcols_CFLAGS = $(libsmartcols_tests_cflags)
++test_smartcols_LDADD = $(libsmartcols_tests_ldadd)
++endif # BUILD_LIBSMARTCOLS_TESTS
++
++
++# move lib from $(usrlib_execdir) to $(libdir) if needed
++install-exec-hook-libsmartcols:
++	if test "$(usrlib_execdir)" != "$(libdir)" -a -f "$(DESTDIR)$(usrlib_execdir)/libsmartcols.so"; then \
++		mkdir -p $(DESTDIR)$(libdir); \
++		mv $(DESTDIR)$(usrlib_execdir)/libsmartcols.so.* $(DESTDIR)$(libdir); \
++		so_img_name=$$(readlink $(DESTDIR)$(usrlib_execdir)/libsmartcols.so); \
++		so_img_rel_target=$$(echo $(usrlib_execdir) | sed 's,\(^/\|\)[^/][^/]*,..,g'); \
++		(cd $(DESTDIR)$(usrlib_execdir) && \
++			rm -f libsmartcols.so && \
++			$(LN_S) $$so_img_rel_target$(libdir)/$$so_img_name libsmartcols.so); \
++	fi
++
++uninstall-hook-libsmartcols:
++	rm -f $(DESTDIR)$(libdir)/libsmartcols.so*
++
++INSTALL_EXEC_HOOKS += install-exec-hook-libsmartcols
++UNINSTALL_HOOKS += uninstall-hook-libsmartcols
+diff -up util-linux-2.23.2/libsmartcols/src/smartcolsP.h.kzak util-linux-2.23.2/libsmartcols/src/smartcolsP.h
+--- util-linux-2.23.2/libsmartcols/src/smartcolsP.h.kzak	2014-09-25 14:41:48.989843915 +0200
++++ util-linux-2.23.2/libsmartcols/src/smartcolsP.h	2014-09-25 14:41:48.989843915 +0200
+@@ -0,0 +1,173 @@
++/*
++ * smartcolsP.h - private library header file
++ *
++ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
++ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
++ *
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ */
++
++#ifndef _LIBSMARTCOLS_PRIVATE_H
++#define _LIBSMARTCOLS_PRIVATE_H
++
++#include "c.h"
++#include "list.h"
++#include "colors.h"
++#include "debug.h"
++
++#include "libsmartcols.h"
++
++/* features */
++#define CONFIG_LIBSMARTCOLS_ASSERT
++
++#ifdef CONFIG_LIBSMARTCOLS_ASSERT
++# include <assert.h>
++#else
++# define assert(x)
++#endif
++
++/*
++ * Debug
++ */
++#define SCOLS_DEBUG_INIT	(1 << 1)
++#define SCOLS_DEBUG_CELL	(1 << 2)
++#define SCOLS_DEBUG_LINE	(1 << 3)
++#define SCOLS_DEBUG_TAB		(1 << 4)
++#define SCOLS_DEBUG_COL		(1 << 5)
++#define SCOLS_DEBUG_BUFF	(1 << 6)
++#define SCOLS_DEBUG_ALL		0xFFFF
++
++UL_DEBUG_DECLARE_MASK(libsmartcols);
++#define DBG(m, x)	__UL_DBG(libsmartcols, SCOLS_DEBUG_, m, x)
++#define ON_DBG(m, x)	__UL_DBG_CALL(libsmartcols, SCOLS_DEBUG_, m, x)
++#define DBG_FLUSH	__UL_DBG_FLUSH(libsmartcols, SCOLS_DEBUG_)
++
++/*
++ * Generic iterator
++ */
++struct libscols_iter {
++	struct list_head        *p;		/* current position */
++	struct list_head        *head;		/* start position */
++	int			direction;	/* SCOLS_ITER_{FOR,BACK}WARD */
++};
++
++/*
++ * Tree symbols
++ */
++struct libscols_symbols {
++	int	refcount;
++	char	*branch;
++	char	*vert;
++	char	*right;
++};
++
++/*
++ * Table cells
++ */
++struct libscols_cell {
++	char	*data;
++	char	*color;
++	void    *userdata;
++};
++
++
++/*
++ * Table column
++ */
++struct libscols_column {
++	int	refcount;	/* reference counter */
++	size_t	seqnum;		/* column index */
++
++	size_t	width;		/* real column width */
++	size_t	width_min;	/* minimal width (usually header width) */
++	size_t  width_max;	/* maximal width */
++	size_t  width_avg;	/* average width, used to detect extreme fields */
++	double	width_hint;	/* hint (N < 1 is in percent of termwidth) */
++
++	int	flags;
++	int	is_extreme;
++	char	*color;		/* default column color */
++
++	int (*cmpfunc)(struct libscols_cell *,
++		       struct libscols_cell *,
++		       void *);			/* cells comparison function */
++	void *cmpfunc_data;
++
++	struct libscols_cell	header;
++	struct list_head	cl_columns;
++};
++
++/*
++ * Table line
++ */
++struct libscols_line {
++	int	refcount;
++	size_t	seqnum;
++
++	void	*userdata;
++	char	*color;		/* default line color */
++
++	struct libscols_cell	*cells;		/* array with data */
++	size_t			ncells;		/* number of cells */
++
++	struct list_head	ln_lines;	/* table lines */
++	struct list_head	ln_branch;	/* begin of branch (head of ln_children) */
++	struct list_head	ln_children;
++
++	struct libscols_line	*parent;
++};
++
++enum {
++	SCOLS_FMT_HUMAN = 0,		/* default, human readable */
++	SCOLS_FMT_RAW,			/* space separated */
++	SCOLS_FMT_EXPORT		/* COLNAME="data" ... */
++};
++
++/*
++ * The table
++ */
++struct libscols_table {
++	int	refcount;
++	size_t	ncols;		/* number of columns */
++	size_t  ntreecols;	/* number of columns with SCOLS_FL_TREE */
++	size_t	nlines;		/* number of lines */
++	size_t	termwidth;	/* terminal width */
++	size_t  termreduce;	/* extra blank space */
++	FILE	*out;		/* output stream */
++
++	char	*colsep;	/* column separator */
++	char	*linesep;	/* line separator */
++
++	struct list_head	tb_columns;
++	struct list_head	tb_lines;
++	struct libscols_symbols	*symbols;
++
++	int	format;		/* SCOLS_FMT_* */
++
++	/* flags */
++	unsigned int	ascii		:1,	/* don't use unicode */
++			colors_wanted	:1,	/* enable colors */
++			is_term		:1,	/* isatty() */
++			maxout		:1,	/* maximalize output */
++			no_headings	:1;	/* don't print header */
++};
++
++#define IS_ITER_FORWARD(_i)	((_i)->direction == SCOLS_ITER_FORWARD)
++#define IS_ITER_BACKWARD(_i)	((_i)->direction == SCOLS_ITER_BACKWARD)
++
++#define SCOLS_ITER_INIT(itr, list) \
++	do { \
++		(itr)->p = IS_ITER_FORWARD(itr) ? \
++				(list)->next : (list)->prev; \
++		(itr)->head = (list); \
++	} while(0)
++
++#define SCOLS_ITER_ITERATE(itr, res, restype, member) \
++	do { \
++		res = list_entry((itr)->p, restype, member); \
++		(itr)->p = IS_ITER_FORWARD(itr) ? \
++				(itr)->p->next : (itr)->p->prev; \
++	} while(0)
++
++#endif /* _LIBSMARTCOLS_PRIVATE_H */
+diff -up util-linux-2.23.2/libsmartcols/src/symbols.c.kzak util-linux-2.23.2/libsmartcols/src/symbols.c
+--- util-linux-2.23.2/libsmartcols/src/symbols.c.kzak	2014-09-25 14:41:48.989843915 +0200
++++ util-linux-2.23.2/libsmartcols/src/symbols.c	2014-09-25 14:41:48.989843915 +0200
+@@ -0,0 +1,175 @@
++/*
++ * symbols.c - routines for symbol handling
++ *
++ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
++ *
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ */
++
++/**
++ * SECTION: symbols
++ * @title: Symbols
++ * @short_description: symbols API
++ *
++ * An API to access and modify data and information per symbol/symbol group.
++ */
++
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++
++#include "smartcolsP.h"
++
++/**
++ * scols_new_symbols:
++ *
++ * Returns: a pointer to a newly allocated struct libscols_symbols instance.
++ */
++struct libscols_symbols *scols_new_symbols(void)
++{
++	struct libscols_symbols *sy = calloc(1, sizeof(struct libscols_symbols));
++
++	if (!sy)
++		return NULL;
++	sy->refcount = 1;
++	return sy;
++}
++
++/**
++ * scols_ref_symbols:
++ * @sy: a pointer to a struct libscols_symbols instance
++ *
++ * Increases the refcount of @sy.
++ */
++void scols_ref_symbols(struct libscols_symbols *sy)
++{
++	if (sy)
++		sy->refcount++;
++}
++
++/**
++ * scols_unref_symbols:
++ * @sy: a pointer to a struct libscols_symbols instance
++ *
++ * Decreases the refcount of @sy.
++ */
++void scols_unref_symbols(struct libscols_symbols *sy)
++{
++	if (sy && --sy->refcount <= 0) {
++		free(sy->branch);
++		free(sy->vert);
++		free(sy->right);
++		free(sy);
++	}
++}
++
++/**
++ * scols_symbols_set_branch:
++ * @sb: a pointer to a struct libscols_symbols instance
++ * @str: a string which will represent the branch part of a tree output
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_symbols_set_branch(struct libscols_symbols *sb, const char *str)
++{
++	char *p = NULL;
++
++	assert(sb);
++
++	if (!sb)
++		return -EINVAL;
++	if (str) {
++		p = strdup(str);
++		if (!p)
++			return -ENOMEM;
++	}
++	free(sb->branch);
++	sb->branch = p;
++	return 0;
++}
++
++/**
++ * scols_symbols_set_vertical:
++ * @sb: a pointer to a struct libscols_symbols instance
++ * @str: a string which will represent the vertical part of a tree output
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_symbols_set_vertical(struct libscols_symbols *sb, const char *str)
++{
++	char *p = NULL;
++
++	assert(sb);
++
++	if (!sb)
++		return -EINVAL;
++	if (str) {
++		p = strdup(str);
++		if (!p)
++			return -ENOMEM;
++	}
++	free(sb->vert);
++	sb->vert = p;
++	return 0;
++}
++
++/**
++ * scols_symbols_set_right:
++ * @sb: a pointer to a struct libscols_symbols instance
++ * @str: a string which will represent the right part of a tree output
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_symbols_set_right(struct libscols_symbols *sb, const char *str)
++{
++	char *p = NULL;
++
++	assert(sb);
++
++	if (!sb)
++		return -EINVAL;
++	if (str) {
++		p = strdup(str);
++		if (!p)
++			return -ENOMEM;
++	}
++	free(sb->right);
++	sb->right = p;
++	return 0;
++}
++
++/**
++ * scols_copy_symbols:
++ * @sb: a pointer to a struct libscols_symbols instance
++ *
++ * Returns: a newly allocated copy of the @sb symbol group or NULL in caes of an error.
++ */
++struct libscols_symbols *scols_copy_symbols(const struct libscols_symbols *sb)
++{
++	struct libscols_symbols *ret;
++	int rc;
++
++	assert(sb);
++	if (!sb)
++		return NULL;
++
++	ret = scols_new_symbols();
++	if (!ret)
++		return NULL;
++
++	rc = scols_symbols_set_branch(ret, sb->branch);
++	if (!rc)
++		rc = scols_symbols_set_vertical(ret, sb->vert);
++	if (!rc)
++		rc = scols_symbols_set_right(ret, sb->right);
++	if (!rc)
++		return ret;
++
++	scols_unref_symbols(ret);
++	return NULL;
++
++}
++
++
+diff -up util-linux-2.23.2/libsmartcols/src/table.c.kzak util-linux-2.23.2/libsmartcols/src/table.c
+--- util-linux-2.23.2/libsmartcols/src/table.c.kzak	2014-09-25 14:41:48.991843934 +0200
++++ util-linux-2.23.2/libsmartcols/src/table.c	2014-09-25 14:41:48.991843934 +0200
+@@ -0,0 +1,1049 @@
++/*
++ * table.c - functions handling the data at the table level
++ *
++ * Copyright (C) 2010-2014 Karel Zak <kzak@redhat.com>
++ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
++ *
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ */
++
++/**
++ * SECTION: table
++ * @title: Table
++ * @short_description: table data API
++ *
++ * Table data manipulation API.
++ */
++
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <termios.h>
++#include <ctype.h>
++
++#include "nls.h"
++#include "widechar.h"
++#include "smartcolsP.h"
++
++#ifdef HAVE_WIDECHAR
++#define UTF_V	"\342\224\202"	/* U+2502, Vertical line drawing char */
++#define UTF_VR	"\342\224\234"	/* U+251C, Vertical and right */
++#define UTF_H	"\342\224\200"	/* U+2500, Horizontal */
++#define UTF_UR	"\342\224\224"	/* U+2514, Up and right */
++#endif /* !HAVE_WIDECHAR */
++
++#define is_last_column(_tb, _cl) \
++		list_entry_is_last(&(_cl)->cl_columns, &(_tb)->tb_columns)
++
++
++/**
++ * scols_new_table:
++ *
++ * Returns: A newly allocated table.
++ */
++struct libscols_table *scols_new_table(void)
++{
++	struct libscols_table *tb;
++
++	tb = calloc(1, sizeof(struct libscols_table));
++	if (!tb)
++		return NULL;
++
++	tb->refcount = 1;
++	tb->out = stdout;
++
++	INIT_LIST_HEAD(&tb->tb_lines);
++	INIT_LIST_HEAD(&tb->tb_columns);
++
++	DBG(TAB, ul_debugobj(tb, "alloc"));
++	return tb;
++}
++
++/**
++ * scols_ref_table:
++ * @tb: a pointer to a struct libscols_table instance
++ *
++ * Increases the refcount of @tb.
++ */
++void scols_ref_table(struct libscols_table *tb)
++{
++	if (tb)
++		tb->refcount++;
++}
++
++/**
++ * scols_unref_table:
++ * @tb: a pointer to a struct libscols_table instance
++ *
++ * Decreases the refcount of @tb. When the count falls to zero, the instance
++ * is automatically deallocated.
++ */
++void scols_unref_table(struct libscols_table *tb)
++{
++	if (tb && (--tb->refcount <= 0)) {
++		DBG(TAB, ul_debugobj(tb, "dealloc"));
++		scols_table_remove_lines(tb);
++		scols_table_remove_columns(tb);
++		scols_unref_symbols(tb->symbols);
++		free(tb->linesep);
++		free(tb->colsep);
++		free(tb);
++	}
++}
++
++/**
++ * scols_table_add_column:
++ * @tb: a pointer to a struct libscols_table instance
++ * @cl: a pointer to a struct libscols_column instance
++ *
++ * Adds @cl to @tb's column list.
++ *
++ * Returns: 0, a negative number in case of an error.
++ */
++int scols_table_add_column(struct libscols_table *tb, struct libscols_column *cl)
++{
++	assert(tb);
++	assert(cl);
++
++	if (!tb || !cl || !list_empty(&tb->tb_lines))
++		return -EINVAL;
++
++	if (cl->flags & SCOLS_FL_TREE)
++		tb->ntreecols++;
++
++	DBG(TAB, ul_debugobj(tb, "add column %p", cl));
++	list_add_tail(&cl->cl_columns, &tb->tb_columns);
++	cl->seqnum = tb->ncols++;
++	scols_ref_column(cl);
++
++	/* TODO:
++	 *
++	 * Currently it's possible to add/remove columns only if the table is
++	 * empty (see list_empty(tb->tb_lines) above). It would be nice to
++	 * enlarge/reduce lines cells[] always when we add/remove a new column.
++	 */
++	return 0;
++}
++
++/**
++ * scols_table_remove_column:
++ * @tb: a pointer to a struct libscols_table instance
++ * @cl: a pointer to a struct libscols_column instance
++ *
++ * Removes @cl from @tb.
++ *
++ * Returns: 0, a negative number in case of an error.
++ */
++int scols_table_remove_column(struct libscols_table *tb,
++			      struct libscols_column *cl)
++{
++	assert(tb);
++	assert(cl);
++
++	if (!tb || !cl || !list_empty(&tb->tb_lines))
++		return -EINVAL;
++
++	if (cl->flags & SCOLS_FL_TREE)
++		tb->ntreecols--;
++
++	DBG(TAB, ul_debugobj(tb, "remove column %p", cl));
++	list_del_init(&cl->cl_columns);
++	tb->ncols--;
++	scols_unref_column(cl);
++	return 0;
++}
++
++/**
++ * scols_table_remove_columns:
++ * @tb: a pointer to a struct libscols_table instance
++ *
++ * Removes all of @tb's columns.
++ *
++ * Returns: 0, a negative number in case of an error.
++ */
++int scols_table_remove_columns(struct libscols_table *tb)
++{
++	assert(tb);
++
++	if (!tb || !list_empty(&tb->tb_lines))
++		return -EINVAL;
++
++	DBG(TAB, ul_debugobj(tb, "remove all columns"));
++	while (!list_empty(&tb->tb_columns)) {
++		struct libscols_column *cl = list_entry(tb->tb_columns.next,
++					struct libscols_column, cl_columns);
++		scols_table_remove_column(tb, cl);
++	}
++	return 0;
++}
++
++
++/**
++ * scols_table_new_column:
++ * @tb: table
++ * @name: column header
++ * @whint: column width hint (absolute width: N > 1; relative width: N < 1)
++ * @flags: flags integer
++ *
++ * This is shortcut for
++ *
++ *   cl = scols_new_column();
++ *   scols_column_set_....(cl, ...);
++ *   scols_table_add_column(tb, cl);
++ *
++ * The column width is possible to define by three ways:
++ *
++ *  @whint = 0..1    : relative width, percent of terminal width
++ *
++ *  @whint = 1..N    : absolute width, empty colum will be truncated to
++ *                     the column header width
++ *
++ *  @whint = 1..N
++ *
++ * The column is necessary to address by
++ * sequential number. The first defined column has the colnum = 0. For example:
++ *
++ *	scols_table_new_column(tab, "FOO", 0.5, 0);		// colnum = 0
++ *	scols_table_new_column(tab, "BAR", 0.5, 0);		// colnum = 1
++ *      .
++ *      .
++ *	scols_line_get_cell(line, 0);				// FOO column
++ *	scols_line_get_cell(line, 1);				// BAR column
++ *
++ * Returns: newly allocated column
++ */
++struct libscols_column *scols_table_new_column(struct libscols_table *tb,
++					       const char *name,
++					       double whint,
++					       int flags)
++{
++	struct libscols_column *cl;
++	struct libscols_cell *hr;
++
++	assert (tb);
++	if (!tb)
++		return NULL;
++
++	DBG(TAB, ul_debugobj(tb, "new column name=%s, whint=%g, flags=%d",
++				name, whint, flags));
++	cl = scols_new_column();
++	if (!cl)
++		return NULL;
++
++	/* set column name */
++	hr = scols_column_get_header(cl);
++	if (!hr)
++		goto err;
++	if (scols_cell_set_data(hr, name))
++		goto err;
++
++	scols_column_set_whint(cl, whint);
++	scols_column_set_flags(cl, flags);
++
++	if (scols_table_add_column(tb, cl))	/* this increments column ref-counter */
++		goto err;
++
++	scols_unref_column(cl);
++	return cl;
++err:
++	scols_unref_column(cl);
++	return NULL;
++}
++
++/**
++ * scols_table_next_column:
++ * @tb: a pointer to a struct libscols_table instance
++ * @itr: a pointer to a struct libscols_iter instance
++ * @cl: a pointer to a pointer to a struct libscols_column instance
++ *
++ * Returns the next column of @tb via @cl.
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_table_next_column(struct libscols_table *tb,
++			    struct libscols_iter *itr,
++			    struct libscols_column **cl)
++{
++	int rc = 1;
++
++	if (!tb || !itr || !cl)
++		return -EINVAL;
++	*cl = NULL;
++
++	if (!itr->head)
++		SCOLS_ITER_INIT(itr, &tb->tb_columns);
++	if (itr->p != itr->head) {
++		SCOLS_ITER_ITERATE(itr, *cl, struct libscols_column, cl_columns);
++		rc = 0;
++	}
++
++	return rc;
++}
++
++
++/**
++ * scols_table_get_ncols:
++ * @tb: table
++ *
++ * Returns: the ncols table member, a negative number in case of an error.
++ */
++int scols_table_get_ncols(struct libscols_table *tb)
++{
++	assert(tb);
++	return tb ? tb->ncols : -EINVAL;
++}
++
++/**
++ * scols_table_get_nlines:
++ * @tb: table
++ *
++ * Returns: the nlines table member, a negative number in case of an error.
++ */
++int scols_table_get_nlines(struct libscols_table *tb)
++{
++	assert(tb);
++	return tb ? tb->nlines : -EINVAL;
++}
++
++/**
++ * scols_table_set_stream:
++ * @tb: table
++ * @stream: output stream
++ *
++ * Sets the output stream for table @tb.
++ *
++ * Returns: 0, a negative number in case of an error.
++ */
++int scols_table_set_stream(struct libscols_table *tb, FILE *stream)
++{
++	assert(tb);
++	if (!tb)
++		return -EINVAL;
++
++	DBG(TAB, ul_debugobj(tb, "setting alternative stream"));
++	tb->out = stream;
++	return 0;
++}
++
++/**
++ * scols_table_get_stream:
++ * @tb: table
++ *
++ * Gets the output stream for table @tb.
++ *
++ * Returns: stream pointer, NULL in case of an error or an unset stream.
++ */
++FILE *scols_table_get_stream(struct libscols_table *tb)
++{
++	assert(tb);
++	return tb ? tb->out: NULL;
++}
++
++/**
++ * scols_table_reduce_termwidth:
++ * @tb: table
++ * @reduce: width
++ *
++ * Reduce the output width to @reduce.
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_table_reduce_termwidth(struct libscols_table *tb, size_t reduce)
++{
++	assert(tb);
++	if (!tb)
++		return -EINVAL;
++
++	DBG(TAB, ul_debugobj(tb, "reduce terminal width: %zu", reduce));
++	tb->termreduce = reduce;
++	return 0;
++}
++
++/**
++ * scols_table_get_column:
++ * @tb: table
++ * @n: number of column (0..N)
++ *
++ * Returns: pointer to column or NULL
++ */
++struct libscols_column *scols_table_get_column(struct libscols_table *tb,
++					       size_t n)
++{
++	struct libscols_iter itr;
++	struct libscols_column *cl;
++
++	assert(tb);
++	if (!tb)
++		return NULL;
++	if (n >= tb->ncols)
++		return NULL;
++
++	scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
++	while (scols_table_next_column(tb, &itr, &cl) == 0) {
++		if (cl->seqnum == n)
++			return cl;
++	}
++	return NULL;
++}
++
++/**
++ * scols_table_add_line:
++ * @tb: table
++ * @ln: line
++ *
++ * Note that this function calls scols_line_alloc_cells() if number
++ * of the cells in the line is too small for @tb.
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_table_add_line(struct libscols_table *tb, struct libscols_line *ln)
++{
++
++	assert(tb);
++	assert(ln);
++
++	if (!tb || !ln)
++		return -EINVAL;
++
++	if (tb->ncols > ln->ncells) {
++		int rc = scols_line_alloc_cells(ln, tb->ncols);
++		if (rc)
++			return rc;
++	}
++
++	DBG(TAB, ul_debugobj(tb, "add line %p", ln));
++	list_add_tail(&ln->ln_lines, &tb->tb_lines);
++	ln->seqnum = tb->nlines++;
++	scols_ref_line(ln);
++	return 0;
++}
++
++/**
++ * scols_table_remove_line:
++ * @tb: table
++ * @ln: line
++ *
++ * Note that this function does not destroy the parent<->child relationship between lines.
++ * You have to call scols_line_remove_child()
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_table_remove_line(struct libscols_table *tb,
++			    struct libscols_line *ln)
++{
++	assert(tb);
++	assert(ln);
++
++	if (!tb || !ln)
++		return -EINVAL;
++
++	DBG(TAB, ul_debugobj(tb, "remove line %p", ln));
++	list_del_init(&ln->ln_lines);
++	tb->nlines--;
++	scols_unref_line(ln);
++	return 0;
++}
++
++/**
++ * scols_table_remove_lines:
++ * @tb: table
++ *
++ * This empties the table and also destroys all the parent<->child relationships.
++ */
++void scols_table_remove_lines(struct libscols_table *tb)
++{
++	assert(tb);
++	if (!tb)
++		return;
++
++	DBG(TAB, ul_debugobj(tb, "remove all lines"));
++	while (!list_empty(&tb->tb_lines)) {
++		struct libscols_line *ln = list_entry(tb->tb_lines.next,
++						struct libscols_line, ln_lines);
++		if (ln->parent)
++			scols_line_remove_child(ln->parent, ln);
++		scols_table_remove_line(tb, ln);
++	}
++}
++
++/**
++ * scols_table_next_line:
++ * @tb: a pointer to a struct libscols_table instance
++ * @itr: a pointer to a struct libscols_iter instance
++ * @ln: a pointer to a pointer to a struct libscols_line instance
++ *
++ * Finds the next line and returns a pointer to it via @ln.
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_table_next_line(struct libscols_table *tb,
++			  struct libscols_iter *itr,
++			  struct libscols_line **ln)
++{
++	int rc = 1;
++
++	if (!tb || !itr || !ln)
++		return -EINVAL;
++	*ln = NULL;
++
++	if (!itr->head)
++		SCOLS_ITER_INIT(itr, &tb->tb_lines);
++	if (itr->p != itr->head) {
++		SCOLS_ITER_ITERATE(itr, *ln, struct libscols_line, ln_lines);
++		rc = 0;
++	}
++
++	return rc;
++}
++
++/**
++ * scols_table_new_line:
++ * @tb: table
++ * @parent: parental line or NULL
++ *
++ * This is shortcut for
++ *
++ *   ln = scols_new_line();
++ *   scols_table_add_line(tb, ln);
++ *   scols_line_add_child(parent, ln);
++ *
++ *
++ * Returns: newly allocate line
++ */
++struct libscols_line *scols_table_new_line(struct libscols_table *tb,
++					   struct libscols_line *parent)
++{
++	struct libscols_line *ln;
++
++	assert(tb);
++	assert(tb->ncols);
++
++	if (!tb || !tb->ncols)
++		return NULL;
++
++	ln = scols_new_line();
++	if (!ln)
++		return NULL;
++
++	if (scols_table_add_line(tb, ln))
++		goto err;
++	if (parent)
++		scols_line_add_child(parent, ln);
++
++	scols_unref_line(ln);	/* ref-counter incremented by scols_table_add_line() */
++	return ln;
++err:
++	scols_unref_line(ln);
++	return NULL;
++}
++
++/**
++ * scols_table_get_line:
++ * @tb: table
++ * @n: column number (0..N)
++ *
++ * This is a shortcut for
++ *
++ *   ln = scols_new_line();
++ *   scols_line_set_....(cl, ...);
++ *   scols_table_add_line(tb, ln);
++ *
++ * Returns: a newly allocate line
++ */
++struct libscols_line *scols_table_get_line(struct libscols_table *tb,
++					   size_t n)
++{
++	struct libscols_iter itr;
++	struct libscols_line *ln;
++
++	assert(tb);
++	if (!tb)
++		return NULL;
++	if (n >= tb->nlines)
++		return NULL;
++
++	scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
++	while (scols_table_next_line(tb, &itr, &ln) == 0) {
++		if (ln->seqnum == n)
++			return ln;
++	}
++	return NULL;
++}
++
++/**
++ * scols_copy_table:
++ * @tb: table
++ *
++ * Creates a new independent table copy, except struct libscols_symbols that
++ * are shared between the tables.
++ *
++ * Returns: a newly allocated copy of @tb
++ */
++struct libscols_table *scols_copy_table(struct libscols_table *tb)
++{
++	struct libscols_table *ret;
++	struct libscols_line *ln;
++	struct libscols_column *cl;
++	struct libscols_iter itr;
++
++	assert(tb);
++	if (!tb)
++		return NULL;
++	ret = scols_new_table();
++	if (!ret)
++		return NULL;
++
++	DBG(TAB, ul_debugobj(tb, "copy into %p", ret));
++
++	if (tb->symbols)
++		scols_table_set_symbols(ret, tb->symbols);
++
++	/* columns */
++	scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
++	while (scols_table_next_column(tb, &itr, &cl) == 0) {
++		cl = scols_copy_column(cl);
++		if (!cl)
++			goto err;
++		if (scols_table_add_column(ret, cl))
++			goto err;
++		scols_unref_column(cl);
++	}
++
++	/* lines */
++	scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
++	while (scols_table_next_line(tb, &itr, &ln) == 0) {
++		struct libscols_line *newln = scols_copy_line(ln);
++		if (!newln)
++			goto err;
++		if (scols_table_add_line(ret, newln))
++			goto err;
++		if (ln->parent) {
++			struct libscols_line *p =
++				scols_table_get_line(ret, ln->parent->seqnum);
++			if (p)
++				scols_line_add_child(p, newln);
++		}
++		scols_unref_line(newln);
++	}
++
++	/* separators */
++	if (scols_table_set_column_separator(ret, tb->colsep) ||
++	    scols_table_set_line_separator(ret, tb->linesep))
++		goto err;
++
++	return ret;
++err:
++	scols_unref_table(ret);
++	return NULL;
++}
++
++/**
++ * scols_table_set_symbols:
++ * @tb: table
++ * @sy: symbols or NULL
++ *
++ * Add a reference to @sy from the table. The symbols are used by library to
++ * draw tree output. If no symbols are specified then library checks the
++ * current environment to select ASCII or UTF8 symbols. This default behavior
++ * could be controlled by scols_table_enable_ascii().
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_table_set_symbols(struct libscols_table *tb,
++			    struct libscols_symbols *sy)
++{
++	assert(tb);
++
++	if (!tb)
++		return -EINVAL;
++
++	DBG(TAB, ul_debugobj(tb, "setting alternative symbols %p", sy));
++
++	if (tb->symbols)				/* unref old */
++		scols_unref_symbols(tb->symbols);
++	if (sy) {					/* ref user defined */
++		tb->symbols = sy;
++		scols_ref_symbols(sy);
++	} else {					/* default symbols */
++		tb->symbols = scols_new_symbols();
++		if (!tb->symbols)
++			return -ENOMEM;
++#if defined(HAVE_WIDECHAR)
++		if (!scols_table_is_ascii(tb) &&
++		    !strcmp(nl_langinfo(CODESET), "UTF-8")) {
++			scols_symbols_set_branch(tb->symbols, UTF_VR UTF_H);
++			scols_symbols_set_vertical(tb->symbols, UTF_V " ");
++			scols_symbols_set_right(tb->symbols, UTF_UR UTF_H);
++		} else
++#endif
++		{
++			scols_symbols_set_branch(tb->symbols, "|-");
++			scols_symbols_set_vertical(tb->symbols, "| ");
++			scols_symbols_set_right(tb->symbols, "`-");
++		}
++	}
++
++	return 0;
++}
++/**
++ * scols_table_enable_colors:
++ * @tb: table
++ * @enable: 1 or 0
++ *
++ * Enable/disable colors.
++ *
++ * Returns: 0 on success, negative number in case of an error.
++ */
++int scols_table_enable_colors(struct libscols_table *tb, int enable)
++{
++	assert(tb);
++	if (!tb)
++		return -EINVAL;
++
++	DBG(TAB, ul_debugobj(tb, "colors: %s", enable ? "ENABLE" : "DISABLE"));
++	tb->colors_wanted = enable;
++	return 0;
++}
++/**
++ * scols_table_enable_raw:
++ * @tb: table
++ * @enable: 1 or 0
++ *
++ * Enable/disable raw output format. The parsable output formats
++ * (export and raw) are mutually exclusive.
++ *
++ * Returns: 0 on success, negative number in case of an error.
++ */
++int scols_table_enable_raw(struct libscols_table *tb, int enable)
++{
++	assert(tb);
++	if (!tb)
++		return -EINVAL;
++
++	DBG(TAB, ul_debugobj(tb, "raw: %s", enable ? "ENABLE" : "DISABLE"));
++	if (enable)
++		tb->format = SCOLS_FMT_RAW;
++	else if (tb->format == SCOLS_FMT_RAW)
++		tb->format = 0;
++	return 0;
++}
++
++/**
++ * scols_table_enable_export:
++ * @tb: table
++ * @enable: 1 or 0
++ *
++ * Enable/disable export output format (COLUMNAME="value" ...).
++ * The parsable output formats (export and raw) are mutually exclusive.
++ *
++ * Returns: 0 on success, negative number in case of an error.
++ */
++int scols_table_enable_export(struct libscols_table *tb, int enable)
++{
++	assert(tb);
++	if (!tb)
++		return -EINVAL;
++
++	DBG(TAB, ul_debugobj(tb, "export: %s", enable ? "ENABLE" : "DISABLE"));
++	if (enable)
++		tb->format = SCOLS_FMT_EXPORT;
++	else if (tb->format == SCOLS_FMT_EXPORT)
++		tb->format = 0;
++	return 0;
++}
++
++/**
++ * scols_table_enable_ascii:
++ * @tb: table
++ * @enable: 1 or 0
++ *
++ * The ASCII-only output is relevant for tree-like outputs. The library
++ * checks if the current environment is UTF8 compatible by default. This
++ * function overrides this check and force the library to use ASCII chars
++ * for the tree.
++ *
++ * If a custom libcols_symbols are specified (see scols_table_set_symbols()
++ * then ASCII flag setting is ignored.
++ *
++ * Returns: 0 on success, negative number in case of an error.
++ */
++int scols_table_enable_ascii(struct libscols_table *tb, int enable)
++{
++	assert(tb);
++	if (!tb)
++		return -EINVAL;
++
++	DBG(TAB, ul_debugobj(tb, "ascii: %s", enable ? "ENABLE" : "DISABLE"));
++	tb->ascii = enable ? 1 : 0;
++	return 0;
++}
++
++/**
++ * scols_table_enable_noheadings:
++ * @tb: table
++ * @enable: 1 or 0
++ *
++ * Enable/disable header line.
++ *
++ * Returns: 0 on success, negative number in case of an error.
++ */
++int scols_table_enable_noheadings(struct libscols_table *tb, int enable)
++{
++	assert(tb);
++	if (!tb)
++		return -EINVAL;
++	DBG(TAB, ul_debugobj(tb, "noheading: %s", enable ? "ENABLE" : "DISABLE"));
++	tb->no_headings = enable ? 1 : 0;
++	return 0;
++}
++
++/**
++ * scols_table_enable_maxout:
++ * @tb: table
++ * @enable: 1 or 0
++ *
++ * The extra space after last column is ignored by default. The output
++ * maximization use the extra space for all columns.
++ *
++ * Returns: 0 on success, negative number in case of an error.
++ */
++int scols_table_enable_maxout(struct libscols_table *tb, int enable)
++{
++	assert(tb);
++	if (!tb)
++		return -EINVAL;
++	DBG(TAB, ul_debugobj(tb, "maxout: %s", enable ? "ENABLE" : "DISABLE"));
++	tb->maxout = enable ? 1 : 0;
++	return 0;
++}
++
++/**
++ * scols_table_colors_wanted:
++ * @tb: table
++ *
++ * Returns: 1 if colors are enabled.
++ */
++int scols_table_colors_wanted(struct libscols_table *tb)
++{
++	assert(tb);
++	return tb && tb->colors_wanted;
++}
++
++/**
++ * scols_table_is_empty:
++ * @tb: table
++ *
++ * Returns: 1  if the table is empty.
++ */
++int scols_table_is_empty(struct libscols_table *tb)
++{
++	assert(tb);
++	return !tb || !tb->nlines;
++}
++
++/**
++ * scols_table_is_ascii:
++ * @tb: table
++ *
++ * Returns: 1 if ASCII tree is enabled.
++ */
++int scols_table_is_ascii(struct libscols_table *tb)
++{
++	assert(tb);
++	return tb && tb->ascii;
++}
++
++/**
++ * scols_table_is_noheadings:
++ * @tb: table
++ *
++ * Returns: 1 if header output is disabled.
++ */
++int scols_table_is_noheadings(struct libscols_table *tb)
++{
++	assert(tb);
++	return tb && tb->no_headings;
++}
++
++/**
++ * scols_table_is_export:
++ * @tb: table
++ *
++ * Returns: 1 if export output format is enabled.
++ */
++int scols_table_is_export(struct libscols_table *tb)
++{
++	assert(tb);
++	return tb && tb->format == SCOLS_FMT_EXPORT;
++}
++
++/**
++ * scols_table_is_raw:
++ * @tb: table
++ *
++ * Returns: 1 if raw output format is enabled.
++ */
++int scols_table_is_raw(struct libscols_table *tb)
++{
++	assert(tb);
++	return tb && tb->format == SCOLS_FMT_RAW;
++}
++
++
++/**
++ * scols_table_is_maxout
++ * @tb: table
++ *
++ * Returns: 1 if output maximization is enabled, negative value in case of an error.
++ */
++int scols_table_is_maxout(struct libscols_table *tb)
++{
++	assert(tb);
++	return tb && tb->maxout;
++}
++
++/**
++ * scols_table_is_tree:
++ * @tb: table
++ *
++ * Returns: returns 1 tree-like output is expected.
++ */
++int scols_table_is_tree(struct libscols_table *tb)
++{
++	assert(tb);
++	return tb && tb->ntreecols > 0;
++}
++
++/**
++ * scols_table_set_column_separator:
++ * @tb: table
++ * @sep: separator
++ *
++ * Sets the column separator of @tb to @sep.
++ * Please note that @sep should always take up a single cell in the output.
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_table_set_column_separator(struct libscols_table *tb, const char *sep)
++{
++	char *p = NULL;
++
++	assert (tb);
++
++	if (!tb)
++		return -EINVAL;
++
++	if (sep) {
++		p = strdup(sep);
++		if (!p)
++			return -ENOMEM;
++	}
++
++	DBG(TAB, ul_debugobj(tb, "new columns separator: %s", sep));
++	free(tb->colsep);
++	tb->colsep = p;
++	return 0;
++}
++
++/**
++ * scols_table_set_line_separator:
++ * @tb: table
++ * @sep: separator
++ *
++ * Sets the line separator of @tb to @sep.
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_table_set_line_separator(struct libscols_table *tb, const char *sep)
++{
++	char *p = NULL;
++
++	assert (tb);
++
++	if (!tb)
++		return -EINVAL;
++
++	if (sep) {
++		p = strdup(sep);
++		if (!p)
++			return -ENOMEM;
++	}
++
++	DBG(TAB, ul_debugobj(tb, "new lines separator: %s", sep));
++	free(tb->linesep);
++	tb->linesep = p;
++	return 0;
++}
++
++/**
++ * scols_table_get_column_separator:
++ * @tb: table
++ *
++ * Returns: @tb column separator, NULL in case of an error
++ */
++char *scols_table_get_column_separator(struct libscols_table *tb)
++{
++	assert (tb);
++
++	if (!tb)
++		return NULL;
++	return tb->colsep;
++}
++
++/**
++ * scols_table_get_line_separator:
++ * @tb: table
++ *
++ * Returns: @tb line separator, NULL in case of an error
++ */
++char *scols_table_get_line_separator(struct libscols_table *tb)
++{
++	assert (tb);
++
++	if (!tb)
++		return NULL;
++	return tb->linesep;
++
++}
++
++static int cells_cmp_wrapper(struct list_head *a, struct list_head *b, void *data)
++{
++	struct libscols_column *cl = (struct libscols_column *) data;
++	struct libscols_line *ra, *rb;
++	struct libscols_cell *ca, *cb;
++
++	assert(a);
++	assert(b);
++	assert(cl);
++
++	ra = list_entry(a, struct libscols_line, ln_lines);
++	rb = list_entry(b, struct libscols_line, ln_lines);
++	ca = scols_line_get_cell(ra, cl->seqnum);
++	cb = scols_line_get_cell(rb, cl->seqnum);
++
++	return cl->cmpfunc(ca, cb, cl->cmpfunc_data);
++}
++
++/**
++ * scols_sort_table:
++ * @tb: table
++ * @cl: order by this column
++ *
++ * Orders the table by the column. See also scols_column_set_cmpfunc().
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_sort_table(struct libscols_table *tb, struct libscols_column *cl)
++{
++	assert(tb);
++	assert(cl);
++
++	if (!tb || !cl)
++		return -EINVAL;
++
++	DBG(TAB, ul_debugobj(tb, "sorting table"));
++	list_sort(&tb->tb_lines, cells_cmp_wrapper, cl);
++	return 0;
++}
+diff -up util-linux-2.23.2/libsmartcols/src/table_print.c.kzak util-linux-2.23.2/libsmartcols/src/table_print.c
+--- util-linux-2.23.2/libsmartcols/src/table_print.c.kzak	2014-09-25 14:41:48.992843944 +0200
++++ util-linux-2.23.2/libsmartcols/src/table_print.c	2014-09-25 14:41:48.992843944 +0200
+@@ -0,0 +1,841 @@
++/*
++ * table.c - functions handling the data at the table level
++ *
++ * Copyright (C) 2010-2014 Karel Zak <kzak@redhat.com>
++ *
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ */
++
++/**
++ * SECTION: table_print
++ * @title: Table print
++ * @short_description: table print API
++ *
++ * Table output API.
++ */
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <termios.h>
++#include <ctype.h>
++
++#include "nls.h"
++#include "mbsalign.h"
++#include "widechar.h"
++#include "ttyutils.h"
++#include "carefulputc.h"
++#include "smartcolsP.h"
++
++/* This is private struct to work with output data */
++struct libscols_buffer {
++	char	*begin;		/* begin of the buffer */
++	char	*cur;		/* current end of  the buffer */
++	char	*encdata;	/* encoded buffer mbs_safe_encode() */
++
++	size_t	bufsz;		/* size of the buffer */
++	size_t	art_idx;	/* begin of the tree ascii art or zero */
++};
++
++static struct libscols_buffer *new_buffer(size_t sz)
++{
++	struct libscols_buffer *buf = malloc(sz + sizeof(struct libscols_buffer));
++
++	if (!buf)
++		return NULL;
++
++	buf->cur = buf->begin = ((char *) buf) + sizeof(struct libscols_buffer);
++	buf->encdata = NULL;
++	buf->bufsz = sz;
++
++	DBG(BUFF, ul_debugobj(buf, "alloc (size=%zu)", sz));
++	return buf;
++}
++
++static void free_buffer(struct libscols_buffer *buf)
++{
++	if (!buf)
++		return;
++	DBG(BUFF, ul_debugobj(buf, "dealloc"));
++	free(buf->encdata);
++	free(buf);
++}
++
++static int buffer_reset_data(struct libscols_buffer *buf)
++{
++	if (!buf)
++		return -EINVAL;
++
++	/*DBG(BUFF, ul_debugobj(buf, "reset data"));*/
++	buf->begin[0] = '\0';
++	buf->cur = buf->begin;
++	buf->art_idx = 0;
++	return 0;
++}
++
++static int buffer_append_data(struct libscols_buffer *buf, const char *str)
++{
++	size_t maxsz, sz;
++
++	if (!buf)
++		return -EINVAL;
++	if (!str || !*str)
++		return 0;
++
++	sz = strlen(str);
++	maxsz = buf->bufsz - (buf->cur - buf->begin);
++
++	if (maxsz <= sz)
++		return -EINVAL;
++
++	memcpy(buf->cur, str, sz + 1);
++	buf->cur += sz;
++	return 0;
++}
++
++static int buffer_set_data(struct libscols_buffer *buf, const char *str)
++{
++	int rc = buffer_reset_data(buf);
++	return rc ? rc : buffer_append_data(buf, str);
++}
++
++/* save the current buffer possition to art_idx */
++static void buffer_set_art_index(struct libscols_buffer *buf)
++{
++	if (buf) {
++		buf->art_idx = buf->cur - buf->begin;
++		/*DBG(BUFF, ul_debugobj(buf, "art index: %zu", buf->art_idx));*/
++	}
++}
++
++static char *buffer_get_data(struct libscols_buffer *buf)
++{
++	return buf ? buf->begin : NULL;
++}
++
++/* encode data by mbs_safe_encode() to avoid control and non-printable chars */
++static char *buffer_get_safe_data(struct libscols_buffer *buf, size_t *cells)
++{
++	char *data = buffer_get_data(buf);
++	char *res = NULL;
++
++	if (!data)
++		goto nothing;
++
++	if (!buf->encdata) {
++		buf->encdata = malloc(mbs_safe_encode_size(buf->bufsz) + 1);
++		if (!buf->encdata)
++			goto nothing;
++	}
++
++	res = mbs_safe_encode_to_buffer(data, cells, buf->encdata);
++	if (!res || !*cells || *cells == (size_t) -1)
++		goto nothing;
++	return res;
++nothing:
++	*cells = 0;
++	return NULL;
++}
++
++/* returns size in bytes of the ascii art (according to art_idx) in safe encoding */
++static size_t buffer_get_safe_art_size(struct libscols_buffer *buf)
++{
++	char *data = buffer_get_data(buf);
++	size_t bytes = 0;
++
++	if (!data || !buf->art_idx)
++		return 0;
++
++	mbs_safe_nwidth(data, buf->art_idx, &bytes);
++	return bytes;
++}
++
++#define is_last_column(_tb, _cl) \
++		list_entry_is_last(&(_cl)->cl_columns, &(_tb)->tb_columns)
++
++#define colsep(tb) ((tb)->colsep ? (tb)->colsep : " ")
++#define linesep(tb) ((tb)->linesep ? (tb)->linesep : "\n")
++
++static int print_data(struct libscols_table *tb,
++		      struct libscols_column *cl,
++		      struct libscols_line *ln,	/* optional */
++		      struct libscols_cell *ce,	/* optional */
++		      struct libscols_buffer *buf)
++{
++	size_t len = 0, i, width, bytes;
++	const char *color = NULL;
++	char *data;
++
++	assert(tb);
++	assert(cl);
++
++	DBG(TAB, ul_debugobj(tb,
++			" -> data, column=%p, line=%p, cell=%p, buff=%p",
++			cl, ln, ce, buf));
++
++	data = buffer_get_data(buf);
++	if (!data)
++		data = "";
++
++	/* raw mode */
++	if (scols_table_is_raw(tb)) {
++		fputs_nonblank(data, tb->out);
++		if (!is_last_column(tb, cl))
++			fputs(colsep(tb), tb->out);
++		return 0;
++	}
++
++	/* NAME=value mode */
++	if (scols_table_is_export(tb)) {
++		fprintf(tb->out, "%s=", scols_cell_get_data(&cl->header));
++		fputs_quoted(data, tb->out);
++		if (!is_last_column(tb, cl))
++			fputs(colsep(tb), tb->out);
++		return 0;
++	}
++
++	if (tb->colors_wanted) {
++		if (ce && !color)
++			color = ce->color;
++		if (ln && !color)
++			color = ln->color;
++		if (!color)
++			color = cl->color;
++	}
++
++	/* encode, note that 'len' and 'width' are number of cells, not bytes */
++	data = buffer_get_safe_data(buf, &len);
++	if (!data)
++		data = "";
++	width = cl->width;
++	bytes = strlen(data);
++
++	if (is_last_column(tb, cl) && len < width && !scols_table_is_maxout(tb))
++		width = len;
++
++	/* truncate data */
++	if (len > width && scols_column_is_trunc(cl)) {
++		len = width;
++		bytes = mbs_truncate(data, &len);	/* updates 'len' */
++
++		if (!data || bytes == (size_t) -1) {
++			bytes = len = 0;
++			data = NULL;
++		}
++	}
++
++	if (data) {
++		if (scols_column_is_right(cl)) {
++			size_t xw = cl->width;
++			if (color)
++				fputs(color, tb->out);
++			fprintf(tb->out, "%*s", (int) xw, data);
++			if (color)
++				fputs(UL_COLOR_RESET, tb->out);
++			if (len < xw)
++				len = xw;
++		} else if (color) {
++			char *p = data;
++			size_t art = buffer_get_safe_art_size(buf);
++
++			/* we don't want to colorize tree ascii art */
++			if (scols_column_is_tree(cl) && art && art < bytes) {
++				fwrite(p, 1, art, tb->out);
++				p += art;
++			}
++
++			fputs(color, tb->out);
++			fputs(p, tb->out);
++			fputs(UL_COLOR_RESET, tb->out);
++		} else
++			fputs(data, tb->out);
++	}
++	for (i = len; i < width; i++)
++		fputs(" ", tb->out);		/* padding */
++
++	if (!is_last_column(tb, cl)) {
++		if (len > width && !scols_column_is_trunc(cl)) {
++			fputs(linesep(tb), tb->out);
++			for (i = 0; i <= (size_t) cl->seqnum; i++) {
++				struct libscols_column *x = scols_table_get_column(tb, i);
++				fprintf(tb->out, "%*s ", -((int)x->width), " ");
++			}
++		} else
++			fputs(colsep(tb), tb->out);	/* columns separator */
++	}
++
++	return 0;
++}
++
++/* returns pointer to the end of used data */
++static int line_ascii_art_to_buffer(struct libscols_table *tb,
++				    struct libscols_line *ln,
++				    struct libscols_buffer *buf)
++{
++	const char *art;
++	int rc;
++
++	assert(ln);
++	assert(buf);
++
++	if (!ln->parent)
++		return 0;
++
++	rc = line_ascii_art_to_buffer(tb, ln->parent, buf);
++	if (rc)
++		return rc;
++
++	if (list_entry_is_last(&ln->ln_children, &ln->parent->ln_branch))
++		art = "  ";
++	else
++		art = tb->symbols->vert;
++
++	return buffer_append_data(buf, art);
++}
++
++static int cell_to_buffer(struct libscols_table *tb,
++			  struct libscols_line *ln,
++			  struct libscols_column *cl,
++			  struct libscols_buffer *buf)
++{
++	const char *data;
++	struct libscols_cell *ce;
++	int rc = 0;
++
++	assert(tb);
++	assert(ln);
++	assert(cl);
++	assert(buf);
++	assert(cl->seqnum <= tb->ncols);
++
++	buffer_reset_data(buf);
++
++	ce = scols_line_get_cell(ln, cl->seqnum);
++	data = ce ? scols_cell_get_data(ce) : NULL;
++	if (!data)
++		return 0;
++
++	if (!scols_column_is_tree(cl))
++		return buffer_set_data(buf, data);
++
++	/*
++	 * Tree stuff
++	 */
++	if (ln->parent) {
++		rc = line_ascii_art_to_buffer(tb, ln->parent, buf);
++
++		if (!rc && list_entry_is_last(&ln->ln_children, &ln->parent->ln_branch))
++			rc = buffer_append_data(buf, tb->symbols->right);
++		else if (!rc)
++			rc = buffer_append_data(buf, tb->symbols->branch);
++		if (!rc)
++			buffer_set_art_index(buf);
++	}
++
++	if (!rc)
++		rc = buffer_append_data(buf, data);
++	return rc;
++}
++
++/*
++ * Prints data, data maybe be printed in more formats (raw, NAME=xxx pairs) and
++ * control and non-printable chars maybe encoded in \x?? hex encoding.
++ */
++static int print_line(struct libscols_table *tb,
++		      struct libscols_line *ln,
++		      struct libscols_buffer *buf)
++{
++	int rc = 0;
++	struct libscols_column *cl;
++	struct libscols_iter itr;
++
++	assert(ln);
++
++	DBG(TAB, ul_debugobj(tb, "printing line, line=%p, buff=%p", ln, buf));
++
++	scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
++	while (rc == 0 && scols_table_next_column(tb, &itr, &cl) == 0) {
++		rc = cell_to_buffer(tb, ln, cl, buf);
++		if (!rc)
++			rc = print_data(tb, cl, ln,
++					scols_line_get_cell(ln, cl->seqnum),
++					buf);
++	}
++
++	if (rc == 0)
++		fputs(linesep(tb), tb->out);
++	return 0;
++}
++
++static int print_header(struct libscols_table *tb, struct libscols_buffer *buf)
++{
++	int rc = 0;
++	struct libscols_column *cl;
++	struct libscols_iter itr;
++
++	assert(tb);
++
++	if (scols_table_is_noheadings(tb) ||
++	    scols_table_is_export(tb) ||
++	    list_empty(&tb->tb_lines))
++		return 0;
++
++	DBG(TAB, ul_debugobj(tb, "printing header"));
++
++	/* set width according to the size of data
++	 */
++	scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
++	while (rc == 0 && scols_table_next_column(tb, &itr, &cl) == 0) {
++		rc = buffer_set_data(buf, scols_cell_get_data(&cl->header));
++		if (!rc)
++			rc = print_data(tb, cl, NULL, &cl->header, buf);
++	}
++
++	if (rc == 0)
++		fputs(linesep(tb), tb->out);
++	return rc;
++}
++
++static int print_table(struct libscols_table *tb, struct libscols_buffer *buf)
++{
++	int rc;
++	struct libscols_line *ln;
++	struct libscols_iter itr;
++
++	assert(tb);
++
++	rc = print_header(tb, buf);
++
++	scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
++	while (rc == 0 && scols_table_next_line(tb, &itr, &ln) == 0)
++		rc = print_line(tb, ln, buf);
++
++	return rc;
++}
++
++static int print_tree_line(struct libscols_table *tb,
++			   struct libscols_line *ln,
++			   struct libscols_buffer *buf)
++{
++	int rc;
++	struct list_head *p;
++
++	rc = print_line(tb, ln, buf);
++	if (rc)
++		return rc;
++	if (list_empty(&ln->ln_branch))
++		return 0;
++
++	/* print all children */
++	list_for_each(p, &ln->ln_branch) {
++		struct libscols_line *chld =
++				list_entry(p, struct libscols_line, ln_children);
++		rc = print_tree_line(tb, chld, buf);
++		if (rc)
++			break;
++	}
++
++	return rc;
++}
++
++static int print_tree(struct libscols_table *tb, struct libscols_buffer *buf)
++{
++	int rc;
++	struct libscols_line *ln;
++	struct libscols_iter itr;
++
++	assert(tb);
++
++	DBG(TAB, ul_debugobj(tb, "printing tree"));
++
++	rc = print_header(tb, buf);
++
++	scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
++	while (rc == 0 && scols_table_next_line(tb, &itr, &ln) == 0) {
++		if (ln->parent)
++			continue;
++		rc = print_tree_line(tb, ln, buf);
++	}
++
++	return rc;
++}
++
++static void dbg_column(struct libscols_table *tb, struct libscols_column *cl)
++{
++	DBG(COL, ul_debugobj(cl, "%15s seq=%zu, width=%zd, "
++				 "hint=%d, avg=%zu, max=%zu, min=%zu, "
++				 "extreme=%s",
++
++		cl->header.data, cl->seqnum, cl->width,
++		cl->width_hint > 1 ? (int) cl->width_hint :
++				     (int) (cl->width_hint * tb->termwidth),
++		cl->width_avg,
++		cl->width_max,
++		cl->width_min,
++		cl->is_extreme ? "yes" : "not"));
++}
++
++static void dbg_columns(struct libscols_table *tb)
++{
++	struct libscols_iter itr;
++	struct libscols_column *cl;
++
++	scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
++	while (scols_table_next_column(tb, &itr, &cl) == 0)
++		dbg_column(tb, cl);
++}
++
++/*
++ * This function counts column width.
++ *
++ * For the SCOLS_FL_NOEXTREMES columns is possible to call this function two
++ * times.  The first pass counts width and average width. If the column
++ * contains too large fields (width greater than 2 * average) then the column
++ * is marked as "extreme". In the second pass all extreme fields are ignored
++ * and column width is counted from non-extreme fields only.
++ */
++static int count_column_width(struct libscols_table *tb,
++			      struct libscols_column *cl,
++			      struct libscols_buffer *buf)
++{
++	struct libscols_line *ln;
++	struct libscols_iter itr;
++	int count = 0, rc = 0;
++	size_t sum = 0;
++
++	assert(tb);
++	assert(cl);
++
++	cl->width = 0;
++
++	scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
++	while (scols_table_next_line(tb, &itr, &ln) == 0) {
++		size_t len;
++		char *data;
++
++		rc = cell_to_buffer(tb, ln, cl, buf);
++		if (rc)
++			return rc;
++
++		data = buffer_get_data(buf);
++		len = data ? mbs_safe_width(data) : 0;
++
++		if (len == (size_t) -1)		/* ignore broken multibyte strings */
++			len = 0;
++		if (len > cl->width_max)
++			cl->width_max = len;
++
++		if (cl->is_extreme && len > cl->width_avg * 2)
++			continue;
++		else if (scols_column_is_noextremes(cl)) {
++			sum += len;
++			count++;
++		}
++		if (len > cl->width)
++			cl->width = len;
++	}
++
++	if (count && cl->width_avg == 0) {
++		cl->width_avg = sum / count;
++
++		if (cl->width_max > cl->width_avg * 2)
++			cl->is_extreme = 1;
++	}
++
++	/* check and set minimal column width */
++	if (scols_cell_get_data(&cl->header))
++		cl->width_min = mbs_safe_width(scols_cell_get_data(&cl->header));
++
++	/* enlarge to minimal width */
++	if (cl->width < cl->width_min && !scols_column_is_strict_width(cl))
++		cl->width = cl->width_min;
++
++	/* use relative size for large columns */
++	else if (cl->width_hint >= 1 && cl->width < (size_t) cl->width_hint
++		 && cl->width_min < (size_t) cl->width_hint)
++
++		cl->width = (size_t) cl->width_hint;
++
++	ON_DBG(COL, dbg_column(tb, cl));
++	return rc;
++}
++
++
++/*
++ * This is core of the scols_* voodo...
++ */
++static int recount_widths(struct libscols_table *tb, struct libscols_buffer *buf)
++{
++	struct libscols_column *cl;
++	struct libscols_iter itr;
++	size_t width = 0;		/* output width */
++	int trunc_only, rc = 0;
++	int extremes = 0;
++
++
++	DBG(TAB, ul_debugobj(tb, "recounting widths (termwidth=%zu)", tb->termwidth));
++
++	/* set basic columns width
++	 */
++	scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
++	while (scols_table_next_column(tb, &itr, &cl) == 0) {
++		rc = count_column_width(tb, cl, buf);
++		if (rc)
++			return rc;
++
++		width += cl->width + (is_last_column(tb, cl) ? 0 : 1);
++		extremes += cl->is_extreme;
++	}
++
++	if (!tb->is_term)
++		return 0;
++
++	/* reduce columns with extreme fields
++	 */
++	if (width > tb->termwidth && extremes) {
++		DBG(TAB, ul_debugobj(tb, "   reduce width (extreme columns)"));
++
++		scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
++		while (scols_table_next_column(tb, &itr, &cl) == 0) {
++			size_t org_width;
++
++			if (!cl->is_extreme)
++				continue;
++
++			org_width = cl->width;
++			rc = count_column_width(tb, cl, buf);
++			if (rc)
++				return rc;
++
++			if (org_width > cl->width)
++				width -= org_width - cl->width;
++			else
++				extremes--;	/* hmm... nothing reduced */
++		}
++	}
++
++	if (width < tb->termwidth) {
++		if (extremes) {
++			DBG(TAB, ul_debugobj(tb, "   enlarge width (extreme columns)"));
++
++			/* enlarge the first extreme column */
++			scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
++			while (scols_table_next_column(tb, &itr, &cl) == 0) {
++				size_t add;
++
++				if (!cl->is_extreme)
++					continue;
++
++				/* this column is tooo large, ignore?
++				if (cl->width_max - cl->width >
++						(tb->termwidth - width))
++					continue;
++				*/
++
++				add = tb->termwidth - width;
++				if (add && cl->width + add > cl->width_max)
++					add = cl->width_max - cl->width;
++
++				cl->width += add;
++				width += add;
++
++				if (width == tb->termwidth)
++					break;
++			}
++		}
++
++		if (width < tb->termwidth && scols_table_is_maxout(tb)) {
++			DBG(TAB, ul_debugobj(tb, "   enlarge width (max-out)"));
++
++			/* try enlarge all columns */
++			while (width < tb->termwidth) {
++				scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
++				while (scols_table_next_column(tb, &itr, &cl) == 0) {
++					cl->width++;
++					width++;
++					if (width == tb->termwidth)
++						break;
++				}
++			}
++		} else if (width < tb->termwidth) {
++			/* enlarge the last column */
++			struct libscols_column *cl = list_entry(
++				tb->tb_columns.prev, struct libscols_column, cl_columns);
++
++			DBG(TAB, ul_debugobj(tb, "   enlarge width (last column)"));
++
++			if (!scols_column_is_right(cl) && tb->termwidth - width > 0) {
++				cl->width += tb->termwidth - width;
++				width = tb->termwidth;
++			}
++		}
++	}
++
++	/* bad, we have to reduce output width, this is done in two steps:
++	 * 1/ reduce columns with a relative width and with truncate flag
++	 * 2) reduce columns with a relative width without truncate flag
++	 */
++	trunc_only = 1;
++	while (width > tb->termwidth) {
++		size_t org = width;
++
++		DBG(TAB, ul_debugobj(tb, "   reduce width (current=%zu, "
++					 "wanted=%zu, mode=%s)",
++					width, tb->termwidth,
++					trunc_only ? "trunc-only" : "all-relative"));
++
++		scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
++		while (scols_table_next_column(tb, &itr, &cl) == 0) {
++			if (width <= tb->termwidth)
++				break;
++			if (cl->width_hint > 1 && !scols_column_is_trunc(cl))
++				continue;	/* never truncate columns with absolute sizes */
++			if (scols_column_is_tree(cl))
++				continue;	/* never truncate the tree */
++			if (trunc_only && !scols_column_is_trunc(cl))
++				continue;
++			if (cl->width == cl->width_min)
++				continue;
++
++			/* truncate column with relative sizes */
++			if (cl->width_hint < 1 && cl->width > 0 && width > 0 &&
++			    cl->width > cl->width_hint * tb->termwidth) {
++				cl->width--;
++				width--;
++			}
++			/* truncate column with absolute size */
++			if (cl->width_hint > 1 && cl->width > 0 && width > 0 &&
++			    !trunc_only) {
++				cl->width--;
++				width--;
++			}
++
++		}
++		if (org == width) {
++			if (trunc_only)
++				trunc_only = 0;
++			else
++				break;
++		}
++	}
++
++	DBG(TAB, ul_debugobj(tb, "  result: %zu", width));
++	ON_DBG(TAB, dbg_columns(tb));
++
++	return rc;
++}
++
++static size_t strlen_line(struct libscols_line *ln)
++{
++	size_t i, sz = 0;
++
++	assert(ln);
++
++	for (i = 0; i < ln->ncells; i++) {
++		struct libscols_cell *ce = scols_line_get_cell(ln, i);
++		const char *data = ce ? scols_cell_get_data(ce) : NULL;
++
++		sz += data ? strlen(data) : 0;
++	}
++
++	return sz;
++}
++
++
++
++/**
++ * scols_print_table:
++ * @tb: table
++ *
++ * Prints the table to the output stream.
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_print_table(struct libscols_table *tb)
++{
++	int rc = 0;
++	size_t bufsz;
++	struct libscols_line *ln;
++	struct libscols_iter itr;
++	struct libscols_buffer *buf;
++
++	assert(tb);
++	if (!tb)
++		return -1;
++
++	DBG(TAB, ul_debugobj(tb, "printing"));
++	if (!tb->symbols)
++		scols_table_set_symbols(tb, NULL);	/* use default */
++
++	tb->is_term = isatty(STDOUT_FILENO) ? 1 : 0;
++	tb->termwidth = tb->is_term ? get_terminal_width() : 0;
++	if (tb->termwidth <= 0)
++		tb->termwidth = 80;
++	tb->termwidth -= tb->termreduce;
++
++	bufsz = tb->termwidth;
++
++	scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
++	while (scols_table_next_line(tb, &itr, &ln) == 0) {
++		size_t sz = strlen_line(ln);
++		if (sz > bufsz)
++			bufsz = sz;
++	}
++
++	buf = new_buffer(bufsz + 1);	/* data + space for \0 */
++	if (!buf)
++		return -ENOMEM;
++
++	if (!(scols_table_is_raw(tb) || scols_table_is_export(tb))) {
++		rc = recount_widths(tb, buf);
++		if (rc != 0)
++			goto done;
++	}
++
++	if (scols_table_is_tree(tb))
++		rc = print_tree(tb, buf);
++	else
++		rc = print_table(tb, buf);
++
++done:
++	free_buffer(buf);
++	return rc;
++}
++
++/**
++ * scols_print_table_to_string:
++ * @tb: table
++ * @data: pointer to the beginning of a memory area to print to
++ *
++ * Prints the table to @data.
++ *
++ * Returns: 0, a negative value in case of an error.
++ */
++int scols_print_table_to_string(struct libscols_table *tb, char **data)
++{
++#ifdef HAVE_OPEN_MEMSTREAM
++	FILE *stream;
++	size_t sz;
++	int rc;
++
++	if (!tb)
++		return -EINVAL;
++
++	DBG(TAB, ul_debugobj(tb, "printing to string"));
++
++	/* create a stream for output */
++	stream = open_memstream(data, &sz);
++	if (!stream)
++		return -ENOMEM;
++
++	scols_table_set_stream(tb, stream);
++	rc = scols_print_table(tb);
++	fclose(stream);
++
++	return rc;
++#else
++	return -ENOSYS;
++#endif
++}
++
+diff -up util-linux-2.23.2/libsmartcols/src/test.c.kzak util-linux-2.23.2/libsmartcols/src/test.c
+--- util-linux-2.23.2/libsmartcols/src/test.c.kzak	2014-09-25 14:41:48.993843953 +0200
++++ util-linux-2.23.2/libsmartcols/src/test.c	2014-09-25 14:41:48.993843953 +0200
+@@ -0,0 +1,218 @@
++/*
++ * Copyright (C) 2010-2014 Karel Zak <kzak@redhat.com>
++ *
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ */
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <errno.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <dirent.h>
++#include <getopt.h>
++
++#include "c.h"
++#include "nls.h"
++#include "strutils.h"
++
++#include "libsmartcols.h"
++
++static int add_children(struct libscols_table *tb,
++			struct libscols_line *ln, int fd);
++
++
++enum { COL_MODE, COL_SIZE, COL_NAME };
++
++/* add columns to the @tb */
++static void setup_columns(struct libscols_table *tb, int notree)
++{
++	if (!scols_table_new_column(tb, "MODE", 0.3, 0))
++		goto fail;
++	if (!scols_table_new_column(tb, "SIZE", 5, SCOLS_FL_RIGHT))
++		goto fail;
++	if (!scols_table_new_column(tb, "NAME", 0.5,
++			(notree ? 0 : SCOLS_FL_TREE) | SCOLS_FL_NOEXTREMES))
++		goto fail;
++
++	return;
++fail:
++	scols_unref_table(tb);
++	err(EXIT_FAILURE, "faild to create output columns");
++}
++
++/* add a new line to @tb, the content is based on @st */
++static int add_line_from_stat(struct libscols_table *tb,
++			      struct libscols_line *parent,
++			      int parent_fd,
++			      struct stat *st,
++			      const char *name)
++{
++	struct libscols_line *ln;
++	char modbuf[11], *p;
++	mode_t mode = st->st_mode;
++	int rc = 0;
++
++	ln = scols_table_new_line(tb, parent);
++	if (!ln)
++		err(EXIT_FAILURE, "failed to create output line");
++
++	/* MODE; local buffer, use scols_line_set_data() that calls strdup() */
++	strmode(mode, modbuf);
++	if (scols_line_set_data(ln, COL_MODE, modbuf))
++		goto fail;
++
++	/* SIZE; already allocated string, use scols_line_refer_data() */
++	p = size_to_human_string(0, st->st_size);
++	if (!p || scols_line_refer_data(ln, COL_SIZE, p))
++		goto fail;
++
++	/* NAME */
++	if (scols_line_set_data(ln, COL_NAME, name))
++		goto fail;
++
++	/* colors */
++	if (scols_table_colors_wanted(tb)) {
++		struct libscols_cell *ce = scols_line_get_cell(ln, COL_NAME);
++
++		if (S_ISDIR(mode))
++			scols_cell_set_color(ce, "blue");
++		else if (S_ISLNK(mode))
++			scols_cell_set_color(ce, "cyan");
++		else if (S_ISBLK(mode))
++			scols_cell_set_color(ce, "magenta");
++		else if ((mode & S_IXOTH) || (mode & S_IXGRP) || (mode & S_IXUSR))
++			scols_cell_set_color(ce, "green");
++	}
++
++	if (S_ISDIR(st->st_mode)) {
++		int fd;
++
++		if (parent_fd >= 0)
++			fd = openat(parent_fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC);
++		else
++			fd = open(name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC);
++		if (fd >= 0) {
++			rc = add_children(tb, ln, fd);
++			close(fd);
++		}
++	}
++	return rc;
++fail:
++	err(EXIT_FAILURE, "failed to create cell data");
++	return -1;
++}
++
++/* read all entrines from directory addressed by @fd */
++static int add_children(struct libscols_table *tb,
++			struct libscols_line *ln,
++			int fd)
++{
++	DIR *dir;
++	struct dirent *d;
++
++	dir = fdopendir(fd);
++	if (!dir)
++		return -errno;
++
++	while ((d = readdir(dir))) {
++		struct stat st;
++
++		if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0)
++			continue;
++		if (fstatat(fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW) != 0)
++			continue;
++		add_line_from_stat(tb, ln, fd, &st, d->d_name);
++	}
++	closedir(dir);
++	return 0;
++}
++
++static void add_lines(struct libscols_table *tb, const char *dirname)
++{
++	struct stat st;
++
++	if (lstat(dirname, &st))
++		err(EXIT_FAILURE, "%s", dirname);
++
++	add_line_from_stat(tb, NULL, -1, &st, dirname);
++}
++
++static void __attribute__((__noreturn__)) usage(FILE *out)
++{
++	fprintf(out, " %s [options] [<dir> ...]\n\n", program_invocation_short_name);
++	fputs(" -c, --csv            display a csv-like output\n", out);
++	fputs(" -i, --ascii          use ascii characters only\n", out);
++	fputs(" -l, --list           use list format output\n", out);
++	fputs(" -n, --noheadings     don't print headings\n", out);
++	fputs(" -p, --pairs          use key=\"value\" output format\n", out);
++	fputs(" -r, --raw            use raw output format\n", out);
++
++	exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
++}
++
++int main(int argc, char *argv[])
++{
++	struct libscols_table *tb;
++	int c, notree = 0;
++
++	static const struct option longopts[] = {
++		{ "ascii",	0, 0, 'i' },
++		{ "csv",        0, 0, 'c' },
++		{ "list",       0, 0, 'l' },
++		{ "noheadings",	0, 0, 'n' },
++		{ "pairs",      0, 0, 'p' },
++		{ "raw",      0, 0, 'r' },
++
++		{ NULL, 0, 0, 0 },
++	};
++
++	setlocale(LC_ALL, "");	/* just to have enable UTF8 chars */
++
++	scols_init_debug(0);
++
++	tb = scols_new_table();
++	if (!tb)
++		err(EXIT_FAILURE, "faild to create output table");
++
++	while((c = getopt_long(argc, argv, "cilnpr", longopts, NULL)) != -1) {
++		switch(c) {
++		case 'c':
++			scols_table_set_column_separator(tb, ",");
++			scols_table_enable_raw(tb, 1);
++			notree = 1;
++			break;
++		case 'i':
++			scols_table_enable_ascii(tb, 1);
++			break;
++		case 'l':
++			notree = 1;
++			break;
++		case 'n':
++			scols_table_enable_noheadings(tb, 1);
++			break;
++		case 'p':
++			scols_table_enable_export(tb, 1);
++			notree = 1;
++			break;
++		case 'r':
++			scols_table_enable_raw(tb, 1);
++			notree = 1;
++			break;
++		default:
++			usage(stderr);
++		}
++	}
++
++	scols_table_enable_colors(tb, 1);
++	setup_columns(tb, notree);
++
++	while (optind < argc)
++		add_lines(tb, argv[optind++]);
++
++	scols_print_table(tb);
++	scols_unref_table(tb);
++
++	return EXIT_SUCCESS;
++}
+diff -up util-linux-2.23.2/libsmartcols/src/version.c.kzak util-linux-2.23.2/libsmartcols/src/version.c
+--- util-linux-2.23.2/libsmartcols/src/version.c.kzak	2014-09-25 14:41:48.993843953 +0200
++++ util-linux-2.23.2/libsmartcols/src/version.c	2014-09-25 14:41:48.993843953 +0200
+@@ -0,0 +1,62 @@
++/*
++ * version.c - Return the version of the library
++ *
++ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
++ *
++ * See COPYING.libmount for the License of this software.
++ */
++
++/**
++ * SECTION: version-utils
++ * @title: Version functions
++ * @short_description: functions to get the library version.
++ *
++ * Note that library version is not the same thing as SONAME version. The
++ * libsmarcols uses symbols versioning and SONAME is not modified for releases.
++ *
++ * The library version and symbols version follow util-linux package versioning.
++ */
++
++#include <ctype.h>
++
++#include "smartcolsP.h"
++
++static const char *lib_version = LIBSMARTCOLS_VERSION;
++
++/**
++ * scols_parse_version_string:
++ * @ver_string: version string (e.g "2.18.0")
++ *
++ * Returns: release version code.
++ */
++int scols_parse_version_string(const char *ver_string)
++{
++	const char *cp;
++	int version = 0;
++
++	assert(ver_string);
++
++	for (cp = ver_string; *cp; cp++) {
++		if (*cp == '.')
++			continue;
++		if (!isdigit(*cp))
++			break;
++		version = (version * 10) + (*cp - '0');
++	}
++	return version;
++}
++
++/**
++ * scols_get_library_version:
++ * @ver_string: return pointer to the static library version string if not NULL
++ *
++ * Returns: release version number.
++ */
++int scols_get_library_version(const char **ver_string)
++{
++	if (ver_string)
++		*ver_string = lib_version;
++
++	return scols_parse_version_string(lib_version);
++}
++
+diff -up util-linux-2.23.2/lib/tt.c.kzak util-linux-2.23.2/lib/tt.c
+--- util-linux-2.23.2/lib/tt.c.kzak	2013-07-15 10:25:46.280049032 +0200
++++ util-linux-2.23.2/lib/tt.c	2014-09-25 14:41:48.982843848 +0200
+@@ -52,140 +52,6 @@ static const struct tt_symbols utf8_tt_s
+ #define is_last_column(_tb, _cl) \
+ 		list_entry_is_last(&(_cl)->cl_columns, &(_tb)->tb_columns)
+ 
+-/*
+- * Counts number of cells in multibyte string. For all control and
+- * non-printable chars is the result width enlarged to store \x?? hex
+- * sequence. See mbs_safe_encode().
+- */
+-static size_t mbs_safe_width(const char *s)
+-{
+-	mbstate_t st;
+-	const char *p = s;
+-	size_t width = 0;
+-
+-	memset(&st, 0, sizeof(st));
+-
+-	while (p && *p) {
+-		if (iscntrl((unsigned char) *p)) {
+-			width += 4;			/* *p encoded to \x?? */
+-			p++;
+-		}
+-#ifdef HAVE_WIDECHAR
+-		else {
+-			wchar_t wc;
+-			size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st);
+-
+-			if (len == 0)
+-				break;
+-
+-			if (len == (size_t) -1 || len == (size_t) -2) {
+-				len = 1;
+-				width += (isprint((unsigned char) *p) ? 1 : 4);
+-
+-			} if (!iswprint(wc))
+-				width += len * 4;	/* hex encode whole sequence */
+-			else
+-				width += wcwidth(wc);	/* number of cells */
+-			p += len;
+-		}
+-#else
+-		else if (!isprint((unsigned char) *p)) {
+-			width += 4;			/* *p encoded to \x?? */
+-			p++;
+-		} else {
+-			width++;
+-			p++;
+-		}
+-#endif
+-	}
+-
+-	return width;
+-}
+-
+-/*
+- * Returns allocated string where all control and non-printable chars are
+- * replaced with \x?? hex sequence.
+- */
+-static char *mbs_safe_encode(const char *s, size_t *width)
+-{
+-	mbstate_t st;
+-	const char *p = s;
+-	char *res, *r;
+-	size_t sz = s ? strlen(s) : 0;
+-
+-
+-	if (!sz)
+-		return NULL;
+-
+-	memset(&st, 0, sizeof(st));
+-
+-	res = malloc((sz * 4) + 1);
+-	if (!res)
+-		return NULL;
+-
+-	r = res;
+-	*width = 0;
+-
+-	while (p && *p) {
+-		if (iscntrl((unsigned char) *p)) {
+-			sprintf(r, "\\x%02x", (unsigned char) *p);
+-			r += 4;
+-			*width += 4;
+-			p++;
+-		}
+-#ifdef HAVE_WIDECHAR
+-		else {
+-			wchar_t wc;
+-			size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st);
+-
+-			if (len == 0)
+-				break;		/* end of string */
+-
+-			if (len == (size_t) -1 || len == (size_t) -2) {
+-				len = 1;
+-				/*
+-				 * Not valid multibyte sequence -- maybe it's
+-				 * printable char according to the current locales.
+-				 */
+-				if (!isprint((unsigned char) *p)) {
+-					sprintf(r, "\\x%02x", (unsigned char) *p);
+-					r += 4;
+-					*width += 4;
+-				} else {
+-					width++;
+-					*r++ = *p;
+-				}
+-			} else if (!iswprint(wc)) {
+-				size_t i;
+-				for (i = 0; i < len; i++) {
+-					sprintf(r, "\\x%02x", (unsigned char) *p);
+-					r += 4;
+-					*width += 4;
+-				}
+-			} else {
+-				memcpy(r, p, len);
+-				r += len;
+-				*width += wcwidth(wc);
+-			}
+-			p += len;
+-		}
+-#else
+-		else if (!isprint((unsigned char) *p)) {
+-			sprintf(r, "\\x%02x", (unsigned char) *p);
+-			p++;
+-			r += 4;
+-			*width += 4;
+-		} else {
+-			*r++ = *p++;
+-			*width++;
+-		}
+-#endif
+-	}
+-
+-	*r = '\0';
+-
+-	return res;
+-}
+ 
+ /*
+  * @flags: TT_FL_* flags (usually TT_FL_{ASCII,RAW})
+diff -up util-linux-2.23.2/Makefile.am.kzak util-linux-2.23.2/Makefile.am
+--- util-linux-2.23.2/Makefile.am.kzak	2013-06-13 09:46:10.334649886 +0200
++++ util-linux-2.23.2/Makefile.am	2014-09-25 14:41:48.979843819 +0200
+@@ -22,6 +22,7 @@ dist_noinst_DATA = $(dist_man_MANS)
+ #
+ ul_libblkid_incdir = $(top_builddir)/libblkid/src
+ ul_libmount_incdir = $(top_builddir)/libmount/src
++ul_libsmartcols_incdir = $(top_builddir)/libsmartcols/src
+ ul_libuuid_incdir  = $(top_srcdir)/libuuid/src
+ ul_libfdisk_incdir  = $(top_srcdir)/libfdisk/src
+ 
+@@ -77,6 +78,7 @@ include lib/Makemodule.am
+ include libuuid/Makemodule.am
+ include libblkid/Makemodule.am
+ include libmount/Makemodule.am
++include libsmartcols/Makemodule.am
+ include libfdisk/Makemodule.am
+ 
+ include schedutils/Makemodule.am
diff --git a/SOURCES/2.26-logger-man-kern.patch b/SOURCES/2.26-logger-man-kern.patch
new file mode 100644
index 0000000..b7b9434
--- /dev/null
+++ b/SOURCES/2.26-logger-man-kern.patch
@@ -0,0 +1,72 @@
+diff -up util-linux-2.23.2/misc-utils/logger.1.kzak util-linux-2.23.2/misc-utils/logger.1
+--- util-linux-2.23.2/misc-utils/logger.1.kzak	2015-06-24 12:18:23.938735038 +0200
++++ util-linux-2.23.2/misc-utils/logger.1	2015-06-24 12:18:33.154667053 +0200
+@@ -125,28 +125,49 @@ flag is not provided, standard input is
+ The
+ .B logger
+ utility exits 0 on success, and >0 if an error occurs.
+-.PP
++.SH FACILITIES AND LEVELS
+ Valid facility names are:
+-.IR auth , \ authpriv
+-(for security information of a sensitive nature),
+-.IR cron , \ daemon , \ ftp , \ kern
+-(can't be generated from user process),
+-.IR lpr , \ mail , \ news , \ security
+-(deprecated synonym for
+-.IR auth ), \ syslog , \ user , \ uucp ,
+-and
+-.IR local0 \ to \ local7 ,
+-inclusive.
++.IP
++.TS
++tab(:);
++left l l.
++\fBauth
++\fBauthpriv\fR:for security information of a sensitive nature
++\fBcron
++\fBdaemon
++\fBftp
++\fBkern\fR:cannot be generated from userspace process, automatically converted to \fBuser
++\fBlpr
++\fBmail
++\fBnews
++\fBsyslog
++\fBuser
++\fBuucp
++\fBlocal0
++  to:
++\fBlocal7
++\fBsecurity\fR:deprecated synonym for \fBauth
++.TE
+ .PP
+ Valid level names are:
+-.IR alert , \ crit , \ debug , \ emerg , \ err , \ error
+-(deprecated synonym for
+-.IR err ), \ info , \ notice , \ panic
+-(deprecated synonym for
+-.IR  emerg ), \ warning , \ warn
+-(deprecated synonym for
+-.IR warning ).
+-For the priority order and intended purposes of these levels, see
++.IP
++.TS
++tab(:);
++left l l.
++\fBemerg
++\fBalert
++\fBcrit
++\fBerr
++\fBwarning
++\fBnotice
++\fBinfo
++\fBdebug
++\fBpanic\fR:deprecated synonym for \fBemerg
++\fBerror\fR:deprecated synonym for \fBerr
++\fBwarn\fR:deprecated synonym for \fBwarning
++.TE
++.PP
++For the priority order and intended purposes of these facilities and levels, see
+ .BR syslog (3).
+ .SH EXAMPLES
+ logger System rebooted
diff --git a/SOURCES/2.26-login-SIGXFSZ.patch b/SOURCES/2.26-login-SIGXFSZ.patch
new file mode 100644
index 0000000..0f49c9a
--- /dev/null
+++ b/SOURCES/2.26-login-SIGXFSZ.patch
@@ -0,0 +1,39 @@
+diff -up util-linux-2.23.2/login-utils/login.c.kzak util-linux-2.23.2/login-utils/login.c
+--- util-linux-2.23.2/login-utils/login.c.kzak	2015-06-24 11:03:45.123285155 +0200
++++ util-linux-2.23.2/login-utils/login.c	2015-06-24 11:46:19.168114438 +0200
+@@ -495,6 +495,7 @@ static void log_audit(struct login_conte
+ 
+ static void log_lastlog(struct login_context *cxt)
+ {
++	struct sigaction sa, oldsa_xfsz;
+ 	struct lastlog ll;
+ 	time_t t;
+ 	int fd;
+@@ -502,9 +503,14 @@ static void log_lastlog(struct login_con
+ 	if (!cxt->pwd)
+ 		return;
+ 
++	/* lastlog is huge on systems with large UIDs, ignore SIGXFSZ */
++	memset(&sa, 0, sizeof(sa));
++	sa.sa_handler = SIG_IGN;
++	sigaction(SIGXFSZ, &sa, &oldsa_xfsz);
++
+ 	fd = open(_PATH_LASTLOG, O_RDWR | O_CREAT, 0);
+ 	if (fd < 0)
+-		return;
++		goto done;
+ 
+ 	if (lseek(fd, (off_t) cxt->pwd->pw_uid * sizeof(ll), SEEK_SET) == -1)
+ 		goto done;
+@@ -542,7 +548,10 @@ static void log_lastlog(struct login_con
+ 	if (write_all(fd, (char *)&ll, sizeof(ll)))
+ 		warn(_("write lastlog failed"));
+ done:
+-	close(fd);
++	if (fd >= 0)
++		close(fd);
++
++	sigaction(SIGXFSZ, &oldsa_xfsz, NULL);		/* restore original setting */
+ }
+ 
+ /*
diff --git a/SOURCES/2.26-lsblk-mpath.patch b/SOURCES/2.26-lsblk-mpath.patch
new file mode 100644
index 0000000..1e7fae2
--- /dev/null
+++ b/SOURCES/2.26-lsblk-mpath.patch
@@ -0,0 +1,64 @@
+diff -up util-linux-2.23.2/misc-utils/lsblk.c.kzak util-linux-2.23.2/misc-utils/lsblk.c
+--- util-linux-2.23.2/misc-utils/lsblk.c.kzak	2015-06-25 11:01:10.543344225 +0200
++++ util-linux-2.23.2/misc-utils/lsblk.c	2015-06-25 11:14:17.085404974 +0200
+@@ -953,11 +953,13 @@ static void set_tt_data(struct blkdev_cx
+ 	};
+ }
+ 
+-static void print_device(struct blkdev_cxt *cxt, struct tt_line *tt_parent)
++static void fill_table_line(struct blkdev_cxt *cxt, struct tt_line *tt_parent)
+ {
+ 	int i;
+ 
+ 	cxt->tt_line = tt_add_line(lsblk->tt, tt_parent);
++	if (!cxt->tt_line)
++		return;
+ 
+ 	for (i = 0; i < ncolumns; i++)
+ 		set_tt_data(cxt, i, get_column_id(i), cxt->tt_line);
+@@ -1084,7 +1086,7 @@ static int list_partitions(struct blkdev
+ 				goto next;
+ 
+ 			wholedisk_cxt->parent = &part_cxt;
+-			print_device(&part_cxt, parent_cxt ? parent_cxt->tt_line : NULL);
++			fill_table_line(&part_cxt, parent_cxt ? parent_cxt->tt_line : NULL);
+ 			if (!lsblk->nodeps)
+ 				process_blkdev(wholedisk_cxt, &part_cxt, 0, NULL);
+ 		} else {
+@@ -1098,7 +1100,7 @@ static int list_partitions(struct blkdev
+ 
+ 			/* Print whole disk only once */
+ 			if (r)
+-				print_device(wholedisk_cxt, parent_cxt ? parent_cxt->tt_line : NULL);
++				fill_table_line(wholedisk_cxt, parent_cxt ? parent_cxt->tt_line : NULL);
+ 			if (ps == 0 && !lsblk->nodeps)
+ 				process_blkdev(&part_cxt, wholedisk_cxt, 0, NULL);
+ 		}
+@@ -1171,9 +1173,11 @@ static int list_deps(struct blkdev_cxt *
+ 			    process_blkdev(&dep, cxt, 1, d->d_name);
+ 		}
+ 		/* The dependency is a whole device. */
+-		else if (!set_cxt(&dep, cxt, NULL, d->d_name))
+-			process_blkdev(&dep, cxt, 1, NULL);
+-
++		else if (!set_cxt(&dep, cxt, NULL, d->d_name)) {
++			/* For inverse tree we don't want to show partitions
++			 * if the dependence is pn whle-disk */
++			process_blkdev(&dep, cxt, lsblk->inverse ? 0 : 1, NULL); 
++		}
+ 		reset_blkdev_cxt(&dep);
+ 	}
+ 	closedir(dir);
+@@ -1185,9 +1189,10 @@ static int process_blkdev(struct blkdev_
+ 			  int do_partitions, const char *part_name)
+ {
+ 	if (do_partitions && cxt->npartitions)
+-		return list_partitions(cxt, parent, part_name);
++		list_partitions(cxt, parent, part_name);                /* partitoins + whole-disk */
++	else
++		fill_table_line(cxt, parent ? parent->tt_line : NULL); /* whole-disk only */
+ 
+-	print_device(cxt, parent ? parent->tt_line : NULL);
+ 	return list_deps(cxt);
+ }
+ 
diff --git a/SOURCES/2.26-lslogins.patch b/SOURCES/2.26-lslogins.patch
new file mode 100644
index 0000000..4693263
--- /dev/null
+++ b/SOURCES/2.26-lslogins.patch
@@ -0,0 +1,2131 @@
+diff -up util-linux-2.23.2/configure.ac.kzak util-linux-2.23.2/configure.ac
+--- util-linux-2.23.2/configure.ac.kzak	2014-12-12 15:27:43.505631342 +0100
++++ util-linux-2.23.2/configure.ac	2014-12-12 15:28:30.571177081 +0100
+@@ -1027,6 +1027,11 @@ UL_REQUIRES_HAVE([lscpu], [cpu_set_t], [
+ AM_CONDITIONAL(BUILD_LSCPU, test "x$build_lscpu" = xyes)
+ 
+ 
++UL_BUILD_INIT([lslogins], [check])
++UL_REQUIRES_BUILD([lslogins], [libsmartcols])
++AM_CONDITIONAL([BUILD_LSLOGINS], [test "x$build_lslogins" = xyes])
++
++
+ UL_BUILD_INIT([chcpu], [check])
+ UL_REQUIRES_LINUX([chcpu])
+ UL_REQUIRES_HAVE([chcpu], [cpu_set_t], [cpu_set_t type])
+@@ -1404,6 +1409,37 @@ fi
+ AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != "xno" ])
+ 
+ 
++#
++# Backport from upstrem to RHEL7.1
++#
++AC_ARG_WITH([systemd],
++  AS_HELP_STRING([--with-systemd], [build with support for systemd]),
++  [], [with_systemd=check]
++)
++
++have_systemd=no
++AS_IF([test "x$with_systemd" != xno], [
++  # new version -- all libsystemd-* libs merged into libsystemd
++  PKG_CHECK_MODULES([SYSTEMD], [libsystemd], [have_systemd=yes], [have_systemd=no])
++  # old versions
++  AS_IF([test "x$have_systemd" != "xyes"], [
++    PKG_CHECK_MODULES([SYSTEMD_DAEMON], [libsystemd-daemon],
++		      [have_systemd_daemon=yes], [have_systemd_daemon=no])
++    PKG_CHECK_MODULES([SYSTEMD_JOURNAL], [libsystemd-journal],
++		      [have_systemd_journal=yes], [have_systemd_journal=no])
++    AS_IF([test "x$have_systemd_daemon" = "xyes" -a "x$have_systemd_journal" = "xyes" ],[
++	   have_systemd=yes])
++  ])
++  AS_CASE([$with_systemd:$have_systemd],
++    [yes:no],
++      [AC_MSG_ERROR([systemd expected but libsystemd not found])],
++    [*:yes],
++       AC_DEFINE([HAVE_LIBSYSTEMD], [1], [Define if libsystemd is available])
++  )
++])
++
++
++
+ AC_ARG_WITH([bashcompletiondir],
+   AS_HELP_STRING([--with-bashcompletiondir=DIR], [Bash completions directory]),
+   [],
+diff -up util-linux-2.23.2/include/Makemodule.am.kzak util-linux-2.23.2/include/Makemodule.am
+--- util-linux-2.23.2/include/Makemodule.am.kzak	2013-07-15 10:25:46.277049008 +0200
++++ util-linux-2.23.2/include/Makemodule.am	2014-12-12 15:28:30.571177081 +0100
+@@ -35,6 +35,7 @@ dist_noinst_HEADERS += \
+ 	include/procutils.h \
+ 	include/randutils.h \
+ 	include/rpmatch.h \
++	include/readutmp.h \
+ 	include/setproctitle.h \
+ 	include/strutils.h \
+ 	include/swapheader.h \
+diff -up util-linux-2.23.2/include/readutmp.h.kzak util-linux-2.23.2/include/readutmp.h
+--- util-linux-2.23.2/include/readutmp.h.kzak	2014-12-12 15:28:30.571177081 +0100
++++ util-linux-2.23.2/include/readutmp.h	2014-12-12 15:28:30.571177081 +0100
+@@ -0,0 +1,28 @@
++/* Declarations for GNU's read utmp module.
++
++   Copyright (C) 1992-2007, 2009-2014 Free Software Foundation, Inc.
++
++   This program is free software: you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; either version 3 of the License, or
++   (at your option) any later version.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
++
++/* Written by jla; revised by djm */
++
++#ifndef READUTMP_H
++#define READUTMP_H
++
++#include <sys/types.h>
++#include <utmp.h>
++
++int read_utmp (char const *file, size_t *n_entries, struct utmp **utmp_buf);
++
++#endif /* READUTMP_H */
+diff -up util-linux-2.23.2/lib/Makemodule.am.kzak util-linux-2.23.2/lib/Makemodule.am
+--- util-linux-2.23.2/lib/Makemodule.am.kzak	2013-07-30 10:39:26.202738200 +0200
++++ util-linux-2.23.2/lib/Makemodule.am	2014-12-12 15:28:30.572177092 +0100
+@@ -25,7 +25,8 @@ libcommon_la_SOURCES = \
+ 	lib/wholedisk.c \
+ 	lib/ttyutils.c \
+ 	lib/xgetpass.c \
+-	lib/exec_shell.c
++	lib/exec_shell.c \
++	lib/readutmp.c
+ 
+ if LINUX
+ libcommon_la_SOURCES += \
+diff -up util-linux-2.23.2/lib/readutmp.c.kzak util-linux-2.23.2/lib/readutmp.c
+--- util-linux-2.23.2/lib/readutmp.c.kzak	2014-12-12 15:28:30.572177092 +0100
++++ util-linux-2.23.2/lib/readutmp.c	2014-12-12 15:28:30.572177092 +0100
+@@ -0,0 +1,76 @@
++/* GNU's read utmp module.
++
++	 Copyright (C) 1992-2001, 2003-2006, 2009-2014 Free Software Foundation, Inc.
++
++	 This program is free software: you can redistribute it and/or modify
++	 it under the terms of the GNU General Public License as published by
++	 the Free Software Foundation; either version 3 of the License, or
++	 (at your option) any later version.
++
++	 This program is distributed in the hope that it will be useful,
++	 but WITHOUT ANY WARRANTY; without even the implied warranty of
++	 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
++	 GNU General Public License for more details.
++
++	 You should have received a copy of the GNU General Public License
++	 along with this program.	If not, see <http://www.gnu.org/licenses/>.	*/
++
++/* Written by jla; revised by djm */
++/* extracted for util-linux by ooprala */
++
++#include <errno.h>
++#include <stdio.h>
++
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <signal.h>
++#include <stdbool.h>
++#include <string.h>
++#include <stdlib.h>
++#include <stdint.h>
++
++#include "xalloc.h"
++#include "readutmp.h"
++
++/* Read the utmp entries corresponding to file FILE into freshly-
++	 malloc'd storage, set *UTMP_BUF to that pointer, set *N_ENTRIES to
++	 the number of entries, and return zero.	If there is any error,
++	 return -1, setting errno, and don't modify the parameters.
++	 If OPTIONS & READ_UTMP_CHECK_PIDS is nonzero, omit entries whose
++	 process-IDs do not currently exist.	*/
++int
++read_utmp (char const *file, size_t *n_entries, struct utmp **utmp_buf)
++{
++	size_t n_read = 0;
++	size_t n_alloc = 0;
++	struct utmp *utmp = NULL;
++	struct utmp *u;
++
++	/* Ignore the return value for now.
++		 Solaris' utmpname returns 1 upon success -- which is contrary
++		 to what the GNU libc version does.	In addition, older GNU libc
++		 versions are actually void.	 */
++	utmpname(file);
++
++	setutent();
++
++	errno = 0;
++	while ((u = getutent()) != NULL) {
++		if (n_read == n_alloc) {
++			n_alloc += 32;
++			utmp = xrealloc(utmp, n_alloc * sizeof (struct utmp));
++			if (!utmp)
++				return -1;
++		}
++		utmp[n_read++] = *u;
++	}
++	if (!u && errno)
++		return -1;
++
++	endutent();
++
++	*n_entries = n_read;
++	*utmp_buf = utmp;
++
++	return 0;
++}
+diff -up util-linux-2.23.2/login-utils/login.c.kzak util-linux-2.23.2/login-utils/login.c
+--- util-linux-2.23.2/login-utils/login.c.kzak	2014-12-12 15:27:43.436630542 +0100
++++ util-linux-2.23.2/login-utils/login.c	2014-12-12 15:28:30.573177104 +0100
+@@ -923,124 +923,6 @@ static void loginpam_session(struct logi
+ }
+ 
+ /*
+- * We need to check effective UID/GID. For example $HOME could be on root
+- * squashed NFS or on NFS with UID mapping and access(2) uses real UID/GID.
+- * The open(2) seems as the surest solution.
+- * -- kzak@redhat.com (10-Apr-2009)
+- */
+-static int effective_access(const char *path, int mode)
+-{
+-	int fd = open(path, mode);
+-	if (fd != -1)
+-		close(fd);
+-	return fd == -1 ? -1 : 0;
+-}
+-
+-/*
+- * Check per accout or global hush-login setting.
+- *
+- * Hushed mode is enabled:
+- *
+- * a) if global (e.g. /etc/hushlogins) hush file exists:
+- *     1) for ALL ACCOUNTS if the file is empty
+- *     2) for the current user if the username or shell are found in the file
+- *
+- * b) if ~/.hushlogin file exists
+- *
+- * The ~/.hushlogin is ignored if the global hush file exists.
+- *
+- * The HUSHLOGIN_FILE login.def variable overwrites the default hush filename.
+- *
+- * Note that shadow-utils login(1) does not support "a1)". The "a1)" is
+- * necessary if you want to use PAM for "Last login" message.
+- *
+- * -- Karel Zak <kzak@redhat.com> (26-Aug-2011)
+- *
+- *
+- * Per-account check requires some explanation: As root we may not be able to
+- * read the directory of the user if it is on an NFS mounted filesystem. We
+- * temporarily set our effective uid to the user-uid making sure that we keep
+- * root privs. in the real uid.
+- *
+- * A portable solution would require a fork(), but we rely on Linux having the
+- * BSD setreuid()
+- */
+-static int get_hushlogin_status(struct passwd *pwd)
+-{
+-	const char *files[] = { _PATH_HUSHLOGINS, _PATH_HUSHLOGIN, NULL };
+-	const char *file;
+-	char buf[BUFSIZ];
+-	int i;
+-
+-	file = getlogindefs_str("HUSHLOGIN_FILE", NULL);
+-	if (file) {
+-		if (!*file)
+-			return 0;	/* empty HUSHLOGIN_FILE defined */
+-
+-		files[0] = file;
+-		files[1] = NULL;
+-	}
+-
+-	for (i = 0; files[i]; i++) {
+-		int ok = 0;
+-
+-		file = files[i];
+-
+-		/* Global hush-file*/
+-		if (*file == '/') {
+-			struct stat st;
+-			FILE *f;
+-
+-			if (stat(file, &st) != 0)
+-				continue;	/* file does not exist */
+-
+-			if (st.st_size == 0)
+-				return 1;	/* for all accounts */
+-
+-			f = fopen(file, "r");
+-			if (!f)
+-				continue;	/* ignore errors... */
+-
+-			while (ok == 0 && fgets(buf, sizeof(buf), f)) {
+-				buf[strlen(buf) - 1] = '\0';
+-				ok = !strcmp(buf, *buf == '/' ? pwd->pw_shell :
+-								pwd->pw_name);
+-			}
+-			fclose(f);
+-			if (ok)
+-				return 1;	/* found username/shell */
+-
+-			return 0;		/* ignore per-account files */
+-		}
+-
+-		/* Per-account setting */
+-		if (strlen(pwd->pw_dir) + sizeof(file) + 2 > sizeof(buf))
+-			continue;
+-		else {
+-			uid_t ruid = getuid();
+-			gid_t egid = getegid();
+-
+-			sprintf(buf, "%s/%s", pwd->pw_dir, file);
+-
+-			if (setregid(-1, pwd->pw_gid) == 0 &&
+-			    setreuid(0, pwd->pw_uid) == 0)
+-				ok = effective_access(buf, O_RDONLY) == 0;
+-
+-			if (setuid(0) != 0 ||
+-			    setreuid(ruid, 0) != 0 ||
+-			    setregid(-1, egid) != 0) {
+-				syslog(LOG_ALERT, _("hush login status: restore original IDs failed"));
+-				exit(EXIT_FAILURE);
+-			}
+-			if (ok)
+-				return 1;	/* enabled by user */
+-		}
+-	}
+-
+-	return 0;
+-}
+-
+-/*
+  * Detach the controlling terminal, fork, restore syslog stuff and create a new
+  * session.
+  */
+@@ -1372,7 +1254,7 @@ int main(int argc, char **argv)
+ 
+ 	endpwent();
+ 
+-	cxt.quiet = get_hushlogin_status(pwd);
++	cxt.quiet = get_hushlogin_status(pwd, 1);
+ 
+ 	log_utmp(&cxt);
+ 	log_audit(&cxt, 1);
+diff -up util-linux-2.23.2/login-utils/logindefs.c.kzak util-linux-2.23.2/login-utils/logindefs.c
+--- util-linux-2.23.2/login-utils/logindefs.c.kzak	2013-06-13 09:46:10.442650810 +0200
++++ util-linux-2.23.2/login-utils/logindefs.c	2014-12-12 15:28:30.573177104 +0100
+@@ -27,6 +27,9 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <sys/syslog.h>
++#include <sys/stat.h>
++#include <sys/types.h>
++#include <pwd.h>
+ 
+ #include "c.h"
+ #include "closestream.h"
+@@ -259,6 +262,135 @@ int logindefs_setenv(const char *name, c
+ 	return val ? setenv(name, val, 1) : -1;
+ }
+ 
++/*
++ * We need to check the effective UID/GID. For example, $HOME could be on a
++ * root-squashed NFS or on an NFS with UID mapping, and access(2) uses the
++ * real UID/GID.  Then open(2) seems as the surest solution.
++ * -- kzak@redhat.com (10-Apr-2009)
++ */
++int effective_access(const char *path, int mode)
++{
++	int fd = open(path, mode);
++	if (fd != -1)
++		close(fd);
++	return fd == -1 ? -1 : 0;
++}
++
++
++/*
++ * Check the per-account or the global hush-login setting.
++ *
++ * Hushed mode is enabled:
++ *
++ * a) if a global (e.g. /etc/hushlogins) hush file exists:
++ *     1) for ALL ACCOUNTS if the file is empty
++ *     2) for the current user if the username or shell is found in the file
++ *
++ * b) if a ~/.hushlogin file exists
++ *
++ * The ~/.hushlogin file is ignored if the global hush file exists.
++ *
++ * The HUSHLOGIN_FILE login.def variable overrides the default hush filename.
++ *
++ * Note that shadow-utils login(1) does not support "a1)". The "a1)" is
++ * necessary if you want to use PAM for "Last login" message.
++ *
++ * -- Karel Zak <kzak@redhat.com> (26-Aug-2011)
++ *
++ *
++ * The per-account check requires some explanation: As root we may not be able
++ * to read the directory of the user if it is on an NFS-mounted filesystem. We
++ * temporarily set our effective uid to the user-uid, making sure that we keep
++ * root privileges in the real uid.
++ *
++ * A portable solution would require a fork(), but we rely on Linux having the
++ * BSD setreuid().
++ */
++
++int get_hushlogin_status(struct passwd *pwd, int force_check)
++{
++	const char *files[] = { _PATH_HUSHLOGINS, _PATH_HUSHLOGIN, NULL };
++	const char *file;
++	char buf[BUFSIZ];
++	int i;
++
++	file = getlogindefs_str("HUSHLOGIN_FILE", NULL);
++	if (file) {
++		if (!*file)
++			return 0;	/* empty HUSHLOGIN_FILE defined */
++
++		files[0] = file;
++		files[1] = NULL;
++	}
++
++	for (i = 0; files[i]; i++) {
++		int ok = 0;
++
++		file = files[i];
++
++		/* global hush-file */
++		if (*file == '/') {
++			struct stat st;
++			FILE *f;
++
++			if (stat(file, &st) != 0)
++				continue;	/* file does not exist */
++
++			if (st.st_size == 0)
++				return 1;	/* for all accounts */
++
++			f = fopen(file, "r");
++			if (!f)
++				continue;	/* ignore errors... */
++
++			while (ok == 0 && fgets(buf, sizeof(buf), f)) {
++				buf[strlen(buf) - 1] = '\0';
++				ok = !strcmp(buf, *buf == '/' ? pwd->pw_shell :
++								pwd->pw_name);
++			}
++			fclose(f);
++			if (ok)
++				return 1;	/* found username/shell */
++
++			return 0;		/* ignore per-account files */
++		}
++
++		/* per-account setting */
++		if (strlen(pwd->pw_dir) + sizeof(file) + 2 > sizeof(buf))
++			continue;
++
++		sprintf(buf, "%s/%s", pwd->pw_dir, file);
++
++		if (force_check) {
++			uid_t ruid = getuid();
++			gid_t egid = getegid();
++
++			if (setregid(-1, pwd->pw_gid) == 0 &&
++			    setreuid(0, pwd->pw_uid) == 0)
++				ok = effective_access(buf, O_RDONLY) == 0;
++
++			if (setuid(0) != 0 ||
++			    setreuid(ruid, 0) != 0 ||
++			    setregid(-1, egid) != 0) {
++				syslog(LOG_ALERT, _("hush login status: restore original IDs failed"));
++				exit(EXIT_FAILURE);
++			}
++			if (ok)
++				return 1;	/* enabled by user */
++		}
++		else {
++			int rc;
++			rc = effective_access(buf, O_RDONLY);
++			if (rc == 0)
++				return 1;
++			else if (rc == -1 && errno == EACCES)
++					return -1;
++		}
++
++	}
++
++	return 0;
++}
+ #ifdef TEST_PROGRAM
+ int main(int argc, char *argv[])
+ {
+diff -up util-linux-2.23.2/login-utils/logindefs.h.kzak util-linux-2.23.2/login-utils/logindefs.h
+--- util-linux-2.23.2/login-utils/logindefs.h.kzak	2013-02-27 17:46:29.887020770 +0100
++++ util-linux-2.23.2/login-utils/logindefs.h	2014-12-12 15:28:30.573177104 +0100
+@@ -8,5 +8,7 @@ extern unsigned long getlogindefs_num(co
+ extern const char *getlogindefs_str(const char *name, const char *dflt);
+ extern void free_getlogindefs_data(void);
+ extern int logindefs_setenv(const char *name, const char *conf, const char *dflt);
++extern int effective_access(const char *path, int mode);
++extern int get_hushlogin_status(struct passwd *pwd, int force_check);
+ 
+ #endif /* UTIL_LINUX_LOGINDEFS_H */
+diff -up util-linux-2.23.2/login-utils/lslogins.1.kzak util-linux-2.23.2/login-utils/lslogins.1
+--- util-linux-2.23.2/login-utils/lslogins.1.kzak	2014-12-12 15:28:30.574177115 +0100
++++ util-linux-2.23.2/login-utils/lslogins.1	2014-12-12 15:28:30.574177115 +0100
+@@ -0,0 +1,132 @@
++.\" Copyright 2014 Ondrej Oprala (ondrej.oprala@gmail.com)
++.\" May be distributed under the GNU General Public License
++.TH LSLOGINS "1" "April 2014" "util-linux" "User Commands"
++.SH NAME
++lslogins \- display information about known users in the system
++.SH SYNOPSIS
++.B lslogins
++[\fIoptions\fR] [\fB-s\fR|\fB-u\fR[=\fIUID\fR]] [\fB-g \fIgroups\fR] [\fB-l \fIlogins\fR]
++.SH DESCRIPTION
++.PP
++Examine the wtmp and btmp logs, /etc/shadow (if necessary) and /etc/passwd
++and output the desired data.
++.PP
++The default action is to list info about all the users in the system.
++.SH OPTIONS
++Mandatory arguments to long options are mandatory for short options too.
++.TP
++\fB\-a\fR, \fB\-\-acc\-expiration\fR
++Display data about the date of last password change and the account expiration
++date (see \fBshadow\fR(5) for more info).  (Requires root priviliges.)
++.TP
++\fB\-\-btmp\-file \fIpath\fP
++Alternate path for btmp.
++.TP
++\fB\-c\fR, \fB\-\-colon\-separate\fR
++Separate info about each user with a colon instead of a newline.
++.TP
++\fB\-e\fR, \fB\-\-export\fR
++Output data in the format of NAME=VALUE.
++.TP
++\fB\-f\fR, \fB\-\-failed\fR
++Display data about the users' last failed login attempts.
++.TP
++\fB\-G\fR, \fB\-\-groups\-info\fR
++Show information about groups.
++.TP
++\fB\-g\fR, \fB\-\-groups\fR=\fIgroups\fR
++Only show data of users belonging to \fIgroups\fR.  More than one group
++may be specified; the list has to be comma-separated.
++.TP
++\fB\-h\fR, \fB\-\-help\fR
++Display help information and exit.
++.TP
++\fB\-L\fR, \fB\-\-last\fR
++Display data containing information about the users' last login sessions.
++.TP
++\fB\-l\fR, \fB\-\-logins\fR=\fIlogins\fR
++Only show data of users with a login specified in \fIlogins\fR (user names or user
++IDS).  More than one login may be specified; the list has to be comma-separated.
++.TP
++\fB\-m\fR, \fB\-\-supp\-groups\fR
++Show supplementary groups.
++.TP
++\fB\-n\fR, \fB\-\-newline\fR
++Display each piece of information on a separate line.
++.TP
++\fB\-\-noheadings\fR
++Do not print a header line.
++.TP
++\fB\-\-notruncate\fR
++Don't truncate output.
++.TP
++\fB\-o\fR, \fB\-\-output \fIlist\fP
++Specify which output columns to print.  Use
++.B \-\-help
++to get a list of all supported columns.
++.TP
++\fB\-p\fR, \fB\-\-pwd\fR
++Display information related to login by password (see also \fB\-afL).
++.TP
++\fB\-r\fR, \fB\-\-raw\fR
++Raw output (no columnation).
++.TP
++\fB\-s\fR, \fB\-\-system\-accs\fR[=\fIthreshold\fR]
++Show system accounts.  These are by default all accounts with a UID below 1000
++(non-inclusive), with the exception of either nobody or nfsnobody (UID 65534).  The UID
++threshold can also be specified explicitly (necessary for some distributions that
++allocate UIDs starting from 100, 500 - or an entirely different value - rather than 1000).
++.TP
++\fB\-\-time-format\fR \fItype\fP
++Display dates in short, full or iso format.  The default is short, this time
++format is designed to be space efficient and human readable.
++.TP
++\fB\-u\fR, \fB\-\-user\-accs\fR[=\fIthreshold\fR]
++Show user accounts.  These are by default all accounts with UID above 1000
++(inclusive), with the exception of either nobody or nfsnobody (UID 65534).  The UID
++threshold can also be specified explicitly (necessary for some distributions that
++allocate UIDs starting from 100, 500 - or an entirely different value - rather than 1000).
++.TP
++\fB\-V\fR, \fB\-\-version\fR
++Display version information and exit.
++.TP
++\fB\-\-wtmp\-file \fIpath\fP
++Alternate path for wtmp.
++.TP
++\fB\-Z\fR, \fB\-\-context\fR
++Display the users' security context.
++.TP
++\fB\-z\fR, \fB\-\-print0\fR
++Delimit user entries with a nul character, instead of a newline.
++
++.SH NOTES
++The default UID thresholds are read from /etc/login.defs.
++
++.SH EXIT STATUS
++.TP
++0
++if OK,
++.TP
++1
++if incorrect arguments specified,
++.TP
++2
++if a serious error occurs (e.g. a corrupt log).
++.SH SEE ALSO
++\fBgroup\fP(5), \fBpasswd\fP(5), \fBshadow\fP(5), \fButmp\fP(5)
++.SH HISTORY
++The \fBlslogins\fP utility is inspired by the \fBlogins\fP utility, which first appeared in FreeBSD 4.10.
++.SH AUTHORS
++.MT ooprala@redhat.com
++Ondrej Oprala
++.ME
++.br
++.MT kzak@redhat.com
++Karel Zak
++.ME
++
++.SH AVAILABILITY
++The lslogins command is part of the util-linux package and is available from
++.UR ftp://\:ftp.kernel.org\:/pub\:/linux\:/utils\:/util-linux/
++Linux Kernel Archive
++.UE .
+diff -up util-linux-2.23.2/login-utils/lslogins.c.kzak util-linux-2.23.2/login-utils/lslogins.c
+--- util-linux-2.23.2/login-utils/lslogins.c.kzak	2014-12-12 15:28:30.575177127 +0100
++++ util-linux-2.23.2/login-utils/lslogins.c	2014-12-12 15:29:19.084739609 +0100
+@@ -0,0 +1,1476 @@
++/*
++ * lslogins - List information about users on the system
++ *
++ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
++ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it would 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 <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <getopt.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <sys/syslog.h>
++#include <pwd.h>
++#include <grp.h>
++#include <shadow.h>
++#include <paths.h>
++#include <time.h>
++#include <utmp.h>
++#include <signal.h>
++#include <err.h>
++#include <limits.h>
++#include <ctype.h>
++
++#include <search.h>
++
++#include <libsmartcols.h>
++#ifdef HAVE_LIBSELINUX
++# include <selinux/selinux.h>
++#endif
++
++#ifdef HAVE_LIBSYSTEMD
++# include <systemd/sd-journal.h>
++#endif
++
++#include "c.h"
++#include "nls.h"
++#include "closestream.h"
++#include "xalloc.h"
++#include "list.h"
++#include "strutils.h"
++#include "optutils.h"
++#include "pathnames.h"
++#include "logindefs.h"
++#include "readutmp.h"
++#include "procutils.h"
++
++/*
++ * column description
++ */
++struct lslogins_coldesc {
++	const char *name;
++	const char *help;
++	const char *pretty_name;
++
++	double whint;	/* width hint */
++	long flag;
++};
++
++static int lslogins_flag;
++
++#define UL_UID_MIN 1000
++#define UL_UID_MAX 60000
++#define UL_SYS_UID_MIN 201
++#define UL_SYS_UID_MAX 999
++
++/* we use the value of outmode to determine
++ * appropriate flags for the libsmartcols table
++ * (e.g., a value of out_newline would imply a raw
++ * table with the column separator set to '\n').
++ */
++static int outmode;
++/*
++ * output modes
++ */
++enum {
++	OUT_COLON = 1,
++	OUT_EXPORT,
++	OUT_NEWLINE,
++	OUT_RAW,
++	OUT_NUL,
++	OUT_PRETTY
++};
++
++struct lslogins_user {
++	char *login;
++	uid_t uid;
++	char *group;
++	gid_t gid;
++	char *gecos;
++
++	int pwd_empty;
++	int nologin;
++	int pwd_lock;
++	int pwd_deny;
++
++	gid_t *sgroups;
++	size_t nsgroups;
++
++	char *pwd_ctime;
++	char *pwd_warn;
++	char *pwd_expire;
++	char *pwd_ctime_min;
++	char *pwd_ctime_max;
++
++	char *last_login;
++	char *last_tty;
++	char *last_hostname;
++
++	char *failed_login;
++	char *failed_tty;
++
++#ifdef HAVE_LIBSELINUX
++	security_context_t context;
++#endif
++	char *homedir;
++	char *shell;
++	char *pwd_status;
++	int   hushed;
++	char *nprocs;
++
++};
++
++/*
++ * time modes
++ * */
++enum {
++	TIME_INVALID = 0,
++	TIME_SHORT,
++	TIME_FULL,
++	TIME_ISO,
++};
++
++/*
++ * flags
++ */
++enum {
++	F_SYSAC	= (1 << 3),
++	F_USRAC	= (1 << 4),
++};
++
++/*
++ * IDs
++ */
++enum {
++	COL_USER = 0,
++	COL_UID,
++	COL_GECOS,
++	COL_HOME,
++	COL_SHELL,
++	COL_NOLOGIN,
++	COL_PWDLOCK,
++	COL_PWDEMPTY,
++	COL_PWDDENY,
++	COL_GROUP,
++	COL_GID,
++	COL_SGROUPS,
++	COL_SGIDS,
++	COL_LAST_LOGIN,
++	COL_LAST_TTY,
++	COL_LAST_HOSTNAME,
++	COL_FAILED_LOGIN,
++	COL_FAILED_TTY,
++	COL_HUSH_STATUS,
++	COL_PWD_WARN,
++	COL_PWD_CTIME,
++	COL_PWD_CTIME_MIN,
++	COL_PWD_CTIME_MAX,
++	COL_PWD_EXPIR,
++	COL_SELINUX,
++	COL_NPROCS,
++};
++
++#define is_wtmp_col(x)	((x) == COL_LAST_LOGIN     || \
++			 (x) == COL_LAST_TTY       || \
++			 (x) == COL_LAST_HOSTNAME)
++
++#define is_btmp_col(x)	((x) == COL_FAILED_LOGIN   || \
++			 (x) == COL_FAILED_TTY)
++
++enum {
++	STATUS_FALSE = 0,
++	STATUS_TRUE,
++	STATUS_UNKNOWN
++};
++
++static const char *const status[] = {
++	[STATUS_FALSE]	= "0",
++	[STATUS_TRUE]	= "1",
++	[STATUS_UNKNOWN]= NULL
++};
++
++static const char *const pretty_status[] = {
++	[STATUS_FALSE]	= N_("no"),
++	[STATUS_TRUE]	= N_("yes"),
++	[STATUS_UNKNOWN]= NULL
++};
++
++#define get_status(x)	(outmode == OUT_PRETTY ? pretty_status[(x)] : status[(x)])
++
++static const struct lslogins_coldesc coldescs[] =
++{
++	[COL_USER]          = { "USER",		N_("user name"), N_("Username"), 0.1, SCOLS_FL_NOEXTREMES },
++	[COL_UID]           = { "UID",		N_("user ID"), "UID", 1, SCOLS_FL_RIGHT},
++	[COL_PWDEMPTY]      = { "PWD-EMPTY",	N_("password not required"), N_("Password not required"), 1, SCOLS_FL_RIGHT },
++	[COL_PWDDENY]       = { "PWD-DENY",	N_("login by password disabled"), N_("Login by password disabled"), 1, SCOLS_FL_RIGHT },
++	[COL_PWDLOCK]       = { "PWD-LOCK",	N_("password defined, but locked"), N_("Password is locked"), 1, SCOLS_FL_RIGHT },
++	[COL_NOLOGIN]       = { "NOLOGIN",	N_("log in disabled by nologin(8) or pam_nologin(8)"), N_("No login"), 1, SCOLS_FL_RIGHT },
++	[COL_GROUP]         = { "GROUP",	N_("primary group name"), N_("Primary group"), 0.1 },
++	[COL_GID]           = { "GID",		N_("primary group ID"), "GID", 1, SCOLS_FL_RIGHT },
++	[COL_SGROUPS]       = { "SUPP-GROUPS",	N_("supplementary group names"), N_("Supplementary groups"), 0.1 },
++	[COL_SGIDS]         = { "SUPP-GIDS",    N_("supplementary group IDs"), N_("Supplementary group IDs"), 0.1 },
++	[COL_HOME]          = { "HOMEDIR",	N_("home directory"), N_("Home directory"), 0.1 },
++	[COL_SHELL]         = { "SHELL",	N_("login shell"), N_("Shell"), 0.1 },
++	[COL_GECOS]         = { "GECOS",	N_("full user name"), N_("Gecos field"), 0.1, SCOLS_FL_TRUNC },
++	[COL_LAST_LOGIN]    = { "LAST-LOGIN",	N_("date of last login"), N_("Last login"), 0.1, SCOLS_FL_RIGHT },
++	[COL_LAST_TTY]      = { "LAST-TTY",	N_("last tty used"), N_("Last terminal"), 0.05 },
++	[COL_LAST_HOSTNAME] = { "LAST-HOSTNAME",N_("hostname during the last session"), N_("Last hostname"),  0.1},
++	[COL_FAILED_LOGIN]  = { "FAILED-LOGIN",	N_("date of last failed login"), N_("Failed login"), 0.1 },
++	[COL_FAILED_TTY]    = { "FAILED-TTY",	N_("where did the login fail?"), N_("Failed login terminal"), 0.05 },
++	[COL_HUSH_STATUS]   = { "HUSHED",	N_("user's hush settings"), N_("Hushed"), 1, SCOLS_FL_RIGHT },
++	[COL_PWD_WARN]      = { "PWD-WARN",	N_("days user is warned of password expiration"), N_("Password expiration warn interval"), 0.1, SCOLS_FL_RIGHT },
++	[COL_PWD_EXPIR]     = { "PWD-EXPIR",	N_("password expiration date"), N_("Password expiration"), 0.1, SCOLS_FL_RIGHT },
++	[COL_PWD_CTIME]     = { "PWD-CHANGE",	N_("date of last password change"), N_("Password changed"), 0.1, SCOLS_FL_RIGHT},
++	[COL_PWD_CTIME_MIN] = { "PWD-MIN",	N_("number of days required between changes"), N_("Minimum change time"), 0.1, SCOLS_FL_RIGHT },
++	[COL_PWD_CTIME_MAX] = { "PWD-MAX",	N_("max number of days a password may remain unchanged"), N_("Maximum change time"), 0.1, SCOLS_FL_RIGHT },
++	[COL_SELINUX]       = { "CONTEXT",	N_("the user's security context"), N_("Selinux context"), 0.1 },
++	[COL_NPROCS]        = { "PROC",         N_("number of processes run by the user"), N_("Running processes"), 1, SCOLS_FL_RIGHT },
++};
++
++struct lslogins_control {
++	struct utmp *wtmp;
++	size_t wtmp_size;
++
++	struct utmp *btmp;
++	size_t btmp_size;
++
++	void *usertree;
++
++	uid_t uid;
++	uid_t UID_MIN;
++	uid_t UID_MAX;
++
++	uid_t SYS_UID_MIN;
++	uid_t SYS_UID_MAX;
++
++	char **ulist;
++	size_t ulsiz;
++
++	unsigned int time_mode;
++
++	const char *journal_path;
++
++	unsigned int selinux_enabled : 1,
++		     ulist_on : 1,
++		     noheadings : 1,
++		     notrunc : 1;
++};
++
++/* these have to remain global since there's no other reasonable way to pass
++ * them for each call of fill_table() via twalk() */
++static struct libscols_table *tb;
++
++/* columns[] array specifies all currently wanted output column. The columns
++ * are defined by coldescs[] array and you can specify (on command line) each
++ * column twice. That's enough, dynamically allocated array of the columns is
++ * unnecessary overkill and over-engineering in this case */
++static int columns[ARRAY_SIZE(coldescs) * 2];
++static int ncolumns;
++
++static inline size_t err_columns_index(size_t arysz, size_t idx)
++{
++	if (idx >= arysz)
++		errx(EXIT_FAILURE, _("too many columns specified, "
++				     "the limit is %zu columns"),
++				arysz - 1);
++	return idx;
++}
++
++#define add_column(ary, n, id)	\
++		((ary)[ err_columns_index(ARRAY_SIZE(ary), (n)) ] = (id))
++
++static struct timeval now;
++
++static int date_is_today(time_t t)
++{
++	if (now.tv_sec == 0)
++		gettimeofday(&now, NULL);
++	return t / (3600 * 24) == now.tv_sec / (3600 * 24);
++}
++
++static int date_is_thisyear(time_t t)
++{
++	if (now.tv_sec == 0)
++		gettimeofday(&now, NULL);
++	return t / (3600 * 24 * 365) == now.tv_sec / (3600 * 24 * 365);
++}
++
++static int column_name_to_id(const char *name, size_t namesz)
++{
++	size_t i;
++
++	for (i = 0; i < ARRAY_SIZE(coldescs); i++) {
++		const char *cn = coldescs[i].name;
++
++		if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
++			return i;
++	}
++	warnx(_("unknown column: %s"), name);
++	return -1;
++}
++
++static char *make_time(int mode, time_t time)
++{
++	char *s;
++	struct tm tm;
++	char buf[64] = {0};
++
++	localtime_r(&time, &tm);
++
++	switch(mode) {
++	case TIME_FULL:
++		asctime_r(&tm, buf);
++		if (*(s = buf + strlen(buf) - 1) == '\n')
++			*s = '\0';
++		break;
++	case TIME_SHORT:
++		if (date_is_today(time))
++			strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
++		else if (date_is_thisyear(time))
++			strftime(buf, sizeof(buf), "%b%d/%H:%M", &tm);
++		else
++			strftime(buf, sizeof(buf), "%Y-%b%d", &tm);
++		break;
++	case TIME_ISO:
++		strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", &tm);
++		break;
++	default:
++		errx(EXIT_FAILURE, _("unsupported time type"));
++	}
++	return xstrdup(buf);
++}
++
++
++static char *uidtostr(uid_t uid)
++{
++	char *str_uid = NULL;
++	xasprintf(&str_uid, "%u", uid);
++	return str_uid;
++}
++
++static char *gidtostr(gid_t gid)
++{
++	char *str_gid = NULL;
++	xasprintf(&str_gid, "%u", gid);
++	return str_gid;
++}
++
++static char *build_sgroups_string(gid_t *sgroups, size_t nsgroups, int want_names)
++{
++	size_t n = 0, maxlen, len;
++	char *res, *p;
++
++	if (!nsgroups)
++		return NULL;
++
++	len = maxlen = nsgroups * 10;
++	res = p = xmalloc(maxlen);
++
++	while (n < nsgroups) {
++		int x;
++again:
++		if (!want_names)
++			x = snprintf(p, len, "%u,", sgroups[n]);
++		else {
++			struct group *grp = getgrgid(sgroups[n]);
++			if (!grp) {
++				free(res);
++				return NULL;
++			}
++			x = snprintf(p, len, "%s,", grp->gr_name);
++		}
++
++		if (x < 0 || (size_t) x + 1 > len) {
++			size_t cur = p - res;
++
++			maxlen *= 2;
++			res = xrealloc(res, maxlen);
++			p = res + cur;
++			len = maxlen - cur;
++			goto again;
++		}
++
++		len -= x;
++		p += x;
++		++n;
++	}
++
++	if (p > res)
++		*(p - 1) = '\0';
++
++	return res;
++}
++
++static struct utmp *get_last_wtmp(struct lslogins_control *ctl, const char *username)
++{
++	size_t n = 0;
++	size_t len;
++
++	if (!username)
++		return NULL;
++
++	len = strlen(username);
++	n = ctl->wtmp_size - 1;
++	do {
++		if (!strncmp(username, ctl->wtmp[n].ut_user,
++		    len < UT_NAMESIZE ? len : UT_NAMESIZE))
++			return ctl->wtmp + n;
++	} while (n--);
++	return NULL;
++
++}
++
++static int require_wtmp(void)
++{
++	size_t i;
++	for (i = 0; i < (size_t) ncolumns; i++)
++		if (is_wtmp_col(columns[i]))
++			return 1;
++	return 0;
++}
++
++static int require_btmp(void)
++{
++	size_t i;
++	for (i = 0; i < (size_t) ncolumns; i++)
++		if (is_btmp_col(columns[i]))
++			return 1;
++	return 0;
++}
++
++static struct utmp *get_last_btmp(struct lslogins_control *ctl, const char *username)
++{
++	size_t n = 0;
++	size_t len;
++
++	if (!username)
++		return NULL;
++
++	len = strlen(username);
++	n = ctl->btmp_size - 1;
++	do {
++		if (!strncmp(username, ctl->btmp[n].ut_user,
++		    len < UT_NAMESIZE ? len : UT_NAMESIZE))
++			return ctl->btmp + n;
++	}while (n--);
++	return NULL;
++
++}
++
++static int parse_wtmp(struct lslogins_control *ctl, char *path)
++{
++	int rc = 0;
++
++	rc = read_utmp(path, &ctl->wtmp_size, &ctl->wtmp);
++	if (rc < 0 && errno != EACCES)
++		err(EXIT_FAILURE, "%s", path);
++	return rc;
++}
++
++static int parse_btmp(struct lslogins_control *ctl, char *path)
++{
++	int rc = 0;
++
++	rc = read_utmp(path, &ctl->btmp_size, &ctl->btmp);
++	if (rc < 0 && errno != EACCES)
++		err(EXIT_FAILURE, "%s", path);
++	return rc;
++}
++
++static int get_sgroups(gid_t **list, size_t *len, struct passwd *pwd)
++{
++	size_t n = 0;
++
++	*len = 0;
++	*list = NULL;
++
++	/* first let's get a supp. group count */
++	getgrouplist(pwd->pw_name, pwd->pw_gid, *list, (int *) len);
++	if (!*len)
++		return -1;
++
++	*list = xcalloc(1, *len * sizeof(gid_t));
++
++	/* now for the actual list of GIDs */
++	if (-1 == getgrouplist(pwd->pw_name, pwd->pw_gid, *list, (int *) len))
++		return -1;
++
++	/* getgroups also returns the user's primary GID - dispose of it */
++	while (n < *len) {
++		if ((*list)[n] == pwd->pw_gid)
++			break;
++		++n;
++	}
++
++	if (*len)
++		(*list)[n] = (*list)[--(*len)];
++	return 0;
++}
++
++static int get_nprocs(const uid_t uid)
++{
++	int nprocs = 0;
++	pid_t pid;
++	struct proc_processes *proc = proc_open_processes();
++
++	proc_processes_filter_by_uid(proc, uid);
++
++	while (!proc_next_pid(proc, &pid))
++		++nprocs;
++
++	proc_close_processes(proc);
++	return nprocs;
++}
++
++static int valid_pwd(const char *str)
++{
++	const char *p;
++
++	for (p = str; p && *p; p++)
++		if (!isalnum((unsigned int) *p))
++			return 0;
++	return p > str ? 1 : 0;
++}
++
++static struct lslogins_user *get_user_info(struct lslogins_control *ctl, const char *username)
++{
++	struct lslogins_user *user;
++	struct passwd *pwd;
++	struct group *grp;
++	struct spwd *shadow;
++	struct utmp *user_wtmp = NULL, *user_btmp = NULL;
++	int n = 0;
++	time_t time;
++	uid_t uid;
++	errno = 0;
++
++	pwd = username ? getpwnam(username) : getpwent();
++	if (!pwd)
++		return NULL;
++
++	ctl->uid = uid = pwd->pw_uid;
++
++	/* nfsnobody is an exception to the UID_MAX limit.  This is "nobody" on
++	 * some systems; the decisive point is the UID - 65534 */
++	if ((lslogins_flag & F_USRAC) &&
++	    strcmp("nfsnobody", pwd->pw_name) != 0 &&
++	    uid != 0) {
++		if (uid < ctl->UID_MIN || uid > ctl->UID_MAX) {
++			errno = EAGAIN;
++			return NULL;
++		}
++
++	} else if ((lslogins_flag & F_SYSAC) &&
++		   (uid < ctl->SYS_UID_MIN || uid > ctl->SYS_UID_MAX)) {
++		errno = EAGAIN;
++		return NULL;
++	}
++
++	user = xcalloc(1, sizeof(struct lslogins_user));
++
++	grp = getgrgid(pwd->pw_gid);
++	if (!grp)
++		return NULL;
++
++	if (ctl->wtmp)
++		user_wtmp = get_last_wtmp(ctl, pwd->pw_name);
++	if (ctl->btmp)
++		user_btmp = get_last_btmp(ctl, pwd->pw_name);
++
++	lckpwdf();
++	shadow = getspnam(pwd->pw_name);
++	ulckpwdf();
++
++	/* required  by tseach() stuff */
++	user->uid = pwd->pw_uid;
++
++	while (n < ncolumns) {
++		switch (columns[n++]) {
++		case COL_USER:
++			user->login = xstrdup(pwd->pw_name);
++			break;
++		case COL_UID:
++			user->uid = pwd->pw_uid;
++			break;
++		case COL_GROUP:
++			user->group = xstrdup(grp->gr_name);
++			break;
++		case COL_GID:
++			user->gid = pwd->pw_gid;
++			break;
++		case COL_SGROUPS:
++		case COL_SGIDS:
++			if (get_sgroups(&user->sgroups, &user->nsgroups, pwd))
++				err(EXIT_FAILURE, _("failed to get supplementary groups"));
++			break;
++		case COL_HOME:
++			user->homedir = xstrdup(pwd->pw_dir);
++			break;
++		case COL_SHELL:
++			user->shell = xstrdup(pwd->pw_shell);
++			break;
++		case COL_GECOS:
++			user->gecos = xstrdup(pwd->pw_gecos);
++			break;
++		case COL_LAST_LOGIN:
++			if (user_wtmp) {
++				time = user_wtmp->ut_tv.tv_sec;
++				user->last_login = make_time(ctl->time_mode, time);
++			}
++			break;
++		case COL_LAST_TTY:
++			if (user_wtmp)
++				user->last_tty = xstrdup(user_wtmp->ut_line);
++			break;
++		case COL_LAST_HOSTNAME:
++			if (user_wtmp)
++				user->last_hostname = xstrdup(user_wtmp->ut_host);
++			break;
++		case COL_FAILED_LOGIN:
++			if (user_btmp) {
++				time = user_btmp->ut_tv.tv_sec;
++				user->failed_login = make_time(ctl->time_mode, time);
++			}
++			break;
++		case COL_FAILED_TTY:
++			if (user_btmp)
++				user->failed_tty = xstrdup(user_btmp->ut_line);
++			break;
++		case COL_HUSH_STATUS:
++			user->hushed = get_hushlogin_status(pwd, 0);
++			if (user->hushed == -1)
++				user->hushed = STATUS_UNKNOWN;
++			break;
++		case COL_PWDEMPTY:
++			if (shadow) {
++				if (!*shadow->sp_pwdp) /* '\0' */
++					user->pwd_empty = STATUS_TRUE;
++			} else
++				user->pwd_empty = STATUS_UNKNOWN;
++			break;
++		case COL_PWDDENY:
++			if (shadow) {
++				if ((*shadow->sp_pwdp == '!' ||
++				     *shadow->sp_pwdp == '*') &&
++				    !valid_pwd(shadow->sp_pwdp + 1))
++					user->pwd_deny = STATUS_TRUE;
++			} else
++				user->pwd_deny = STATUS_UNKNOWN;
++			break;
++
++		case COL_PWDLOCK:
++			if (shadow) {
++				if (*shadow->sp_pwdp == '!' && valid_pwd(shadow->sp_pwdp + 1))
++					user->pwd_lock = STATUS_TRUE;
++			} else
++				user->pwd_lock = STATUS_UNKNOWN;
++			break;
++		case COL_NOLOGIN:
++			if (strstr(pwd->pw_shell, "nologin"))
++				user->nologin = 1;
++			else if (pwd->pw_uid)
++				user->nologin = access("/etc/nologin", F_OK) == 0 ||
++						access("/var/run/nologin", F_OK) == 0;
++			break;
++		case COL_PWD_WARN:
++			if (shadow && shadow->sp_warn >= 0)
++				xasprintf(&user->pwd_warn, "%ld", shadow->sp_warn);
++			break;
++		case COL_PWD_EXPIR:
++			if (shadow && shadow->sp_expire >= 0)
++				user->pwd_expire = make_time(TIME_SHORT,
++						shadow->sp_expire * 86400);
++			break;
++		case COL_PWD_CTIME:
++			/* sp_lstchg is specified in days, showing hours
++			 * (especially in non-GMT timezones) would only serve
++			 * to confuse */
++			if (shadow)
++				user->pwd_ctime = make_time(TIME_SHORT,
++						shadow->sp_lstchg * 86400);
++			break;
++		case COL_PWD_CTIME_MIN:
++			if (shadow && shadow->sp_min > 0)
++				xasprintf(&user->pwd_ctime_min, "%ld", shadow->sp_min);
++			break;
++		case COL_PWD_CTIME_MAX:
++			if (shadow && shadow->sp_max > 0)
++				xasprintf(&user->pwd_ctime_max, "%ld", shadow->sp_max);
++			break;
++		case COL_SELINUX:
++#ifdef HAVE_LIBSELINUX
++			if (ctl->selinux_enabled) {
++				/* typedefs and pointers are pure evil */
++				security_context_t con = NULL;
++				if (getcon(&con) == 0)
++					user->context = con;
++			}
++#endif
++			break;
++		case COL_NPROCS:
++			xasprintf(&user->nprocs, "%d", get_nprocs(pwd->pw_uid));
++			break;
++		default:
++			/* something went very wrong here */
++			err(EXIT_FAILURE, "fatal: unknown error");
++			break;
++		}
++	}
++
++	return user;
++}
++
++/* some UNIX implementations set errno iff a passwd/grp/...
++ * entry was not found. The original UNIX logins(1) utility always
++ * ignores invalid login/group names, so we're going to as well.*/
++#define IS_REAL_ERRNO(e) !((e) == ENOENT || (e) == ESRCH || \
++		(e) == EBADF || (e) == EPERM || (e) == EAGAIN)
++
++/* get a definitive list of users we want info about... */
++
++static int str_to_uint(char *s, unsigned int *ul)
++{
++	char *end;
++	if (!s || !*s)
++		return -1;
++	*ul = strtoul(s, &end, 0);
++	if (!*end)
++		return 0;
++	return 1;
++}
++
++static int get_ulist(struct lslogins_control *ctl, char *logins, char *groups)
++{
++	char *u, *g;
++	size_t i = 0, n = 0, *arsiz;
++	struct group *grp;
++	struct passwd *pwd;
++	char ***ar;
++	uid_t uid;
++	gid_t gid;
++
++	ar = &ctl->ulist;
++	arsiz = &ctl->ulsiz;
++
++	/* an arbitrary starting value */
++	*arsiz = 32;
++	*ar = xcalloc(1, sizeof(char *) * (*arsiz));
++
++	if (logins) {
++		while ((u = strtok(logins, ","))) {
++			logins = NULL;
++
++			/* user specified by UID? */
++			if (!str_to_uint(u, &uid)) {
++				pwd = getpwuid(uid);
++				if (!pwd)
++					continue;
++				u = pwd->pw_name;
++			}
++			(*ar)[i++] = xstrdup(u);
++
++			if (i == *arsiz)
++				*ar = xrealloc(*ar, sizeof(char *) * (*arsiz += 32));
++		}
++		ctl->ulist_on = 1;
++	}
++
++	if (groups) {
++		/* FIXME: this might lead to duplicit entries, although not visible
++		 * in output, crunching a user's info multiple times is very redundant */
++		while ((g = strtok(groups, ","))) {
++			n = 0;
++			groups = NULL;
++
++			/* user specified by GID? */
++			if (!str_to_uint(g, &gid))
++				grp = getgrgid(gid);
++			else
++				grp = getgrnam(g);
++
++			if (!grp)
++				continue;
++
++			while ((u = grp->gr_mem[n++])) {
++				(*ar)[i++] = xstrdup(u);
++
++				if (i == *arsiz)
++					*ar = xrealloc(*ar, sizeof(char *) * (*arsiz += 32));
++			}
++		}
++		ctl->ulist_on = 1;
++	}
++	*arsiz = i;
++	return 0;
++}
++
++static void free_ctl(struct lslogins_control *ctl)
++{
++	size_t n = 0;
++
++	free(ctl->wtmp);
++	free(ctl->btmp);
++
++	while (n < ctl->ulsiz)
++		free(ctl->ulist[n++]);
++
++	free(ctl->ulist);
++	free(ctl);
++}
++
++static struct lslogins_user *get_next_user(struct lslogins_control *ctl)
++{
++	struct lslogins_user *u;
++	errno = 0;
++	while (!(u = get_user_info(ctl, NULL))) {
++		/* no "false" errno-s here, iff we're unable to
++		 * get a valid user entry for any reason, quit */
++		if (errno == EAGAIN)
++			continue;
++		return NULL;
++	}
++	return u;
++}
++
++static int get_user(struct lslogins_control *ctl, struct lslogins_user **user,
++		    const char *username)
++{
++	*user = get_user_info(ctl, username);
++	if (!*user && errno)
++		if (IS_REAL_ERRNO(errno))
++			return -1;
++	return 0;
++}
++
++static int cmp_uid(const void *a, const void *b)
++{
++	uid_t x = ((struct lslogins_user *)a)->uid;
++	uid_t z = ((struct lslogins_user *)b)->uid;
++	return x > z ? 1 : (x < z ? -1 : 0);
++}
++
++static int create_usertree(struct lslogins_control *ctl)
++{
++	struct lslogins_user *user = NULL;
++	size_t n = 0;
++
++	if (ctl->ulist_on) {
++		while (n < ctl->ulsiz) {
++			if (get_user(ctl, &user, ctl->ulist[n]))
++				return -1;
++			if (user) /* otherwise an invalid user name has probably been given */
++				tsearch(user, &ctl->usertree, cmp_uid);
++			++n;
++		}
++	} else {
++		while ((user = get_next_user(ctl)))
++			tsearch(user, &ctl->usertree, cmp_uid);
++	}
++	return 0;
++}
++
++static struct libscols_table *setup_table(struct lslogins_control *ctl)
++{
++	struct libscols_table *tb = scols_new_table();
++	int n = 0;
++
++	if (!tb)
++		errx(EXIT_FAILURE, _("failed to initialize output table"));
++	if (ctl->noheadings)
++		scols_table_enable_noheadings(tb, 1);
++
++	switch(outmode) {
++	case OUT_COLON:
++		scols_table_enable_raw(tb, 1);
++		scols_table_set_column_separator(tb, ":");
++		break;
++	case OUT_NEWLINE:
++		scols_table_set_column_separator(tb, "\n");
++		/* fallthrough */
++	case OUT_EXPORT:
++		scols_table_enable_export(tb, 1);
++		break;
++	case OUT_NUL:
++		scols_table_set_line_separator(tb, "\0");
++		/* fallthrough */
++	case OUT_RAW:
++		scols_table_enable_raw(tb, 1);
++		break;
++	case OUT_PRETTY:
++		scols_table_enable_noheadings(tb, 1);
++	default:
++		break;
++	}
++
++	while (n < ncolumns) {
++		int flags = coldescs[columns[n]].flag;
++
++		if (ctl->notrunc)
++			flags &= ~SCOLS_FL_TRUNC;
++
++		if (!scols_table_new_column(tb,
++				coldescs[columns[n]].name,
++				coldescs[columns[n]].whint,
++				flags))
++			goto fail;
++		++n;
++	}
++
++	return tb;
++fail:
++	scols_unref_table(tb);
++	return NULL;
++}
++
++static void fill_table(const void *u, const VISIT which, const int depth __attribute__((unused)))
++{
++	struct libscols_line *ln;
++	struct lslogins_user *user = *(struct lslogins_user **)u;
++	int n = 0;
++
++	if (which == preorder || which == endorder)
++		return;
++
++	ln = scols_table_new_line(tb, NULL);
++	while (n < ncolumns) {
++		int rc = 0;
++
++		switch (columns[n]) {
++		case COL_USER:
++			rc = scols_line_set_data(ln, n, user->login);
++			break;
++		case COL_UID:
++			rc = scols_line_refer_data(ln, n, uidtostr(user->uid));
++			break;
++		case COL_PWDEMPTY:
++			rc = scols_line_set_data(ln, n, get_status(user->pwd_empty));
++			break;
++		case COL_NOLOGIN:
++			rc = scols_line_set_data(ln, n, get_status(user->nologin));
++			break;
++		case COL_PWDLOCK:
++			rc = scols_line_set_data(ln, n, get_status(user->pwd_lock));
++			break;
++		case COL_PWDDENY:
++			rc = scols_line_set_data(ln, n, get_status(user->pwd_deny));
++			break;
++		case COL_GROUP:
++			rc = scols_line_set_data(ln, n, user->group);
++			break;
++		case COL_GID:
++			rc = scols_line_refer_data(ln, n, gidtostr(user->gid));
++			break;
++		case COL_SGROUPS:
++			rc = scols_line_refer_data(ln, n,
++				build_sgroups_string(user->sgroups,
++						     user->nsgroups,
++						     TRUE));
++			break;
++		case COL_SGIDS:
++			rc = scols_line_refer_data(ln, n,
++				build_sgroups_string(user->sgroups,
++						     user->nsgroups,
++						     FALSE));
++			break;
++		case COL_HOME:
++			rc = scols_line_set_data(ln, n, user->homedir);
++			break;
++		case COL_SHELL:
++			rc = scols_line_set_data(ln, n, user->shell);
++			break;
++		case COL_GECOS:
++			rc = scols_line_set_data(ln, n, user->gecos);
++			break;
++		case COL_LAST_LOGIN:
++			rc = scols_line_set_data(ln, n, user->last_login);
++			break;
++		case COL_LAST_TTY:
++			rc = scols_line_set_data(ln, n, user->last_tty);
++			break;
++		case COL_LAST_HOSTNAME:
++			rc = scols_line_set_data(ln, n, user->last_hostname);
++			break;
++		case COL_FAILED_LOGIN:
++			rc = scols_line_set_data(ln, n, user->failed_login);
++			break;
++		case COL_FAILED_TTY:
++			rc = scols_line_set_data(ln, n, user->failed_tty);
++			break;
++		case COL_HUSH_STATUS:
++			rc = scols_line_set_data(ln, n, get_status(user->hushed));
++			break;
++		case COL_PWD_WARN:
++			rc = scols_line_set_data(ln, n, user->pwd_warn);
++			break;
++		case COL_PWD_EXPIR:
++			rc = scols_line_set_data(ln, n, user->pwd_expire);
++			break;
++		case COL_PWD_CTIME:
++			rc = scols_line_set_data(ln, n, user->pwd_ctime);
++			break;
++		case COL_PWD_CTIME_MIN:
++			rc = scols_line_set_data(ln, n, user->pwd_ctime_min);
++			break;
++		case COL_PWD_CTIME_MAX:
++			rc = scols_line_set_data(ln, n, user->pwd_ctime_max);
++			break;
++		case COL_SELINUX:
++#ifdef HAVE_LIBSELINUX
++			rc = scols_line_set_data(ln, n, user->context);
++#endif
++			break;
++		case COL_NPROCS:
++			rc = scols_line_set_data(ln, n, user->nprocs);
++			break;
++		default:
++			/* something went very wrong here */
++			err(EXIT_FAILURE, _("internal error: unknown column"));
++		}
++
++		if (rc != 0)
++			err(EXIT_FAILURE, _("failed to set data"));
++		++n;
++	}
++	return;
++}
++#ifdef HAVE_LIBSYSTEMD
++static void print_journal_tail(const char *journal_path, uid_t uid, size_t len)
++{
++	sd_journal *j;
++	char *match, *buf;
++	uint64_t x;
++	time_t t;
++	const char *identifier, *pid, *message;
++	size_t identifier_len, pid_len, message_len;
++
++	if (journal_path)
++		sd_journal_open_directory(&j, journal_path, 0);
++	else
++		sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
++
++	buf = xmalloc(sizeof(char) * 16);
++	xasprintf(&match, "_UID=%d", uid);
++
++	sd_journal_add_match(j, match, 0);
++	sd_journal_seek_tail(j);
++	sd_journal_previous_skip(j, len);
++
++	do {
++		if (0 > sd_journal_get_data(j, "SYSLOG_IDENTIFIER",
++				(const void **) &identifier, &identifier_len))
++			return;
++		if (0 > sd_journal_get_data(j, "_PID",
++				(const void **) &pid, &pid_len))
++			return;
++		if (0 > sd_journal_get_data(j, "MESSAGE",
++				(const void **) &message, &message_len))
++			return;
++
++		sd_journal_get_realtime_usec(j, &x);
++		t = x / 1000000;
++		strftime(buf, 16, "%b %d %H:%M:%S", localtime(&t));
++
++		fprintf(stdout, "%s", buf);
++
++		identifier = strchr(identifier, '=') + 1;
++		pid = strchr(pid, '=') + 1		;
++		message = strchr(message, '=') + 1;
++
++		fprintf(stdout, " %s", identifier);
++		fprintf(stdout, "[%s]:", pid);
++		fprintf(stdout, "%s\n", message);
++	} while (sd_journal_next(j));
++
++	free(buf);
++	free(match);
++	sd_journal_flush_matches(j);
++	sd_journal_close(j);
++}
++#endif
++
++static int print_pretty(struct libscols_table *tb)
++{
++	struct libscols_iter *itr = scols_new_iter(SCOLS_ITER_FORWARD);
++	struct libscols_column *col;
++	struct libscols_cell *data;
++	struct libscols_line *ln;
++	const char *hstr, *dstr;
++	int n = 0;
++
++	ln = scols_table_get_line(tb, 0);
++	while (!scols_table_next_column(tb, itr, &col)) {
++
++		data = scols_line_get_cell(ln, n);
++
++		hstr = _(coldescs[columns[n]].pretty_name);
++		dstr = scols_cell_get_data(data);
++
++		if (dstr)
++			printf("%s:%*c%-36s\n", hstr, 35 - (int)strlen(hstr), ' ', dstr);
++		++n;
++	}
++
++	scols_free_iter(itr);
++	return 0;
++
++}
++
++static int print_user_table(struct lslogins_control *ctl)
++{
++	tb = setup_table(ctl);
++	if (!tb)
++		return -1;
++
++	twalk(ctl->usertree, fill_table);
++	if (outmode == OUT_PRETTY) {
++		print_pretty(tb);
++#ifdef HAVE_LIBSYSTEMD
++		fprintf(stdout, _("\nLast logs:\n"));
++		print_journal_tail(ctl->journal_path, ctl->uid, 3);
++		fputc('\n', stdout);
++#endif
++	} else
++		scols_print_table(tb);
++	return 0;
++}
++
++static void free_user(void *f)
++{
++	struct lslogins_user *u = f;
++	free(u->login);
++	free(u->group);
++	free(u->gecos);
++	free(u->sgroups);
++	free(u->pwd_ctime);
++	free(u->pwd_warn);
++	free(u->pwd_ctime_min);
++	free(u->pwd_ctime_max);
++	free(u->last_login);
++	free(u->last_tty);
++	free(u->last_hostname);
++	free(u->failed_login);
++	free(u->failed_tty);
++	free(u->homedir);
++	free(u->shell);
++	free(u->pwd_status);
++#ifdef HAVE_LIBSELINUX
++	freecon(u->context);
++#endif
++	free(u);
++}
++
++struct lslogins_timefmt {
++	const char *name;
++	int val;
++};
++
++static struct lslogins_timefmt timefmts[] = {
++	{ "short", TIME_SHORT },
++	{ "full", TIME_FULL },
++	{ "iso", TIME_ISO },
++};
++
++static void __attribute__((__noreturn__)) usage(FILE *out)
++{
++	size_t i;
++
++	fputs(USAGE_HEADER, out);
++	fprintf(out, _(" %s [options]\n"), program_invocation_short_name);
++
++	fputs(USAGE_OPTIONS, out);
++	fputs(_(" -a, --acc-expiration     display info about passwords expiration\n"), out);
++	fputs(_(" -c, --colon-separate     display data in a format similar to /etc/passwd\n"), out);
++	fputs(_(" -e, --export             display in an export-able output format\n"), out);
++	fputs(_(" -f, --failed             display data about the users' last failed logins\n"), out);
++	fputs(_(" -G, --groups-info        display information about groups\n"), out);
++	fputs(_(" -g, --groups=<groups>    display users belonging to a group in <groups>\n"), out);
++	fputs(_(" -L, --last               show info about the users' last login sessions\n"), out);
++	fputs(_(" -l, --logins=<logins>    display only users from <logins>\n"), out);
++	fputs(_(" -m, --supp-groups        display supplementary groups as well\n"), out);
++	fputs(_(" -n, --newline            display each piece of information on a new line\n"), out);
++	fputs(_("     --noheadings         don't print headings\n"), out);
++	fputs(_("     --notruncate         don't truncate output\n"), out);
++	fputs(_(" -o, --output[=<list>]    define the columns to output\n"), out);
++	fputs(_(" -p, --pwd                display information related to login by password.\n"), out);
++	fputs(_(" -r, --raw                display in raw mode\n"), out);
++	fputs(_(" -s, --system-accs        display system accounts\n"), out);
++	fputs(_("     --time-format=<type> display dates in short, full or iso format\n"), out);
++	fputs(_(" -u, --user-accs          display user accounts\n"), out);
++	fputs(_(" -Z, --context            display SELinux contexts\n"), out);
++	fputs(_(" -z, --print0             delimit user entries with a nul character\n"), out);
++	fputs(_("     --wtmp-file <path>   set an alternate path for wtmp\n"), out);
++	fputs(_("     --btmp-file <path>   set an alternate path for btmp\n"), out);
++	fputs(USAGE_SEPARATOR, out);
++	fputs(USAGE_HELP, out);
++	fputs(USAGE_VERSION, out);
++
++	fprintf(out, _("\nAvailable columns:\n"));
++
++	for (i = 0; i < ARRAY_SIZE(coldescs); i++)
++		fprintf(out, " %14s  %s\n", coldescs[i].name,
++				_(coldescs[i].help));
++
++	fprintf(out, _("\nFor more details see lslogins(1).\n"));
++
++	exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
++}
++
++int main(int argc, char *argv[])
++{
++	int c, opt_o = 0;
++	char *logins = NULL, *groups = NULL;
++	char *path_wtmp = _PATH_WTMP, *path_btmp = _PATH_BTMP;
++	struct lslogins_control *ctl = xcalloc(1, sizeof(struct lslogins_control));
++	size_t i;
++
++	/* long only options. */
++	enum {
++		OPT_VER = CHAR_MAX + 1,
++		OPT_WTMP,
++		OPT_BTMP,
++		OPT_NOTRUNC,
++		OPT_NOHEAD,
++		OPT_TIME_FMT,
++	};
++
++	static const struct option longopts[] = {
++		{ "acc-expiration", no_argument,	0, 'a' },
++		{ "colon-separate", no_argument,	0, 'c' },
++		{ "export",         no_argument,	0, 'e' },
++		{ "failed",         no_argument,	0, 'f' },
++		{ "groups",         required_argument,	0, 'g' },
++		{ "help",           no_argument,	0, 'h' },
++		{ "logins",         required_argument,	0, 'l' },
++		{ "supp-groups",    no_argument,	0, 'G' },
++		{ "newline",        no_argument,	0, 'n' },
++		{ "notruncate",     no_argument,	0, OPT_NOTRUNC },
++		{ "noheadings",     no_argument,	0, OPT_NOHEAD },
++		{ "output",         required_argument,	0, 'o' },
++		{ "last",           no_argument,	0, 'L', },
++		{ "raw",            no_argument,	0, 'r' },
++		{ "system-accs",    no_argument,	0, 's' },
++		{ "time-format",    required_argument,	0, OPT_TIME_FMT },
++		{ "user-accs",      no_argument,	0, 'u' },
++		{ "version",        no_argument,	0, 'V' },
++		{ "pwd",            no_argument,	0, 'p' },
++		{ "print0",         no_argument,	0, 'z' },
++		{ "wtmp-file",      required_argument,	0, OPT_WTMP },
++		{ "btmp-file",      required_argument,	0, OPT_BTMP },
++#ifdef HAVE_LIBSELINUX
++		{ "context",        no_argument,	0, 'Z' },
++#endif
++		{ NULL,             0, 			0,  0  }
++	};
++
++	static const ul_excl_t excl[] = {	/* rows and cols in ASCII order */
++		{ 'G', 'o' },
++		{ 'L', 'o' },
++		{ 'Z', 'o' },
++		{ 'a', 'o' },
++		{ 'c','n','r','z' },
++		{ 'o', 'p' },
++		{ 0 }
++	};
++	int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
++
++	setlocale(LC_ALL, "");
++	bindtextdomain(PACKAGE, LOCALEDIR);
++	textdomain(PACKAGE);
++	atexit(close_stdout);
++
++	ctl->time_mode = TIME_SHORT;
++
++	/* very basic default */
++	add_column(columns, ncolumns++, COL_UID);
++	add_column(columns, ncolumns++, COL_USER);
++
++	while ((c = getopt_long(argc, argv, "acfGg:hLl:no:prsuVxzZ",
++				longopts, NULL)) != -1) {
++
++		err_exclusive_options(c, longopts, excl, excl_st);
++
++		switch (c) {
++		case 'a':
++			add_column(columns, ncolumns++, COL_PWD_WARN);
++			add_column(columns, ncolumns++, COL_PWD_CTIME_MIN);
++			add_column(columns, ncolumns++, COL_PWD_CTIME_MAX);
++			add_column(columns, ncolumns++, COL_PWD_CTIME);
++			add_column(columns, ncolumns++, COL_PWD_EXPIR);
++			break;
++		case 'c':
++			outmode = OUT_COLON;
++			break;
++		case 'e':
++			outmode = OUT_EXPORT;
++			break;
++		case 'f':
++			add_column(columns, ncolumns++, COL_FAILED_LOGIN);
++			add_column(columns, ncolumns++, COL_FAILED_TTY);
++			break;
++		case 'G':
++			add_column(columns, ncolumns++, COL_GID);
++			add_column(columns, ncolumns++, COL_GROUP);
++			add_column(columns, ncolumns++, COL_SGIDS);
++			add_column(columns, ncolumns++, COL_SGROUPS);
++			break;
++		case 'g':
++			groups = optarg;
++			break;
++		case 'h':
++			usage(stdout);
++			break;
++		case 'L':
++			add_column(columns, ncolumns++, COL_LAST_TTY);
++			add_column(columns, ncolumns++, COL_LAST_HOSTNAME);
++			add_column(columns, ncolumns++, COL_LAST_LOGIN);
++			break;
++		case 'l':
++			logins = optarg;
++			break;
++		case 'n':
++			outmode = OUT_NEWLINE;
++			break;
++		case 'o':
++			if (optarg) {
++				if (*optarg == '=')
++					optarg++;
++				ncolumns = string_to_idarray(optarg,
++						columns, ARRAY_SIZE(columns),
++						column_name_to_id);
++				if (ncolumns < 0)
++					return EXIT_FAILURE;
++			}
++			opt_o = 1;
++			break;
++		case 'r':
++			outmode = OUT_RAW;
++			break;
++		case 's':
++			ctl->SYS_UID_MIN = getlogindefs_num("SYS_UID_MIN", UL_SYS_UID_MIN);
++			ctl->SYS_UID_MAX = getlogindefs_num("SYS_UID_MAX", UL_SYS_UID_MAX);
++			lslogins_flag |= F_SYSAC;
++			break;
++		case 'u':
++			ctl->UID_MIN = getlogindefs_num("UID_MIN", UL_UID_MIN);
++			ctl->UID_MAX = getlogindefs_num("UID_MAX", UL_UID_MAX);
++			lslogins_flag |= F_USRAC;
++			break;
++		case 'p':
++			add_column(columns, ncolumns++, COL_PWDEMPTY);
++			add_column(columns, ncolumns++, COL_PWDLOCK);
++			add_column(columns, ncolumns++, COL_PWDDENY);
++			add_column(columns, ncolumns++, COL_NOLOGIN);
++			add_column(columns, ncolumns++, COL_HUSH_STATUS);
++			break;
++		case 'z':
++			outmode = OUT_NUL;
++			break;
++		case OPT_WTMP:
++			path_wtmp = optarg;
++			break;
++		case OPT_BTMP:
++			path_btmp = optarg;
++			break;
++		case OPT_NOTRUNC:
++			ctl->notrunc = 1;
++			break;
++		case OPT_NOHEAD:
++			ctl->noheadings = 1;
++			break;
++		case OPT_TIME_FMT:
++			{
++				size_t i;
++
++				for (i = 0; i < ARRAY_SIZE(timefmts); i++) {
++					if (strcmp(timefmts[i].name, optarg) == 0) {
++						ctl->time_mode = timefmts[i].val;
++						break;
++					}
++				}
++				if (ctl->time_mode == TIME_INVALID)
++					usage(stderr);
++			}
++			break;
++		case 'V':
++			printf(UTIL_LINUX_VERSION);
++			return EXIT_SUCCESS;
++		case 'Z':
++		{
++#ifdef HAVE_LIBSELINUX
++			int sl = is_selinux_enabled();
++			if (sl < 0)
++				warn(_("failed to request selinux state"));
++			else
++				ctl->selinux_enabled = sl == 1;
++#endif
++			add_column(columns, ncolumns++, COL_SELINUX);
++			break;
++		}
++		default:
++			usage(stderr);
++		}
++	}
++
++	if (argc - optind == 1) {
++		if (strchr(argv[optind], ','))
++			errx(EXIT_FAILURE, _("Only one user may be specified. Use -l for multiple users."));
++		logins = argv[optind];
++		outmode = OUT_PRETTY;
++	} else if (argc != optind)
++		usage(stderr);
++
++	scols_init_debug(0);
++
++	/* lslogins -u -s == lslogins */
++	if (lslogins_flag & F_USRAC && lslogins_flag & F_SYSAC)
++		lslogins_flag &= ~(F_USRAC | F_SYSAC);
++
++	if (outmode == OUT_PRETTY && !opt_o) {
++		/* all columns for lslogins <username> */
++		for (ncolumns = 0, i = 0; i < ARRAY_SIZE(coldescs); i++)
++			 columns[ncolumns++] = i;
++
++	} else if (ncolumns == 2 && !opt_o) {
++		/* default colummns */
++		add_column(columns, ncolumns++, COL_NPROCS);
++		add_column(columns, ncolumns++, COL_PWDLOCK);
++		add_column(columns, ncolumns++, COL_PWDDENY);
++		add_column(columns, ncolumns++, COL_LAST_LOGIN);
++		add_column(columns, ncolumns++, COL_GECOS);
++	}
++
++	if (require_wtmp())
++		parse_wtmp(ctl, path_wtmp);
++	if (require_btmp())
++		parse_btmp(ctl, path_btmp);
++
++	if (logins || groups)
++		get_ulist(ctl, logins, groups);
++
++	if (create_usertree(ctl))
++		return EXIT_FAILURE;
++
++	print_user_table(ctl);
++
++	scols_unref_table(tb);
++	tdestroy(ctl->usertree, free_user);
++	free_ctl(ctl);
++
++	return EXIT_SUCCESS;
++}
+diff -up util-linux-2.23.2/login-utils/Makemodule.am.kzak util-linux-2.23.2/login-utils/Makemodule.am
+--- util-linux-2.23.2/login-utils/Makemodule.am.kzak	2013-06-13 09:46:10.441650801 +0200
++++ util-linux-2.23.2/login-utils/Makemodule.am	2014-12-12 15:28:30.576177139 +0100
+@@ -145,6 +145,25 @@ endif
+ endif # BUILD_NEWGRP
+ 
+ 
++if BUILD_LSLOGINS
++usrbin_exec_PROGRAMS += lslogins
++dist_man_MANS += login-utils/lslogins.1
++lslogins_SOURCES = \
++	login-utils/lslogins.c \
++	login-utils/logindefs.c \
++	login-utils/logindefs.h
++lslogins_LDADD = $(LDADD) libcommon.la libsmartcols.la
++lslogins_CFLAGS = $(AM_CFLAGS) -I$(ul_libsmartcols_incdir)
++if HAVE_SELINUX
++lslogins_LDADD += -lselinux
++endif
++if HAVE_SYSTEMD
++lslogins_LDADD += $(SYSTEMD_LIBS) $(SYSTEMD_JOURNAL_LIBS)
++lslogins_CFLAGS += $(SYSTEMD_CFLAGS) $(SYSTEMD_JOURNAL_CFLAGS)
++endif
++endif # BUILD_LSLOGINS
++
++
+ if BUILD_VIPW
+ usrsbin_exec_PROGRAMS += vipw
+ dist_man_MANS += \
diff --git a/SOURCES/2.26-mount-man-move.patch b/SOURCES/2.26-mount-man-move.patch
new file mode 100644
index 0000000..1a290a4
--- /dev/null
+++ b/SOURCES/2.26-mount-man-move.patch
@@ -0,0 +1,12 @@
+diff -up util-linux-2.23.2/sys-utils/mount.8.kzak util-linux-2.23.2/sys-utils/mount.8
+--- util-linux-2.23.2/sys-utils/mount.8.kzak	2014-09-25 11:03:25.492822164 +0200
++++ util-linux-2.23.2/sys-utils/mount.8	2014-09-25 11:04:00.102152375 +0200
+@@ -451,7 +451,7 @@ has to be a mountpoint.
+ 
+ Note that moving a mount residing under a shared mount is invalid and
+ unsupported. Use
+-.B findmnt -o TARGET,PROPAGATION /dir
++.B findmnt -o TARGET,PROPAGATION
+ to see the current propagation flags.
+ .RE
+ 
diff --git a/SOURCES/2.26-raw-stat.patch b/SOURCES/2.26-raw-stat.patch
new file mode 100644
index 0000000..1ca1bee
--- /dev/null
+++ b/SOURCES/2.26-raw-stat.patch
@@ -0,0 +1,12 @@
+diff -up util-linux-2.23.2/disk-utils/raw.c.kzak util-linux-2.23.2/disk-utils/raw.c
+--- util-linux-2.23.2/disk-utils/raw.c.kzak	2013-06-13 09:46:10.382650297 +0200
++++ util-linux-2.23.2/disk-utils/raw.c	2015-01-13 14:51:24.877755962 +0100
+@@ -220,7 +220,7 @@ static int query(int minor_raw, const ch
+ 	if (raw_name) {
+ 		struct stat statbuf;
+ 
+-		if (!stat(raw_name, &statbuf))
++		if (stat(raw_name, &statbuf) != 0)
+ 			err(EXIT_RAW_ACCESS,
+ 			    _("Cannot locate raw device '%s'"), raw_name);
+ 		if (!S_ISCHR(statbuf.st_mode))
diff --git a/SOURCES/2.26-su-coredump-message.patch b/SOURCES/2.26-su-coredump-message.patch
new file mode 100644
index 0000000..8d2b9ba
--- /dev/null
+++ b/SOURCES/2.26-su-coredump-message.patch
@@ -0,0 +1,17 @@
+diff -up util-linux-2.23.2/login-utils/su-common.c.kzak util-linux-2.23.2/login-utils/su-common.c
+--- util-linux-2.23.2/login-utils/su-common.c.kzak	2015-06-24 11:14:25.102395082 +0200
++++ util-linux-2.23.2/login-utils/su-common.c	2015-06-24 11:22:20.472859684 +0200
+@@ -359,10 +359,9 @@ create_watching_parent (void)
+       if (pid != (pid_t)-1)
+ 	if (WIFSIGNALED (status))
+ 	  {
+-	    status = WTERMSIG (status) + 128;
+-	    if (WCOREDUMP (status))
+-	      fprintf (stderr, _("%s (core dumped)\n"),
+-                 strsignal (WTERMSIG (status)));
++            fprintf (stderr, "%s%s\n", strsignal (WTERMSIG (status)),
++                     WCOREDUMP (status) ? _(" (core dumped)") : "");
++            status = WTERMSIG (status) + 128;
+ 	  }
+ 	else
+ 	  status = WEXITSTATUS (status);
diff --git a/SOURCES/2.26-unshare-rebase.patch b/SOURCES/2.26-unshare-rebase.patch
new file mode 100644
index 0000000..672ff36
--- /dev/null
+++ b/SOURCES/2.26-unshare-rebase.patch
@@ -0,0 +1,757 @@
+diff -up util-linux-2.23.2/include/pathnames.h.kzak util-linux-2.23.2/include/pathnames.h
+--- util-linux-2.23.2/include/pathnames.h.kzak	2015-06-26 10:00:19.111877564 +0200
++++ util-linux-2.23.2/include/pathnames.h	2015-06-26 10:00:51.623630869 +0200
+@@ -85,6 +85,10 @@
+ #define _PATH_PROC_LOCKS        "/proc/locks"
+ #define _PATH_PROC_CDROMINFO	"/proc/sys/dev/cdrom/info"
+ 
++#define _PATH_PROC_UIDMAP	"/proc/self/uid_map"
++#define _PATH_PROC_GIDMAP	"/proc/self/gid_map"
++#define _PATH_PROC_SETGROUPS	"/proc/self/setgroups"
++
+ #define _PATH_PROC_ATTR_CURRENT	"/proc/self/attr/current"
+ #define _PATH_PROC_ATTR_EXEC	"/proc/self/attr/exec"
+ #define _PATH_PROC_CAPLASTCAP	"/proc/sys/kernel/cap_last_cap"
+diff -up util-linux-2.23.2/sys-utils/Makemodule.am.kzak util-linux-2.23.2/sys-utils/Makemodule.am
+diff -up util-linux-2.23.2/sys-utils/nsenter.1.kzak util-linux-2.23.2/sys-utils/nsenter.1
+--- util-linux-2.23.2/sys-utils/nsenter.1.kzak	2015-06-26 09:58:39.468633643 +0200
++++ util-linux-2.23.2/sys-utils/nsenter.1	2015-06-26 09:58:51.672541041 +0200
+@@ -1,44 +1,45 @@
+-.TH NSENTER 1 "January 2013" "util-linux" "User Commands"
++.TH NSENTER 1 "June 2013" "util-linux" "User Commands"
+ .SH NAME
+ nsenter \- run program with namespaces of other processes
+ .SH SYNOPSIS
+ .B nsenter
+-.RI [ options ]
+-.RI [ program ]
+-.RI [ arguments ]
++[options]
++.RI [ program
++.RI [ arguments ]]
+ .SH DESCRIPTION
+ Enters the namespaces of one or more other processes and then executes the specified
+ program.  Enterable namespaces are:
+ .TP
+ .B mount namespace
+-mounting and unmounting filesystems will not affect rest of the system
++Mounting and unmounting filesystems will not affect the rest of the system
+ .RB ( CLONE_\:NEWNS
+-flag), except for filesystems which are explicitly marked as shared (by mount
+---make-\:shared).  See /proc\:/self\:/mountinfo for the shared flag.
++flag), except for filesystems which are explicitly marked as shared (with
++\fBmount --make-\:shared\fP; see \fI/proc\:/self\:/mountinfo\fP for the
++\fBshared\fP flag).
+ .TP
+ .B UTS namespace
+-setting hostname, domainname will not affect rest of the system
++Setting hostname or domainname will not affect the rest of the system.
+ .RB ( CLONE_\:NEWUTS
+-flag).
++flag)
+ .TP
+ .B IPC namespace
+-process will have independent namespace for System V message queues, semaphore
+-sets and shared memory segments
++The process will have an independent namespace for System V message queues,
++semaphore sets and shared memory segments.
+ .RB ( CLONE_\:NEWIPC
+-flag).
++flag)
+ .TP
+ .B network namespace
+-process will have independent IPv4 and IPv6 stacks, IP routing tables, firewall
+-rules, the
++The process will have independent IPv4 and IPv6 stacks, IP routing tables,
++firewall rules, the
+ .I /proc\:/net
+ and
+ .I /sys\:/class\:/net
+-directory trees, sockets etc.
++directory trees, sockets, etc.
+ .RB ( CLONE_\:NEWNET
+-flag).
++flag)
+ .TP
+ .B PID namespace
+-children will have a set of PID to process mappings separate from the
++Children will have a set of PID to process mappings separate from the
+ .B nsenter
+ process
+ .RB ( CLONE_\:NEWPID
+@@ -46,18 +47,18 @@ flag).
+ .B nsenter
+ will fork by default if changing the PID namespace, so that the new program
+ and its children share the same PID namespace and are visible to each other.
+-If \-\-no\-fork is used, the new program will be exec'ed without forking.
+-.PP
+-See the
+-.BR clone (2)
+-for exact semantics of the flags.
++If \fB\-\-no\-fork\fP is used, the new program will be exec'ed without forking.
+ .TP
+-If program is not given, run ``${SHELL}'' (default: /bin\:/sh).
++.B user namespace
++The process will have a distinct set of UIDs, GIDs and capabilities.
++.RB ( CLONE_\:NEWUSER
++flag)
++.TP
++See \fBclone\fP(2) for the exact semantics of the flags.
++.TP
++If \fIprogram\fP is not given, then ``${SHELL}'' is run (default: /bin\:/sh).
+ 
+ .SH OPTIONS
+-Argument with square brakets, such as [\fIfile\fR], means optional argument.
+-Command line syntax to specify optional argument \-\-mount=/path\:/to\:/file.
+-Please notice the equals sign.
+ .TP
+ \fB\-t\fR, \fB\-\-target\fR \fIpid\fP
+ Specify a target process to get contexts from.  The paths to the contexts
+@@ -83,6 +84,9 @@ the network namespace
+ /proc/\fIpid\fR/ns/pid
+ the PID namespace
+ .TP
++/proc/\fIpid\fR/ns/user
++the user namespace
++.TP
+ /proc/\fIpid\fR/root
+ the root directory
+ .TP
+@@ -91,51 +95,71 @@ the working directory respectively
+ .PD
+ .RE
+ .TP
+-\fB\-m\fR, \fB\-\-mount\fR [\fIfile\fR]
+-Enter the mount namespace.  If no file is specified enter the mount namespace
+-of the target process.  If file is specified enter the mount namespace
++\fB\-m\fR, \fB\-\-mount\fR[=\fIfile\fR]
++Enter the mount namespace.  If no file is specified, enter the mount namespace
++of the target process.  If file is specified, enter the mount namespace
+ specified by file.
+ .TP
+-\fB\-u\fR, \fB\-\-uts\fR [\fIfile\fR]
+-Enter the UTS namespace.  If no file is specified enter the UTS namespace of
+-the target process.  If file is specified enter the UTS namespace specified by
++\fB\-u\fR, \fB\-\-uts\fR[=\fIfile\fR]
++Enter the UTS namespace.  If no file is specified, enter the UTS namespace of
++the target process.  If file is specified, enter the UTS namespace specified by
+ file.
+ .TP
+-\fB\-i\fR, \fB\-\-ipc\fR [\fIfile\fR]
+-Enter the IPC namespace.  If no file is specified enter the IPC namespace of
+-the target process.  If file is specified enter the IPC namespace specified by
++\fB\-i\fR, \fB\-\-ipc\fR[=\fIfile\fR]
++Enter the IPC namespace.  If no file is specified, enter the IPC namespace of
++the target process.  If file is specified, enter the IPC namespace specified by
+ file.
+ .TP
+-\fB\-n\fR, \fB\-\-net\fR [\fIfile\fR]
+-Enter the network namespace.  If no file is specified enter the network
+-namespace of the target process.  If file is specified enter the network
++\fB\-n\fR, \fB\-\-net\fR[=\fIfile\fR]
++Enter the network namespace.  If no file is specified, enter the network
++namespace of the target process.  If file is specified, enter the network
+ namespace specified by file.
+ .TP
+-\fB\-p\fR, \fB\-\-pid\fR [\fIfile\fR]
+-Enter the PID namespace.  If no file is specified enter the PID namespace of
+-the target process.  If file is specified enter the PID namespace specified by
++\fB\-p\fR, \fB\-\-pid\fR[=\fIfile\fR]
++Enter the PID namespace.  If no file is specified, enter the PID namespace of
++the target process.  If file is specified, enter the PID namespace specified by
+ file.
+ .TP
+-\fB\-r\fR, \fB\-\-root\fR [\fIdirectory\fR]
+-Set the root directory.  If no directory is specified set the root directory to
+-the root directory of the target process.  If directory is specified set the
++\fB\-U\fR, \fB\-\-user\fR[=\fIfile\fR]
++Enter the user namespace.  If no file is specified, enter the user namespace of
++the target process.  If file is specified, enter the user namespace specified by
++file.  See also the \fB\-\-setuid\fR and \fB\-\-setgid\fR options.
++.TP
++\fB\-G\fR, \fB\-\-setgid\fR \fIgid\fR
++Set the group ID which will be used in the entered namespace and drop
++supplementary groups.
++.BR nsenter (1)
++always sets GID for user namespaces, the default is 0.
++.TP
++\fB\-S\fR, \fB\-\-setuid\fR \fIuid\fR
++Set the user ID which will be used in the entered namespace.
++.BR nsenter (1)
++always sets UID for user namespaces, the default is 0.
++.TP
++\fB\-\-preserve\-credentials\fR
++Don't modify UID and GID when enter user namespace. The default is to
++drops supplementary groups and sets GID and UID to 0.
++.TP
++\fB\-r\fR, \fB\-\-root\fR[=\fIdirectory\fR]
++Set the root directory.  If no directory is specified, set the root directory to
++the root directory of the target process.  If directory is specified, set the
+ root directory to the specified directory.
+ .TP
+-\fB\-w\fR, \fB\-\-wd\fR [\fIdirectory\fR]
+-Set the working directory.  If no directory is specified set the working
++\fB\-w\fR, \fB\-\-wd\fR[=\fIdirectory\fR]
++Set the working directory.  If no directory is specified, set the working
+ directory to the working directory of the target process.  If directory is
+-specified set the working directory to the specified directory.
++specified, set the working directory to the specified directory.
+ .TP
+-\fB\-F\fR, \fB\-\-no-fork\fR
+-Do not fork before exec'ing the specified program.  By default when entering a
+-pid namespace enter calls fork before calling exec so that the children will be
+-in the newly entered pid namespace.
++\fB\-F\fR, \fB\-\-no\-fork\fR
++Do not fork before exec'ing the specified program.  By default, when entering a
++PID namespace, \fBnsenter\fP calls \fBfork\fP before calling \fBexec\fP so that
++any children will also be in the newly entered PID namespace.
+ .TP
+ \fB\-V\fR, \fB\-\-version\fR
+ Display version information and exit.
+ .TP
+ \fB\-h\fR, \fB\-\-help\fR
+-Print a help message.
++Display help text and exit.
+ .SH SEE ALSO
+ .BR setns (2),
+ .BR clone (2)
+diff -up util-linux-2.23.2/sys-utils/nsenter.c.kzak util-linux-2.23.2/sys-utils/nsenter.c
+--- util-linux-2.23.2/sys-utils/nsenter.c.kzak	2015-06-26 09:58:39.468633643 +0200
++++ util-linux-2.23.2/sys-utils/nsenter.c	2015-06-26 09:58:51.673541033 +0200
+@@ -28,6 +28,7 @@
+ #include <assert.h>
+ #include <sys/types.h>
+ #include <sys/wait.h>
++#include <grp.h>
+ 
+ #include "strutils.h"
+ #include "nls.h"
+@@ -42,7 +43,12 @@ static struct namespace_file {
+ 	int fd;
+ } namespace_files[] = {
+ 	/* Careful the order is significant in this array.
++	 *
++	 * The user namespace comes first, so that it is entered
++	 * first.  This gives an unprivileged user the potential to
++	 * enter the other namespaces.
+ 	 */
++	{ .nstype = CLONE_NEWUSER, .name = "ns/user", .fd = -1 },
+ 	{ .nstype = CLONE_NEWIPC,  .name = "ns/ipc",  .fd = -1 },
+ 	{ .nstype = CLONE_NEWUTS,  .name = "ns/uts",  .fd = -1 },
+ 	{ .nstype = CLONE_NEWNET,  .name = "ns/net",  .fd = -1 },
+@@ -56,18 +62,25 @@ static void usage(int status)
+ 	FILE *out = status == EXIT_SUCCESS ? stdout : stderr;
+ 
+ 	fputs(USAGE_HEADER, out);
+-	fprintf(out, _(" %s [options] <program> [args...]\n"),
++	fprintf(out, _(" %s [options] <program> [<argument>...]\n"),
+ 		program_invocation_short_name);
+ 
++	fputs(USAGE_SEPARATOR, out);
++	fputs(_("Run a program with namespaces of other processes.\n"), out);
++
+ 	fputs(USAGE_OPTIONS, out);
+ 	fputs(_(" -t, --target <pid>     target process to get namespaces from\n"), out);
+-	fputs(_(" -m, --mount [=<file>]  enter mount namespace\n"), out);
+-	fputs(_(" -u, --uts   [=<file>]  enter UTS namespace (hostname etc)\n"), out);
+-	fputs(_(" -i, --ipc   [=<file>]  enter System V IPC namespace\n"), out);
+-	fputs(_(" -n, --net   [=<file>]  enter network namespace\n"), out);
+-	fputs(_(" -p, --pid   [=<file>]  enter pid namespace\n"), out);
+-	fputs(_(" -r, --root  [=<dir>]   set the root directory\n"), out);
+-	fputs(_(" -w, --wd    [=<dir>]   set the working directory\n"), out);
++	fputs(_(" -m, --mount[=<file>]   enter mount namespace\n"), out);
++	fputs(_(" -u, --uts[=<file>]     enter UTS namespace (hostname etc)\n"), out);
++	fputs(_(" -i, --ipc[=<file>]     enter System V IPC namespace\n"), out);
++	fputs(_(" -n, --net[=<file>]     enter network namespace\n"), out);
++	fputs(_(" -p, --pid[=<file>]     enter pid namespace\n"), out);
++	fputs(_(" -U, --user[=<file>]    enter user namespace\n"), out);
++	fputs(_(" -S, --setuid <uid>     set uid in entered namespace\n"), out);
++	fputs(_(" -G, --setgid <gid>     set gid in entered namespace\n"), out);
++	fputs(_("     --preserve-credentials do not touch uids or gids\n"), out);
++	fputs(_(" -r, --root[=<dir>]     set the root directory\n"), out);
++	fputs(_(" -w, --wd[=<dir>]       set the working directory\n"), out);
+ 	fputs(_(" -F, --no-fork          do not fork before exec'ing <program>\n"), out);
+ 
+ 	fputs(USAGE_SEPARATOR, out);
+@@ -153,6 +166,9 @@ static void continue_as_child(void)
+ 
+ int main(int argc, char *argv[])
+ {
++	enum {
++		OPT_PRESERVE_CRED = CHAR_MAX + 1
++	};
+ 	static const struct option longopts[] = {
+ 		{ "help", no_argument, NULL, 'h' },
+ 		{ "version", no_argument, NULL, 'V'},
+@@ -162,24 +178,30 @@ int main(int argc, char *argv[])
+ 		{ "ipc", optional_argument, NULL, 'i' },
+ 		{ "net", optional_argument, NULL, 'n' },
+ 		{ "pid", optional_argument, NULL, 'p' },
++		{ "user", optional_argument, NULL, 'U' },
++		{ "setuid", required_argument, NULL, 'S' },
++		{ "setgid", required_argument, NULL, 'G' },
+ 		{ "root", optional_argument, NULL, 'r' },
+ 		{ "wd", optional_argument, NULL, 'w' },
+ 		{ "no-fork", no_argument, NULL, 'F' },
++		{ "preserve-credentials", no_argument, NULL, OPT_PRESERVE_CRED },
+ 		{ NULL, 0, NULL, 0 }
+ 	};
+ 
+ 	struct namespace_file *nsfile;
+-	int c, namespaces = 0;
+-	bool do_rd = false, do_wd = false;
++	int c, namespaces = 0, setgroups_nerrs = 0, preserve_cred = 0;
++	bool do_rd = false, do_wd = false, force_uid = false, force_gid = false;
+ 	int do_fork = -1; /* unknown yet */
++	uid_t uid = 0;
++	gid_t gid = 0;
+ 
+-	setlocale(LC_MESSAGES, "");
++	setlocale(LC_ALL, "");
+ 	bindtextdomain(PACKAGE, LOCALEDIR);
+ 	textdomain(PACKAGE);
+ 	atexit(close_stdout);
+ 
+ 	while ((c =
+-		getopt_long(argc, argv, "hVt:m::u::i::n::p::r::w::F",
++		getopt_long(argc, argv, "+hVt:m::u::i::n::p::U::S:G:r::w::F",
+ 			    longopts, NULL)) != -1) {
+ 		switch (c) {
+ 		case 'h':
+@@ -221,6 +243,20 @@ int main(int argc, char *argv[])
+ 			else
+ 				namespaces |= CLONE_NEWPID;
+ 			break;
++		case 'U':
++			if (optarg)
++				open_namespace_fd(CLONE_NEWUSER, optarg);
++			else
++				namespaces |= CLONE_NEWUSER;
++			break;
++		case 'S':
++			uid = strtoul_or_err(optarg, _("failed to parse uid"));
++			force_uid = true;
++			break;
++		case 'G':
++			gid = strtoul_or_err(optarg, _("failed to parse gid"));
++			force_gid = true;
++			break;
+ 		case 'F':
+ 			do_fork = 0;
+ 			break;
+@@ -236,6 +272,9 @@ int main(int argc, char *argv[])
+ 			else
+ 				do_wd = true;
+ 			break;
++		case OPT_PRESERVE_CRED:
++			preserve_cred = 1;
++			break;
+ 		default:
+ 			usage(EXIT_FAILURE);
+ 		}
+@@ -253,6 +292,26 @@ int main(int argc, char *argv[])
+ 		open_target_fd(&wd_fd, "cwd", NULL);
+ 
+ 	/*
++	 * Update namespaces variable to contain all requested namespaces
++	 */
++	for (nsfile = namespace_files; nsfile->nstype; nsfile++) {
++		if (nsfile->fd < 0)
++			continue;
++		namespaces |= nsfile->nstype;
++	}
++
++	/* for user namespaces we always set UID and GID (default is 0)
++	 * and clear root's groups if --preserve-credentials is no specified */
++	if ((namespaces & CLONE_NEWUSER) && !preserve_cred) {
++		force_uid = true, force_gid = true;
++
++		/* We call setgroups() before and after we enter user namespace,
++		 * let's complain only if both fail */
++		if (setgroups(0, NULL) != 0)
++			setgroups_nerrs++;
++	}
++
++	/*
+ 	 * Now that we know which namespaces we want to enter, enter them.
+ 	 */
+ 	for (nsfile = namespace_files; nsfile->nstype; nsfile++) {
+@@ -302,6 +361,15 @@ int main(int argc, char *argv[])
+ 	if (do_fork == 1)
+ 		continue_as_child();
+ 
++	if (force_uid || force_gid) {
++		if (force_gid && setgroups(0, NULL) != 0 && setgroups_nerrs)	/* drop supplementary groups */
++			err(EXIT_FAILURE, _("setgroups failed"));
++		if (force_gid && setgid(gid) < 0)		/* change GID */
++			err(EXIT_FAILURE, _("setgid failed"));
++		if (force_uid && setuid(uid) < 0)		/* change UID */
++			err(EXIT_FAILURE, _("setuid failed"));
++	}
++
+ 	if (optind < argc) {
+ 		execvp(argv[optind], argv + optind);
+ 		err(EXIT_FAILURE, _("failed to execute %s"), argv[optind]);
+diff -up util-linux-2.23.2/sys-utils/unshare.1.kzak util-linux-2.23.2/sys-utils/unshare.1
+--- util-linux-2.23.2/sys-utils/unshare.1.kzak	2015-06-26 09:58:39.484633521 +0200
++++ util-linux-2.23.2/sys-utils/unshare.1	2015-06-26 09:58:51.673541033 +0200
+@@ -1,28 +1,27 @@
+-.\" Process this file with
+-.\" groff -man -Tascii lscpu.1
+-.\"
+-.TH UNSHARE 1 "July 2013" "util-linux" "User Commands"
++.TH UNSHARE 1 "July 2014" "util-linux" "User Commands"
+ .SH NAME
+ unshare \- run program with some namespaces unshared from parent
+ .SH SYNOPSIS
+ .B unshare
+-.RI [ options ]
++[options]
+ .I program
+ .RI [ arguments ]
+ .SH DESCRIPTION
+ Unshares the indicated namespaces from the parent process and then executes
+-the specified program.  The namespaces to be unshared are indicated via
++the specified \fIprogram\fR.  The namespaces to be unshared are indicated via
+ options.  Unshareable namespaces are:
+ .TP
+ .BR "mount namespace"
+ Mounting and unmounting filesystems will not affect the rest of the system
+ (\fBCLONE_NEWNS\fP flag), except for filesystems which are explicitly marked as
+-shared (with \fBmount --make-shared\fP; see \fI/proc/self/mountinfo\fP for the
+-\fBshared\fP flags).
+-
+-It's recommended to use \fBmount --make-rprivate\fP or \fBmount --make-rslave\fP
+-after \fBunshare --mount\fP to make sure that mountpoints in the new namespace
+-are really unshared from parental namespace.
++shared (with \fBmount --make-shared\fP; see \fI/proc/self/mountinfo\fP or
++\fBfindmnt -o+PROPAGATION\fP for the \fBshared\fP flags).
++.sp
++.B unshare
++automatically sets propagation to \fBprivate\fP
++in the new mount namespace to make sure that the new namespace is really
++unshared. This feature is possible to disable by option \fB\-\-propagation unchanged\fP.
++Note that \fBprivate\fP is the kernel default.
+ .TP
+ .BR "UTS namespace"
+ Setting hostname or domainname will not affect the rest of the system.
+@@ -40,13 +39,14 @@ sockets, etc.  (\fBCLONE_NEWNET\fP flag)
+ .BR "pid namespace"
+ Children will have a distinct set of PID to process mappings from their parent.
+ (\fBCLONE_NEWPID\fP flag)
++.TP
++.BR "user namespace"
++The process will have a distinct set of UIDs, GIDs and capabilities.
++(\fBCLONE_NEWUSER\fP flag)
+ .PP
+ See \fBclone\fR(2) for the exact semantics of the flags.
+ .SH OPTIONS
+ .TP
+-.BR \-h , " \-\-help"
+-Display help text and exit.
+-.TP
+ .BR \-i , " \-\-ipc"
+ Unshare the IPC namespace.
+ .TP
+@@ -63,16 +63,68 @@ See also the \fB--fork\fP and \fB--mount
+ .BR \-u , " \-\-uts"
+ Unshare the UTS namespace.
+ .TP
++.BR \-U , " \-\-user"
++Unshare the user namespace.
++.TP
+ .BR \-f , " \-\-fork"
+ Fork the specified \fIprogram\fR as a child process of \fBunshare\fR rather than
+ running it directly.  This is useful when creating a new pid namespace.
+ .TP
+-.BR \-\-mount-proc "[=\fImountpoint\fP]"
+-Just before running the program, mount the proc filesystem at the \fImountpoint\fP
++.BR \-\-mount\-proc "[=\fImountpoint\fP]"
++Just before running the program, mount the proc filesystem at \fImountpoint\fP
+ (default is /proc).  This is useful when creating a new pid namespace.  It also
+ implies creating a new mount namespace since the /proc mount would otherwise
+-mess up existing programs on the system. The new proc filesystem is explicitly
++mess up existing programs on the system.  The new proc filesystem is explicitly
+ mounted as private (by MS_PRIVATE|MS_REC).
++.TP
++.BR \-r , " \-\-map\-root\-user"
++Run the program only after the current effective user and group IDs have been mapped to
++the superuser UID and GID in the newly created user namespace.  This makes it possible to
++conveniently gain capabilities needed to manage various aspects of the newly created
++namespaces (such as configuring interfaces in the network namespace or mounting filesystems in
++the mount namespace) even when run unprivileged.  As a mere convenience feature, it does not support
++more sophisticated use cases, such as mapping multiple ranges of UIDs and GIDs.
++This option implies --setgroups=deny.
++.TP
++.BR "\-\-propagation \fIprivate|shared|slave|unchanged\fP"
++Recursively sets mount propagation flag in the new mount namespace. The default
++is to set the propagation to \fIprivate\fP, this feature is possible to disable
++by \fIunchanged\fP argument. The options is silently ignored when mount namespace (\fB\-\-mount\fP)
++is not requested.
++.TP
++.BR "\-\-setgroups \fIallow|deny\fP"
++Allow or deny
++.BR setgroups (2)
++syscall in user namespaces.
++
++.BR setgroups(2)
++is only callable with CAP_SETGID and CAP_SETGID in a user
++namespace (since Linux 3.19) does not give you permission to call setgroups(2)
++until after GID map has been set. The GID map is writable by root when
++.BR setgroups(2)
++is enabled and GID map becomes writable by unprivileged processes when
++.BR setgroups(2)
++is permanently disabled.
++.TP
++.BR \-V , " \-\-version"
++Display version information and exit.
++.TP
++.BR \-h , " \-\-help"
++Display help text and exit.
++.SH EXAMPLES
++.TP
++.B # unshare --fork --pid --mount-proc readlink /proc/self
++.TQ
++1
++.br
++Establish a PID namespace, ensure we're PID 1 in it against newly mounted
++procfs instance.
++.TP
++.B $ unshare --map-root-user --user sh -c whoami
++.TQ
++root
++.br
++Establish a user namespace as an unprivileged user with a root user within it.
+ .SH SEE ALSO
+ .BR unshare (2),
+ .BR clone (2),
+diff -up util-linux-2.23.2/sys-utils/unshare.c.kzak util-linux-2.23.2/sys-utils/unshare.c
+--- util-linux-2.23.2/sys-utils/unshare.c.kzak	2015-06-26 09:58:39.484633521 +0200
++++ util-linux-2.23.2/sys-utils/unshare.c	2015-06-26 09:58:51.673541033 +0200
+@@ -32,19 +32,117 @@
+ 
+ #include "nls.h"
+ #include "c.h"
++#include "closestream.h"
+ #include "namespace.h"
+ #include "exec_shell.h"
+ #include "xalloc.h"
+ #include "pathnames.h"
++#include "all-io.h"
+ 
++/* 'private' is kernel default */
++#define UNSHARE_PROPAGATION_DEFAULT	(MS_REC | MS_PRIVATE)
++
++enum {
++	SETGROUPS_NONE = -1,
++	SETGROUPS_DENY = 0,
++	SETGROUPS_ALLOW = 1,
++};
++
++static const char *setgroups_strings[] =
++{
++	[SETGROUPS_DENY] = "deny",
++	[SETGROUPS_ALLOW] = "allow"
++};
++
++static int setgroups_str2id(const char *str)
++{
++	size_t i;
++
++	for (i = 0; i < ARRAY_SIZE(setgroups_strings); i++)
++		if (strcmp(str, setgroups_strings[i]) == 0)
++			return i;
++
++	errx(EXIT_FAILURE, _("unsupported --setgroups argument '%s'"), str);
++}
++
++static void setgroups_control(int action)
++{
++	const char *file = _PATH_PROC_SETGROUPS;
++	const char *cmd;
++	int fd;
++
++	if (action < 0 || (size_t) action >= ARRAY_SIZE(setgroups_strings))
++		return;
++	cmd = setgroups_strings[action];
++
++	fd = open(file, O_WRONLY);
++	if (fd < 0) {
++		if (errno == ENOENT)
++			return;
++		 err(EXIT_FAILURE, _("cannot open %s"), file);
++	}
++
++	if (write_all(fd, cmd, strlen(cmd)))
++		err(EXIT_FAILURE, _("write failed %s"), file);
++	close(fd);
++}
++
++static void map_id(const char *file, uint32_t from, uint32_t to)
++{
++	char *buf;
++	int fd;
++
++	fd = open(file, O_WRONLY);
++	if (fd < 0)
++		 err(EXIT_FAILURE, _("cannot open %s"), file);
++
++	xasprintf(&buf, "%u %u 1", from, to);
++	if (write_all(fd, buf, strlen(buf)))
++		err(EXIT_FAILURE, _("write failed %s"), file);
++	free(buf);
++	close(fd);
++}
++
++static unsigned long parse_propagation(const char *str)
++{
++	size_t i;
++	static const struct prop_opts {
++		const char *name;
++		unsigned long flag;
++	} opts[] = {
++		{ "slave",	MS_REC | MS_SLAVE },
++		{ "private",	MS_REC | MS_PRIVATE },
++		{ "shared",     MS_REC | MS_SHARED },
++		{ "unchanged",        0 }
++	};
++
++	for (i = 0; i < ARRAY_SIZE(opts); i++) {
++		if (strcmp(opts[i].name, str) == 0)
++			return opts[i].flag;
++	}
++
++	errx(EXIT_FAILURE, _("unsupported propagation mode: %s"), str);
++}
++
++static void set_propagation(unsigned long flags)
++{
++	if (flags == 0)
++		return;
++
++	if (mount("none", "/", NULL, flags, NULL) != 0)
++		err(EXIT_FAILURE, _("cannot change root filesystem propagation"));
++}
+ 
+ static void usage(int status)
+ {
+ 	FILE *out = status == EXIT_SUCCESS ? stdout : stderr;
+ 
+ 	fputs(USAGE_HEADER, out);
+-	fprintf(out,
+-	      _(" %s [options] <program> [args...]\n"),	program_invocation_short_name);
++	fprintf(out, _(" %s [options] <program> [<argument>...]\n"),
++		program_invocation_short_name);
++
++	fputs(USAGE_SEPARATOR, out);
++	fputs(_("Run a program with some namespaces unshared from the parent.\n"), out);
+ 
+ 	fputs(USAGE_OPTIONS, out);
+ 	fputs(_(" -m, --mount               unshare mounts namespace\n"), out);
+@@ -52,8 +150,13 @@ static void usage(int status)
+ 	fputs(_(" -i, --ipc                 unshare System V IPC namespace\n"), out);
+ 	fputs(_(" -n, --net                 unshare network namespace\n"), out);
+ 	fputs(_(" -p, --pid                 unshare pid namespace\n"), out);
++	fputs(_(" -U, --user                unshare user namespace\n"), out);
+ 	fputs(_(" -f, --fork                fork before launching <program>\n"), out);
+ 	fputs(_("     --mount-proc[=<dir>]  mount proc filesystem first (implies --mount)\n"), out);
++	fputs(_(" -r, --map-root-user       map current user to root (implies --user)\n"), out);
++	fputs(_("     --propagation <slave|shared|private|unchanged>\n"
++	        "                           modify mount propagation in mount namespace\n"), out);
++	fputs(_(" -s, --setgroups allow|deny  control the setgroups syscall in user namespaces\n"), out);
+ 
+ 	fputs(USAGE_SEPARATOR, out);
+ 	fputs(USAGE_HELP, out);
+@@ -66,7 +169,9 @@ static void usage(int status)
+ int main(int argc, char *argv[])
+ {
+ 	enum {
+-		OPT_MOUNTPROC = CHAR_MAX + 1
++		OPT_MOUNTPROC = CHAR_MAX + 1,
++		OPT_PROPAGATION,
++		OPT_SETGROUPS
+ 	};
+ 	static const struct option longopts[] = {
+ 		{ "help", no_argument, 0, 'h' },
+@@ -76,20 +181,29 @@ int main(int argc, char *argv[])
+ 		{ "ipc", no_argument, 0, 'i' },
+ 		{ "net", no_argument, 0, 'n' },
+ 		{ "pid", no_argument, 0, 'p' },
++		{ "user", no_argument, 0, 'U' },
+ 		{ "fork", no_argument, 0, 'f' },
+ 		{ "mount-proc", optional_argument, 0, OPT_MOUNTPROC },
++		{ "map-root-user", no_argument, 0, 'r' },
++		{ "propagation", required_argument, 0, OPT_PROPAGATION },
++		{ "setgroups", required_argument, 0, OPT_SETGROUPS },
+ 		{ NULL, 0, 0, 0 }
+ 	};
+ 
++	int setgrpcmd = SETGROUPS_NONE;
+ 	int unshare_flags = 0;
+-	int c, forkit = 0;
++	int c, forkit = 0, maproot = 0;
+ 	const char *procmnt = NULL;
++	unsigned long propagation = UNSHARE_PROPAGATION_DEFAULT;
++	uid_t real_euid = geteuid();
++	gid_t real_egid = getegid();;
+ 
+ 	setlocale(LC_ALL, "");
+ 	bindtextdomain(PACKAGE, LOCALEDIR);
+ 	textdomain(PACKAGE);
++	atexit(close_stdout);
+ 
+-	while ((c = getopt_long(argc, argv, "+fhVmuinp", longopts, NULL)) != -1) {
++	while ((c = getopt_long(argc, argv, "+fhVmuinpUr", longopts, NULL)) != -1) {
+ 		switch (c) {
+ 		case 'f':
+ 			forkit = 1;
+@@ -114,10 +228,23 @@ int main(int argc, char *argv[])
+ 		case 'p':
+ 			unshare_flags |= CLONE_NEWPID;
+ 			break;
++		case 'U':
++			unshare_flags |= CLONE_NEWUSER;
++			break;
+ 		case OPT_MOUNTPROC:
+ 			unshare_flags |= CLONE_NEWNS;
+ 			procmnt = optarg ? optarg : "/proc";
+ 			break;
++		case 'r':
++			unshare_flags |= CLONE_NEWUSER;
++			maproot = 1;
++			break;
++		case OPT_SETGROUPS:
++			setgrpcmd = setgroups_str2id(optarg);
++			break;
++		case OPT_PROPAGATION:
++			propagation = parse_propagation(optarg);
++			break;
+ 		default:
+ 			usage(EXIT_FAILURE);
+ 		}
+@@ -146,6 +273,25 @@ int main(int argc, char *argv[])
+ 		}
+ 	}
+ 
++	if (maproot) {
++		if (setgrpcmd == SETGROUPS_ALLOW)
++			errx(EXIT_FAILURE, _("options --setgroups=allow and "
++					"--map-root-user are mutually exclusive"));
++
++		/* since Linux 3.19 unprivileged writing of /proc/self/gid_map
++		 * has s been disabled unless /proc/self/setgroups is written
++		 * first to permanently disable the ability to call setgroups
++		 * in that user namespace. */
++		setgroups_control(SETGROUPS_DENY);
++		map_id(_PATH_PROC_UIDMAP, 0, real_euid);
++		map_id(_PATH_PROC_GIDMAP, 0, real_egid);
++
++	} else if (setgrpcmd != SETGROUPS_NONE)
++		setgroups_control(setgrpcmd);
++
++	if ((unshare_flags & CLONE_NEWNS) && propagation)
++		set_propagation(propagation);
++
+ 	if (procmnt &&
+ 	    (mount("none", procmnt, NULL, MS_PRIVATE|MS_REC, NULL) != 0 ||
+ 	     mount("proc", procmnt, "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL) != 0))
diff --git a/SOURCES/2.27-libblkid-xfs-log.patch b/SOURCES/2.27-libblkid-xfs-log.patch
new file mode 100644
index 0000000..190074f
--- /dev/null
+++ b/SOURCES/2.27-libblkid-xfs-log.patch
@@ -0,0 +1,32 @@
+From d5b7d2912afceac3774d1aaea9e8486b54d4e9e9 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 13 Oct 2015 12:01:29 +0200
+Subject: [PATCH] libblkid: make XFS Log visible for wipefs
+
+Reported-by: Peter Rajnoha <prajnoha@redhat.com>
+Signed-off-by: root <root@ws.net.home>
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libblkid/src/superblocks/xfs.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/libblkid/src/superblocks/xfs.c b/libblkid/src/superblocks/xfs.c
+index a6c04a2..d13c849 100644
+--- a/libblkid/src/superblocks/xfs.c
++++ b/libblkid/src/superblocks/xfs.c
+@@ -260,6 +260,12 @@ static int probe_xfs_log(blkid_probe pr, const struct blkid_idmag *mag)
+ 
+ 		if (xlog_valid_rec_header(rhead)) {
+ 			blkid_probe_set_uuid_as(pr, rhead->h_uuid, "LOGUUID");
++
++			if (blkid_probe_set_magic(pr, i * 512,
++						sizeof(rhead->h_magicno),
++						(unsigned char *) &rhead->h_magicno))
++				return 1;
++
+ 			return 0;
+ 		}
+ 	}
+-- 
+2.4.3
+
diff --git a/SOURCES/2.28-lslogins-rebase.patch b/SOURCES/2.28-lslogins-rebase.patch
new file mode 100644
index 0000000..fd0cdb4
--- /dev/null
+++ b/SOURCES/2.28-lslogins-rebase.patch
@@ -0,0 +1,460 @@
+diff -up util-linux-2.23.2/include/pathnames.h.kzak util-linux-2.23.2/include/pathnames.h
+--- util-linux-2.23.2/include/pathnames.h.kzak	2016-03-16 15:17:42.648298525 +0100
++++ util-linux-2.23.2/include/pathnames.h	2016-03-16 15:18:13.769055345 +0100
+@@ -36,6 +36,7 @@
+ #endif
+ #define	_PATH_MOTDFILE		"/etc/motd"
+ #define	_PATH_NOLOGIN		"/etc/nologin"
++#define _PATH_VAR_NOLOGIN       "/var/run/nologin"
+ 
+ #define _PATH_LOGIN		"/bin/login"
+ #define _PATH_INITTAB		"/etc/inittab"
+diff -up util-linux-2.23.2/login-utils/lslogins.1.kzak util-linux-2.23.2/login-utils/lslogins.1
+--- util-linux-2.23.2/login-utils/lslogins.1.kzak	2016-03-16 15:17:42.639298595 +0100
++++ util-linux-2.23.2/login-utils/lslogins.1	2016-03-16 15:18:13.769055345 +0100
+@@ -5,7 +5,10 @@
+ lslogins \- display information about known users in the system
+ .SH SYNOPSIS
+ .B lslogins
+-[\fIoptions\fR] [\fB-s\fR|\fB-u\fR[=\fIUID\fR]] [\fB-g \fIgroups\fR] [\fB-l \fIlogins\fR]
++[options]
++.RB [ \-s | \-u [ =\fIUID ]]
++.RB [ \-g " \fIgroups\fR]"
++.RB [ \-l " \fIlogins\fR]"
+ .SH DESCRIPTION
+ .PP
+ Examine the wtmp and btmp logs, /etc/shadow (if necessary) and /etc/passwd
+@@ -17,7 +20,7 @@ Mandatory arguments to long options are
+ .TP
+ \fB\-a\fR, \fB\-\-acc\-expiration\fR
+ Display data about the date of last password change and the account expiration
+-date (see \fBshadow\fR(5) for more info).  (Requires root priviliges.)
++date (see \fBshadow\fR(5) for more info).  (Requires root privileges.)
+ .TP
+ \fB\-\-btmp\-file \fIpath\fP
+ Alternate path for btmp.
+@@ -31,7 +34,7 @@ Output data in the format of NAME=VALUE.
+ \fB\-f\fR, \fB\-\-failed\fR
+ Display data about the users' last failed login attempts.
+ .TP
+-\fB\-G\fR, \fB\-\-groups\-info\fR
++\fB\-G\fR, \fB\-\-supp\-groups\fR
+ Show information about groups.
+ .TP
+ \fB\-g\fR, \fB\-\-groups\fR=\fIgroups\fR
+@@ -48,9 +51,6 @@ Display data containing information abou
+ Only show data of users with a login specified in \fIlogins\fR (user names or user
+ IDS).  More than one login may be specified; the list has to be comma-separated.
+ .TP
+-\fB\-m\fR, \fB\-\-supp\-groups\fR
+-Show supplementary groups.
+-.TP
+ \fB\-n\fR, \fB\-\-newline\fR
+ Display each piece of information on a separate line.
+ .TP
+@@ -71,21 +71,21 @@ Display information related to login by
+ \fB\-r\fR, \fB\-\-raw\fR
+ Raw output (no columnation).
+ .TP
+-\fB\-s\fR, \fB\-\-system\-accs\fR[=\fIthreshold\fR]
++\fB\-s\fR, \fB\-\-system\-accs\fR
+ Show system accounts.  These are by default all accounts with a UID below 1000
+-(non-inclusive), with the exception of either nobody or nfsnobody (UID 65534).  The UID
+-threshold can also be specified explicitly (necessary for some distributions that
+-allocate UIDs starting from 100, 500 - or an entirely different value - rather than 1000).
++(non-inclusive), with the exception of either nobody or nfsnobody (UID 65534).
++This hardcoded default maybe overwritten by parameters SYS_UID_MIN and SYS_UID_MAX in
++the file /etc/login.defs.
+ .TP
+-\fB\-\-time-format\fR \fItype\fP
++\fB\-\-time\-format\fR \fItype\fP
+ Display dates in short, full or iso format.  The default is short, this time
+ format is designed to be space efficient and human readable.
+ .TP
+-\fB\-u\fR, \fB\-\-user\-accs\fR[=\fIthreshold\fR]
++\fB\-u\fR, \fB\-\-user\-accs\fR
+ Show user accounts.  These are by default all accounts with UID above 1000
+-(inclusive), with the exception of either nobody or nfsnobody (UID 65534).  The UID
+-threshold can also be specified explicitly (necessary for some distributions that
+-allocate UIDs starting from 100, 500 - or an entirely different value - rather than 1000).
++(inclusive), with the exception of either nobody or nfsnobody (UID 65534).
++This hardcoded default maybe overwritten by parameters UID_MIN and UID_MAX in
++the file /etc/login.defs.
+ .TP
+ \fB\-V\fR, \fB\-\-version\fR
+ Display version information and exit.
+diff -up util-linux-2.23.2/login-utils/lslogins.c.kzak util-linux-2.23.2/login-utils/lslogins.c
+--- util-linux-2.23.2/login-utils/lslogins.c.kzak	2016-03-16 15:17:42.639298595 +0100
++++ util-linux-2.23.2/login-utils/lslogins.c	2016-03-16 15:22:49.845899268 +0100
+@@ -144,6 +144,7 @@ enum {
+ 	TIME_SHORT,
+ 	TIME_FULL,
+ 	TIME_ISO,
++	TIME_ISO_SHORT,
+ };
+ 
+ /*
+@@ -350,6 +351,9 @@ static char *make_time(int mode, time_t
+ 	case TIME_ISO:
+ 		strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", &tm);
+ 		break;
++	case TIME_ISO_SHORT:
++		strftime(buf, sizeof(buf), "%Y-%m-%d", &tm);
++		break;
+ 	default:
+ 		errx(EXIT_FAILURE, _("unsupported time type"));
+ 	}
+@@ -396,7 +400,7 @@ again:
+ 			x = snprintf(p, len, "%s,", grp->gr_name);
+ 		}
+ 
+-		if (x < 0 || (size_t) x + 1 > len) {
++		if (x < 0 || (size_t) x >= len) {
+ 			size_t cur = p - res;
+ 
+ 			maxlen *= 2;
+@@ -496,21 +500,24 @@ static int parse_btmp(struct lslogins_co
+ static int get_sgroups(gid_t **list, size_t *len, struct passwd *pwd)
+ {
+ 	size_t n = 0;
++	int ngroups = 0;
+ 
+ 	*len = 0;
+ 	*list = NULL;
+ 
+ 	/* first let's get a supp. group count */
+-	getgrouplist(pwd->pw_name, pwd->pw_gid, *list, (int *) len);
+-	if (!*len)
++	getgrouplist(pwd->pw_name, pwd->pw_gid, *list, &ngroups);
++	if (!ngroups)
+ 		return -1;
+ 
+-	*list = xcalloc(1, *len * sizeof(gid_t));
++	*list = xcalloc(1, ngroups * sizeof(gid_t));
+ 
+ 	/* now for the actual list of GIDs */
+-	if (-1 == getgrouplist(pwd->pw_name, pwd->pw_gid, *list, (int *) len))
++	if (-1 == getgrouplist(pwd->pw_name, pwd->pw_gid, *list, &ngroups))
+ 		return -1;
+ 
++	*len = (size_t) ngroups;
++
+ 	/* getgroups also returns the user's primary GID - dispose of it */
+ 	while (n < *len) {
+ 		if ((*list)[n] == pwd->pw_gid)
+@@ -520,6 +527,7 @@ static int get_sgroups(gid_t **list, siz
+ 
+ 	if (*len)
+ 		(*list)[n] = (*list)[--(*len)];
++
+ 	return 0;
+ }
+ 
+@@ -685,8 +693,8 @@ static struct lslogins_user *get_user_in
+ 			if (strstr(pwd->pw_shell, "nologin"))
+ 				user->nologin = 1;
+ 			else if (pwd->pw_uid)
+-				user->nologin = access("/etc/nologin", F_OK) == 0 ||
+-						access("/var/run/nologin", F_OK) == 0;
++				user->nologin = access(_PATH_NOLOGIN, F_OK) == 0 ||
++						access(_PATH_VAR_NOLOGIN, F_OK) == 0;
+ 			break;
+ 		case COL_PWD_WARN:
+ 			if (shadow && shadow->sp_warn >= 0)
+@@ -694,7 +702,8 @@ static struct lslogins_user *get_user_in
+ 			break;
+ 		case COL_PWD_EXPIR:
+ 			if (shadow && shadow->sp_expire >= 0)
+-				user->pwd_expire = make_time(TIME_SHORT,
++				user->pwd_expire = make_time(ctl->time_mode == TIME_ISO ?
++						TIME_ISO_SHORT : ctl->time_mode,
+ 						shadow->sp_expire * 86400);
+ 			break;
+ 		case COL_PWD_CTIME:
+@@ -702,7 +711,8 @@ static struct lslogins_user *get_user_in
+ 			 * (especially in non-GMT timezones) would only serve
+ 			 * to confuse */
+ 			if (shadow)
+-				user->pwd_ctime = make_time(TIME_SHORT,
++				user->pwd_ctime = make_time(ctl->time_mode == TIME_ISO ?
++						TIME_ISO_SHORT : ctl->time_mode,
+ 						shadow->sp_lstchg * 86400);
+ 			break;
+ 		case COL_PWD_CTIME_MIN:
+@@ -852,7 +862,7 @@ static int get_user(struct lslogins_cont
+ 		    const char *username)
+ {
+ 	*user = get_user_info(ctl, username);
+-	if (!*user && errno)
++	if (!*user)
+ 		if (IS_REAL_ERRNO(errno))
+ 			return -1;
+ 	return 0;
+@@ -887,33 +897,33 @@ static int create_usertree(struct lslogi
+ 
+ static struct libscols_table *setup_table(struct lslogins_control *ctl)
+ {
+-	struct libscols_table *tb = scols_new_table();
++	struct libscols_table *table = scols_new_table();
+ 	int n = 0;
+ 
+-	if (!tb)
++	if (!table)
+ 		errx(EXIT_FAILURE, _("failed to initialize output table"));
+ 	if (ctl->noheadings)
+-		scols_table_enable_noheadings(tb, 1);
++		scols_table_enable_noheadings(table, 1);
+ 
+ 	switch(outmode) {
+ 	case OUT_COLON:
+-		scols_table_enable_raw(tb, 1);
+-		scols_table_set_column_separator(tb, ":");
++		scols_table_enable_raw(table, 1);
++		scols_table_set_column_separator(table, ":");
+ 		break;
+ 	case OUT_NEWLINE:
+-		scols_table_set_column_separator(tb, "\n");
++		scols_table_set_column_separator(table, "\n");
+ 		/* fallthrough */
+ 	case OUT_EXPORT:
+-		scols_table_enable_export(tb, 1);
++		scols_table_enable_export(table, 1);
+ 		break;
+ 	case OUT_NUL:
+-		scols_table_set_line_separator(tb, "\0");
++		scols_table_set_line_separator(table, "\0");
+ 		/* fallthrough */
+ 	case OUT_RAW:
+-		scols_table_enable_raw(tb, 1);
++		scols_table_enable_raw(table, 1);
+ 		break;
+ 	case OUT_PRETTY:
+-		scols_table_enable_noheadings(tb, 1);
++		scols_table_enable_noheadings(table, 1);
+ 	default:
+ 		break;
+ 	}
+@@ -924,7 +934,7 @@ static struct libscols_table *setup_tabl
+ 		if (ctl->notrunc)
+ 			flags &= ~SCOLS_FL_TRUNC;
+ 
+-		if (!scols_table_new_column(tb,
++		if (!scols_table_new_column(table,
+ 				coldescs[columns[n]].name,
+ 				coldescs[columns[n]].whint,
+ 				flags))
+@@ -932,9 +942,9 @@ static struct libscols_table *setup_tabl
+ 		++n;
+ 	}
+ 
+-	return tb;
++	return table;
+ fail:
+-	scols_unref_table(tb);
++	scols_unref_table(table);
+ 	return NULL;
+ }
+ 
+@@ -1050,10 +1060,10 @@ static void fill_table(const void *u, co
+ 	return;
+ }
+ #ifdef HAVE_LIBSYSTEMD
+-static void print_journal_tail(const char *journal_path, uid_t uid, size_t len)
++static void print_journal_tail(const char *journal_path, uid_t uid, size_t len, int time_mode)
+ {
+ 	sd_journal *j;
+-	char *match, *buf;
++	char *match, *timestamp;
+ 	uint64_t x;
+ 	time_t t;
+ 	const char *identifier, *pid, *message;
+@@ -1064,7 +1074,6 @@ static void print_journal_tail(const cha
+ 	else
+ 		sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
+ 
+-	buf = xmalloc(sizeof(char) * 16);
+ 	xasprintf(&match, "_UID=%d", uid);
+ 
+ 	sd_journal_add_match(j, match, 0);
+@@ -1074,37 +1083,35 @@ static void print_journal_tail(const cha
+ 	do {
+ 		if (0 > sd_journal_get_data(j, "SYSLOG_IDENTIFIER",
+ 				(const void **) &identifier, &identifier_len))
+-			return;
++			goto done;
+ 		if (0 > sd_journal_get_data(j, "_PID",
+ 				(const void **) &pid, &pid_len))
+-			return;
++			goto done;
+ 		if (0 > sd_journal_get_data(j, "MESSAGE",
+ 				(const void **) &message, &message_len))
+-			return;
++			goto done;
+ 
+ 		sd_journal_get_realtime_usec(j, &x);
+ 		t = x / 1000000;
+-		strftime(buf, 16, "%b %d %H:%M:%S", localtime(&t));
+-
+-		fprintf(stdout, "%s", buf);
+-
++		timestamp = make_time(time_mode, t);
++		/* Get rid of journal entry field identifiers */
+ 		identifier = strchr(identifier, '=') + 1;
+-		pid = strchr(pid, '=') + 1		;
++		pid = strchr(pid, '=') + 1;
+ 		message = strchr(message, '=') + 1;
+ 
+-		fprintf(stdout, " %s", identifier);
+-		fprintf(stdout, "[%s]:", pid);
+-		fprintf(stdout, "%s\n", message);
++		fprintf(stdout, "%s %s[%s]: %s\n", timestamp, identifier, pid,
++			message);
++		free(timestamp);
+ 	} while (sd_journal_next(j));
+ 
+-	free(buf);
++done:
+ 	free(match);
+ 	sd_journal_flush_matches(j);
+ 	sd_journal_close(j);
+ }
+ #endif
+ 
+-static int print_pretty(struct libscols_table *tb)
++static int print_pretty(struct libscols_table *table)
+ {
+ 	struct libscols_iter *itr = scols_new_iter(SCOLS_ITER_FORWARD);
+ 	struct libscols_column *col;
+@@ -1113,8 +1120,8 @@ static int print_pretty(struct libscols_
+ 	const char *hstr, *dstr;
+ 	int n = 0;
+ 
+-	ln = scols_table_get_line(tb, 0);
+-	while (!scols_table_next_column(tb, itr, &col)) {
++	ln = scols_table_get_line(table, 0);
++	while (!scols_table_next_column(table, itr, &col)) {
+ 
+ 		data = scols_line_get_cell(ln, n);
+ 
+@@ -1142,7 +1149,7 @@ static int print_user_table(struct lslog
+ 		print_pretty(tb);
+ #ifdef HAVE_LIBSYSTEMD
+ 		fprintf(stdout, _("\nLast logs:\n"));
+-		print_journal_tail(ctl->journal_path, ctl->uid, 3);
++		print_journal_tail(ctl->journal_path, ctl->uid, 3, ctl->time_mode);
+ 		fputc('\n', stdout);
+ #endif
+ 	} else
+@@ -1175,16 +1182,25 @@ static void free_user(void *f)
+ 	free(u);
+ }
+ 
+-struct lslogins_timefmt {
+-	const char *name;
+-	int val;
+-};
++static int parse_time_mode(const char *optarg)
++{
++	struct lslogins_timefmt {
++		const char *name;
++		const int val;
++	};
++	static const struct lslogins_timefmt timefmts[] = {
++		{"iso", TIME_ISO},
++		{"full", TIME_FULL},
++		{"short", TIME_SHORT},
++	};
++	size_t i;
+ 
+-static struct lslogins_timefmt timefmts[] = {
+-	{ "short", TIME_SHORT },
+-	{ "full", TIME_FULL },
+-	{ "iso", TIME_ISO },
+-};
++	for (i = 0; i < ARRAY_SIZE(timefmts); i++) {
++		if (strcmp(timefmts[i].name, optarg) == 0)
++			return timefmts[i].val;
++	}
++	errx(EXIT_FAILURE, _("unknown time format: %s"), optarg);
++}
+ 
+ static void __attribute__((__noreturn__)) usage(FILE *out)
+ {
+@@ -1193,16 +1209,18 @@ static void __attribute__((__noreturn__)
+ 	fputs(USAGE_HEADER, out);
+ 	fprintf(out, _(" %s [options]\n"), program_invocation_short_name);
+ 
++	fputs(USAGE_SEPARATOR, out);
++	fputs(_("Display information about known users in the system.\n"), out);
++
+ 	fputs(USAGE_OPTIONS, out);
+ 	fputs(_(" -a, --acc-expiration     display info about passwords expiration\n"), out);
+ 	fputs(_(" -c, --colon-separate     display data in a format similar to /etc/passwd\n"), out);
+ 	fputs(_(" -e, --export             display in an export-able output format\n"), out);
+ 	fputs(_(" -f, --failed             display data about the users' last failed logins\n"), out);
+-	fputs(_(" -G, --groups-info        display information about groups\n"), out);
++	fputs(_(" -G, --supp-groups        display information about groups\n"), out);
+ 	fputs(_(" -g, --groups=<groups>    display users belonging to a group in <groups>\n"), out);
+ 	fputs(_(" -L, --last               show info about the users' last login sessions\n"), out);
+ 	fputs(_(" -l, --logins=<logins>    display only users from <logins>\n"), out);
+-	fputs(_(" -m, --supp-groups        display supplementary groups as well\n"), out);
+ 	fputs(_(" -n, --newline            display each piece of information on a new line\n"), out);
+ 	fputs(_("     --noheadings         don't print headings\n"), out);
+ 	fputs(_("     --notruncate         don't truncate output\n"), out);
+@@ -1226,7 +1244,7 @@ static void __attribute__((__noreturn__)
+ 		fprintf(out, " %14s  %s\n", coldescs[i].name,
+ 				_(coldescs[i].help));
+ 
+-	fprintf(out, _("\nFor more details see lslogins(1).\n"));
++	fprintf(out, USAGE_MAN_TAIL("lslogins(1)"));
+ 
+ 	exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
+ }
+@@ -1241,8 +1259,7 @@ int main(int argc, char *argv[])
+ 
+ 	/* long only options. */
+ 	enum {
+-		OPT_VER = CHAR_MAX + 1,
+-		OPT_WTMP,
++		OPT_WTMP = CHAR_MAX + 1,
+ 		OPT_BTMP,
+ 		OPT_NOTRUNC,
+ 		OPT_NOHEAD,
+@@ -1300,7 +1317,7 @@ int main(int argc, char *argv[])
+ 	add_column(columns, ncolumns++, COL_UID);
+ 	add_column(columns, ncolumns++, COL_USER);
+ 
+-	while ((c = getopt_long(argc, argv, "acfGg:hLl:no:prsuVxzZ",
++	while ((c = getopt_long(argc, argv, "acefGg:hLl:no:prsuVzZ",
+ 				longopts, NULL)) != -1) {
+ 
+ 		err_exclusive_options(c, longopts, excl, excl_st);
+@@ -1394,18 +1411,7 @@ int main(int argc, char *argv[])
+ 			ctl->noheadings = 1;
+ 			break;
+ 		case OPT_TIME_FMT:
+-			{
+-				size_t i;
+-
+-				for (i = 0; i < ARRAY_SIZE(timefmts); i++) {
+-					if (strcmp(timefmts[i].name, optarg) == 0) {
+-						ctl->time_mode = timefmts[i].val;
+-						break;
+-					}
+-				}
+-				if (ctl->time_mode == TIME_INVALID)
+-					usage(stderr);
+-			}
++			ctl->time_mode = parse_time_mode(optarg);
+ 			break;
+ 		case 'V':
+ 			printf(UTIL_LINUX_VERSION);
+@@ -1433,7 +1439,7 @@ int main(int argc, char *argv[])
+ 		logins = argv[optind];
+ 		outmode = OUT_PRETTY;
+ 	} else if (argc != optind)
+-		usage(stderr);
++		errx(EXIT_FAILURE, _("Only one user may be specified. Use -l for multiple users."));
+ 
+ 	scols_init_debug(0);
+ 
diff --git a/SOURCES/nologin.8 b/SOURCES/nologin.8
new file mode 100644
index 0000000..5cb1601
--- /dev/null
+++ b/SOURCES/nologin.8
@@ -0,0 +1,63 @@
+.\"	$OpenBSD: nologin.8,v 1.8 1999/06/04 02:45:19 aaron Exp $
+.\"	$NetBSD: nologin.8,v 1.3 1995/03/18 14:59:09 cgd Exp $
+.\"
+.\" Copyright (c) 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)nologin.8	8.1 (Berkeley) 6/19/93
+.\"
+.Dd February 15, 1997
+.Dt NOLOGIN 8
+.Os
+.Sh NAME
+.Nm nologin
+.Nd politely refuse a login
+.Sh SYNOPSIS
+.Nm nologin
+.Sh DESCRIPTION
+.Nm
+displays a message that an account is not available and
+exits non-zero.
+It is intended as a replacement shell field for accounts that
+have been disabled.
+.Pp
+If the file
+.Pa /etc/nologin.txt
+exists,
+.Nm
+displays its contents to the user instead of the default message.
+.Sh SEE ALSO
+.Xr login 1
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.4 .
diff --git a/SOURCES/nologin.c b/SOURCES/nologin.c
new file mode 100644
index 0000000..8a51ba9
--- /dev/null
+++ b/SOURCES/nologin.c
@@ -0,0 +1,58 @@
+/*	$OpenBSD: nologin.c,v 1.2 1997/04/04 16:51:37 millert Exp $	*/
+
+/*
+ * Copyright (c) 1997, Jason Downs.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+/* Distinctly different from _PATH_NOLOGIN. */
+#define _PATH_NOLOGIN_TXT	"/etc/nologin.txt"
+
+#define DEFAULT_MESG	"This account is currently not available.\n"
+
+/*ARGSUSED*/
+int main(argc, argv)
+	int argc;
+	char *argv[];
+{
+	int nfd, nrd;
+	char nbuf[128];
+
+	nfd = open(_PATH_NOLOGIN_TXT, O_RDONLY);
+	if (nfd < 0) {
+		write(STDOUT_FILENO, DEFAULT_MESG, strlen(DEFAULT_MESG));
+		exit (1);
+	}
+
+	while ((nrd = read(nfd, nbuf, sizeof(nbuf))) > 0)
+		write(STDOUT_FILENO, nbuf, nrd);
+	close (nfd);
+
+	exit (1);
+}
diff --git a/SOURCES/rhel7.0-unshare-user.patch b/SOURCES/rhel7.0-unshare-user.patch
new file mode 100644
index 0000000..56ec755
--- /dev/null
+++ b/SOURCES/rhel7.0-unshare-user.patch
@@ -0,0 +1,154 @@
+diff -up util-linux-2.23.2/sys-utils/nsenter.1.kzak util-linux-2.23.2/sys-utils/nsenter.1
+--- util-linux-2.23.2/sys-utils/nsenter.1.kzak	2014-03-12 12:39:19.283577293 +0100
++++ util-linux-2.23.2/sys-utils/nsenter.1	2014-03-12 12:42:08.930336415 +0100
+@@ -47,12 +47,7 @@ flag).
+ will fork by default if changing the PID namespace, so that the new program
+ and its children share the same PID namespace and are visible to each other.
+ If \-\-no\-fork is used, the new program will be exec'ed without forking.
+-.TP
+-.B user namespace
+-process will have distinct set of UIDs, GIDs and capabilities
+-.RB ( CLONE_\:NEWUSER
+-flag).
+-.TP
++.PP
+ See the
+ .BR clone (2)
+ for exact semantics of the flags.
+@@ -88,9 +83,6 @@ the network namespace
+ /proc/\fIpid\fR/ns/pid
+ the PID namespace
+ .TP
+-/proc/\fIpid\fR/ns/user
+-the user namespace
+-.TP
+ /proc/\fIpid\fR/root
+ the root directory
+ .TP
+@@ -124,11 +116,6 @@ Enter the PID namespace.  If no file is
+ the target process.  If file is specified enter the PID namespace specified by
+ file.
+ .TP
+-\fB\-U\fR, \fB\-\-user\fR [\fIfile\fR]
+-Enter the user namespace.  If no file is specified enter the user namespace of
+-the target process.  If file is specified enter the user namespace specified by
+-file.
+-.TP
+ \fB\-r\fR, \fB\-\-root\fR [\fIdirectory\fR]
+ Set the root directory.  If no directory is specified set the root directory to
+ the root directory of the target process.  If directory is specified set the
+diff -up util-linux-2.23.2/sys-utils/nsenter.c.kzak util-linux-2.23.2/sys-utils/nsenter.c
+--- util-linux-2.23.2/sys-utils/nsenter.c.kzak	2014-03-12 12:39:10.402485179 +0100
++++ util-linux-2.23.2/sys-utils/nsenter.c	2014-03-12 12:44:07.986570461 +0100
+@@ -42,12 +42,7 @@ static struct namespace_file {
+ 	int fd;
+ } namespace_files[] = {
+ 	/* Careful the order is significant in this array.
+-	 *
+-	 * The user namespace comes first, so that it is entered
+-	 * first.  This gives an unprivileged user the potential to
+-	 * enter the other namespaces.
+ 	 */
+-	{ .nstype = CLONE_NEWUSER, .name = "ns/user", .fd = -1 },
+ 	{ .nstype = CLONE_NEWIPC,  .name = "ns/ipc",  .fd = -1 },
+ 	{ .nstype = CLONE_NEWUTS,  .name = "ns/uts",  .fd = -1 },
+ 	{ .nstype = CLONE_NEWNET,  .name = "ns/net",  .fd = -1 },
+@@ -71,7 +66,6 @@ static void usage(int status)
+ 	fputs(_(" -i, --ipc   [=<file>]  enter System V IPC namespace\n"), out);
+ 	fputs(_(" -n, --net   [=<file>]  enter network namespace\n"), out);
+ 	fputs(_(" -p, --pid   [=<file>]  enter pid namespace\n"), out);
+-	fputs(_(" -U, --user  [=<file>]  enter user namespace\n"), out);
+ 	fputs(_(" -r, --root  [=<dir>]   set the root directory\n"), out);
+ 	fputs(_(" -w, --wd    [=<dir>]   set the working directory\n"), out);
+ 	fputs(_(" -F, --no-fork          do not fork before exec'ing <program>\n"), out);
+@@ -168,7 +162,6 @@ int main(int argc, char *argv[])
+ 		{ "ipc", optional_argument, NULL, 'i' },
+ 		{ "net", optional_argument, NULL, 'n' },
+ 		{ "pid", optional_argument, NULL, 'p' },
+-		{ "user", optional_argument, NULL, 'U' },
+ 		{ "root", optional_argument, NULL, 'r' },
+ 		{ "wd", optional_argument, NULL, 'w' },
+ 		{ "no-fork", no_argument, NULL, 'F' },
+@@ -186,7 +179,7 @@ int main(int argc, char *argv[])
+ 	atexit(close_stdout);
+ 
+ 	while ((c =
+-		getopt_long(argc, argv, "hVt:m::u::i::n::p::U::r::w::F",
++		getopt_long(argc, argv, "hVt:m::u::i::n::p::r::w::F",
+ 			    longopts, NULL)) != -1) {
+ 		switch (c) {
+ 		case 'h':
+@@ -228,12 +221,6 @@ int main(int argc, char *argv[])
+ 			else
+ 				namespaces |= CLONE_NEWPID;
+ 			break;
+-		case 'U':
+-			if (optarg)
+-				open_namespace_fd(CLONE_NEWUSER, optarg);
+-			else
+-				namespaces |= CLONE_NEWUSER;
+-			break;
+ 		case 'F':
+ 			do_fork = 0;
+ 			break;
+diff -up util-linux-2.23.2/sys-utils/unshare.1.kzak util-linux-2.23.2/sys-utils/unshare.1
+--- util-linux-2.23.2/sys-utils/unshare.1.kzak	2014-03-12 12:39:41.367806340 +0100
++++ util-linux-2.23.2/sys-utils/unshare.1	2014-03-12 12:40:25.186260760 +0100
+@@ -34,9 +34,6 @@ etc. (\fBCLONE_NEWNET\fP flag).
+ .BR "pid namespace"
+ children will have a distinct set of pid to process mappings than their parent.
+ (\fBCLONE_NEWPID\fP flag).
+-.TP
+-.BR "user namespace"
+-process will have distinct set of uids, gids and capabilities. (\fBCLONE_NEWUSER\fP flag).
+ .PP
+ See the \fBclone\fR(2) for exact semantics of the flags.
+ .SH OPTIONS
+@@ -58,9 +55,6 @@ Unshare the network namespace.
+ .TP
+ .BR \-p , " \-\-pid"
+ Unshare the pid namespace.
+-.TP
+-.BR \-U , " \-\-user"
+-Unshare the user namespace.
+ .SH SEE ALSO
+ .BR unshare (2),
+ .BR clone (2)
+diff -up util-linux-2.23.2/sys-utils/unshare.c.kzak util-linux-2.23.2/sys-utils/unshare.c
+--- util-linux-2.23.2/sys-utils/unshare.c.kzak	2014-03-12 12:39:46.385858383 +0100
++++ util-linux-2.23.2/sys-utils/unshare.c	2014-03-12 12:44:49.955005384 +0100
+@@ -45,7 +45,6 @@ static void usage(int status)
+ 	fputs(_(" -i, --ipc         unshare System V IPC namespace\n"), out);
+ 	fputs(_(" -n, --net         unshare network namespace\n"), out);
+ 	fputs(_(" -p, --pid         unshare pid namespace\n"), out);
+-	fputs(_(" -U, --user        unshare user namespace\n"), out);
+ 
+ 	fputs(USAGE_SEPARATOR, out);
+ 	fputs(USAGE_HELP, out);
+@@ -65,7 +64,6 @@ int main(int argc, char *argv[])
+ 		{ "ipc", no_argument, 0, 'i' },
+ 		{ "net", no_argument, 0, 'n' },
+ 		{ "pid", no_argument, 0, 'p' },
+-		{ "user", no_argument, 0, 'U' },
+ 		{ NULL, 0, 0, 0 }
+ 	};
+ 
+@@ -78,7 +76,7 @@ int main(int argc, char *argv[])
+ 	textdomain(PACKAGE);
+ 	atexit(close_stdout);
+ 
+-	while ((c = getopt_long(argc, argv, "hVmuinpU", longopts, NULL)) != -1) {
++	while ((c = getopt_long(argc, argv, "hVmuinp", longopts, NULL)) != -1) {
+ 		switch (c) {
+ 		case 'h':
+ 			usage(EXIT_SUCCESS);
+@@ -100,9 +98,6 @@ int main(int argc, char *argv[])
+ 		case 'p':
+ 			unshare_flags |= CLONE_NEWPID;
+ 			break;
+-		case 'U':
+-			unshare_flags |= CLONE_NEWUSER;
+-			break;
+ 		default:
+ 			usage(EXIT_FAILURE);
+ 		}
diff --git a/SOURCES/util-linux-60-raw.rules b/SOURCES/util-linux-60-raw.rules
new file mode 100644
index 0000000..abbf79d
--- /dev/null
+++ b/SOURCES/util-linux-60-raw.rules
@@ -0,0 +1,8 @@
+#
+# Enter raw device bindings here.
+#
+# An example would be:
+#   ACTION=="add", KERNEL=="sda", RUN+="/usr/bin/raw /dev/raw/raw1 %N"
+# to bind /dev/raw/raw1 to /dev/sda, or
+#   ACTION=="add", ENV{MAJOR}=="8", ENV{MINOR}=="1", RUN+="/usr/bin/raw /dev/raw/raw2 %M %m"
+# to bind /dev/raw/raw2 to the device with major 8, minor 1.
diff --git a/SOURCES/util-linux-chsh-chfn.pamd b/SOURCES/util-linux-chsh-chfn.pamd
new file mode 100644
index 0000000..2dbc0aa
--- /dev/null
+++ b/SOURCES/util-linux-chsh-chfn.pamd
@@ -0,0 +1,6 @@
+#%PAM-1.0
+auth       sufficient   pam_rootok.so
+auth       include      system-auth
+account    include      system-auth
+password   include      system-auth
+session    include      system-auth
diff --git a/SOURCES/util-linux-login.pamd b/SOURCES/util-linux-login.pamd
new file mode 100644
index 0000000..3c03927
--- /dev/null
+++ b/SOURCES/util-linux-login.pamd
@@ -0,0 +1,18 @@
+#%PAM-1.0
+auth [user_unknown=ignore success=ok ignore=ignore default=bad] pam_securetty.so
+auth       substack     system-auth
+auth       include      postlogin
+account    required     pam_nologin.so
+account    include      system-auth
+password   include      system-auth
+# pam_selinux.so close should be the first session rule
+session    required     pam_selinux.so close
+session    required     pam_loginuid.so
+session    optional     pam_console.so
+# pam_selinux.so open should only be followed by sessions to be executed in the user context
+session    required     pam_selinux.so open
+session    required     pam_namespace.so
+session    optional     pam_keyinit.so force revoke
+session    include      system-auth
+session    include      postlogin
+-session   optional     pam_ck_connector.so
diff --git a/SOURCES/util-linux-remote.pamd b/SOURCES/util-linux-remote.pamd
new file mode 100644
index 0000000..2f22cc2
--- /dev/null
+++ b/SOURCES/util-linux-remote.pamd
@@ -0,0 +1,16 @@
+#%PAM-1.0
+auth       required     pam_securetty.so
+auth       substack     password-auth
+auth       include      postlogin
+account    required     pam_nologin.so
+account    include      password-auth
+password   include      password-auth
+# pam_selinux.so close should be the first session rule
+session    required     pam_selinux.so close
+session    required     pam_loginuid.so
+# pam_selinux.so open should only be followed by sessions to be executed in the user context
+session    required     pam_selinux.so open
+session    required     pam_namespace.so
+session    optional     pam_keyinit.so force revoke
+session    include      password-auth
+session    include      postlogin
diff --git a/SOURCES/util-linux-runuser-l.pamd b/SOURCES/util-linux-runuser-l.pamd
new file mode 100644
index 0000000..7a9a48c
--- /dev/null
+++ b/SOURCES/util-linux-runuser-l.pamd
@@ -0,0 +1,5 @@
+#%PAM-1.0
+auth		include		runuser
+session		optional	pam_keyinit.so force revoke
+-session	optional	pam_systemd.so
+session		include		runuser
diff --git a/SOURCES/util-linux-runuser.pamd b/SOURCES/util-linux-runuser.pamd
new file mode 100644
index 0000000..37f0e84
--- /dev/null
+++ b/SOURCES/util-linux-runuser.pamd
@@ -0,0 +1,5 @@
+#%PAM-1.0
+auth		sufficient	pam_rootok.so
+session		optional	pam_keyinit.so revoke
+session		required	pam_limits.so
+session		required	pam_unix.so
diff --git a/SOURCES/util-linux-su-l.pamd b/SOURCES/util-linux-su-l.pamd
new file mode 100644
index 0000000..656a139
--- /dev/null
+++ b/SOURCES/util-linux-su-l.pamd
@@ -0,0 +1,6 @@
+#%PAM-1.0
+auth		include		su
+account		include		su
+password	include		su
+session		optional	pam_keyinit.so force revoke
+session		include		su
diff --git a/SOURCES/util-linux-su.pamd b/SOURCES/util-linux-su.pamd
new file mode 100644
index 0000000..030657f
--- /dev/null
+++ b/SOURCES/util-linux-su.pamd
@@ -0,0 +1,14 @@
+#%PAM-1.0
+auth		sufficient	pam_rootok.so
+# Uncomment the following line to implicitly trust users in the "wheel" group.
+#auth		sufficient	pam_wheel.so trust use_uid
+# Uncomment the following line to require a user to be in the "wheel" group.
+#auth		required	pam_wheel.so use_uid
+auth		substack	system-auth
+auth		include		postlogin
+account		sufficient	pam_succeed_if.so uid = 0 use_uid quiet
+account		include		system-auth
+password	include		system-auth
+session		include		system-auth
+session		include		postlogin
+session		optional	pam_xauth.so
diff --git a/SOURCES/v2.26-nsenter-selinux.patch b/SOURCES/v2.26-nsenter-selinux.patch
new file mode 100644
index 0000000..0676127
--- /dev/null
+++ b/SOURCES/v2.26-nsenter-selinux.patch
@@ -0,0 +1,129 @@
+diff -up util-linux-2.23.2/sys-utils/Makemodule.am.kzak util-linux-2.23.2/sys-utils/Makemodule.am
+--- util-linux-2.23.2/sys-utils/Makemodule.am.kzak	2015-06-26 10:21:34.337221288 +0200
++++ util-linux-2.23.2/sys-utils/Makemodule.am	2015-06-26 10:22:18.719885983 +0200
+@@ -308,7 +308,7 @@ if BUILD_NSENTER
+ usrbin_exec_PROGRAMS += nsenter
+ dist_man_MANS += sys-utils/nsenter.1
+ nsenter_SOURCES = sys-utils/nsenter.c
+-nsenter_LDADD = $(LDADD) libcommon.la
++nsenter_LDADD = $(LDADD) libcommon.la $(SELINUX_LIBS)
+ endif
+ 
+ if BUILD_HWCLOCK
+diff -up util-linux-2.23.2/sys-utils/nsenter.1.kzak util-linux-2.23.2/sys-utils/nsenter.1
+--- util-linux-2.23.2/sys-utils/nsenter.1.kzak	2015-06-26 10:14:00.947646586 +0200
++++ util-linux-2.23.2/sys-utils/nsenter.1	2015-06-26 10:21:34.337221288 +0200
+@@ -155,6 +155,11 @@ Do not fork before exec'ing the specifie
+ PID namespace, \fBnsenter\fP calls \fBfork\fP before calling \fBexec\fP so that
+ any children will also be in the newly entered PID namespace.
+ .TP
++\fB\-Z\fR, \fB\-\-follow\-context\fR
++Set the SELinux security context used for executing a new process according to
++already running process specified by \fB\-\-target\fR PID. (The util-linux has
++to be compiled with SELinux support otherwise the option is unavailable.)
++.TP
+ \fB\-V\fR, \fB\-\-version\fR
+ Display version information and exit.
+ .TP
+@@ -163,10 +168,14 @@ Display help text and exit.
+ .SH SEE ALSO
+ .BR setns (2),
+ .BR clone (2)
+-.SH AUTHOR
+-.MT ebiederm@xmission.com
++.SH AUTHORS
++.UR biederm@xmission.com
+ Eric Biederman
+-.ME
++.UE
++.br
++.UR kzak@redhat.com
++Karel Zak
++.UE
+ .SH AVAILABILITY
+ The nsenter command is part of the util-linux package and is available from
+ .UR ftp://\:ftp.kernel.org\:/pub\:/linux\:/utils\:/util-linux/
+diff -up util-linux-2.23.2/sys-utils/nsenter.c.kzak util-linux-2.23.2/sys-utils/nsenter.c
+--- util-linux-2.23.2/sys-utils/nsenter.c.kzak	2015-06-26 10:14:00.947646586 +0200
++++ util-linux-2.23.2/sys-utils/nsenter.c	2015-06-26 10:21:34.337221288 +0200
+@@ -30,6 +30,10 @@
+ #include <sys/wait.h>
+ #include <grp.h>
+ 
++#ifdef HAVE_LIBSELINUX
++# include <selinux/selinux.h>
++#endif
++
+ #include "strutils.h"
+ #include "nls.h"
+ #include "c.h"
+@@ -82,6 +86,9 @@ static void usage(int status)
+ 	fputs(_(" -r, --root[=<dir>]     set the root directory\n"), out);
+ 	fputs(_(" -w, --wd[=<dir>]       set the working directory\n"), out);
+ 	fputs(_(" -F, --no-fork          do not fork before exec'ing <program>\n"), out);
++#ifdef HAVE_LIBSELINUX
++	fputs(_(" -Z, --follow-context   set SELinux context according to --target PID\n"), out);
++#endif
+ 
+ 	fputs(USAGE_SEPARATOR, out);
+ 	fputs(USAGE_HELP, out);
+@@ -185,6 +192,9 @@ int main(int argc, char *argv[])
+ 		{ "wd", optional_argument, NULL, 'w' },
+ 		{ "no-fork", no_argument, NULL, 'F' },
+ 		{ "preserve-credentials", no_argument, NULL, OPT_PRESERVE_CRED },
++#ifdef HAVE_LIBSELINUX
++		{ "follow-context", no_argument, NULL, 'Z' },
++#endif
+ 		{ NULL, 0, NULL, 0 }
+ 	};
+ 
+@@ -194,6 +204,9 @@ int main(int argc, char *argv[])
+ 	int do_fork = -1; /* unknown yet */
+ 	uid_t uid = 0;
+ 	gid_t gid = 0;
++#ifdef HAVE_LIBSELINUX
++	bool selinux = 0;
++#endif
+ 
+ 	setlocale(LC_ALL, "");
+ 	bindtextdomain(PACKAGE, LOCALEDIR);
+@@ -201,7 +214,7 @@ int main(int argc, char *argv[])
+ 	atexit(close_stdout);
+ 
+ 	while ((c =
+-		getopt_long(argc, argv, "+hVt:m::u::i::n::p::U::S:G:r::w::F",
++		getopt_long(argc, argv, "+hVt:m::u::i::n::p::U::S:G:r::w::FZ",
+ 			    longopts, NULL)) != -1) {
+ 		switch (c) {
+ 		case 'h':
+@@ -275,11 +288,30 @@ int main(int argc, char *argv[])
+ 		case OPT_PRESERVE_CRED:
+ 			preserve_cred = 1;
+ 			break;
++#ifdef HAVE_LIBSELINUX
++		case 'Z':
++			selinux = 1;
++			break;
++#endif
+ 		default:
+ 			usage(EXIT_FAILURE);
+ 		}
+ 	}
+ 
++#ifdef HAVE_LIBSELINUX
++	if (selinux && is_selinux_enabled() > 0) {
++		char *scon = NULL;
++
++		if (!namespace_target_pid)
++			errx(EXIT_FAILURE, _("no target PID specified for --follow-context"));
++		if (getpidcon(namespace_target_pid, &scon) < 0)
++			errx(EXIT_FAILURE, _("failed to get %d SELinux context"),
++					(int) namespace_target_pid);
++		if (setexeccon(scon) < 0)
++			errx(EXIT_FAILURE, _("failed to set exec context to '%s'"), scon);
++		freecon(scon);
++	}
++#endif
+ 	/*
+ 	 * Open remaining namespace and directory descriptors.
+ 	 */
diff --git a/SPECS/util-linux.spec b/SPECS/util-linux.spec
new file mode 100644
index 0000000..7ddf276
--- /dev/null
+++ b/SPECS/util-linux.spec
@@ -0,0 +1,3025 @@
+### Header
+Summary: A collection of basic system utilities
+Name: util-linux
+Version: 2.23.2
+Release: 43%{?dist}.2
+License: GPLv2 and GPLv2+ and LGPLv2+ and BSD with advertising and Public Domain
+Group: System Environment/Base
+URL: http://en.wikipedia.org/wiki/Util-linux
+
+%define upstream_version %{version}
+
+### Macros
+%define cytune_archs %{ix86} alpha %{arm}
+%define compldir %{_datadir}/bash-completion/completions/
+
+### Dependencies
+BuildRequires: audit-libs-devel >= 1.0.6
+BuildRequires: gettext-devel
+BuildRequires: libselinux-devel
+BuildRequires: ncurses-devel
+BuildRequires: pam-devel
+BuildRequires: zlib-devel
+BuildRequires: popt-devel
+BuildRequires: libutempter-devel
+Buildrequires: systemd-devel
+Buildrequires: libuser-devel
+BuildRequires: libcap-ng-devel
+BuildRequires: autoconf
+BuildRequires: automake
+BuildRequires: libtool
+
+### Sources
+Source0: ftp://ftp.kernel.org/pub/linux/utils/util-linux/v2.23/util-linux-%{upstream_version}.tar.xz
+Source1: util-linux-login.pamd
+Source2: util-linux-remote.pamd
+Source3: util-linux-chsh-chfn.pamd
+Source4: util-linux-60-raw.rules
+Source8: nologin.c
+Source9: nologin.8
+Source12: util-linux-su.pamd
+Source13: util-linux-su-l.pamd
+Source14: util-linux-runuser.pamd
+Source15: util-linux-runuser-l.pamd
+
+### Obsoletes & Conflicts & Provides
+Conflicts: bash-completion < 1:2.1-1
+# su(1) and runuser(1) merged into util-linux v2.22
+Conflicts: coreutils < 8.20
+# eject has been merged into util-linux v2.22
+Obsoletes: eject <= 2.1.5
+Provides: eject = 2.1.6
+# sulogin, utmpdump merged into util-linux v2.22
+Conflicts: sysvinit-tools < 2.88-8
+# old versions of e2fsprogs contain fsck, uuidgen
+Conflicts: e2fsprogs < 1.41.8-5
+# rename from util-linux-ng back to util-linux
+Obsoletes: util-linux-ng < 2.19
+Provides: util-linux-ng = %{version}-%{release}
+Conflicts: filesystem < 3
+Provides: /bin/dmesg
+Provides: /bin/kill
+Provides: /bin/more
+Provides: /bin/mount
+Provides: /bin/umount
+Provides: /sbin/blkid
+Provides: /sbin/blockdev
+Provides: /sbin/findfs
+Provides: /sbin/fsck
+Provides: /sbin/nologin
+
+Requires(post): coreutils
+Requires: pam >= 1.1.3-7, /etc/pam.d/system-auth
+Requires: audit-libs >= 1.0.6
+Requires: libuuid = %{version}-%{release}
+Requires: libblkid = %{version}-%{release}
+Requires: libmount = %{version}-%{release}
+
+### Ready for upstream?
+###
+# 151635 - makeing /var/log/lastlog
+Patch0: 2.23-login-lastlog-create.patch
+
+# v2.24 backport: #972457
+Patch1: 2.24-agetty-clocal.patch
+# v2.24 backport: #987787 - Remove lastlogin from su
+Patch2: 2.24-su-suppress-PAM-info-messages.patch
+# v2.24 backport: #950497 - problem umounting loop device
+Patch3: 2.24-libmount-canonicalize-for-conversion-from-loopdev.patch
+# v2.24 backport: #921498 - multiple internal testsuite failures
+Patch4: 2.24-tests-portability.patch
+# v2.24 backport: #1005566 - recount_geometry: Process /usr/sbin/fdisk was killed by signal 8 (SIGFPE)
+Patch5: 2.24-libfdisk-fix-SIGFPE.patch
+# v2.24 backport: #1005194 - su generates incorrect log entries
+Patch6: 2.24-su-fix-lastlog-and-btmp-logging.patch
+# v2.24 backport: #1006462 - RFE: allow \S escape that defaults to PRETTY_NAME in /etc/issue handling
+Patch7: 2.24-agetty-etc-os-release.patch
+# v2.24 backport: #1010193 - libmount umount issues
+Patch8: 2.24-libmount-mem.patch
+# v2.24 backport: #1009349 - Joking sfdisk rewriting PT after "n"
+Patch9: 2.24-sfdisk-y-n-miscmatch.patch
+# v2.24 backport: #1007885 - utmpdump is not IPv6 ready
+Patch10: 2.24-utmpdump-ipv6.patch
+# v2.24 backport: #1024366 - losetup does not use loop-control to add device
+Patch11: 2.24-losetup-add-device.patch
+# v2.24 backport: 1016471 - Document that blockdev --setbsz call has never worked
+Patch12: 2.24-blockdev-setbsz-hint.patch
+# v2.25 backport: #1039189 - taskset man page PERMISSIONS section is incorrect
+Patch13: 2.25-taskset-man-fix-permissions.patch
+# v2.25 backport: #1050852 - lscpu: support discontinuous NUMA nodes
+Patch14: 2.25-lib-add-path_strdup.patch
+Patch15: 2.25-lscpu-discontinuous-NUMA-nodes.patch
+Patch16: 2.25-lscpu-sort-NUMA.patch
+# v2.25 backport: #1046849 - filesystem type is not correctly displayed by df command
+Patch17: 2.25-libblkid-Identify-extN-file-system-properly.patch
+# v2.25 backport: #1055490 - libblkid: Do not problem for backup btrfs superblock
+Patch18: 2.25-libblkid-no-more-probe-for-btrfs-backup-superblock.patch
+# v2.25 backport: #1054186 - wipefs does not clean gpt header fully, PMBR remains
+Patch19: 2.25-libblkid-detect-alone-PMBR.patch
+Patch20: 2.25-wipefs-call-BLKRRPART-when-erase-partition-table.patch
+# v2.25 backport: #977162 - fix the description of XFS "allocsize="
+Patch21: 2.25-mount-man-xfs.patch
+# rhel7.0: #1073851 - disable user namespaces
+Patch22: rhel7.0-unshare-user.patch
+# v2.25 backpoprt: #1078618 - flock nfs file fails on nfsv4
+Patch23: 2.25-flock-nfs4.patch
+# v2.25 backport: #1047376 - blkid hangs while reading from /dev/fd0
+Patch24: 2.25-libblkid-io-errors.patch
+#v2.24 and v2.25 backport: #1079931 - fsck: warning on kdump boot
+Patch25: 2.24-fsck-fstab.patch
+Patch26: 2.25-fsck-nohelper.patch
+
+#
+# RHEL 7.1
+#
+# 1067354 - dmesg -w output not line-buffered
+Patch27: 2.25-dmesg-w.patch
+# 1072298 - util-linux/lscpu: '--sysroot' broken on XFS
+Patch28: 2.25-lscpu-d_type.patch
+# 1072930 - hwclock --systohc can hang on busy or virtual machine
+Patch29: 2.25-hwclock-hang.patch
+# 1077310 - wipefs problem with some live .isos
+Patch30: 2.25-wipefs-nested-pt.patch
+# 1077864 - Backport swapon: allow a more flexible swap discard policy
+Patch31: 2.25-swapon-discard.patch
+# 1080407 - libblkid XFS detection is too fragile
+Patch32: 2.25-libblkid-xfs.patch
+# RHEL6.6 port #1115442 - kill(1) doesn't check errno after calling strtol() 
+Patch33: 2.17-kill-strtol.patch
+# 1127823 - losetup does not accept offset
+Patch34: 2.24-losetup-offset.patch
+# 1127891 - wipefs 4k disks and gpt partitions
+Patch35: 2.25-libblkid-gpt-512.patch
+# 1136111 - "findmnt" returns incomplete output on kernel-3.14
+Patch36: 2.24-libmount-3.14.patch
+# backport from upstream: #1140591 - improve mount --move documentation
+Patch37: 2.26-mount-man-move.patch
+# RHEL6.6 port: #1131522 - backport --fork and --mount-proc to unshare(1) 
+Patch38: 2.24-unshare-mount-fork.patch
+# Backport from upstream (v2.25-214-g8a4c64e): #1113043 - backport lslogins(1)
+Patch39: 2.26-libsmartcols.patch
+Patch40: 2.26-lslogins.patch
+# 1149278 - partx fails to update a specific partition other than the first
+Patch41: 2.24-partx-update.patch
+# 1156352 - blkdiscard progress report and interruptibility of the process
+Patch42: 2.26-blkdiscard.patch
+# 1181444 - raw command fails with "Cannot locate raw device".
+Patch43: 2.26-raw-stat.patch
+
+#
+# RHEL 7.2
+#
+Patch44: 2.25-uuidd-timeout.patch
+# 1225235 - blockdev --report fails on loop and pmem devices
+Patch45: 2.25-blockdev-geom.patch
+# 1225053 - [RFE] backport fstrim -a and unit file
+Patch46: 2.25-fstrim-all.patch
+# 1131523 - mount does not appear to be correctly documented for default mount options
+Patch47: 2.25-mount-man-default.patch
+# 1147526 - Incorrect message printed when su is killed
+Patch48: 2.26-su-coredump-message.patch
+# 1165702 - make login(1) insensitive to SIGXFSZ and huge lastlog
+Patch49: 2.26-login-SIGXFSZ.patch
+# 1184558 - logger silently changes facility from kern to user
+Patch50: 2.26-logger-man-kern.patch
+# 1198243 - blkid does not recognize xfs external log device
+Patch51: 2.25-libblkid-xfs-log.patch
+# 1208081 - lsblk does not list dm-multipath and partitioned devices
+Patch52: 2.26-lsblk-mpath.patch
+# 1209594 - RHEL7: unshare: add --propagation, use MS_PRIVATE by default
+# 1229436 - Remove patch that disables User Namespaces
+Patch53: 2.26-unshare-rebase.patch
+# 1116100 - Add -Z SELInux option to nsenter
+Patch54: v2.26-nsenter-selinux.patch
+# 1199619 - os-prober attempts to mount thin pool devices
+Patch55: 2.25-libblkid-thinpool.patch
+# 1251250 - blkid outputs nothing for some partitions (e.g. sun label)
+Patch56: 2.25-libblkid-return-codes.patch
+# 1182831 - blkid incorrectly detects boot sec + MBR as FAT
+Patch57: 2.26-libblkid-fat.patch
+
+#
+# RHEL7.3
+#
+# 1301091 - [libblkid] Failed to get offset of the xfs_external_log signature
+Patch58: 2.27-libblkid-xfs-log.patch
+# 1291554 - lslogins crash when executed with buggy username
+Patch59: 2.28-lslogins-rebase.patch
+# 1092520 - util-linux - PIE and RELRO check
+Patch60: 0060-build-sys-add-CFLAGS-and-LDFLAGS-for-daemons-and-sha.patch
+# 1248003 - mount only parses <param>=<value> lines from fstab fs_spec field available from blkid block device
+Patch61: 0061-libmount-be-more-restrictive-about-valid-tag-names.patch
+# 1271850 - mount -a doesn't catch a typo in /etc/fstab and a typo in /etc/fstab can make a system not reboot properly
+Patch62: 0062-mount-umount-swapon-fsck-lsblk-findmnt-ignore-malfor.patch
+# 1290689 - util-linux: /bin/login does not retry getpwnam_r with larger buffers, leading to login failure
+Patch63: 0063-login-mount-fix-__SC_GETPW_R_SIZE_MAX-usage.patch
+# 1296366 - Bash completion for more(1) handles file names with spaces incorrectly
+Patch64: 0064-bash-completion-use-n-as-IFS-when-ask-for-filenames.patch
+# 1296521 - RHEL7: update audit event in hwclock
+Patch65: 0065-hwclock-change-audit-message.patch
+# 1304426 - [rfe] /bin/su should be improved to reduce stack use
+Patch66: 0066-su-clean-up-groups-initialization.patch
+# 1326615 - util-linux/lscpu: Fix model and model name on Power Systems
+Patch67: 0067-lscpu-Fix-model-and-model-name-on-Power-Systems.patch
+# 1326615 - util-linux/lscpu: Fix model and model name on Power Systems
+Patch68: 0068-lscpu-use-cpu-and-revision-tag-if-available.patch
+# 1335671 - extra quotes around UUID confuses findfs in RHEL (but not in Fedora)
+Patch69: 0069-findfs-add-ability-to-work-with-PART-UUID-LABEL-too.patch
+# 1335671 - extra quotes around UUID confuses findfs in RHEL (but not in Fedora)
+Patch70: 0070-libblkid-fix-memory-leak-in-blkid_parse_tag_string.patch
+# 587393 - [RFE] Make sure util-linux is ready for writable overlays
+Patch71: 0071-findmnt-don-t-rely-on-st_dev-for-target.patch
+# 587393 - [RFE] Make sure util-linux is ready for writable overlays
+Patch72: 0072-libmount-cleanup-fs-root-detection-code.patch
+# 587393 - [RFE] Make sure util-linux is ready for writable overlays
+Patch73: 0073-libmount-mark-overlay-as-pseudo-FS.patch
+# 1344222 - logger port option in help is misleading
+Patch74: 0074-logger-be-more-precise-about-port-description.patch
+# 1344482 - util-linux fails valid_pmbr() size checks if device is > 2.14TB, Device label type: dos instead of gpt
+Patch75: 0075-libfdisk-gpt-be-more-careful-with-64bit-constants.patch
+# 1332084 - [RFE] Inclusion of lsns command in util-linux Package
+Patch76: 0076-lsns-backport-new-command.patch
+# 1153770 - backport lsipc
+Patch77: 0077-lib-strutils-make-strmode-more-generic.patch
+# 1153770 - backport lsipc
+Patch78: 0078-lsipc-backport-new-command.patch
+# 1327886 - Backport blkdiscard's "-z" flag to RHEL
+Patch79: 0079-blkdiscard-backport-zeroout-support.patch
+# 1029385 - lack of non-ascii support
+Patch80: 0080-sulogin-and-agetty-virtual-consoles-support-xvc-and-.patch
+# 1298384 - RFE: add SCHED_DEADLINE support to chrt
+Patch81: 0081-chrt-backport-DEADLINE-scheduler-support.patch
+# 1304246 - fdisk 'f' subcommand updates partition ranges wrongly
+Patch82: 0082-fdisk-backport-DOS-logical-partitions-chain-reorder.patch
+# 1153770 - backport lsipc
+Patch83: 0083-tests-cleanup-tests.patch
+# 1281839 - [RFE]Bind mounts should be handled gracefully by the operating system
+Patch84: 0084-libmount-add-support-for-bind-ro.patch
+# 1007734 - blkid shows devices as /dev/block/$MAJOR:$MINOR
+Patch85: 0085-libblkid-store-only-canonical-devnames-to-the-cache.patch
+# 1349536 - Extended partition loop in MBR partition table leads to DOS
+Patch86: 0086-libblkid-avoid-recursion-in-EBR.patch
+
+#
+# RHEL7.4
+#
+# 1405238 - findmnt --target behaviour changed in 7.3, shows all mount-points in chroot
+Patch87: 0087-findmnt-fix-target-behaviour.patch
+# 1419474
+Patch88: 0088-su-properly-clear-child-PID.patch
+# 1344102 - fdisk does not handle 4kN devices correctly in 'Blocks' calculation
+Patch89: 0089-fdisk-fix-Blocks-column-calculation.patch
+# 1344720 - when fdisk detects gpt table, expected menu items seem to be missing in the 'm' output
+Patch90: 0090-fdisk-fix-menu-for-GPT.patch
+# 1323916 - logger unnecessarily splits messages sent via stdin into 1024 byte chunks
+Patch91: 0091-logger-backport-size.patch
+# 1344726 - [RFE] fdisk: output UID from gpt in fdisk when detecting that a gpt partition table is present
+Patch92: 0092-fdisk-print-header-UUID-for-GPT.patch
+# 1362662 - fdisk -l fails/stops on first passive/not ready device, works on RHEL6
+Patch93: 0093-fdisk-improve-l-error-handling.patch
+# 1369436 - losetup man page incorrect syntax for Setup loop device
+Patch94: 0094-losetup-improve-man-page-SYNOPSIS.patch
+# 1392656 - [LLNL 7.4 Bug] fix buffer overflows in util-linux with upstream patch
+Patch95: 0095-libblkid-fix-potential-bufer-overflows.patch
+# 1370959 - [FJ7.3 Bug]: man 8 umount is wrong.
+Patch96: 0096-umount-fix-obsolete-info-about-loop-in-umount.8.patch
+# 1357746 - mount -av" report NFS "successfully mounted" but it is not.
+Patch97: 0097-mount-fix-all-and-nofail-return-code.patch
+# 1417722 - umount -a results in selinux being reported as Disabled
+Patch98: 0098-umount-exclude-selinuxfs-from-all.patch
+# 1402825 - RHEL7: "sfdisk -s" can't list the disk size
+Patch99: 0099-sfdisk-remove-useless-CDROM-detection-for-s.patch
+# 1403973 - /usr/bin/more crash on repeat search on failed regex match
+Patch100: 0100-more-fix-repeat-search-crash.patch
+# 1403971 - /usr/bin/more crash in end_it due to double free
+Patch101: 0101-more-avoid-double-free-on-exit.patch
+# 1358095 - ipcs shows wrong gid information
+Patch102: 0102-ipcs-show-gid-instead-of-uid.patch
+# 1358097 - ipcs shows strange status message in ja locale
+Patch103: 0103-ipcs-fix-JP-status-message.patch
+# 1378100 - fix swapon discard option parsing
+Patch104: 0104-swapon-fix-discard-option-parsing.patch
+# 1416467 - [RFE] Add support for posix_fallocate(3) call in fallocate(1) utility
+Patch105: 0105-fallocate-Added-posix_fallocate-support.patch
+# 1358755 - Backport request for zramctl on util-linux v2.23.2
+Patch106: 0106-zramctl-backport-from-v2.29.patch
+# 1392661 - [LLNL 7.4 Bug] add zfs patches to util-linux
+Patch107: 0107-libblkid-zfs-let-s-keep-compiler-happy.patch
+Patch108: 0108-blkid-make-zfs-detection-more-robust.patch
+Patch109: 0109-zfs-make-less-syscalls.patch
+Patch110: 0110-libblkid-zfs-keep-bufferes-read-only.patch
+Patch111: 0111-libblkid-don-t-mark-zfs-as-RAID.patch
+Patch112: 0112-tests-update-ZFS-test.patch
+Patch113: 0113-libblkid-zfs-add-cast-to-fix-UB-cppcheck.patch
+Patch114: 0114-libblkid-Avoid-OOB-access-on-illegal-ZFS-superblocks.patch
+# 1360764 - SMT: "Threads Per Core" will automatically change when odd or even number of vcpu are enabled online.
+# 1397709 - [7.4 FEAT] Refresh code for lscpu to support s390x cpu topology
+Patch115: 0115-lscpu-backport-from-v2.29.patch
+# 1402183 - [HPE 7.3 Bug] fdisk -l does not list non-BTT NVDIMM devices
+Patch116: 0116-fdisk-use-sysfs_devno_is_wholedisk.patch
+# 1358755 - Backport request for zramctl on util-linux v2.23.2
+Patch117: 0117-zramctl-add-bash-completion.patch
+Patch118: 0118-zramctl-make-mm_stat-parser-more-robust.patch
+# 1344720 - when fdisk detects gpt table, expected menu items seem to be missing in the 'm' output
+Patch119: 0119-fdisk-improve-menu-and-u-for-GPT.patch
+# 1360764 1397709 - lscpu rebase
+Patch120: 0120-tests-update-for-RHEL7.4-changes.patch
+# 1358755 - Backport request for zramctl on util-linux v2.23.2
+Patch121: 0121-zramctl-be-more-specific-about-default-output.patch
+# 1344726 - [RFE] fdisk: output UID from gpt in fdisk when detecting that a gpt partition table is present
+Patch122: 0122-libfdisk-gpt-fix-UUID-printing.patch
+# 1451704 - [Intel 7.4 BUG] IMSM RAID on 4k disks not assembled on boot
+Patch123: 0123-libblkid-Add-metadata-signature-check-for-IMSM-on-4K.patch
+# 1455664 - lscpu causes kernel panic on HPE Comanche / Cavium ThunderX2 (cn99xx)
+Patch124: 0124-lscpu-use-sysfs-for-table-access-if-available.patch
+# 1457744 - lscpu -e get crashed after offline one host cpu on amd machine
+Patch125: 0125-lscpu-improve-for-offline-CPUs-on-AMD.patch
+
+# RHEL7.4.Z
+# 1499760 - gvfs-udisks2-volume-monitor generates huge amount of audit log with access denied messages
+Patch126: 0126-libmount-use-eacess-rather-than-open-to-check-mtab-u.patch
+Patch127: 0127-libmount-fix-access-utab-write-test.patch
+
+%description
+The util-linux package contains a large variety of low-level system
+utilities that are necessary for a Linux system to function. Among
+others, Util-linux contains the fdisk configuration tool and the login
+program.
+
+%package -n libmount
+Summary: Device mounting library
+Group: Development/Libraries
+License: LGPLv2+
+Requires: libblkid = %{version}-%{release}
+Requires: libuuid = %{version}-%{release}
+Conflicts: filesystem < 3
+
+%description -n libmount
+This is the device mounting library, part of util-linux.
+
+
+%package -n libmount-devel
+Summary: Device mounting library
+Group: Development/Libraries
+License: LGPLv2+
+Requires: libmount = %{version}-%{release}
+Requires: pkgconfig
+
+%description -n libmount-devel
+This is the device mounting development library and headers,
+part of util-linux.
+
+
+%package -n libblkid
+Summary: Block device ID library
+Group: Development/Libraries
+License: LGPLv2+
+Requires: libuuid = %{version}-%{release}
+Conflicts: filesystem < 3
+Requires(post): coreutils
+
+%description -n libblkid
+This is block device identification library, part of util-linux.
+
+
+%package -n libblkid-devel
+Summary: Block device ID library
+Group: Development/Libraries
+License: LGPLv2+
+Requires: libblkid = %{version}-%{release}
+Requires: pkgconfig
+
+%description -n libblkid-devel
+This is the block device identification development library and headers,
+part of util-linux.
+
+
+%package -n libuuid
+Summary: Universally unique ID library
+Group: Development/Libraries
+License: BSD
+Conflicts: filesystem < 3
+
+%description -n libuuid
+This is the universally unique ID library, part of util-linux.
+
+The libuuid library generates and parses 128-bit universally unique
+id's (UUID's).  A UUID is an identifier that is unique across both
+space and time, with respect to the space of all UUIDs.  A UUID can
+be used for multiple purposes, from tagging objects with an extremely
+short lifetime, to reliably identifying very persistent objects
+across a network.
+
+See also the "uuid" package, which is a separate implementation.
+
+%package -n libuuid-devel
+Summary: Universally unique ID library
+Group: Development/Libraries
+License: BSD
+Requires: libuuid = %{version}-%{release}
+Requires: pkgconfig
+
+%description -n libuuid-devel
+This is the universally unique ID development library and headers,
+part of util-linux.
+
+The libuuid library generates and parses 128-bit universally unique
+id's (UUID's).  A UUID is an identifier that is unique across both
+space and time, with respect to the space of all UUIDs.  A UUID can
+be used for multiple purposes, from tagging objects with an extremely
+short lifetime, to reliably identifying very persistent objects
+across a network.
+
+See also the "uuid-devel" package, which is a separate implementation.
+
+
+%package -n uuidd
+Summary: Helper daemon to guarantee uniqueness of time-based UUIDs
+Group: System Environment/Daemons
+Requires: libuuid = %{version}-%{release}
+License: GPLv2
+Requires: systemd
+Requires(pre): shadow-utils
+Requires(post): systemd-units
+Requires(preun): systemd-units
+
+%description -n uuidd
+The uuidd package contains a userspace daemon (uuidd) which guarantees
+uniqueness of time-based UUID generation even at very high rates on
+SMP systems.
+
+
+%prep
+%autosetup -p1 -n %{name}-%{upstream_version}
+
+cp %{SOURCE8} %{SOURCE9} .
+
+%build
+unset LINGUAS || :
+
+# unfortunately, we did changes to build-system
+./autogen.sh
+
+# we modify .po files by RHEL patches
+rm -f po/stamp*
+
+export CFLAGS="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 $RPM_OPT_FLAGS"
+export SUID_CFLAGS="-fpie"
+export SUID_LDFLAGS="-pie -Wl,-z,relro -Wl,-z,now"
+export DAEMON_CFLAGS="$SUID_CFLAGS"
+export DAEMON_LDFLAGS="$SUID_LDFLAGS"
+%configure \
+	--with-systemdsystemunitdir=%{_unitdir} \
+	--disable-silent-rules \
+	--disable-wall \
+	--disable-bfs \
+	--disable-pg \
+	--enable-socket-activation \
+	--enable-chfn-chsh \
+	--enable-write \
+	--enable-raw \
+	--with-udev \
+	--with-selinux \
+	--with-audit \
+	--with-utempter \
+	--disable-makeinstall-chown \
+%ifnarch %cytune_archs
+	--disable-cytune \
+%endif
+%ifarch s390 s390x
+	--disable-hwclock \
+	--disable-fdformat
+%endif
+
+# build util-linux
+make %{?_smp_mflags}
+
+# build nologin
+gcc $CFLAGS -o nologin nologin.c
+
+
+%check
+#to run tests use "--with check"
+%if %{?_with_check:1}%{!?_with_check:0}
+make check
+%endif
+
+
+%install
+rm -rf ${RPM_BUILD_ROOT}
+mkdir -p ${RPM_BUILD_ROOT}%{_bindir}
+mkdir -p ${RPM_BUILD_ROOT}%{_mandir}/man{1,6,8,5}
+mkdir -p ${RPM_BUILD_ROOT}%{_sbindir}
+mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/{pam.d,security/console.apps}
+mkdir -p ${RPM_BUILD_ROOT}/var/log
+touch ${RPM_BUILD_ROOT}/var/log/lastlog
+chmod 0644 ${RPM_BUILD_ROOT}/var/log/lastlog
+
+# install util-linux
+make install DESTDIR=${RPM_BUILD_ROOT}
+
+# install nologin
+install -m 755 nologin ${RPM_BUILD_ROOT}%{_sbindir}
+install -m 644 nologin.8 ${RPM_BUILD_ROOT}%{_mandir}/man8
+
+# raw
+echo '.so man8/raw.8' > $RPM_BUILD_ROOT%{_mandir}/man8/rawdevices.8
+{
+	# see RH bugzilla #216664
+	mkdir -p ${RPM_BUILD_ROOT}%{_prefix}/lib/udev/rules.d
+	pushd ${RPM_BUILD_ROOT}%{_prefix}/lib/udev/rules.d
+	install -m 644 %{SOURCE4} ./60-raw.rules
+	popd
+}
+
+# sbin -> bin
+mv ${RPM_BUILD_ROOT}%{_sbindir}/raw ${RPM_BUILD_ROOT}%{_bindir}/raw
+
+# And a dirs uuidd needs that the makefiles don't create
+install -d ${RPM_BUILD_ROOT}/run/uuidd
+install -d ${RPM_BUILD_ROOT}/var/lib/libuuid
+
+# libtool junk
+rm -rf ${RPM_BUILD_ROOT}%{_libdir}/*.la
+
+%ifarch %{sparc}
+rm -rf ${RPM_BUILD_ROOT}%{_bindir}/sunhostid
+cat << E-O-F > ${RPM_BUILD_ROOT}%{_bindir}/sunhostid
+#!/bin/sh
+# this should be _bindir/sunhostid or somesuch.
+# Copyright 1999 Peter Jones, <pjones@redhat.com> .
+# GPL and all that good stuff apply.
+(
+idprom=\`cat /proc/openprom/idprom\`
+echo \$idprom|dd bs=1 skip=2 count=2
+echo \$idprom|dd bs=1 skip=27 count=6
+echo
+) 2>/dev/null
+E-O-F
+chmod 755 ${RPM_BUILD_ROOT}%{_bindir}/sunhostid
+%endif
+
+# PAM settings
+{
+	pushd ${RPM_BUILD_ROOT}%{_sysconfdir}/pam.d
+	install -m 644 %{SOURCE1} ./login
+	install -m 644 %{SOURCE2} ./remote
+	install -m 644 %{SOURCE3} ./chsh
+	install -m 644 %{SOURCE3} ./chfn
+	install -m 644 %{SOURCE12} ./su
+	install -m 644 %{SOURCE13} ./su-l
+	install -m 644 %{SOURCE14} ./runuser
+	install -m 644 %{SOURCE15} ./runuser-l
+	popd
+}
+
+%ifnarch s390 s390x
+ln -sf hwclock ${RPM_BUILD_ROOT}%{_sbindir}/clock
+echo ".so man8/hwclock.8" > ${RPM_BUILD_ROOT}%{_mandir}/man8/clock.8
+%endif
+
+# unsupported on SPARCs
+%ifarch %{sparc}
+for I in /sbin/sfdisk \
+	%{_mandir}/man8/sfdisk.8* \
+	%doc Documentation/sfdisk.txt \
+	/sbin/cfdisk \
+	%{_mandir}/man8/cfdisk.8*; do
+	
+	rm -f $RPM_BUILD_ROOT$I
+done
+%endif
+
+# we install getopt-*.{bash,tcsh} as doc files
+chmod 644 misc-utils/getopt-*.{bash,tcsh}
+rm -f ${RPM_BUILD_ROOT}%{_datadir}/getopt/*
+rmdir ${RPM_BUILD_ROOT}%{_datadir}/getopt
+
+ln -sf /proc/mounts %{buildroot}/etc/mtab
+
+
+# remove static libs
+rm -f $RPM_BUILD_ROOT%{_libdir}/lib{uuid,blkid,mount}.a
+
+# find MO files
+%find_lang %name
+
+# the files section supports only one -f option...
+mv %{name}.lang %{name}.files
+
+# create list of setarch(8) symlinks
+find  $RPM_BUILD_ROOT%{_bindir}/ -regextype posix-egrep -type l \
+	-regex ".*(linux32|linux64|s390|s390x|i386|ppc|ppc64|ppc32|sparc|sparc64|sparc32|sparc32bash|mips|mips64|mips32|ia64|x86_64)$" \
+	-printf "%{_bindir}/%f\n" >> %{name}.files
+
+find  $RPM_BUILD_ROOT%{_mandir}/man8 -regextype posix-egrep  \
+	-regex ".*(linux32|linux64|s390|s390x|i386|ppc|ppc64|ppc32|sparc|sparc64|sparc32|sparc32bash|mips|mips64|mips32|ia64|x86_64)\.8.*" \
+	-printf "%{_mandir}/man8/%f*\n" >> %{name}.files
+
+%post
+# only for minimal buildroots without /var/log
+[ -d /var/log ] || mkdir -p /var/log
+touch /var/log/lastlog
+chown root:root /var/log/lastlog
+chmod 0644 /var/log/lastlog
+# Fix the file context, do not use restorecon
+if [ -x /usr/sbin/selinuxenabled ] && /usr/sbin/selinuxenabled; then
+	SECXT=$( /usr/sbin/matchpathcon -n /var/log/lastlog 2> /dev/null )
+	if [ -n "$SECXT" ]; then
+		# Selinux enabled, but without policy? It's true for buildroots
+		# without selinux stuff on host machine with enabled selinux.
+		# We don't want to use any RPM dependence on selinux policy for
+		# matchpathcon(2). SELinux policy should be optional.
+		/usr/bin/chcon "$SECXT"  /var/log/lastlog >/dev/null 2>&1 || :
+	fi
+fi
+if [ ! -L /etc/mtab ]; then
+	ln -fs /proc/mounts /etc/mtab
+fi
+
+%post -n libblkid
+/sbin/ldconfig
+
+### Move blkid cache to /run
+[ -d /run/blkid ] || mkdir -p /run/blkid
+for I in /etc/blkid.tab /etc/blkid.tab.old \
+         /etc/blkid/blkid.tab /etc/blkid/blkid.tab.old; do
+
+	if [ -f "$I" ]; then
+		mv "$I" /run/blkid/ || :
+	fi
+done
+
+%postun -n libblkid -p /sbin/ldconfig
+
+%post -n libuuid -p /sbin/ldconfig
+%postun -n libuuid -p /sbin/ldconfig
+
+%post -n libmount -p /sbin/ldconfig
+%postun -n libmount -p /sbin/ldconfig
+
+%pre -n uuidd
+getent group uuidd >/dev/null || groupadd -r uuidd
+getent passwd uuidd >/dev/null || \
+useradd -r -g uuidd -d /var/lib/libuuid -s /sbin/nologin \
+    -c "UUID generator helper daemon" uuidd
+exit 0
+
+%post -n uuidd
+if [ $1 -eq 1 ]; then
+	# Package install,
+	/bin/systemctl enable uuidd.service >/dev/null 2>&1 || :
+	/bin/systemctl start uuidd.service > /dev/null 2>&1 || :
+else
+	# Package upgrade
+	if /bin/systemctl --quiet is-enabled uuidd.service ; then
+		/bin/systemctl reenable uuidd.service >/dev/null 2>&1 || :
+	fi
+fi
+
+%preun -n uuidd
+if [ "$1" = 0 ]; then
+	/bin/systemctl stop uuidd.service > /dev/null 2>&1 || :
+	/bin/systemctl disable uuidd.service > /dev/null 2>&1 || :
+fi
+
+
+%files -f %{name}.files
+%defattr(-,root,root)
+%doc README NEWS AUTHORS
+%doc Documentation/deprecated.txt Documentation/licenses/*
+%doc misc-utils/getopt-*.{bash,tcsh}
+
+%config(noreplace)	%{_sysconfdir}/pam.d/chfn
+%config(noreplace)	%{_sysconfdir}/pam.d/chsh
+%config(noreplace)	%{_sysconfdir}/pam.d/login
+%config(noreplace)	%{_sysconfdir}/pam.d/remote
+%config(noreplace)	%{_sysconfdir}/pam.d/su
+%config(noreplace)	%{_sysconfdir}/pam.d/su-l
+%config(noreplace)	%{_sysconfdir}/pam.d/runuser
+%config(noreplace)	%{_sysconfdir}/pam.d/runuser-l
+%config(noreplace)	%{_prefix}/lib/udev/rules.d/60-raw.rules
+
+%attr(4755,root,root)	%{_bindir}/mount
+%attr(4755,root,root)	%{_bindir}/umount
+%attr(4755,root,root)	%{_bindir}/su
+%attr(755,root,root)	%{_bindir}/login
+%attr(4711,root,root)	%{_bindir}/chfn
+%attr(4711,root,root)	%{_bindir}/chsh
+%attr(2755,root,tty)	%{_bindir}/write
+
+%ghost %attr(0644,root,root) %verify(not md5 size mtime) /var/log/lastlog
+%ghost %verify(not md5 size mtime) %config(noreplace,missingok) /etc/mtab
+
+%{_unitdir}/fstrim.*
+
+%{_bindir}/cal
+%{_bindir}/chrt
+%{_bindir}/col
+%{_bindir}/colcrt
+%{_bindir}/colrm
+%{_bindir}/column
+%{_bindir}/dmesg
+%{_bindir}/eject
+%{_bindir}/fallocate
+%{_bindir}/findmnt
+%{_bindir}/flock
+%{_bindir}/getopt
+%{_bindir}/hexdump
+%{_bindir}/ionice
+%{_bindir}/ipcmk
+%{_bindir}/ipcrm
+%{_bindir}/ipcs
+%{_bindir}/isosize
+%{_bindir}/kill
+%{_bindir}/lsipc
+%{_bindir}/lsns
+%{_bindir}/logger
+%{_bindir}/look
+%{_bindir}/lsblk
+%{_bindir}/lscpu
+%{_bindir}/lslocks
+%{_bindir}/lslogins
+%{_bindir}/mcookie
+%{_bindir}/more
+%{_bindir}/mountpoint
+%{_bindir}/namei
+%{_bindir}/nsenter
+%{_bindir}/prlimit
+%{_bindir}/raw
+%{_bindir}/rename
+%{_bindir}/renice
+%{_bindir}/rev
+%{_bindir}/script
+%{_bindir}/scriptreplay
+%{_bindir}/setarch
+%{_bindir}/setpriv
+%{_bindir}/setsid
+%{_bindir}/setterm
+%{_bindir}/tailf
+%{_bindir}/taskset
+%{_bindir}/ul
+%{_bindir}/unshare
+%{_bindir}/utmpdump
+%{_bindir}/uuidgen
+%{_bindir}/wdctl
+%{_bindir}/whereis
+%{_mandir}/man1/cal.1*
+%{_mandir}/man1/chfn.1*
+%{_mandir}/man1/chrt.1*
+%{_mandir}/man1/chsh.1*
+%{_mandir}/man1/col.1*
+%{_mandir}/man1/colcrt.1*
+%{_mandir}/man1/colrm.1*
+%{_mandir}/man1/column.1*
+%{_mandir}/man1/dmesg.1*
+%{_mandir}/man1/eject.1*
+%{_mandir}/man1/fallocate.1*
+%{_mandir}/man1/flock.1*
+%{_mandir}/man1/getopt.1*
+%{_mandir}/man1/hexdump.1*
+%{_mandir}/man1/ionice.1*
+%{_mandir}/man1/ipcmk.1*
+%{_mandir}/man1/ipcrm.1*
+%{_mandir}/man1/ipcs.1*
+%{_mandir}/man1/kill.1*
+%{_mandir}/man1/logger.1*
+%{_mandir}/man1/login.1*
+%{_mandir}/man1/look.1*
+%{_mandir}/man1/lscpu.1*
+%{_mandir}/man1/lslogins.1*
+%{_mandir}/man1/lsipc.1*
+%{_mandir}/man1/mcookie.1*
+%{_mandir}/man1/more.1*
+%{_mandir}/man1/mountpoint.1*
+%{_mandir}/man1/namei.1*
+%{_mandir}/man1/nsenter.1*
+%{_mandir}/man1/prlimit.1*
+%{_mandir}/man1/rename.1*
+%{_mandir}/man1/renice.1*
+%{_mandir}/man1/rev.1*
+%{_mandir}/man1/runuser.1*
+%{_mandir}/man1/script.1*
+%{_mandir}/man1/scriptreplay.1*
+%{_mandir}/man1/setpriv.1*
+%{_mandir}/man1/setsid.1*
+%{_mandir}/man1/setterm.1*
+%{_mandir}/man1/su.1*
+%{_mandir}/man1/tailf.1*
+%{_mandir}/man1/taskset.1*
+%{_mandir}/man1/ul.1*
+%{_mandir}/man1/unshare.1*
+%{_mandir}/man1/utmpdump.1.gz
+%{_mandir}/man1/uuidgen.1*
+%{_mandir}/man1/whereis.1*
+%{_mandir}/man1/write.1*
+%{_mandir}/man5/fstab.5*
+%{_mandir}/man8/addpart.8*
+%{_mandir}/man8/agetty.8*
+%{_mandir}/man8/blkdiscard.8*
+%{_mandir}/man8/blkid.8*
+%{_mandir}/man8/blockdev.8*
+%{_mandir}/man8/chcpu.8*
+%{_mandir}/man8/ctrlaltdel.8*
+%{_mandir}/man8/delpart.8*
+%{_mandir}/man8/fdisk.8*
+%{_mandir}/man8/findfs.8*
+%{_mandir}/man8/findmnt.8*
+%{_mandir}/man8/fsck.8*
+%{_mandir}/man8/fsck.cramfs.8*
+%{_mandir}/man8/fsck.minix.8*
+%{_mandir}/man8/fsfreeze.8*
+%{_mandir}/man8/fstrim.8*
+%{_mandir}/man8/isosize.8*
+%{_mandir}/man8/ldattach.8*
+%{_mandir}/man8/losetup.8*
+%{_mandir}/man8/lsblk.8*
+%{_mandir}/man8/lslocks.8*
+%{_mandir}/man8/lsns.8*
+%{_mandir}/man8/mkfs.8*
+%{_mandir}/man8/mkfs.cramfs.8*
+%{_mandir}/man8/mkfs.minix.8*
+%{_mandir}/man8/mkswap.8*
+%{_mandir}/man8/mount.8*
+%{_mandir}/man8/nologin.8*
+%{_mandir}/man8/partx.8*
+%{_mandir}/man8/pivot_root.8*
+%{_mandir}/man8/raw.8*
+%{_mandir}/man8/rawdevices.8*
+%{_mandir}/man8/readprofile.8*
+%{_mandir}/man8/resizepart.8*
+%{_mandir}/man8/rtcwake.8*
+%{_mandir}/man8/setarch.8*
+%{_mandir}/man8/sulogin.8*
+%{_mandir}/man8/swaplabel.8*
+%{_mandir}/man8/swapoff.8*
+%{_mandir}/man8/swapon.8*
+%{_mandir}/man8/switch_root.8*
+%{_mandir}/man8/umount.8*
+%{_mandir}/man8/wdctl.8*
+%{_mandir}/man8/wipefs.8*
+%{_mandir}/man8/zramctl.8*
+%{_sbindir}/addpart
+%{_sbindir}/agetty
+%{_sbindir}/blkdiscard
+%{_sbindir}/blkid
+%{_sbindir}/blockdev
+%{_sbindir}/chcpu
+%{_sbindir}/ctrlaltdel
+%{_sbindir}/delpart
+%{_sbindir}/fdisk
+%{_sbindir}/findfs
+%{_sbindir}/fsck
+%{_sbindir}/fsck.cramfs
+%{_sbindir}/fsck.minix
+%{_sbindir}/fsfreeze
+%{_sbindir}/fstrim
+%{_sbindir}/ldattach
+%{_sbindir}/losetup
+%{_sbindir}/mkfs
+%{_sbindir}/mkfs.cramfs
+%{_sbindir}/mkfs.minix
+%{_sbindir}/mkswap
+%{_sbindir}/nologin
+%{_sbindir}/partx
+%{_sbindir}/pivot_root
+%{_sbindir}/readprofile
+%{_sbindir}/resizepart
+%{_sbindir}/rtcwake
+%{_sbindir}/runuser
+%{_sbindir}/sulogin
+%{_sbindir}/swaplabel
+%{_sbindir}/swapoff
+%{_sbindir}/swapon
+%{_sbindir}/switch_root
+%{_sbindir}/wipefs
+%{_sbindir}/zramctl
+%{compldir}/addpart
+%{compldir}/blkdiscard
+%{compldir}/blkid
+%{compldir}/blockdev
+%{compldir}/cal
+%{compldir}/chcpu
+%{compldir}/chfn
+%{compldir}/chrt
+%{compldir}/chsh
+%{compldir}/col
+%{compldir}/colcrt
+%{compldir}/colrm
+%{compldir}/column
+%{compldir}/ctrlaltdel
+%{compldir}/delpart
+%{compldir}/dmesg
+%{compldir}/eject
+%{compldir}/fallocate
+%{compldir}/fdisk
+%{compldir}/findmnt
+%{compldir}/flock
+%{compldir}/fsck
+%{compldir}/fsck.cramfs
+%{compldir}/fsck.minix
+%{compldir}/fsfreeze
+%{compldir}/fstrim
+%{compldir}/getopt
+%{compldir}/hexdump
+%{compldir}/ionice
+%{compldir}/ipcrm
+%{compldir}/ipcs
+%{compldir}/isosize
+%{compldir}/ldattach
+%{compldir}/logger
+%{compldir}/look
+%{compldir}/losetup
+%{compldir}/lsblk
+%{compldir}/lscpu
+%{compldir}/lslocks
+%{compldir}/mcookie
+%{compldir}/mkfs
+%{compldir}/mkfs.cramfs
+%{compldir}/mkfs.minix
+%{compldir}/mkswap
+%{compldir}/more
+%{compldir}/mountpoint
+%{compldir}/namei
+%{compldir}/nsenter
+%{compldir}/partx
+%{compldir}/pivot_root
+%{compldir}/prlimit
+%{compldir}/raw
+%{compldir}/readprofile
+%{compldir}/rename
+%{compldir}/renice
+%{compldir}/resizepart
+%{compldir}/rev
+%{compldir}/rtcwake
+%{compldir}/runuser
+%{compldir}/script
+%{compldir}/scriptreplay
+%{compldir}/setarch
+%{compldir}/setpriv
+%{compldir}/setsid
+%{compldir}/setterm
+%{compldir}/su
+%{compldir}/swaplabel
+%{compldir}/swapon
+%{compldir}/tailf
+%{compldir}/taskset
+%{compldir}/ul
+%{compldir}/unshare
+%{compldir}/utmpdump
+%{compldir}/uuidgen
+%{compldir}/wdctl
+%{compldir}/whereis
+%{compldir}/wipefs
+%{compldir}/write
+%{compldir}/zramctl
+
+%ifnarch s390 s390x
+%{_sbindir}/clock
+%{_sbindir}/fdformat
+%{_sbindir}/hwclock
+%{_mandir}/man8/fdformat.8*
+%{_mandir}/man8/hwclock.8*
+%{_mandir}/man8/clock.8*
+%{compldir}/fdformat
+%{compldir}/hwclock
+%endif
+
+%ifnarch %{sparc}
+%doc Documentation/sfdisk.txt
+%{_sbindir}/cfdisk
+%{_sbindir}/sfdisk
+%{_mandir}/man8/cfdisk.8*
+%{_mandir}/man8/sfdisk.8*
+%{compldir}/cfdisk
+%{compldir}/sfdisk
+%endif
+
+%ifarch %{sparc}
+%{_bindir}/sunhostid
+%endif
+
+%ifarch %cytune_archs
+%{_bindir}/cytune
+%{_mandir}/man8/cytune.8*
+%{compldir}/cytune
+%endif
+
+
+%files -n uuidd
+%defattr(-,root,root)
+%doc Documentation/licenses/COPYING.GPLv2
+%{_mandir}/man8/uuidd.8*
+%{_sbindir}/uuidd
+%{_unitdir}/uuidd.*
+%dir %attr(2775, uuidd, uuidd) /var/lib/libuuid
+%dir %attr(2775, uuidd, uuidd) /run/uuidd
+%{compldir}/uuidd
+
+
+%files -n libmount
+%defattr(-,root,root)
+%doc libmount/COPYING
+%{_libdir}/libmount.so.*
+
+%files -n libmount-devel
+%defattr(-,root,root)
+%doc libmount/COPYING
+%{_libdir}/libmount.so
+%{_includedir}/libmount
+%{_libdir}/pkgconfig/mount.pc
+
+
+%files -n libblkid
+%defattr(-,root,root)
+%doc libblkid/COPYING
+%{_libdir}/libblkid.so.*
+
+%files -n libblkid-devel
+%defattr(-,root,root)
+%doc libblkid/COPYING
+%{_libdir}/libblkid.so
+%{_includedir}/blkid
+%{_mandir}/man3/libblkid.3*
+%{_libdir}/pkgconfig/blkid.pc
+
+
+%files -n libuuid
+%defattr(-,root,root)
+%doc libuuid/COPYING
+%{_libdir}/libuuid.so.*
+
+%files -n libuuid-devel
+%defattr(-,root,root)
+%doc libuuid/COPYING
+%{_libdir}/libuuid.so
+%{_includedir}/uuid
+%{_mandir}/man3/uuid.3*
+%{_mandir}/man3/uuid_clear.3*
+%{_mandir}/man3/uuid_compare.3*
+%{_mandir}/man3/uuid_copy.3*
+%{_mandir}/man3/uuid_generate.3*
+%{_mandir}/man3/uuid_generate_random.3*
+%{_mandir}/man3/uuid_generate_time.3*
+%{_mandir}/man3/uuid_generate_time_safe.3*
+%{_mandir}/man3/uuid_is_null.3*
+%{_mandir}/man3/uuid_parse.3*
+%{_mandir}/man3/uuid_time.3*
+%{_mandir}/man3/uuid_unparse.3*
+%{_libdir}/pkgconfig/uuid.pc
+
+%changelog
+* Thu Nov 09 2017 Karel Zak <kzak@redhat.com> 2.23.2-43.el7_4.2
+- improve libmount eaccess test (bug #1499760)
+
+* Mon Oct 30 2017 Karel Zak <kzak@redhat.com> 2.23.2-43.el7_4.1
+- fix #1499760 - gvfs-udisks2-volume-monitor generates huge amount of audit log with access denied messages
+
+* Thu Jun 01 2017 Karel Zak <kzak@redhat.com> 2.23.2-43
+- fix #1457744 - lscpu -e get crashed after offline one host cpu on amd machine
+
+* Wed May 31 2017 Karel Zak <kzak@redhat.com> 2.23.2-42
+- fix #1455664 - lscpu causes kernel panic on HPE Comanche / Cavium ThunderX2 (cn99xx)
+
+* Tue May 23 2017 Karel Zak <kzak@redhat.com> 2.23.2-41
+- fix #1451704 - IMSM RAID on 4k disks not assembled on boot
+- force gettext messages refresh (for #1358097 bugfix)
+
+* Wed May 10 2017 Karel Zak <kzak@redhat.com> 2.23.2-40
+- improve libfdisk GPT UUID printing (#1344726)
+
+* Tue Apr 04 2017 Karel Zak <kzak@redhat.com> 2.23.2-39
+- update package regression tests (due to #1360764 #1397709)
+- improve zramctl man page (#1358755)
+
+* Tue Apr 04 2017 Karel Zak <kzak@redhat.com> 2.23.2-38
+- improve fdisk menu for GPT (#1344720)
+
+* Thu Mar 30 2017 Karel Zak <kzak@redhat.com> 2.23.2-37
+- improve zram mm_stat parser (#1358755)
+
+* Wed Mar 22 2017 Karel Zak <kzak@redhat.com> 2.23.2-36
+- fix #1344102 - fdisk does not handle 4kN devices correctly in 'Blocks' calculation
+- fix #1344720 - when fdisk detects gpt table, expected menu items seem to be missing in the 'm' output
+- fix #1323916 - logger unnecessarily splits messages sent via stdin into 1024 byte chunks
+- fix #1344726 - [RFE] fdisk: output UID from gpt in fdisk when detecting that a gpt partition table is present
+- fix #1362662 - fdisk -l fails/stops on first passive/not ready device, works on RHEL6
+- fix #1369436 - losetup man page incorrect syntax for Setup loop device
+- fix #1392656 - [LLNL 7.4 Bug] fix buffer overflows in util-linux with upstream patch
+- fix #1370959 - [FJ7.3 Bug]: man 8 umount is wrong.
+- fix #1357746 - mount -av" report NFS "successfully mounted" but it is not.
+- fix #1417722 - umount -a results in selinux being reported as Disabled
+- fix #1402825 - RHEL7: "sfdisk -s" can't list the disk size
+- fix #1403973 - /usr/bin/more crash on repeat search on failed regex match
+- fix #1403971 - /usr/bin/more crash in end_it due to double free
+- fix #1358095 - ipcs shows wrong gid information
+- fix #1358097 - ipcs shows strange status message in ja locale
+- fix #1378100 - fix swapon discard option parsing
+- fix #1416467 - [RFE] Add support for posix_fallocate(3) call in fallocate(1) utility
+- fix #1358755 - Backport request for zramctl on util-linux v2.23.2
+- fix #1392661 - [LLNL 7.4 Bug] add zfs patches to util-linux
+- fix #1360764 - SMT: "Threads Per Core" will automatically change when odd or even number of vcpu are enabled online.
+- fix #1397709 - [7.4 FEAT] Refresh code for lscpu to support s390x cpu topology
+- fix #1402183 - [HPE 7.3 Bug] fdisk -l does not list non-BTT NVDIMM devices
+
+* Wed Feb  8 2017 Karel Zak <kzak@redhat.com> 2.23.2-35
+* fix #1419474 - su: properly clear child PID
+
+* Mon Jan 23 2017 Karel Zak <kzak@redhat.com> 2.23.2-34
+- fix #1405238 - findmnt --target behaviour changed in 7.3, shows all mount-points in chroot
+
+* Tue Jul 12 2016 Karel Zak <kzak@redhat.com> 2.23.2-33
+- improve patch for #1007734 (libblkid realpaths)
+
+* Tue Jul 12 2016 Karel Zak <kzak@redhat.com> 2.23.2-32
+- improve patch for chrt(1) deadline support #1298384
+- fix #1007734 - blkid shows devices as /dev/block/$MAJOR:$MINOR
+- fix #1349536 - Extended partition loop in MBR partition table leads to DOS
+
+* Mon Jul 04 2016 Karel Zak <kzak@redhat.com> 2.23.2-31
+- improve spec file for #1092520
+
+* Fri Jul 01 2016 Karel Zak <kzak@redhat.com> 2.23.2-30
+- improve patch for chrt(1) deadline support #1298384
+- improve regression tests
+
+* Thu Jun 30 2016 Karel Zak <kzak@redhat.com> 2.23.2-29
+- fix #1029385 - lack of non-ascii support
+- fix #1092520 - util-linux - PIE and RELRO check
+- fix #1153770 - backport lsipc
+- fix #1248003 - mount only parses <param>=<value> lines from fstab fs_spec field available from blkid block device
+- fix #1271850 - mount -a doesn't catch a typo in /etc/fstab and a typo in /etc/fstab can make a system not reboot properly
+- fix #1281839 - [RFE]Bind mounts should be handled gracefully by the operating system
+- fix #1290689 - util-linux: /bin/login does not retry getpwnam_r with larger buffers, leading to login failure
+- fix #1296366 - Bash completion for more(1) handles file names with spaces incorrectly
+- fix #1296521 - RHEL7: update audit event in hwclock
+- fix #1298384 - RFE: add SCHED_DEADLINE support to chrt
+- fix #1304246 - fdisk 'f' subcommand updates partition ranges wrongly
+- fix #1304426 - [rfe] /bin/su should be improved to reduce stack use
+- fix #1326615 - util-linux/lscpu: Fix model and model name on Power Systems
+- fix #1327886 - Backport blkdiscard's "-z" flag to RHEL
+- fix #1332084 - [RFE] Inclusion of lsns command in util-linux Package
+- fix #1335671 - extra quotes around UUID confuses findfs in RHEL (but not in Fedora)
+- fix #1344222 - logger port option in help is misleading
+- fix #1344482 - util-linux fails valid_pmbr() size checks if device is > 2.14TB, Device label type: dos instead of gpt
+- fix #587393 - [RFE] Make sure util-linux is ready for writable overlays
+
+* Wed Mar 16 2016 Karel Zak <kzak@redhat.com> 2.23.2-28
+- fix #1291554 - lslogins crash when executed with buggy username
+
+* Thu Jan 28 2016 Karel Zak <kzak@redhat.com> 2.23.2-27
+- fix #1301091 - [libblkid] Failed to get offset of the xfs_external_log signature
+
+* Fri Aug 21 2015 Karel Zak <kzak@redhat.com> 2.23.2-26
+- fix #1182831 - blkid incorrectly detects boot sec + MBR as FAT
+
+* Wed Aug 12 2015 Karel Zak <kzak@redhat.com> 2.23.2-25
+- fix #1251250 - blkid outputs nothing for some partitions (e.g. sun label)
+
+* Thu Jul  2 2015 Karel Zak <kzak@redhat.com> 2.23.2-24
+- fix #1199619 - os-prober attempts to mount thin pool devices
+
+* Tue Jun 23 2015 Karel Zak <kzak@redhat.com> 2.23.2-23
+- fix #1225235 - blockdev --report fails on loop and pmem devices
+- fix #1225053 - [RFE] backport fstrim -a and unit file
+- fix #1131523 - mount does not appear to be correctly documented for default mount options
+- fix #1147526 - Incorrect message printed when su is killed
+- fix #1165702 - make login(1) insensitive to SIGXFSZ and huge lastlog
+- fix #1184558 - logger silently changes facility from kern to user
+- fix #1198243 - blkid does not recognize xfs external log device
+- fix #1208081 - lsblk does not list dm-multipath and partitioned devices
+- fix #1209594 - RHEL7: unshare: add --propagation, use MS_PRIVATE by default
+- fix #1229436 - Remove patch that disables User Namespaces
+- fix #1116100 - Add -Z SELInux option to nsenter
+
+* Mon Apr 20 2015 Karel Zak <kzak@redhat.com> 2.23.2-22
+- fix #1092039 - uuidd not configured to run permanently
+
+* Tue Jan 13 2015 Karel Zak <kzak@redhat.com> 2.23.2-21
+- fix #1181444 - raw command fails with "Cannot locate raw device"
+
+* Fri Dec 12 2014 Karel Zak <kzak@redhat.com> 2.23.2-20
+- fix lslogins patch (#1113043)
+
+* Mon Oct 27 2014 Karel Zak <kzak@redhat.com> 2.23.2-19
+- fix #1156352 - blkdiscard progress report and interruptibility of the process
+
+* Fri Oct 10 2014 Karel Zak <kzak@redhat.com> 2.23.2-18
+- fix #1149278 - partx fails to update a specific partition other than the first
+
+* Thu Sep 25 2014 Karel Zak <kzak@redhat.com> 2.23.2-17
+- fix #1067354 - dmesg -w output not line-buffered
+- fix #1072298 - util-linux/lscpu: '--sysroot' broken on XFS
+- fix #1072930 - hwclock --systohc can hang on busy or virtual machine
+- fix #1077310 - wipefs problem with some live .isos
+- fix #1077864 - swapon: allow a more flexible swap discard policy
+- fix #1080407 - libblkid XFS detection is too fragile
+- fix #1115442 - kill(1) doesn't check errno after calling strtol()
+- fix #1127823 - losetup does not accept offset
+- fix #1127891 - wipefs 4k disks and gpt partitions
+- fix #1136111 - "findmnt" returns incomplete output on kernel-3.14
+- fix #1140591 - improve mount --move documentation
+- fix #1131522 - backport --fork and --mount-proc to unshare(1)
+- fix #1113043 - backport lslogins(1)
+
+* Fri Mar 28 2014 Karel Zak <kzak@redhat.com> 2.23.2-16
+- fix bugs in patch for #1047376
+
+* Tue Mar 25 2014 Karel Zak <kzak@redhat.com> 2.23.2-15
+- fix #1078618 - flock nfs file fails on nfsv4
+- fix #1047376 - blkid hangs while reading from /dev/fd0
+- fix #1079931 - fsck: warning on kdump boot
+
+* Wed Mar 12 2014 Karel Zak <kzak@redhat.com> 2.23.2-14
+- fix #1073851 - disable user namespaces at all
+
+* Thu Feb 20 2014 Karel Zak <kzak@redhat.com> 2.23.2-13
+- fix #1061751 - nsenter set uid for user namespaces
+
+* Fri Jan 24 2014 Daniel Mach <dmach@redhat.com> - 2.23.2-12
+- Mass rebuild 2014-01-24
+
+* Thu Jan 23 2014 Karel Zak <kzak@redhat.com> 2.23.2-11
+- fix #1046849 - filesystem type is not correctly displayed by df command
+- fix #1055490 - libblkid: Do not problem for backup btrfs superblock
+- fix #1054186 - wipefs does not clean gpt header fully, PMBR remains
+
+* Tue Jan 14 2014 Karel Zak <kzak@redhat.com> 2.23.2-10
+- sort NOMA nodes in lscpu(1) output to improve fix for #1050852
+
+* Tue Jan 14 2014 Karel Zak <kzak@redhat.com> 2.23.2-9
+- fix #1039189 - taskset man page PERMISSIONS section is incorrect
+- fix #1050852 - lscpu: support discontinuous NUMA nodes
+
+* Fri Dec 27 2013 Daniel Mach <dmach@redhat.com> - 2.23.2-8
+- Mass rebuild 2013-12-27
+
+* Fri Nov 15 2013 Karel Zak <kzak@redhat.com> 2.23.2-7
+- fix #1024366 - losetup does not use loop-control to add device
+- fix #1016471 - document that blockdev --setbsz call has never worked
+
+* Mon Oct  7 2013 Karel Zak <kzak@redhat.com> 2.23.2-6
+- fix #1010193 - libmount umount issues
+- fix #1009349 - Joking sfdisk rewriting PT after "n"
+- fix #1007885 - utmpdump is not IPv6 ready
+
+* Thu Sep 12 2013 Karel Zak <kzak@redhat.com> 2.23.2-5
+- fix #1006462 - RFE: allow \S escape that defaults to PRETTY_NAME in /etc/issue handling
+
+* Mon Sep  9 2013 Karel Zak <kzak@redhat.com> 2.23.2-4
+- fix #1005566 - recount_geometry: Process /usr/sbin/fdisk was killed by signal 8 (SIGFPE)
+- fix #1005194 - su generates incorrect log entries
+
+* Mon Sep  9 2013 Karel Zak <kzak@redhat.com> 2.23.2-3
+- refresh and rename patches
+- fix #987787 - Remove lastlogin from su
+- fix #950497 - problem umounting loop device
+- fix #921498 - multiple internal testsuite failures
+
+* Thu Aug  1 2013 Karel Zak <kzak@redhat.com> 2.23.2-2
+- fix 990083 - su doesn't work with pam_ecryptfs
+
+* Wed Jul 31 2013 Karel Zak <kzak@redhat.com> 2.23.2-1
+- upgrade to stable release 2.23.2
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux/v2.23/v2.23.2-ReleaseNotes
+
+* Thu Jun 13 2013 Karel Zak <kzak@redhat.com> 2.23.1-3
+- fix #972457 - agetty idle I/O polling causes elevated CPU usage
+
+* Wed Jun  5 2013 Karel Zak <kzak@redhat.com> 2.23.1-2
+- fix #962145 - in.telnetd immediately closes connection
+
+* Tue May 28 2013 Karel Zak <kzak@redhat.com> 2.23.1-1
+- upgrade to 2.23.1
+- backport agetty --local-line path
+
+* Thu Apr 25 2013 Karel Zak <kzak@redhat.com> 2.23-1
+- upgrade to 2.23
+- add --with check to call make check
+
+* Mon Apr 15 2013 Karel Zak <kzak@redhat.com> 2.23-0.7
+- remove unused patches
+
+* Mon Apr 15 2013 Karel Zak <kzak@redhat.com> 2.23-0.6
+- remove floppy from util-linux
+
+* Fri Apr 12 2013 Karel Zak <kzak@redhat.com> 2.23-0.5
+- fix #948274 - interruption code 0x4003B in libmount.so.1.1.0
+
+* Wed Apr 10 2013 Karel Zak <kzak@redhat.com> 2.23-0.4
+- upgrade to the release 2.23-rc2
+
+* Wed Mar 27 2013 Karel Zak <kzak@redhat.com> 2.23-0.3
+- libblkid ntfs bugfix for build on s390
+
+* Wed Mar 27 2013 Karel Zak <kzak@redhat.com> 2.23-0.2
+- add upstream patches for to fix umount and mount.<type>
+
+* Fri Mar 22 2013 Karel Zak <kzak@redhat.com> 2.23-0.1
+- upgrade to the release 2.23-rc1
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux/v2.23/v2.23-ReleaseNotes
+- add nsenter and blkdiscard
+- remove tunelp
+
+* Wed Feb 20 2013 Karel Zak <kzak@redhat.com> 2.22.2-6
+- fix  #912778 - "runuser -l" doesn't register session to systemd
+
+* Tue Feb 19 2013 Karel Zak <kzak@redhat.com> 2.22.2-5
+- fix #902512 - Dependency failed for /home (and blkid fails to tell UUID)
+- refresh old patches
+
+* Wed Feb  6 2013 Karel Zak <kzak@redhat.com> 2.22.2-4
+- improve convertion to mtab symlink in post script
+- spec file cleanup (based on #894199)
+
+* Sun Feb  3 2013 Karel Zak <kzak@redhat.com> 2.22.2-3
+- fix #882305 - agetty: unstable /dev/tty* permissions
+- fix #885314 - hexdump segfault
+- fix #896447 - No newlines in piped "cal" command
+- fix libblkid cache usage (upstream patch)
+- fix #905008 - uuidd: /usr/sbin/uuidd has incorrect file permissions
+
+* Tue Jan 15 2013 Karel Zak <kzak@redhat.com> 2.22.2-2
+- fix #889888 - wipefs does not completely wipe btrfs volume
+
+* Thu Dec 13 2012 Karel Zak <kzak@redhat.com> 2.22.2-1
+- upgrade to upstream maintenance release 2.22.2
+
+* Mon Nov 19 2012 Karel Zak <kzak@redhat.com> 2.22.1-5
+- sources cleanup
+
+* Fri Nov 16 2012 Karel Zak <kzak@redhat.com> 2.22.1-4
+- fix #872787 - su: COMMAND not specified
+
+* Thu Nov  1 2012 Karel Zak <kzak@redhat.com> 2.22.1-3
+- backport upstream runuser(1)
+- enable su(1)
+
+* Thu Nov  1 2012 Karel Zak <kzak@redhat.com> 2.22.1-2
+- apply pathes from upstream stable/v2.22 branch
+- fix #865961 - wipefs -a should use O_EXCL
+
+* Thu Oct 10 2012 Karel Zak <kzak@redhat.com> 2.22.1-1
+- upgrade to the release 2.22.1
+
+* Wed Oct  3 2012 Karel Zak <kzak@redhat.com> 2.22-2
+- remove obsolete references to e2fsprogs
+
+* Thu Sep  6 2012 Karel Zak <kzak@redhat.com> 2.22-1
+- upgrade to the release 2.22
+- enable eject(1) from util-linux, obsolete original eject package
+- fix #853164 - setuid program should have full RELRO
+- fix #851230 - probe_ntfs: /usr/sbin/blkid was killed by SIGSEGV
+
+* Thu Aug 16 2012 Karel Zak <kzak@redhat.com> 2.22-0.1
+- upgrade to the release 2.22-rc2
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux/v2.22/v2.22-ReleaseNotes
+- add sulogin, utmpdump, lslocks, wdctl
+
+* Fri Jul 27 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.21.2-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild
+
+* Wed Jun 13 2012 Karel Zak <kzak@redhat.com> 2.21.2-2
+- replace udev dependenceis with systemd
+
+* Fri May 25 2012 Karel Zak <kzak@redhat.com> 2.21.2-1
+- upgrade to bugfix release 2.21.2
+- fix #814699 - namei(1) incorrectly resolves relative symlinks
+- fix #820707 - Impossible to unmount nfsv4/krb5 mounts after network disconnect
+- fix #816877 - libmount does not close device fd before mount(2)
+- fix #822705 - unable to login after installing
+
+* Fri Mar 30 2012 Karel Zak <kzak@redhat.com> 2.21.1-1
+- upgrade to bugfix release 2.21.1
+
+* Fri Feb 24 2012 Karel Zak <kzak@redhat.com> 2.21-1
+- upgrade to release 2.21
+
+* Thu Feb 09 2012 Karel Zak <kzak@redhat.com> 2.21-0.2
+- fix #788703 - /run/blkid does not exist
+
+* Thu Feb 07 2012 Karel Zak <kzak@redhat.com> 2.21-0.1
+- upgrade to the release 2.21-rc2
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux/v2.21/v2.21-ReleaseNotes
+- add {fsck,mkfs}.minix
+- add new command chcpu(8)
+- add new command prlimit(1)
+- enable raw(8) command
+- move 60-raw.rules from /etc from /usr/lib/udev/rules.d
+- move blkid cache from etc to /run/blkid
+
+* Wed Jan 25 2012 Harald Hoyer <harald@redhat.com> 2.20.1-5
+- install everything in /usr
+  https://fedoraproject.org/wiki/Features/UsrMove
+
+* Sat Jan 14 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.20.1-4
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild
+
+* Tue Nov 22 2011 Karel Zak <kzak@redhat.com> 2.20.1-3
+- fix #748216 - util-linux requires pam >= 1.1.3-7
+- remove ddate(1)
+
+* Wed Oct 26 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.20.1-2
+- Rebuilt for glibc bug#747377
+
+* Thu Oct 20 2011 Karel Zak <kzak@redhat.com> 2.20.1-1
+- upgrade to the release 2.20.1
+  ftp://ftp.infradead.org/pub/util-linux/v2.20/v2.20.1-ReleaseNotes
+
+* Mon Aug 29 2011 Karel Zak <kzak@redhat.com> 2.20-1
+- upgrade to the release 2.20
+
+* Wed Aug 17 2011 Karel Zak <kzak@redhat.com> 2.20-0.2
+- upgrade to the release 2.20-rc2
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux/v2.20/v2.20-rc2-ChangeLog
+
+* Fri Aug  2 2011 Karel Zak <kzak@redhat.com> 2.20-0.1
+- upgrade to the release 2.20-rc1
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux/v2.20/v2.20-ReleaseNotes
+
+* Mon Jul  4 2011 Karel Zak <kzak@redhat.com> 2.19.1-2
+- fix #716483 - /var/tmp --(BIND-mounted)--> /tmp disrupts/hangs bootup
+- fix #709681 - failure to mount if a mount point ends with a slash in /etc/fstab
+- fix #709319 - 'mount -a' mounts already mounted directories
+- fix kernel version parsing
+
+* Fri May  6 2011 Karel Zak <kzak@redhat.com> 2.19.1-1
+- upgrade to the release 2.19.1
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux/v2.19/v2.19.1-ReleaseNotes
+
+* Wed Apr 20 2011 Karel Zak <kzak@redhat.com> 2.19.1-0.1
+- upgrade to the release 2.19.1-rc1
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux/v2.19/v2.19.1-rc1-ChangeLog
+
+* Mon Mar  7 2011 Karel Zak <kzak@redhat.com> 2.19-2
+- fix #682502 - Broken source URL to floppy tarball, new version available
+- upgrade to floppy-0.18
+
+* Thu Feb 10 2011 Karel Zak <kzak@redhat.com> 2.19-1
+- upgrade to the release 2.19
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux/v2.19/v2.19-ReleaseNotes
+- remove /sbin/mount.tmpfs -- integrated to mount(8)
+
+* Tue Feb  8 2011 Karel Zak <kzak@redhat.com> 2.19-0.6
+- fix #665062 - add support for the postlogin PAM stack to util-linux-ng
+
+* Mon Feb 07 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.19-0.5
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild
+
+* Tue Jan 25 2011 Karel Zak <kzak@redhat.com> 2.19-0.4
+- upgrade to the release 2.19-rc3
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux/v2.19/v2.19-rc3-ChangeLog
+
+* Tue Jan 25 2011 Karel Zak <kzak@redhat.com> 2.19-0.3
+- upgrade to the release 2.19-rc2
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux/v2.19/v2.19-rc2-ChangeLog
+- fix #671893 - SELinux is preventing /bin/chown from 'setattr' accesses
+  on the file mounts.
+
+* Wed Jan 19 2011 Karel Zak <kzak@redhat.com> 2.19-0.2
+- clean up specfile (review #667416)
+
+* Wed Jan  5 2011 Karel Zak <kzak@redhat.com> 2.19-0.1
+- upgrade to the release 2.19-rc1
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux/v2.19/v2.19-ReleaseNotes
+
+* Tue Oct 26 2010 Karel Zak <kzak@redhat.com> 2.18-5
+- fix #645640 - new "-s" parameter parsing in agetty does not work
+- add -l (lock) support to fsck
+
+* Wed Aug 18 2010 Karel Zak <kzak@redhat.com> 2.18-4
+- fix #623685 - please extend agetty to not require a baud rate to be specified
+
+* Thu Aug  5 2010 Karel Zak <kzak@redhat.com> 2.18-3
+- fix #620924 - /sbin/mount.tmpfs uses not available /usr/bin/id
+
+* Mon Aug  2 2010 Karel Zak <kzak@redhat.com> 2.18-2
+- fix #615719 - tmpfs mount fails with 'user' option.
+- fix #598631 - shutdown, reboot, halt and C-A-D don't work
+- fix #618957 - ISO images listed in fstab are mounted twice at boot
+
+* Wed Jun 30 2010 Karel Zak <kzak@redhat.com> 2.18-1
+- upgrade to the final 2.18
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/v2.18/v2.18-ReleaseNotes
+ 
+* Fri Jun 18 2010 Karel Zak <kzak@redhat.com> 2.18-0.2
+- upgrade to 2.18-rc2
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/v2.18/v2.18-rc2-ChangeLog
+
+* Tue Jun  8 2010 Karel Zak <kzak@redhat.com> 2.18-0.1
+- upgrade to the release 2.18-rc1
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/v2.18/v2.18-ReleaseNotes
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/v2.18/v2.18-rc1-ChangeLog
+
+* Mon Apr 12 2010 Karel Zak <kzak@redhat.com> 2.17.2-1
+- fix #581252 - remounting tmpfs fails because of hidden rootcontext=
+- fix #580296 - "rtcwake" does miss the "off" option
+- fix #575734 - use microsecond resolution for blkid cache entries
+- upgrade to the bugfix release 2.17.2
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/v2.17/v2.17.2-ReleaseNotes
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/v2.17/v2.17.2-ChangeLog
+- minor fixed in spec file
+
+* Thu Mar 11 2010 Karel Zak <kzak@redhat.com> 2.17.1-2
+- fix #533874 - libblkid should allow scanning of slow devices (eg. cdroms)
+
+* Mon Feb 22 2010 Karel Zak <kzak@redhat.com> 2.17.1-1
+- upgrade to the final 2.17.1
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/v2.17/v2.17.1-ReleaseNotes
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/v2.17/v2.17.1-ChangeLog
+
+* Tue Feb 16 2010 Karel Zak <kzak@redhat.com> 2.17.1-0.1
+- upgrade to 2.17.1-rc1
+
+* Tue Feb 16 2010 Karel Zak <kzak@redhat.com> 2.17-4
+- fix uuidd init script
+
+* Fri Feb 12 2010 Karel Zak <kzak@redhat.com> 2.17-3
+- fix #541402 - uuidd initscript lsb compliance
+
+* Fri Jan  8 2010 Karel Zak <kzak@redhat.com> 2.17-2
+- remove Provides: lib{uuid,blkid}-static (thanks to Michael Schwendt)
+- remove useless URL to sf.net
+
+* Thu Jan  8 2010 Karel Zak <kzak@redhat.com> 2.17-1
+- upgrade to the final 2.17
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/v2.17/v2.17-ReleaseNotes
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/v2.17/v2.17-ChangeLog
+- fix #545147 - util-linux-ng : Violation of the Packaging Guidelines
+  (remove uuid and blkid static libs)
+
+* Mon Dec 14 2009 Karel Zak <kzak@redhat.com> 2.17-0.6
+- minor fixes in spec file (fix URL, add Requires, add LGPLv2+)
+
+* Wed Dec  9 2009 Karel Zak <kzak@redhat.com> 2.17-0.5
+- upgrade to 2.17-rc2
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/v2.17/v2.17-rc2-ChangeLog
+
+* Mon Dec  7 2009 Karel Zak <kzak@redhat.com> 2.17-0.4
+- add clock.8 man page (manlink to hwclock)
+- add --help to mount.tmpfs
+
+* Mon Nov 23 2009 Karel Zak <kzak@redhat.com> 2.17-0.3
+- upgrade to 2.17-rc1
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/v2.17/v2.17-rc1-ChangeLog
+
+* Tue Nov 10 2009 Karel Zak <kzak@redhat.com> 2.17-0.2.git10dfc39
+- upgrade to pre-release snapshot (official changelog not available yet, see
+  http://git.kernel.org/?p=utils/util-linux-ng/util-linux-ng.git for now)
+
+* Mon Oct 19 2009 Karel Zak <kzak@redhat.com> 2.17-0.1.git5e51568
+- upgrade to pre-release snapshot (official changelog not available yet, see
+  http://git.kernel.org/?p=utils/util-linux-ng/util-linux-ng.git for now)  
+- new commands: fallocate, unshare, wipefs
+- libblkid supports topology and partitions probing
+- remove support for --rmpart[s] from blockdev(8) (util-linux-ng-2.14-blockdev-rmpart.patch)
+- merged upstream:
+  util-linux-ng-2.14-sfdisk-dump.patch
+  util-linux-ng-2.16-blkid-swsuspend.patch
+  util-linux-ng-2.16-libblkid-compression.patch
+  util-linux-ng-2.16-libblkid-ext2.patch
+  util-linux-ng-2.16-switchroot-tty.patch
+
+* Mon Oct  5 2009 Karel Zak <kzak@redhat.com> 2.16-13
+- fix spec file
+
+* Fri Oct  2 2009 Karel Zak <kzak@redhat.com> 2.16-12
+- release++
+
+* Thu Oct  1 2009 Karel Zak <kzak@redhat.com> 2.16-11
+- fix #519237 - bash: cannot set terminal process group (-1): Inappropriate ioctl for device
+
+* Wed Sep 16 2009 Tomas Mraz <tmraz@redhat.com> - 2.16-10
+- use password-auth common PAM configuration instead of system-auth and
+  drop pam_console.so call from the remote PAM config file
+
+* Mon Sep 14 2009 Karel Zak <kzak@redhat.com> 2.16-9
+- fix #522718 - sfdisk -d /dev/xxx | sfdisk --force /dev/yyy fails when LANG is set
+- fix typo in swsuspend detection
+
+* Wed Aug 26 2009 Tomas Mraz <tmraz@redhat.com> - 2.16-8
+- rebuilt with new audit
+
+* Sun Aug 23 2009 Karel Zak <kzak@redhat.com> 2.16-7
+- fix #518572 - blkid requires ext2.ko to be decompressed on installation media
+
+* Thu Aug 13 2009 Karel Zak <kzak@redhat.com> 2.16-5
+- fix #513104 - blkid returns no fstype for ext2 device when ext2 module not loaded
+
+* Wed Aug  5 2009 Stepan Kasal <skasal@redhat.com> 2.16-4
+- set conflict with versions of e2fsprogs containing fsck
+
+* Thu Jul 30 2009 Karel Zak <kzak@redhat.com> 2.16-3
+- remove the mount.conf support (see #214891)
+
+* Mon Jul 27 2009 Karel Zak <kzak@redhat.com> 2.16-2
+- fix #214891 - add mount.conf and MTAB_LOCK_DIR= option
+
+* Sat Jul 25 2009 Karel Zak <kzak@redhat.com> 2.16-1
+- upgrade to 2.16
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/v2.16/v2.16-ReleaseNotes
+- enable built-in libuuid (replacement for the old uuid stuff from e2fsprogs)
+- new commands switch_root, uuidgen and uuidd (subpackage)
+
+* Wed Jun 10 2009 Karel Zak <kzak@redhat.com> 2.15.1-1
+- upgrade to 2.15.1
+
+* Mon Jun  8 2009 Karel Zak <kzak@redhat.com> 2.15.1-0.2
+- set BuildRequires: e2fsprogs-devel
+- add Requires: e2fsprogs-devel to libblkid-devel
+
+* Thu Jun  4 2009 Karel Zak <kzak@redhat.com> 2.15.1-0.1
+- upgrade to 2.15.1-rc1
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/v2.15/v2.15-ReleaseNotes
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/v2.15/v2.15.1-rc1-ChangeLog 
+- merged patches:
+  util-linux-ng-2.14-login-remote.patch
+  util-linux-ng-2.14-fdisk-4k-I.patch
+  util-linux-ng-2.14-fdisk-4k-II.patch
+  util-linux-ng-2.14-fdisk-4k-III.patch
+  util-linux-ng-2.14-dmesg-r.patch
+  util-linux-ng-2.14-flock-segfaults.patch
+  util-linux-ng-2.14-renice-n.patch
+- new commands: lscpu, ipcmk
+- remove support for "managed" and "kudzu" mount options
+- cleanup spec file
+- enable built-in libblkid (replacement for the old blkid from e2fsprogs)
+
+* Thu Apr  2 2009 Karel Zak <kzak@redhat.com> 2.14.2-8
+- fix #490769 - post scriptlet failed (thanks to Dan Horak)
+ 
+* Fri Mar 20 2009 Karel Zak <kzak@redhat.com> 2.14.2-7
+- fix some nits in mount.tmpfs
+
+* Fri Mar 20 2009 Karel Zak <kzak@redhat.com> 2.14.2-6
+- fix #491175 - mount of tmpfs FSs fail at boot
+
+* Thu Mar 19 2009 Karel Zak <kzak@redhat.com> 2.14.2-5
+- fix #489672 - flock segfaults when file name is not given (upstream)
+- fix #476964 - Mount /var/tmp with tmpfs creates denials
+- fix #487227 - fdisk 4KiB hw sectors support (upstream)
+- fix #477303 - renice doesn't support -n option (upstream)
+
+* Wed Feb 25 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.14.2-4
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild
+
+* Fri Feb 20 2009 Karel Zak <kzak@redhat.com> 2.14.2-3
+- add -r option to dmesg(1)
+
+* Mon Feb  9 2009 Karel Zak <kzak@redhat.com> 2.14.2-2
+- fix typo in spec file
+
+* Mon Feb  9 2009 Karel Zak <kzak@redhat.com> 2.14.2-1
+- upgrade to stable 2.14.2
+  ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/v2.14/v2.14.2-ReleaseNotes
+
+* Thu Jan 22 2009 Karel Zak <kzak@redhat.com> 2.14.2-0.2
+- fix #480413 - util-linux-ng doesn't include scriptreplay
+- fix #479002 - remove dependency on ConsoleKit-libs
+- upgrade to 2.14.2-rc2
+
+* Mon Dec 22 2008 Karel Zak <kzak@redhat.com> 2.14.2-0.1
+- upgrade to 2.14.2-rc1
+- refresh old patches
+
+* Fri Nov 21 2008 Karel Zak <kzak@redhat.com> 2.14.1-5
+- fix #472502 - problem with fdisk and use +sectors for the end of partition
+
+* Mon Oct  6 2008 Karel Zak <kzak@redhat.com> 2.14.1-3
+- fix #465761 -  mount manpage is missing uid/gid mount options for tmpfs
+- refresh util-linux-ng-2.14-mount-file_t.patch (fuzz=0)
+
+* Wed Sep 10 2008 Karel Zak <kzak@redhat.com> 2.14.1-2
+- remove obsolete pam-console support
+
+* Wed Sep 10 2008 Karel Zak <kzak@redhat.com> 2.14.1-1
+- upgrade to stable 2.14.1
+
+* Thu Aug 14 2008 Karel Zak <kzak@redhat.com> 2.14.1-0.1
+- upgrade to 2.14.1-rc1
+- refresh old patches
+
+* Thu Jul 24 2008 Karel Zak <kzak@redhat.com> 2.14-3
+- update util-linux-ng-2.14-mount-file_t.patch to make
+  the SELinux warning optional (verbose mode is required)
+
+* Tue Jul  1 2008 Karel Zak <kzak@redhat.com> 2.14-2
+- fix #390691 - mount should check selinux context on mount, and warn on file_t
+
+* Mon Jun  9 2008 Karel Zak <kzak@redhat.com> 2.14-1
+- upgrade to stable util-linux-ng release
+
+* Mon May 19 2008 Karel Zak <kzak@redhat.com> 2.14-0.1
+- upgrade to 2.14-rc3
+- remove arch(8) (deprecated in favor of uname(1) or arch(1) from coreutils)
+- add a new command ldattach(8)
+- cfdisk(8) linked with libncursesw
+
+* Tue Apr 22 2008 Karel Zak <kzak@redhat.com> 2.13.1-9
+- fix audit log injection attack via login
+
+* Thu Apr 17 2008 Karel Zak <kzak@redhat.com> 2.13.1-8
+- fix location of the command raw(8)
+
+* Tue Apr 15 2008 Karel Zak <kzak@redhat.com> 2.13.1-7
+- fix 244383 - libblkid uses TYPE="swsuspend" for S1SUSPEND/S2SUSPEND
+
+* Wed Apr  2 2008 Karel Zak <kzak@redhat.com> 2.13.1-6
+- fix 439984 - backport mkswap -U
+
+* Wed Mar 26 2008 Tom "spot" Callaway <tcallawa@redhat.com> - 2.13.1-5
+- clean up sparc conditionals
+
+* Tue Feb 19 2008 Fedora Release Engineering <rel-eng@fedoraproject.org> - 2.13.1-4
+- Autorebuild for GCC 4.3
+
+* Mon Jan 28 2008 Karel Zak <kzak@redhat.com> 2.13.1-3
+- upgrade to new upstream release
+- fix #427874 - util-linux-ng gets "excess command line argument" on update
+
+* Wed Jan  2 2008 Karel Zak <kzak@redhat.com> 2.13.1-2
+- update to upstream 2.13.1-rc2
+
+* Wed Dec 12 2007 Dan Walsh <dwalsh@redhat.com> 2.13.1-1
+- Fix pam files so that pam_keyinit happens after pam_selinux.so
+
+* Wed Dec 12 2007 Karel Zak <kzak@redhat.com> 2.13.1-0.2
+- remove viwp and vigr (in favour of shadow-utils)
+
+* Sun Dec  9 2007 Karel Zak <kzak@redhat.com> 2.13.1-0.1
+- update to the latest upstream stable branch
+  (commit: fda9d11739ee88c3b2f22a73f12ec019bd3b8335)
+
+* Wed Oct 31 2007 Karel Zak <kzak@redhat.com> 2.13-4
+- fix #354791 - blockdev command calls the blkpg ioctl with a wrong data structure
+
+* Tue Oct 16 2007 Karel Zak <kzak@redhat.com> 2.13-3
+- fix mount -L | -U segfault
+- fix script die on SIGWINCH
+
+* Thu Oct  4 2007 Karel Zak <kzak@redhat.com> 2.13-2
+- update to the latest upstream stable branch
+
+* Tue Aug 28 2007 Karel Zak <kzak@redhat.com> 2.13-1
+- upgrade to stable util-linux-ng release
+
+* Fri Aug 24 2007 Karel Zak <kzak@redhat.com> 2.13-0.59
+- add release number to util-linux Provides and increment setarch Obsoletes
+- fix #254114 - spec typo
+- upgrade to floppy-0.16
+- add BuildRequires: popt-devel
+
+* Wed Aug 22 2007 Jesse Keating <jkeating@redhat.com>  2.13-0.58
+- Obsolete a sufficiently high enough version of setarch
+
+* Mon Aug 20 2007 Karel Zak <kzak@redhat.com>  2.13-0.57
+- fix #253664 - util-linux-ng fails to build on sparc (patch by Dennis Gilmore)
+- rebase to new GIT snapshot
+
+* Mon Aug 20 2007 Karel Zak <kzak@redhat.com> 2.13-0.56
+- fix obsoletes field
+
+* Mon Aug 20 2007 Karel Zak <kzak@redhat.com> 2.13-0.55
+- util-linux-ng includes setarch(1), define relevat Obsoletes+Provides
+
+* Mon Aug 20 2007 Karel Zak <kzak@redhat.com> 2.13-0.54
+- port "blockdev --rmpart" patch from util-linux
+- use same Provides/Obsoletes setting like in util-linux
+
+* Wed Aug 15 2007 Karel Zak <kzak@redhat.com> 2.13-0.53
+- fix #252046 - review Request: util-linux-ng (util-linux replacement)
+
+* Mon Aug 13 2007 Karel Zak <kzak@redhat.com> 2.13-0.52
+- rebase to util-linux-ng (new util-linux upstream fork,
+		based on util-linux 2.13-pre7)
+- more than 70 Fedora/RHEL patches have been merged to upstream code
+
+* Fri Apr  6 2007 Karel Zak <kzak@redhat.com> 2.13-0.51
+- fix #150493 - hwclock --systohc sets clock 0.5 seconds slow
+- fix #220873 - starting RPC idmapd: Error: RPC MTAB does not exist.
+		(added rpc_pipefs to util-linux-2.13-umount-sysfs.patch)
+- fix #227903 - mount -f does not work with NFS-mounted
+
+* Sat Mar  3 2007 David Zeuthen <davidz@redhat.com> 2.13-0.50
+- include ConsoleKit session module by default (#229172)
+
+* Thu Jan 11 2007 Karel Zak <kzak@redhat.com> 2.13-0.49
+- fix #222293 - undocumented partx,addpart, delpart
+
+* Sun Dec 17 2006 Karel Zak <kzak@redhat.com> 2.13-0.48
+- fix paths in po/Makefile.in.in
+
+* Fri Dec 15 2006 Karel Zak <kzak@redhat.com> 2.13-0.47
+- fix #217240 - namei ignores non-directory components instead of saying "Not a directory"
+- fix #217241 - namei enforces symlink limits inconsistently
+
+* Wed Dec 14 2006 Karel Zak <kzak@redhat.com> 2.13-0.46
+- fix leaking file descriptor in the more command (patch by Steve Grubb)
+
+* Wed Dec 13 2006 Karel Zak <kzak@redhat.com> 2.13-0.45
+- use ncurses only
+- fix #218915 - fdisk -b 4K
+- upgrade to -pre7 release
+- fix building problem with raw0 patch
+- fix #217186 - /bin/sh: @MKINSTALLDIRS@: No such file or directory 
+  (port po/Makefile.in.in from gettext-0.16)
+- sync with FC6 and RHEL5:
+- fix #216489 - SCHED_BATCH option missing in chrt
+- fix #216712 - issues with raw device support ("raw0" is wrong device name)
+- fix #216760 - mount with context or fscontext option fails
+  (temporarily disabled the support for additional contexts -- not supported by kernel yet)
+- fix #211827 - Can't mount with additional contexts
+- fix #213127 - mount --make-unbindable does not work
+- fix #211749 - add -r option to losetup to create a read-only loop
+
+* Thu Oct 12 2006 Karel Zak <kzak@redhat.com> 2.13-0.44
+- fix #209911 - losetup.8 updated (use dm-crypt rather than deprecated cryptoloop)
+- fix #210338 - spurious error from '/bin/login -h $PHONENUMBER' (bug in IPv6 patch)
+- fix #208634 - mkswap "works" without warning on a mounted device
+
+* Sun Oct 01 2006 Jesse Keating <jkeating@redhat.com> - 2.13-0.43
+- rebuilt for unwind info generation, broken in gcc-4.1.1-21
+
+* Wed Sep 20 2006 Karel Zak <kzak@redhat.com> 2.13-0.42
+- remove obsolete NFS code and patches (we use /sbin/mount.nfs
+  and /sbin/umount.nfs from nfs-utils now)
+- move nfs.5 to nfs-utils
+
+* Fri Sep 15 2006 Karel Zak <kzak@redhat.com> 2.13-0.41
+- fix #205038 - mount not allowing sloppy option (exports "-s"
+  to external /sbin/mount.nfs(4) calls) 
+- fix minor bug in util-linux-2.13-mount-twiceloop.patch
+- fix #188193- util-linux should provide plugin infrastructure for HAL
+
+* Mon Aug 21 2006 Karel Zak <kzak@redhat.com> 2.13-0.40
+- fix Makefile.am in util-linux-2.13-mount-context.patch
+- fix #201343 - pam_securetty requires known user to work
+		(split PAM login configuration to two files)
+- fix #203358 - change location of taskset binary to allow for early affinity work
+
+* Fri Aug 11 2006 Karel Zak <kzak@redhat.com> 2.13-0.39
+- fix #199745 - non-existant simpleinit(8) mentioned in ctrlaltdel(8)
+
+* Thu Aug 10 2006 Dan Walsh <dwalsh@redhat.com> 2.13-0.38
+- Change keycreate line to happen after pam_selinux open call so it gets correct context
+
+* Thu Aug 10 2006 Karel Zak <kzak@redhat.com> 2.13-0.37
+- fix #176494 - last -i returns strange IP addresses (patch by Bill Nottingham)
+
+* Thu Jul 27 2006 Karel Zak <kzak@redhat.com> 2.13-0.36
+- fix #198300, #199557 - util-linux "post" scriptlet failure
+
+* Thu Jul 27 2006 Steve Dickson <steved@redhat.com> 2.13-0.35
+- Added the -o fsc flag to nfsmount.
+
+* Wed Jul 26 2006 Karel Zak <kzak@redhat.com> 2.13-0.34
+- rebuild
+
+* Tue Jul 18 2006 Karel Zak <kzak@redhat.com> 2.13-0.33
+- add Requires(post): libselinux
+
+* Mon Jul 17 2006 Karel Zak <kzak@redhat.com> 2.13-0.32
+- add IPv6 support to the login command (patch by Milan Zazrivec)
+- fix #198626 - add keyinit instructions to the login PAM script 
+  (patch by David Howells) 
+
+* Wed Jul 12 2006 Jesse Keating <jkeating@redhat.com> - 2.13-0.31.1
+- rebuild
+
+* Tue Jul 11 2006 Karel Zak <kzak@redhat.com> 2.13-0.31
+- cleanup dependences for post and preun scriptlets
+
+* Mon Jul 10 2006 Karsten Hopp <karsten@redhat.de> 2.13-0.30
+- silence install in minimal buildroot without /var/log
+
+* Fri Jul  7 2006 Karel Zak <kzak@redhat.com> 2.13-0.29 
+- include the raw command for RHELs
+
+* Mon Jun 26 2006 Florian La Roche <laroche@redhat.com> 2.13-0.28
+- move install-info parts from postun to preun
+
+* Wed Jun 21 2006 Dan Walsh <dwalsh@RedHat.com> 2.13-0.27
+- Only execute chcon on machines with selinux enabled
+
+* Wed Jun 14 2006 Steve Dickson <steved@redhat.com> 2.13-0.26
+- Remove unneeded header files from nfsmount.c
+
+* Mon Jun 12 2006 Karel Zak <kzak@redhat.com> 2.13-0.25
+- fix #187014 - umount segfaults for normal user
+- fix #183446 - cal not UTF-8-aware
+- fix #186915 - mount does not translate SELIinux context options though libselinux
+- fix #185500 - Need man page entry for -o context= mount option
+- fix #152579 - missing info about /etc/mtab and /proc/mounts mismatch
+- fix #183890 - missing info about possible ioctl() and fcntl() problems on NFS filesystem
+- fix #191230 - using mount --move results in wrong data in /etc/mtab
+- added mount subtrees support
+- fdisk: wrong number of sectors for large disks (suse#160822)
+- merge fdisk-xvd (#182553) with new fdisk-isfull (#188981) patch 
+- fix #181549 - raw(8) manpage has old information about dd
+- remove asm/page.h usage
+
+* Wed May 24 2006 Dan Walsh <dwalsh@RedHat.com> 2.13-0.24
+- Remove requirement on restorecon, since we can do the same thing
+- with chcon/matchpathcon, and not add requirement on policycoreutils
+
+* Wed May 24 2006 Steve Dickson <steved@redhat.com> 2.13-0.23
+- Fixed bug in patch for bz183713 which cause nfs4 mounts to fail.
+
+* Tue May  2 2006 Steve Dickson <steved@redhat.com> 2.13-0.22
+- Added syslog logging to background mounts as suggested
+  by a customer.
+
+* Mon May  1 2006 Steve Dickson <steved@redhat.com> 2.13-0.21
+- fix #183713 - foreground mounts are not retrying as advertised
+- fix #151549 - Added 'noacl' mount flag
+- fix #169042 - Changed nfsmount to try udp before using tcp when rpc-ing
+		the remote rpc.mountd (iff -o tcp is not specified).
+		This drastically increases the total number of tcp mounts
+		that can happen at once (ala autofs).
+
+* Wed Mar  9 2006 Jesse Keating <jkeating@redhat.com> 2.13-0.20
+- Better calling of restorecon as suggested by Bill Nottingham
+- prereq restorecon to avoid ordering issues
+
+* Wed Mar  9 2006 Jesse Keating <jkeating@redhat.com> 2.13-0.19
+- restorecon /var/log/lastlog
+
+* Wed Mar  8 2006 Karel Zak <kzak@redhat.com> 2.13-0.17
+- fix #181782 - mkswap selinux relabeling (fix util-linux-2.13-mkswap-selinux.patch)
+
+* Wed Feb 22 2006 Karel Zak <kzak@redhat.com> 2.13-0.16
+- fix #181782 - mkswap should automatically add selinux label to swapfile
+- fix #180730 - col is exiting with 1 (fix util-linux-2.12p-col-EILSEQ.patch)
+- fix #181896 - broken example in schedutils man pages
+- fix #177331 - login omits pam_acct_mgmt & pam_chauthtok when authentication is skipped.
+- fix #177523 - umount -a should not unmount sysfs
+- fix #182553 - fdisk -l inside xen guest shows no disks
+
+* Fri Feb 10 2006 Jesse Keating <jkeating@redhat.com> - 2.13-0.15.1
+- bump again for double-long bug on ppc(64)
+
+* Wed Feb  8 2006 Peter Jones <pjones@redhat.com> 2.13-0.15
+- add "blockdev --rmpart N <device>" and "blockdev --rmparts <device>"
+
+* Tue Feb 07 2006 Jesse Keating <jkeating@redhat.com> - 2.13-0.14.1
+- rebuilt for new gcc4.1 snapshot and glibc changes
+
+* Thu Jan 19 2006 Steve Dickson <steved@redhat.com> 2.13-0.14
+- Updated the gssd_check() and idmapd_check(), used with
+  nfsv4 mounts, to looked for the correct file in /var/lock/subsys
+  which stops bogus warnings. 
+
+* Tue Jan  3 2006 Karel Zak <kzak@redhat.com> 2.13-0.13
+- fix #174676 - hwclock audit return code mismatch
+- fix #176441: col truncates data
+- fix #174111 - mount allows loopback devices to be mounted more than once to the same mount point
+- better wide chars usage in the cal command (based on the old 'moremisc' patch)
+
+* Mon Dec 12 2005 Karel Zak <kzak@redhat.com> 2.13-0.12
+- rebuilt
+
+* Fri Dec 09 2005 Jesse Keating <jkeating@redhat.com>
+- rebuilt
+
+* Fri Nov 25 2005 Karel Zak <kzak@redhat.com> 2.13-0.11.pre6
+- update to upstream version 2.13-pre6
+- fix #172203 - mount man page in RHEL4 lacks any info on cifs mount options
+
+* Mon Nov  7 2005 Karel Zak <kzak@redhat.com> 2.13-0.10.pre5
+- fix #171337 - mkfs.cramfs doesn't work correctly with empty files
+
+* Fri Oct 28 2005 Karel Zak <kzak@redhat.com> 2.13-0.9.pre5
+- rebuild
+
+* Wed Oct 26 2005 Karel Zak <kzak@redhat.com> 2.13-0.8.pre5
+- updated version of the patch for hwclock audit
+
+* Thu Oct 20 2005 Karel Zak <kzak@redhat.com> 2.13-0.7.pre5
+- fix #171337 - mkfs.cramfs dies creating installer image
+
+* Thu Oct 20 2005 Karel Zak <kzak@redhat.com> 2.13-0.6.pre5
+- update to upstream 2.13pre5
+- remove separated cramfs1.1 (already in upstream package)
+- remove odd symlink /usr/bin/mkcramfs -> ../../sbin/mkfs.cramfs
+- fix #170171 - ipcs -lm always report "max total shared memory (kbytes) = 0"
+
+* Mon Oct 17 2005 Karel Zak <kzak@redhat.com> 2.13-0.5.pre4
+* fix #170564 - add audit message to login
+
+* Fri Oct  7 2005 Karel Zak <kzak@redhat.com> 2.13-0.4.pre4
+- fix #169628 - /usr/bin/floppy doesn't work with /dev/fd0
+- fix #168436 - login will attempt to run if it has no read/write access to its terminal
+- fix #168434 - login's timeout can fail - needs to call siginterrupt(SIGALRM,1)
+- fix #165253 - losetup missing option -a [new feature]
+- update PAM files (replace pam_stack with new "include" PAM directive)
+- remove kbdrate from src.rpm
+- update to 2.13pre4
+
+* Fri Oct  7 2005 Steve Dickson <steved@redhat.com> 2.13-0.3.pre3
+- fix #170110 - Documentation for 'rsize' and 'wsize' NFS mount options
+		is misleading
+
+* Fri Sep  2 2005 Karel Zak <kzak@redhat.com> 2.13-0.3.pre2
+- fix #166923 - hwclock will not run on a non audit-enabled kernel
+- fix #159410 - mkswap(8) claims max swap area size is 2 GB
+- fix #165863 - swsusp swaps should be reinitialized
+- change /var/log/lastlog perms to 0644
+
+* Tue Aug 16 2005 Karel Zak <kzak@redhat.com> 2.13-0.2.pre2
+- /usr/share/misc/getopt/* -move-> /usr/share/doc/util-linux-2.13/getopt-*
+- the arch command marked as deprecated
+- removed: elvtune, rescuept and setfdprm
+- removed: man8/sln.8 (moved to man-pages, see #10601)
+- removed REDAME.pg and README.reset
+- .spec file cleanup
+- added schedutils (commands: chrt, ionice and taskset)
+
+* Tue Jul 12 2005 Karel Zak <kzak@redhat.com> 2.12p-9.7
+- fix #159339 - util-linux updates for new audit system
+- fix #158737 - sfdisk warning for large partitions, gpt
+- fix #150912 - Add ocfs2 support
+- NULL is better than zero at end of execl()
+
+* Thu Jun 16 2005 Karel Zak <kzak@redhat.com> 2.12p-9.5
+- fix #157656 - CRM 546998: Possible bug in vipw, changes permissions of /etc/shadow and /etc/gshadow
+- fix #159339 - util-linux updates for new audit system (pam_loginuid.so added to util-linux-selinux.pamd)
+- fix #159418 - sfdisk unusable - crashes immediately on invocation
+- fix #157674 - sync option on VFAT mount destroys flash drives
+- fix .spec file /usr/sbin/{hwclock,clock} symlinks
+
+* Wed May  4 2005 Jeremy Katz <katzj@redhat.com> - 2.12p-9.3
+- rebuild against new libe2fsprogs (and libblkid) to fix cramfs auto-detection
+
+* Mon May  2 2005 Karel Zak <kzak@redhat.com> 2.12p-9.2
+- rebuild
+
+* Mon May  2 2005 Karel Zak <kzak@redhat.com> 2.12p-9
+- fix #156597 - look - doesn't work with separators
+
+* Mon Apr 25 2005 Karel Zak <kzak@redhat.com> 2.12p-8
+- fix #154498 - util-linux login & pam session
+- fix #155293 - man 5 nfs should include vers as a mount option
+- fix #76467 - At boot time, fsck chokes on LVs listed by label in fstab
+- new Source URL
+- added note about ATAPI IDE floppy to fdformat.8
+- fix #145355 - Man pages for fstab and fstab-sync in conflict
+
+* Tue Apr  5 2005 Karel Zak <kzak@redhat.com> 2.12p-7
+- enable build with libblkid from e2fsprogs-devel
+- remove workaround for duplicated labels
+
+* Thu Mar 31 2005 Steve Dickson <SteveD@RedHat.com> 2.12p-5
+- Fixed nfs mount to rollback correctly.
+
+* Fri Mar 25 2005 Karel Zak <kzak@redhat.com> 2.12p-4
+- added /var/log/lastlog to util-linux (#151635)
+- disabled 'newgrp' in util-linux (enabled in shadow-utils) (#149997, #151613)
+- improved mtab lock (#143118)
+- fixed ipcs typo (#151156)
+- implemented mount workaround for duplicated labels (#116300)
+
+* Wed Mar 16 2005 Elliot Lee <sopwith@redhat.com> 2.12p-3
+- rebuilt
+
+* Fri Feb 25 2005 Steve Dickson <SteveD@RedHat.com> 2.12p-2
+- Changed nfsmount to only use reserve ports when necessary
+  (bz# 141773) 
+
+* Thu Dec 23 2004 Elliot Lee <sopwith@redhat.com> 2.12p-1
+- Update to util-linux-2.12p. This changes swap header format
+  from - you may need to rerun mkswap if you did a clean install of
+  FC3.
+
+* Fri Dec 10 2004 Elliot Lee <sopwith@redhat.com> 2.12j-1
+- Update to util-linux-2.12j
+
+* Tue Dec  7 2004 Steve Dickson <SteveD@RedHat.com> 2.12a-20
+- Corrected a buffer overflow problem with nfs mounts.
+  (bz# 141733) 
+
+* Wed Dec 01 2004 Elliot Lee <sopwith@redhat.com> 2.12a-19
+- Patches for various bugs.
+
+* Mon Nov 29 2004 Steve Dickson <SteveD@RedHat.com> 2.12a-18
+- Made NFS mounts adhere to the IP protocol if specified on
+  command line as well as made NFS umounts adhere to the
+  current IP protocol. Fix #140016
+
+* Thu Oct 14 2004 Elliot Lee <sopwith@redhat.com> 2.12a-16
+- Add include_raw macro, build with it off for Fedora
+
+* Wed Oct 13 2004 Stephen C. Tweedie <sct@redhat.com> - 2.12a-15
+- Add raw patch to allow binding of devices not yet in /dev
+
+* Wed Oct 13 2004 John (J5) Palmieri <johnp@redhat.com> 2.12a-14
+- Add David Zeuthen's patch to enable the pamconsole flag #133941
+
+* Wed Oct 13 2004 Stephen C. Tweedie <sct@redhat.com> 2.12a-13
+- Restore raw utils (bugzilla #130016)
+
+* Mon Oct 11 2004 Phil Knirsch <pknirsch@redhat.com> 2.12a-12
+- Add the missing remote entry in pam.d
+
+* Wed Oct  6 2004 Steve Dickson <SteveD@RedHat.com>
+- Rechecked in some missing NFS mounting code.
+
+* Wed Sep 29 2004 Elliot Lee <sopwith@redhat.com> 2.12a-10
+- Make swaplabel support work with swapon -a -e
+
+* Tue Sep 28 2004 Steve Dickson <SteveD@RedHat.com>
+- Updated the NFS and NFS4 code to the latest CITI patch set
+  (in which they incorporate a number of our local patches).
+
+* Wed Sep 15 2004 Nalin Dahybhai <nalin@redhat.com> 2.12a-8
+- Fix #132196 - turn on SELinux support at build-time.
+
+* Wed Sep 15 2004 Phil Knirsch <pknirsch@redhat.com> 2.12a-7
+- Fix #91174 with pamstart.patch
+
+* Tue Aug 31 2004 Elliot Lee <sopwith@redhat.com> 2.12a-6
+- Fix #16415, #70616 with rdevman.patch
+- Fix #102566 with loginman.patch
+- Fix #104321 with rescuept.patch (just use plain lseek - we're in _FILE_OFFSET_BITS=64 land now)
+- Fix #130016 - remove raw.
+- Re-add agetty (replacing it with mgetty is too much pain, and mgetty is much larger)
+
+* Thu Aug 26 2004 Steve Dickson <SteveD@RedHat.com>
+- Made the NFS security checks more explicit to avoid confusion
+  (an upstream fix)
+- Also removed a compilation warning
+
+* Wed Aug 11 2004 Alasdair Kergon <agk@redhat.com>
+- Remove unused mount libdevmapper inclusion.
+
+* Wed Aug 11 2004 Alasdair Kergon <agk@redhat.com>
+- Add device-mapper mount-by-label support
+- Fix segfault in mount-by-label when a device without a label is present.
+
+* Wed Aug 11 2004 Steve Dickson <SteveD@RedHat.com>
+- Updated nfs man page to show that intr are on by
+  default for nfs4
+
+* Thu Aug 05 2004 Jindrich Novy <jnovy@redhat.com>
+- modified warning causing heart attack for >16 partitions, #107824
+
+* Fri Jul 09 2004 Elliot Lee <sopwith@redhat.com> 2.12a-3
+- Fix #126623, #126572
+- Patch cleanup
+- Remove agetty (use mgetty, agetty is broken)
+
+* Tue Jun 15 2004 Elliot Lee <sopwith@redhat.com>
+- rebuilt
+
+* Thu Jun 03 2004 Elliot Lee <sopwith@redhat.com> 2.12a-1
+- Update to 2.12a
+- Fix #122448
+
+* Thu May 13 2004 Dan Walsh <dwalsh@RedHat.com> 2.12-19
+- Change pam_selinux to run last
+
+* Tue May 04 2004 Elliot Lee <sopwith@redhat.com> 2.12-18
+- Fix #122448 (autofs issues)
+
+* Fri Apr 23 2004 Elliot Lee <sopwith@redhat.com> 2.12-17
+- Fix #119157 by editing the patch
+- Add patch145 to fix #119986
+
+* Fri Apr 16 2004 Elliot Lee <sopwith@redhat.com> 2.12-16
+- Fix #118803
+
+* Tue Mar 23 2004 Jeremy Katz <katzj@redhat.com> 2.12-15
+- mkcramfs: use PAGE_SIZE for default blocksize (#118681)
+
+* Sat Mar 20 2004 <SteveD@RedHat.com>
+- Updated the nfs-mount.patch to correctly 
+  handle the mounthost option and to ignore 
+  servers that do not set auth flavors
+
+* Tue Mar 16 2004 Dan Walsh <dwalsh@RedHat.com> 2.12-13
+- Fix selinux ordering or pam for login
+
+* Tue Mar 16 2004 <SteveD@RedHat.com>
+- Make RPC error messages displayed with -v argument
+- Added two checks to the nfs4 path what will print warnings
+  when rpc.idmapd and rpc.gssd are not running
+- Ping NFS v4 servers before diving into kernel
+- Make v4 mount interruptible which also make the intr option on by default 
+
+* Sun Mar 13 2004  <SteveD@RedHat.com>
+- Reworked how the rpc.idmapd and rpc.gssd checks were
+  done due to review comments from upstream.
+- Added rpc_strerror() so the '-v' flag will show RPC errors.
+
+* Sat Mar 13 2004  <SteveD@RedHat.com>
+- Added two checks to the nfs4 path what will print warnings
+  when rpc.idmapd and rpc.gssd are not running.
+
+* Thu Mar 11 2004 <SteveD@RedHat.com>
+- Reworked and updated the nfsv4 patches.
+
+* Wed Mar 10 2004 Dan Walsh <dwalsh@RedHat.com>
+- Bump version
+
+* Wed Mar 10 2004 Steve Dickson <SteveD@RedHat.com>
+- Tried to make nfs error message a bit more meaninful
+- Cleaned up some warnings
+
+* Sun Mar  7 2004 Steve Dickson <SteveD@RedHat.com> 
+- Added pesudo flavors for nfsv4 mounts.
+- Added BuildRequires: libselinux-devel and Requires: libselinux
+  when WITH_SELINUX is set. 
+
+* Fri Feb 27 2004 Dan Walsh <dwalsh@redhat.com> 2.12-5
+- check for 2.6.3 kernel in mount options
+
+* Mon Feb 23 2004 Elliot Lee <sopwith@redhat.com> 2.12-4
+- Remove /bin/kill for #116100
+
+* Fri Feb 20 2004 Dan Walsh <dwalsh@redhat.com> 2.12-3
+- rebuilt
+
+* Fri Feb 13 2004 Elliot Lee <sopwith@redhat.com>
+- rebuilt
+
+* Thu Feb 12 2004 Elliot Lee <sopwith@redhat.com> 2.12-1
+- Final 2.12 has been out for ages - might as well use it.
+
+* Wed Jan 28 2004 Steve Dickson <SteveD@RedHat.com> 2.12pre-4
+- Added mount patches that have NFS version 4 support
+
+* Mon Jan 26 2004 Elliot Lee <sopwith@redhat.com> 2.12pre-3
+- Provides: mount losetup
+
+* Mon Jan 26 2004 Dan Walsh <dwalsh@redhat.com> 2.12pre-2
+- Add multiple to /etc/pam.d/login for SELinux
+
+* Thu Jan 15 2004 Elliot Lee <sopwith@redhat.com> 2.12pre-1
+- 2.12pre-1
+- Merge mount/losetup packages into the main package (#112324)
+- Lose separate 
+
+* Mon Nov 3 2003 Dan Walsh <dwalsh@redhat.com> 2.11y-35.sel
+- remove selinux code from login and use pam_selinux
+
+* Thu Oct 30 2003 Dan Walsh <dwalsh@redhat.com> 2.11y-34.sel
+- turn on selinux
+
+* Fri Oct 24 2003 Elliot Lee <sopwith@redhat.com> 2.11y-34
+- Add BuildRequires: texinfo (from a bug# I don't remember)
+- Fix #90588 with mountman patch142.
+
+* Mon Oct 6 2003 Dan Walsh <dwalsh@redhat.com> 2.11y-33
+- turn off selinux
+
+* Thu Sep 25 2003 Dan Walsh <dwalsh@redhat.com> 2.11y-32.sel
+- turn on selinux
+- remove context selection
+
+* Fri Sep 19 2003 Elliot Lee <sopwith@redhat.com> 2.11y-31
+- Add patch140 (alldevs) to fix #101772. Printing the total size of
+  all devices was deemed a lower priority than having all devices
+  (e.g. /dev/ida/c0d9) displayed.
+
+* Fri Sep 12 2003 Dan Walsh <dwalsh@redhat.com> 2.11y-31
+- turn off selinux
+
+* Fri Sep 12 2003 Dan Walsh <dwalsh@redhat.com> 2.11y-30.sel
+- turn on selinux
+
+* Fri Sep 5 2003 Elliot Lee <sopwith@redhat.com> 2.11y-28
+- Fix #103004, #103954
+
+* Fri Sep 5 2003 Dan Walsh <dwalsh@redhat.com> 2.11y-27
+- turn off selinux
+
+* Thu Sep 4 2003 Dan Walsh <dwalsh@redhat.com> 2.11y-26.sel
+- build with selinux
+
+* Mon Aug 11 2003 Elliot Lee <sopwith@redhat.com> 2.11y-25
+- Use urandom instead for mkcramfs
+
+* Tue Jul 29 2003 Dan Walsh <dwalsh@redhat.com> 2.11y-24
+- add SELINUX 2.5 support
+
+* Wed Jul 23 2003 Elliot Lee <sopwith@redhat.com> 2.11y-22
+- #100433 patch
+
+* Mon Jun 14 2003 Elliot Lee <sopwith@redhat.com> 2.11y-20
+- #97381 patch
+
+* Wed Jun 04 2003 Elliot Lee <sopwith@redhat.com>
+- rebuilt
+
+* Mon Apr 21 2003 Elliot Lee <sopwith@redhat.com> 2.11y-17
+- Change patch128 to improve ipcs -l
+
+* Fri Apr 11 2003 Elliot Lee <sopwith@redhat.com> 2.11y-16
+- Fix #85407
+
+* Fri Apr 11 2003 Elliot Lee <sopwith@redhat.com> 2.11y-15
+- Change patch128 to util-linux-2.11f-ipcs-84243-86285.patch to get all
+ipcs fixes
+
+* Thu Apr 10 2003 Matt Wilson <msw@redhat.com> 2.11y-14
+- fix last login date display on AMD64 (#88574)
+
+* Mon Apr  7 2003 Jeremy Katz <katzj@redhat.com> 2.11y-13
+- include sfdisk on ppc
+
+* Fri Mar 28 2003 Jeremy Katz <katzj@redhat.com> 2.11y-12
+- add patch from msw to change mkcramfs blocksize with a command line option
+
+* Tue Mar 25 2003 Phil Knirsch <pknirsch@redhat.com> 2.11y-11
+- Fix segfault on s390x due to wrong usage of BLKGETSIZE.
+
+* Thu Mar 13 2003 Elliot Lee <sopwith@redhat.com> 2.11y-10
+- Really apply the ipcs patch. Doh.
+
+* Mon Feb 24 2003 Elliot Lee <sopwith@redhat.com>
+- rebuilt
+
+* Wed Feb 19 2003 Elliot Lee <sopwith@redhat.com> 2.11y-8
+- ipcs-84243.patch to fix #84243
+
+* Thu Feb 13 2003 Yukihiro Nakai <ynakai@redhat.com> 2.11y-7
+- Update moremisc patch to fix swprintf()'s minimum field (bug #83361).
+
+* Mon Feb 03 2003 Elliot Lee <sopwith@redhat.com> 2.11y-6
+- Fix mcookie segfault on many 64-bit architectures (bug #83345).
+
+* Mon Feb 03 2003 Tim Waugh <twaugh@redhat.com> 2.11y-5
+- Fix underlined multibyte characters (bug #83376).
+
+* Sun Feb 02 2003 Florian La Roche <Florian.LaRoche@redhat.de>
+- rebuild to have again a s390 rpm
+- disable some more apps for mainframe
+
+* Wed Jan 29 2003 Elliot Lee <sopwith@redhat.com> 2.11y-4
+- util-linux-2.11y-umask-82552.patch
+
+* Wed Jan 22 2003 Tim Powers <timp@redhat.com>
+- rebuilt
+
+* Mon Jan 13 2003 Elliot Lee <sopwith@redhat.com> 2.11y-2
+- Fix #81069, #75421
+
+* Mon Jan 13 2003 Elliot Lee <sopwith@redhat.com> 2.11y-1
+- Update to 2.11y
+- Fix #80953
+- Update patch0, patch107, patch117, patch120 for 2.11y
+- Remove patch60, patch61, patch207, patch211, patch212, patch119, patch121
+- Remove patch122, patch200
+
+* Wed Oct 30 2002 Elliot Lee <sopwith@redhat.com> 2.11w-2
+- Remove some crack/unnecessary patches while submitting stuff upstream.
+- Build with -D_FILE_OFFSET_BITS=64
+
+* Tue Oct 29 2002 Elliot Lee <sopwith@redhat.com> 2.11w-1
+- Update to 2.11w, resolve patch conflicts
+
+* Tue Oct 08 2002 Phil Knirsch <pknirsch@redhat.com> 2.11r-10hammer.3
+- Extended util-linux-2.11b-s390x patch to work again.
+
+* Thu Oct 03 2002 Elliot Lee <sopwith@redhat.com> 2.11r-10hammer.2
+- Add patch122 for hwclock on x86_64
+
+* Thu Sep 12 2002 Than Ngo <than@redhat.com> 2.11r-10hammer.1
+- Fixed pam config files
+
+* Wed Sep 11 2002 Bernhard Rosenkraenzer <bero@redhat.com> 2.11r-10hammer
+- Port to hammer
+
+* Fri Aug 30 2002 Elliot Lee <sopwith@redhat.com> 2.11r-10
+- Patch120 (hwclock) to fix #72140
+- Include isosize util
+
+* Wed Aug 7 2002  Elliot Lee <sopwith@redhat.com> 2.11r-9
+- Patch120 (skipraid2) to fix #70353, because the original patch was 
+totally useless.
+
+* Fri Aug 2 2002  Elliot Lee <sopwith@redhat.com> 2.11r-8
+- Patch119 (fdisk-add-primary) from #67898
+
+* Wed Jul 24 2002 Elliot Lee <sopwith@redhat.com> 2.11r-7
+- Really add the gptsize patch, instead of what I think the patch says.
+(+1)
+
+* Tue Jul 23 2002 Elliot Lee <sopwith@redhat.com> 2.11r-6
+- Add the sp[n].size part of the patch from #69603
+
+* Mon Jul 22 2002 Florian La Roche <Florian.LaRoche@redhat.de>
+- adjust mainframe patches
+
+* Tue Jul  2 2002 Bill Nottingham <notting@redhat.com> 2.11r-4
+- only require usermode if we're shipping kbdrate here
+
+* Fri Jun 28 2002 Trond Eivind Glomsrod <teg@redhat.com> 2.11r-3
+- Port the large swap patch to new util-linux... the off_t changes 
+  now in main aren't sufficient
+
+* Thu Jun 27 2002 Elliot Lee <sopwith@redhat.com> 2.11r-2
+- Remove swapondetect (patch301) until it avoids possible false positives.
+
+* Thu Jun 27 2002 Elliot Lee <sopwith@redhat.com> 2.11r-1
+- Update to 2.11r, wheeee
+- Remove unused patches
+
+* Thu Jun 27 2002 Elliot Lee <sopwith@redhat.com> 2.11n-19
+- Make a note here that this package was the source of the single change 
+contained in util-linux-2.11f-18 (in 7.2/Alpha), and also contains the 
+rawman patch from util-linux-2.11f-17.1 (in 2.1AS).
+- Package has no runtime deps on slang, so remove the BuildRequires: 
+slang-devel.
+
+* Fri Jun 21 2002 Tim Powers <timp@redhat.com>
+- automated rebuild
+
+* Thu Jun 20 2002 Elliot Lee <sopwith@redhat.com> 2.11n-17
+- Fix teg's swapondetect patch to not print out the usage message when 
+'swapon -a -e' is run. (#66690) (edit existing patch)
+- Apply hjl's utmp handling patch (#66950) (patch116)
+- Fix fdisk man page notes on IDE disk partition limit (#64013) (patch117)
+- Fix mount.8 man page notes on vfat shortname option (#65628) (patch117)
+- Fix possible cal overflow with widechars (#67090) (patch117)
+
+* Tue Jun 11 2002 Trond Eivind Glomsrod <teg@redhat.com> 2.11n-16
+- support large swap partitions
+- add '-d' option to autodetect available swap partitions
+
+* Thu May 23 2002 Tim Powers <timp@redhat.com>
+- automated rebuild
+
+* Wed May 15 2002 Elliot Lee <sopwith@redhat.com> 2.11n-14
+- Remove kbdrate (again).
+
+* Mon Apr 29 2002 Florian La Roche <Florian.LaRoche@redhat.de>
+- adjust mainframe patches to apply to current rpm
+- do not include fdisk until it is fixed to work on mainframe
+
+* Mon Apr 01 2002 Elliot Lee <sopwith@redhat.com> 2.11n-12
+- Don't strip binaries - rpm does it for us.
+
+* Sun Mar 31 2002 Elliot Lee <sopwith@redhat.com> 2.11n-11
+- Apply patch115 from ejb@ql.org for bug #61868
+
+* Wed Mar 27 2002 Elliot Lee <sopwith@redhat.com> 2.11n-10
+- Finish fixing #60675 (ipcrm man page), updated the patch.
+- Fix #61203 (patch114 - dumboctal.patch).
+
+* Tue Mar 12 2002 Elliot Lee <sopwith@redhat.com> 2.11n-9
+- Update ctty3 patch to ignore SIGHUP while dropping controlling terminal
+
+* Fri Mar 08 2002 Elliot Lee <sopwith@redhat.com> 2.11n-8
+- Update ctty3 patch to drop controlling terminal before forking.
+
+* Fri Mar 08 2002 Elliot Lee <sopwith@redhat.com> 2.11n-7
+  Fix various bugs:
+- Add patch110 (skipraid) to properly skip devices that are part of a RAID array.
+- Add patch111 (mkfsman) to update the mkfs man page's "SEE ALSO" section.
+- remove README.cfdisk
+- Include partx
+- Fix 54741 and related bugs for good(hah!) with patch113 (ctty3)
+
+* Wed Mar 06 2002 Elliot Lee <sopwith@redhat.com> 2.11n-6
+- Put kbdrate in, add usermode dep.
+
+* Tue Feb 26 2002 Elliot Lee <sopwith@redhat.com> 2.11n-5
+- Fix #60363 (tweak raw.8 man page, make rawdevices.8 symlink).
+
+* Tue Jan 28 2002 Bill Nottingham <notting@redhat.com> 2.11n-4
+- remove kbdrate (fixes kbd conflict)
+
+* Fri Dec 28 2001 Elliot Lee <sopwith@redhat.com> 2.11n-3
+- Add util-linux-2.11n-ownerumount.patch (#56593)
+- Add patch102 (util-linux-2.11n-colrm.patch) to fix #51887
+- Fix #53452 nits.
+- Fix #56953 (remove tunelp on s390)
+- Fix #56459, and in addition switch to using sed instead of perl.
+- Fix #58471
+- Fix #57300
+- Fix #37436
+- Fix #32132
+
+* Wed Dec 26 2001 Elliot Lee <sopwith@redhat.com> 2.11n-1
+- Update to 2.11n
+- Merge mount/losetup back in.
+
+* Tue Dec 04 2001 Elliot Lee <sopwith@redhat.com> 2.11f-17
+- Add patch38 (util-linux-2.11f-ctty2.patch) to ignore SIGINT/SIGTERM/SIGQUIT in the parent, so that ^\ won't break things.
+
+* Fri Nov 09 2001 Elliot Lee <sopwith@redhat.com> 2.11f-16
+- Merge patches 36, 75, 76, and 77 into patch #37, to attempt resolve all the remaining issues with #54741.
+
+* Wed Oct 24 2001 Florian La Roche <Florian.LaRoche@redhat.de>
+- add nologin man-page for s390/s390x
+
+* Wed Oct 24 2001 Bernhard Rosenkraenzer <bero@redhat.com> 2.11f-14
+- Don't build kbdrate on s390/s390x
+- Don't make the pivot_root.8 man page executable(!)
+
+* Tue Oct 23 2001 Elliot Lee <sopwith@redhat.com> 2.11f-13
+- Patch/idea #76 from HJL, fixes bug #54741 (race condition in login 
+acquisition of controlling terminal).
+
+* Thu Oct 11 2001 Bill Nottingham <notting@redhat.com>
+- fix permissions problem with vipw & shadow files, again (doh!)
+
+* Tue Oct 09 2001 Erik Troan <ewt@redhat.com>
+- added patch from Olaf Kirch to fix possible pwent structure overwriting
+
+* Fri Sep 28 2001 Elliot Lee <sopwith@redhat.com> 2.11f-10
+- fdisk patch from arjan
+
+* Sun Aug 26 2001 Elliot Lee <sopwith@redhat.com> 2.11f-9
+- Don't include cfdisk, since it appears to be an even bigger pile of junk than fdisk? :)
+
+* Wed Aug  1 2001 Tim Powers <timp@redhat.com>
+- don't require usermode
+
+* Mon Jul 30 2001 Elliot Lee <sopwith@redhat.com> 2.11f-7
+- Incorporate kbdrate back in.
+
+* Mon Jul 30 2001 Bill Nottingham <notting@redhat.com>
+- revert the patch that calls setsid() in login that we had reverted
+  locally but got integrated upstream (#46223)
+
+* Tue Jul 24 2001 Florian La Roche <Florian.LaRoche@redhat.de>
+- correct s390x patch
+
+* Mon Jul 23 2001 Elliot Lee <sopwith@redhat.com>
+- Add my megapatch (various bugs)
+- Include pivot_root (#44828)
+
+* Thu Jul 12 2001 Bill Nottingham <notting@redhat.com>
+- make shadow files 0400, not 0600
+
+* Wed Jul 11 2001 Bill Nottingham <notting@redhat.com>
+- fix permissions problem with vipw & shadow files
+
+* Mon Jun 18 2001 Florian La Roche <Florian.LaRoche@redhat.de>
+- update to 2.11f, remove any merged patches
+- add s390x patches for somewhat larger swap
+
+* Thu Jun 14 2001 Erik Troan <ewt@redhat.com>
+- added --verbose patch to mkcramfs; it's much quieter by default now
+
+* Tue May 22 2001 Erik Troan <ewt@redhat.com>
+- removed warning about starting partitions on cylinder 0 -- swap version2
+  makes it unnecessary
+
+* Wed May  9 2001 Bernhard Rosenkraenzer <bero@redhat.com> 2.11b-2
+- Fix up s390x support
+
+* Mon May  7 2001 Bernhard Rosenkraenzer <bero@redhat.com> 2.11b-1
+- Fix up login for real (a console session should be the controlling tty)
+  by reverting to 2.10s code (#36839, #36840, #39237)
+- Add man page for agetty (#39287)
+- 2.11b, while at it
+
+* Fri Apr 27 2001 Preston Brown <pbrown@redhat.com> 2.11a-4
+- /sbin/nologin from OpenBSD added.
+
+* Fri Apr 20 2001 Bernhard Rosenkraenzer <bero@redhat.com> 2.11a-3
+- Fix up login - exiting immediately even if the password is correct
+  is not exactly a nice feature.
+- Make definite plans to kill people who update login without checking
+  if the new version works ;)
+
+* Tue Apr 17 2001 Erik Troan <ewt@redhat.com>
+- upgraded to 2.11a (kbdrate moved to kbd, among other things)
+- turned off ALLOW_VCS_USE
+- modified mkcramfs to not use a large number of file descriptors
+- include mkfs.bfs
+
+* Sun Apr  8 2001 Matt Wilson <msw@redhat.com>
+- changed Requires: kernel >= 2.2.12-7 to Conflicts: kernel < 2.2.12-7
+  (fixes a initscripts -> util-linux -> kernel -> initscripts prereq loop)
+
+* Tue Mar 20 2001 Matt Wilson <msw@redhat.com>
+- patched mkcramfs to use the PAGE_SIZE from asm/page.h instead of hard
+  coding 4096 (fixes mkcramfs on alpha...)
+
+* Mon Mar 19 2001 Matt Wilson <msw@redhat.com>
+- added mkcramfs (from linux/scripts/mkcramfs)
+
+* Mon Feb 26 2001 Tim Powers <timp@redhat.com>
+- fixed bug #29131, where ipc.info didn't have an info dir entry,
+  added the dir entry to ipc.texi (Patch58)
+
+* Fri Feb 23 2001 Preston Brown <pbrown@redhat.com>
+- use lang finder script
+- install info files
+
+* Thu Feb 08 2001 Erik Troan <ewt@redhat.com>
+- reverted login patch; seems to cause problems
+- added agetty
+
+* Wed Feb 07 2001 Erik Troan <ewt@redhat.com>
+- updated kill man page
+- added patch to fix vipw race
+- updated vipw to edit /etc/shadow and /etc/gshadow, if appropriate
+- added patch to disassociate login from tty, session, and pgrp
+
+* Tue Feb 06 2001 Erik Troan <ewt@redhat.com>
+- fixed problem w/ empty extended partitions
+- added patch to fix the date in the more man page
+- set OPT to pass optimization flags to make rather then RPM_OPT_FLAG
+- fixed fdisk -l /Proc/partitions parsing
+- updated to 2.10s
+
+* Tue Jan 23 2001 Preston Brown <pbrown@redhat.com>
+- danish translations added
+
+* Mon Jan 15 2001 Nalin Dahyabhai <nalin@redhat.com>
+- fix segfault in login in btmp patch (#24025)
+
+* Mon Dec 11 2000 Oliver Paukstadt <oliver.paukstadt@millenux.com>
+- ported to s390
+
+* Wed Nov 01 2000 Florian La Roche <Florian.LaRoche@redhat.de>
+- update to 2.10p
+- update patch37 to newer fdisk version
+
+* Mon Oct  9 2000 Jeff Johnson <jbj@redhat.com>
+- update to 2.10o
+-  fdformat: fixed to work with kernel 2.4.0test6 (Marek Wojtowicz)
+-  login: not installed suid
+-  getopt: by default install aux files in /usr/share/misc
+- update to 2.10n:
+-  added blockdev.8
+-  change to elvtune (andrea)
+-  fixed overrun in agetty (vii@penguinpowered.com)
+-  shutdown: prefer umounting by mount point (rgooch)
+-  fdisk: added plan9
+-  fdisk: remove empty links in chain of extended partitions
+-  hwclock: handle both /dev/rtc and /dev/efirtc (Bill Nottingham)
+-  script: added -f (flush) option (Ivan Schreter)
+-  script: added -q (quiet) option (Per Andreas Buer)
+-  getopt: updated to version 1.1.0 (Frodo Looijaard)
+-  Czech messages (Jiri Pavlovsky)
+- login.1 man page had not /var/spool/mail path (#16998).
+- sln.8 man page (but not executable) included (#10601).
+- teach fdisk 0xde(Dell), 0xee(EFI GPT), 0xef(EFI FAT) partitions (#17610).
+
+* Wed Aug 30 2000 Matt Wilson <msw@redhat.com>
+- rebuild to cope with glibc locale binary incompatibility, again
+
+* Mon Aug 14 2000 Jeff Johnson <jbj@redhat.com>
+- setfdprm should open with O_WRONLY, not 3.
+
+* Fri Aug 11 2000 Jeff Johnson <jbj@redhat.com>
+- fdformat should open with O_WRONLY, not 3.
+
+* Fri Jul 21 2000 Nalin Dahyabhai <nalin@redhat.com>
+- make 'look' look in /usr/share/dict
+
+* Fri Jul 21 2000 Bill Nottingham <notting@redhat.com>
+- put /usr/local/sbin:/usr/local/bin in root's path
+
+* Wed Jul 19 2000 Jakub Jelinek <jakub@redhat.com>
+- rebuild to cope with glibc locale binary incompatibility
+
+* Thu Jul 13 2000 Prospector <bugzilla@redhat.com>
+- automatic rebuild
+
+* Mon Jul 10 2000 Bill Nottingham <notting@redhat.com>
+- enable hwclock to use /dev/efirtc on ia64 (gettext is fun. :( )
+
+* Mon Jul  3 2000 Bill Nottingham <notting@redhat.com>
+- move cfdisk to /usr/sbin, it depends on /usr stuff
+- add rescuept
+
+* Fri Jun 23 2000 Bernhard Rosenkraenzer <bero@redhat.com>
+- point more at the correct path to vi (for "v"), Bug #10882
+
+* Sun Jun  4 2000 Jeff Johnson <jbj@redhat.com>
+- FHS packaging changes.
+
+* Thu Jun  1 2000 Nalin Dahyabhai <nalin@redhat.com>
+- modify PAM setup to use system-auth
+
+* Mon May  1 2000 Bill Nottingham <notting@redhat.com>
+- eek, where did login go? (specfile tweaks)
+
+* Mon Apr 17 2000 Bernhard Rosenkraenzer <bero@redhat.com>
+- 2.10k
+- fix compilation with current glibc
+
+* Tue Mar 21 2000 Bernhard Rosenkraenzer <bero@redhat.com>
+- 2.10h
+
+* Tue Mar  7 2000 Jeff Johnson <jbj@redhat.com>
+- rebuild for sparc baud rates > 38400.
+
+* Sat Mar  4 2000 Matt Wilson <msw@redhat.com>
+- use snprintf - not sprintf - when doing
+  sprintf ("%%s\n", _("Some string")) to avoid overflows and
+  segfaults.
+
+* Mon Feb 21 2000 Jeff Johnson <jbj@redhat.com>
+- raw control file was /dev/raw, now /dev/rawctl.
+- raw access files were /dev/raw*, now /dev/raw/raw*.
+
+* Thu Feb 17 2000 Erik Troan <ewt@redhat.com>
+- -v argument to mkswap wasn't working
+
+* Thu Feb 10 2000 Jakub Jelinek <jakub@redhat.com>
+- Recognize 0xfd on Sun disklabels as RAID
+
+* Tue Feb  8 2000 Bill Nottingham <notting@redhat.com>
+- more lives in /bin, and was linked against /usr/lib/libnurses. Bad.
+
+* Thu Feb 03 2000 Jakub Jelinek <jakub@redhat.com>
+- update to 2.10f
+- fix issues in the new realpath code, avoid leaking memory
+
+* Tue Feb 01 2000 Cristian Gafton <gafton@redhat.com>
+- rebuild to fix dependencies
+- add NFSv3 patches
+
+* Fri Jan 28 2000 Bill Nottingham <notting@redhat.com>
+- don't require csh
+
+* Mon Jan 24 2000 Nalin Dahyabhai <nalin@redhat.com>
+- update to 2.10e
+- add rename
+
+* Thu Jan 20 2000 Jeff Johnson <jbj@redhat.com>
+- strip newlines in logger input.
+
+* Mon Jan 10 2000 Jeff Johnson <jbj@redhat.com>
+- rebuild with correct ncurses libs.
+
+* Tue Dec  7 1999 Matt Wilson <msw@redhat.com>
+- updated to util-linux 2.10c
+- deprecated IMAP login mail notification patch17
+- deprecated raw patch22
+- depricated readprofile patch24
+
+* Tue Dec  7 1999 Bill Nottingham <notting@redhat.com>
+- add patch for readprofile
+
+* Thu Nov 18 1999 Michael K. Johnson <johnsonm@redhat.com>
+- tunelp should come from util-linux
+
+* Tue Nov  9 1999 Jakub Jelinek <jakub@redhat.com>
+- kbdrate cannot use /dev/port on sparc.
+
+* Wed Nov  3 1999 Jakub Jelinek <jakub@redhat.com>
+- fix kbdrate on sparc.
+
+* Wed Oct 27 1999 Bill Nottingham <notting@redhat.com>
+- ship hwclock on alpha.
+
+* Tue Oct  5 1999 Bill Nottingham <notting@redhat.com>
+- don't ship symlinks to rdev if we don't ship rdev.
+
+* Tue Sep 07 1999 Cristian Gafton <gafton@redhat.com>
+- add rawIO support from sct
+
+* Mon Aug 30 1999 Preston Brown <pbrown@redhat.com>
+- don't display "new mail" message when the only piece of mail is from IMAP
+
+* Fri Aug 27 1999 Michael K. Johnson <johnsonm@redhat.com>
+- kbdrate is now a console program
+
+* Thu Aug 26 1999 Jeff Johnson <jbj@redhat.com>
+- hostid is now in sh-utils. On sparc, install hostid as sunhostid (#4581).
+- update to 2.9w:
+-  Updated mount.8 (Yann Droneaud)
+-  Improved makefiles
+-  Fixed flaw in fdisk
+
+* Tue Aug 10 1999 Jeff Johnson <jbj@redhat.com>
+- tsort is now in textutils.
+
+* Wed Aug  4 1999 Bill Nottingham <notting@redhat.com>
+- turn off setuid bit on login. Again. :(
+
+* Tue Aug  3 1999 Peter Jones, <pjones@redhat.com>
+- hostid script for sparc (#3803).
+
+* Tue Aug 03 1999 Christian 'Dr. Disk' Hechelmann <drdisk@tc-gruppe.de>
+- added locale message catalogs to %%file
+- added patch for non-root build
+- vigr.8 and /usr/lib/getopt  man-page was missing from file list
+- /etc/fdprm really is a config file
+
+* Fri Jul 23 1999 Jeff Johnson <jbj@redhat.com>
+- update to 2.9v:
+- cfdisk no longer believes the kernel's HDGETGEO
+	(and may be able to partition a 2 TB disk)
+
+* Fri Jul 16 1999 Jeff Johnson <jbj@redhat.com>
+- update to 2.9u:
+- Czech more.help and messages (Jiri Pavlovsky)
+- Japanese messages (Daisuke Yamashita)
+- fdisk fix (Klaus G. Wagner)
+- mount fix (Hirokazu Takahashi)
+- agetty: enable hardware flow control (Thorsten Kranzkowski)
+- minor cfdisk improvements
+- fdisk no longer accepts a default device
+- Makefile fix
+
+* Tue Jul  6 1999 Jeff Johnson <jbj@redhat.com>
+- update to 2.9t:
+- national language support for hwclock
+- Japanese messages (both by Daisuke Yamashita)
+- German messages and some misc i18n fixes (Elrond)
+- Czech messages (Jiri Pavlovsky)
+- wall fixed for /dev/pts/xx ttys
+- make last and wall use getutent() (Sascha Schumann)
+	[Maybe this is bad: last reading all of wtmp may be too slow.
+	Revert in case people complain.]
+- documented UUID= and LABEL= in fstab.5
+- added some partition types
+- swapon: warn only if verbose
+
+* Fri Jun 25 1999 Jeff Johnson <jbj@redhat.com>
+- update to 2.9s.
+
+* Sat May 29 1999 Jeff Johnson <jbj@redhat.com>
+- fix mkswap sets incorrect bits on sparc64 (#3140).
+
+* Thu Apr 15 1999 Jeff Johnson <jbj@redhat.com>
+- on sparc64 random ioctls on clock interface cause kernel messages.
+
+* Thu Apr 15 1999 Jeff Johnson <jbj@redhat.com>
+- improved raid patch (H.J. Lu).
+
+* Wed Apr 14 1999 Michael K. Johnson <johnsonm@redhat.com>
+- added patch for smartraid controllers
+
+* Sat Apr 10 1999 Cristian Gafton <gafton@redhat.com>
+- fix logging problems caused by setproctitle and PAM interaction
+  (#2045)
+
+* Wed Mar 31 1999 Jeff Johnson <jbj@redhat.com>
+- include docs and examples for sfdisk (#1164)
+
+* Mon Mar 29 1999 Matt Wilson <msw@redhat.com>
+- rtc is not working properly on alpha, we can't use hwclock yet.
+
+* Fri Mar 26 1999 Cristian Gafton <gafton@redhat.com>
+- add patch to make mkswap more 64 bit friendly... Patch from
+  eranian@hpl.hp.com (ahem!)
+
+* Thu Mar 25 1999 Jeff Johnson <jbj@redhat.com>
+- include sfdisk (#1164)
+- fix write (#1784)
+- use positive logic in spec file (ifarch rather than ifnarch).
+- (re)-use 1st matching utmp slot if search by mypid not found.
+- update to 2.9o
+- lastb wants bad logins in wtmp clone /var/run/btmp (#884)
+
+* Thu Mar 25 1999 Jakub Jelinek <jj@ultra.linux.cz>
+- if hwclock is to be compiled on sparc,
+  it must actually work. Also, it should obsolete
+  clock, otherwise it clashes.
+- limit the swap size in mkswap for 2.2.1+ kernels
+  by the actual maximum size kernel can handle.
+- fix kbdrate on sparc, patch by J. S. Connell
+  <ankh@canuck.gen.nz>
+
+* Wed Mar 24 1999 Matt Wilson <msw@redhat.com>
+- added pam_console back into pam.d/login
+
+* Tue Mar 23 1999 Matt Wilson <msw@redhat.com>
+- updated to 2.9i
+- added hwclock for sparcs and alpha
+
+* Mon Mar 22 1999 Erik Troan <ewt@redhat.com>
+- added vigr to file list
+
+* Sun Mar 21 1999 Cristian Gafton <gafton@redhat.com> 
+- auto rebuild in the new build environment (release 12)
+
+* Thu Mar 18 1999 Cristian Gafton <gafton@redhat.com>
+- remove most of the ifnarch arm stuff
+
+* Mon Mar 15 1999 Michael Johnson <johnsonm@redhat.com>
+- added pam_console.so to /etc/pam.d/login
+
+* Thu Feb  4 1999 Michael K. Johnson <johnsonm@redhat.com>
+- .perms patch to login to make it retain root in parent process
+  for pam_close_session to work correctly
+
+* Tue Jan 12 1999 Jeff Johnson <jbj@redhat.com>
+- strip fdisk in buildroot correctly (#718)
+
+* Mon Jan 11 1999 Cristian Gafton <gafton@redhat.com>
+- have fdisk compiled on sparc and arm
+
+* Mon Jan 11 1999 Erik Troan <ewt@redhat.com>
+- added beos partition type to fdisk
+
+* Wed Dec 30 1998 Cristian Gafton <gafton@redhat.com>
+- incorporate fdisk on all arches
+
+* Sat Dec  5 1998 Jeff Johnson <jbj@redhat.com>
+- restore PAM functionality at end of login (Bug #201)
+
+* Thu Dec 03 1998 Cristian Gafton <gafton@redhat.com>
+- patch top build on the arm without PAM and related utilities, for now.
+- build hwclock only on intel
+
+* Wed Nov 18 1998 Cristian Gafton <gafton@redhat.com>
+- upgraded to version 2.9
+
+* Thu Oct 29 1998 Bill Nottingham <notting@redhat.com>
+- build for Raw Hide (slang-1.2.2)
+- patch kbdrate wackiness so it builds with egcs
+
+* Tue Oct 13 1998 Erik Troan <ewt@redhat.com>
+- patched more to use termcap
+
+* Mon Oct 12 1998 Erik Troan <ewt@redhat.com>
+- added warning about alpha/bsd label starting cylinder
+
+* Mon Sep 21 1998 Erik Troan <ewt@redhat.com>
+- use sigsetjmp/siglongjmp in more rather then sig'less versions
+
+* Fri Sep 11 1998 Jeff Johnson <jbj@redhat.com>
+- explicit attrs for setuid/setgid programs
+
+* Thu Aug 27 1998 Cristian Gafton <gafton@redhat.com>
+- sln is now included in glibc
+
+* Sun Aug 23 1998 Jeff Johnson <jbj@redhat.com>
+- add cbm1581 floppy definitions (problem #787)
+
+* Mon Jun 29 1998 Jeff Johnson <jbj@redhat.com>
+- remove /etc/nologin at end of shutdown/halt.
+
+* Fri Jun 19 1998 Jeff Johnson <jbj@redhat.com>
+- add mount/losetup.
+
+* Thu Jun 18 1998 Jeff Johnson <jbj@redhat.com>
+- update to 2.8 with 2.8b clean up. hostid now defunct?
+
+* Mon Jun 01 1998 David S. Miller <davem@dm.cobaltmicro.com>
+- "more" now works properly on sparc
+
+* Sat May 02 1998 Jeff Johnson <jbj@redhat.com>
+- Fix "fdisk -l" fault on mounted cdrom. (prob #513)
+
+* Fri Apr 24 1998 Prospector System <bugs@redhat.com>
+- translations modified for de, fr, tr
+
+* Sat Apr 11 1998 Cristian Gafton <gafton@redhat.com>
+- manhattan rebuild
+
+* Mon Dec 29 1997 Erik Troan <ewt@redhat.com>
+- more didn't suspend properly on glibc
+- use proper tc*() calls rather then ioctl's
+
+* Sun Dec 21 1997 Cristian Gafton <gafton@redhat.com>
+- fixed a security problem in chfn and chsh accepting too 
+  long gecos fields
+
+* Fri Dec 19 1997 Mike Wangsmo <wanger@redhat.com>
+- removed "." from default path
+
+* Tue Dec 02 1997 Cristian Gafton <gafton@redhat.com>
+- added (again) the vipw patch
+
+* Wed Oct 22 1997 Michael Fulbright <msf@redhat.com>
+- minor cleanups for glibc 2.1
+
+* Fri Oct 17 1997 Michael Fulbright <msf@redhat.com>
+- added vfat32 filesystem type to list recognized by fdisk
+
+* Fri Oct 10 1997 Erik Troan <ewt@redhat.com>
+- don't build clock on the alpha 
+- don't install chkdupexe
+
+* Thu Oct 02 1997 Michael K. Johnson <johnsonm@redhat.com>
+- Update to new pam standard.
+- BuildRoot.
+
+* Thu Sep 25 1997 Cristian Gafton <gafton@redhat.com>
+- added rootok and setproctitle patches
+- updated pam config files for chfn and chsh
+
+* Tue Sep 02 1997 Erik Troan <ewt@redhat.com>
+- updated MCONFIG to automatically determine the architecture
+- added glibc header hacks to fdisk code
+- rdev is only available on the intel
+
+* Fri Jul 18 1997 Erik Troan <ewt@redhat.com>
+- update to util-linux 2.7, fixed login problems
+
+* Wed Jun 25 1997 Erik Troan <ewt@redhat.com>
+- Merged Red Hat changes into main util-linux source, updated package to
+  development util-linux (nearly 2.7).
+
+* Tue Apr 22 1997 Michael K. Johnson <johnsonm@redhat.com>
+- LOG_AUTH --> LOG_AUTHPRIV in login and shutdown
+
+* Mon Mar 03 1997 Michael K. Johnson <johnsonm@redhat.com>
+- Moved to new pam and from pam.conf to pam.d
+
+* Tue Feb 25 1997 Michael K. Johnson <johnsonm@redhat.com>
+- pam.patch differentiated between different kinds of bad logins.
+  In particular, "user does not exist" and "bad password" were treated
+  differently.  This was a minor security hole.