diff --git a/SOURCES/0127-agetty-fix-etc-os-release-parsing.patch b/SOURCES/0127-agetty-fix-etc-os-release-parsing.patch
new file mode 100644
index 0000000..0e2e04b
--- /dev/null
+++ b/SOURCES/0127-agetty-fix-etc-os-release-parsing.patch
@@ -0,0 +1,50 @@
+From 6b70da7e86ae17c215c48156a59e76b9f89e8add Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Thu, 5 Oct 2017 11:07:41 +0200
+Subject: [PATCH 127/135] agetty: fix /etc/os-release parsing
+
+For example /etc/os-release:
+
+	VERSION="26 (Twenty Six)"
+	VERSION_ID=26
+
+agetty for \S{VERSION} returns
+
+	_ID=26
+
+because the parser does nor check for '=' after variable name.
+
+Upstream: http://github.com/karelzak/util-linux/commit/949e83997906ab8dd8442f28d74c34bb5a2395ee
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1498462
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ term-utils/agetty.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/term-utils/agetty.c b/term-utils/agetty.c
+index 5692126dd..b626cdbeb 100644
+--- a/term-utils/agetty.c
++++ b/term-utils/agetty.c
+@@ -1280,6 +1280,7 @@ static char *xgetdomainname(void)
+ 	return NULL;
+ }
+ 
++
+ static char *read_os_release(struct options *op, const char *varname)
+ {
+ 	int fd = -1;
+@@ -1329,6 +1330,11 @@ static char *read_os_release(struct options *op, const char *varname)
+ 			continue;
+ 		}
+ 		p += varsz;
++		p += strspn(p, " \t\n\r");
++
++		if (*p != '=')
++			continue;
++
+ 		p += strspn(p, " \t\n\r=\"");
+ 		eol = p + strcspn(p, "\n\r");
+ 		*eol = '\0';
+-- 
+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
deleted file mode 100644
index 02caa94..0000000
--- a/SOURCES/0127-libmount-fix-access-utab-write-test.patch
+++ /dev/null
@@ -1,226 +0,0 @@
-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/0128-fdisk-remove-obsolete-info-about-GPT-from-man-page.patch b/SOURCES/0128-fdisk-remove-obsolete-info-about-GPT-from-man-page.patch
new file mode 100644
index 0000000..fb8be18
--- /dev/null
+++ b/SOURCES/0128-fdisk-remove-obsolete-info-about-GPT-from-man-page.patch
@@ -0,0 +1,33 @@
+From 81ffb923caad0eff603c708cc4d2fe0e3cff295f Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Mon, 16 Oct 2017 12:20:40 +0200
+Subject: [PATCH 128/135] fdisk: remove obsolete info about GPT from man page
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1490984
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ fdisks/fdisk.8 | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+diff --git a/fdisks/fdisk.8 b/fdisks/fdisk.8
+index e4e585f12..39e4ad5c3 100644
+--- a/fdisks/fdisk.8
++++ b/fdisks/fdisk.8
+@@ -33,12 +33,8 @@ fdisk \- manipulate disk partition table
+ (in the first form of invocation)
+ is a menu-driven program for creation and manipulation of
+ partition tables.
+-It understands DOS-type partition tables and BSD- or SUN-type disklabels.
+-
+-.B fdisk
+-does not understand GUID partition tables (GPTs) and it is not designed
+-for large partitions.  In these cases, use the more advanced GNU
+-.BR parted (8).
++It understands GPT (experimental for now), MBR, Sun, SGI and BSD
++partition tables.
+ 
+ .B fdisk
+ does not use DOS-compatible mode and cylinders as display units by default.
+-- 
+2.13.6
+
diff --git a/SOURCES/0129-libfdisk-gpt-sync-type-UUIDs-with-upstream.patch b/SOURCES/0129-libfdisk-gpt-sync-type-UUIDs-with-upstream.patch
new file mode 100644
index 0000000..4419581
--- /dev/null
+++ b/SOURCES/0129-libfdisk-gpt-sync-type-UUIDs-with-upstream.patch
@@ -0,0 +1,112 @@
+From bef54812223745e19561096283653048eae62d90 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Mon, 16 Oct 2017 12:28:03 +0200
+Subject: [PATCH 129/135] libfdisk: (gpt) sync type UUIDs with upstream
+
+This commit updates add types introduced by freedesktop.org, Ceph,
+BSD, Plan 9, QNX, Sony, Lenovo, etc.
+
+Upstream: http://github.com/karelzak/util-linux/commit/5aa8d13b13c3c8eddbd9176ef493dfa70a10616b
+Upstream: http://github.com/karelzak/util-linux/commit/5a1b4999f7f9d152654b4af56f73804ce9407844
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1487031
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libfdisk/src/gpt.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++--------
+ 1 file changed, 51 insertions(+), 8 deletions(-)
+
+diff --git a/libfdisk/src/gpt.c b/libfdisk/src/gpt.c
+index 612ce0971..de30b3dcb 100644
+--- a/libfdisk/src/gpt.c
++++ b/libfdisk/src/gpt.c
+@@ -157,27 +157,53 @@ static struct fdisk_parttype gpt_parttypes[] =
+ 	DEF_GUID("C12A7328-F81F-11D2-BA4B-00A0C93EC93B", N_("EFI System")),
+ 
+ 	DEF_GUID("024DEE41-33E7-11D3-9D69-0008C781F39F", N_("MBR partition scheme")),
++	DEF_GUID("D3BFE2DE-3DAF-11DF-BA40-E3A556D89593", N_("Intel Fast Flash")),
++
+ 	/* Hah!IdontneedEFI */
+-	DEF_GUID("21686148-6449-6E6F-744E-656564454649", N_("BIOS boot partition")),
++	DEF_GUID("21686148-6449-6E6F-744E-656564454649", N_("BIOS boot")),
++
++	/* NIH syndrome */
++	DEF_GUID("F4019732-066E-4E12-8273-346C5641494F", N_("Sony boot partition")),
++	DEF_GUID("BFBFAFE7-A34F-448A-9A5B-6213EB736C22", N_("Lenovo boot partition")),
++
++	/* PowerPC reference platform boot partition */
++	DEF_GUID("9E1A2D38-C612-4316-AA26-8B49521E5A8B", N_("PowerPC PReP boot")),
++
++	/* Open Network Install Environment */
++	DEF_GUID("7412F7D5-A156-4B13-81DC-867174929325", N_("ONIE boot")),
++	DEF_GUID("D4E6E2CD-4469-46F3-B5CB-1BFF57AFC149", N_("ONIE config")),
+ 
+ 	/* Windows */
+ 	DEF_GUID("E3C9E316-0B5C-4DB8-817D-F92DF00215AE", N_("Microsoft reserved")),
+ 	DEF_GUID("EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", N_("Microsoft basic data")),
+ 	DEF_GUID("5808C8AA-7E8F-42E0-85D2-E1E90434CFB3", N_("Microsoft LDM metadata")),
+ 	DEF_GUID("AF9B60A0-1431-4F62-BC68-3311714A69AD", N_("Microsoft LDM data")),
+-	DEF_GUID("DE94BBA4-06D1-4D40-A16A-BFD50179D6AC", N_("Windows recovery evironmnet")),
++	DEF_GUID("DE94BBA4-06D1-4D40-A16A-BFD50179D6AC", N_("Windows recovery environment")),
+ 	DEF_GUID("37AFFC90-EF7D-4E96-91C3-2D7AE055B174", N_("IBM General Parallel Fs")),
++	DEF_GUID("E75CAF8F-F680-4CEE-AFA3-B001E56EFC2D", N_("Microsoft Storage Spaces")),
+ 
+ 	/* HP-UX */
+-	DEF_GUID("75894C1E-3AEB-11D3-B7C1-7B03A0000000", N_("HP-UX data partition")),
+-	DEF_GUID("E2A1E728-32E3-11D6-A682-7B03A0000000", N_("HP-UX service partition")),
++	DEF_GUID("75894C1E-3AEB-11D3-B7C1-7B03A0000000", N_("HP-UX data")),
++	DEF_GUID("E2A1E728-32E3-11D6-A682-7B03A0000000", N_("HP-UX service")),
+ 
+-	/* Linux */
++	/* Linux (http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec) */
++	DEF_GUID("0657FD6D-A4AB-43C4-84E5-0933C84B4F4F", N_("Linux swap")),
+ 	DEF_GUID("0FC63DAF-8483-4772-8E79-3D69D8477DE4", N_("Linux filesystem")),
++	DEF_GUID("3B8F8425-20E0-4F3B-907F-1A25A76F98E8", N_("Linux server data")),
++	DEF_GUID("44479540-F297-41B2-9AF7-D131D5F0458A", N_("Linux root (x86)")),
++	DEF_GUID("69DAD710-2CE4-4E3C-B16C-21A1D49ABED3", N_("Linux root (ARM)")),
++	DEF_GUID("4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709", N_("Linux root (x86-64)")),
++	DEF_GUID("B921B045-1DF0-41C3-AF44-4C6F280D3FAE", N_("Linux root (ARM-64)")),
++	DEF_GUID("993D8D3D-F80E-4225-855A-9DAF8ED7EA97", N_("Linux root	(IA-64)")),
++	DEF_GUID("8DA63339-0007-60C0-C436-083AC8230908", N_("Linux reserved")),
++	DEF_GUID("933AC7E1-2EB4-4F13-B844-0E14E2AEF915", N_("Linux home")),
+ 	DEF_GUID("A19D880F-05FC-4D3B-A006-743F0F84911E", N_("Linux RAID")),
+-	DEF_GUID("0657FD6D-A4AB-43C4-84E5-0933C84B4F4F", N_("Linux swap")),
++	DEF_GUID("BC13C2FF-59E6-4262-A352-B275FD6F7172", N_("Linux extended boot")),
+ 	DEF_GUID("E6D6D379-F507-44C2-A23C-238F2A3DF928", N_("Linux LVM")),
+-	DEF_GUID("8DA63339-0007-60C0-C436-083AC8230908", N_("Linux reserved")),
++	/* ... too crazy, ignore for now:
++	DEF_GUID("7FFEC5C9-2D00-49B7-8941-3EA10A5586B7", N_("Linux plain dm-crypt")),
++	DEF_GUID("CA7D7CCB-63ED-4C53-861C-1742536059CC", N_("Linux LUKS")),
++	*/
+ 
+ 	/* FreeBSD */
+ 	DEF_GUID("516E7CB4-6ECF-11D6-8FF8-00022D09712B", N_("FreeBSD data")),
+@@ -230,9 +256,26 @@ static struct fdisk_parttype gpt_parttypes[] =
+ 	DEF_GUID("85D5E45A-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD data")),
+ 	DEF_GUID("85D5E45E-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD boot")),
+ 	DEF_GUID("85D5E45B-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD swap")),
+-	DEF_GUID("0394Ef8B-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD UFS")),
++	DEF_GUID("0394EF8B-237E-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD UFS")),
+ 	DEF_GUID("85D5E45D-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD ZFS")),
+ 	DEF_GUID("85D5E45C-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD Vinum")),
++
++	/* Ceph */
++	DEF_GUID("45B0969E-9B03-4F30-B4C6-B4B80CEFF106", N_("Ceph Journal")),
++	DEF_GUID("45B0969E-9B03-4F30-B4C6-5EC00CEFF106", N_("Ceph Encrypted Journal")),
++	DEF_GUID("4FBD7E29-9D25-41B8-AFD0-062C0CEFF05D", N_("Ceph OSD")),
++	DEF_GUID("4FBD7E29-9D25-41B8-AFD0-5EC00CEFF05D", N_("Ceph crypt OSD")),
++	DEF_GUID("89C57F98-2FE5-4DC0-89C1-F3AD0CEFF2BE", N_("Ceph disk in creation")),
++	DEF_GUID("89C57F98-2FE5-4DC0-89C1-5EC00CEFF2BE", N_("Ceph crypt disk in creation")),
++
++	/* OpenBSD */
++	DEF_GUID("824CC7A0-36A8-11E3-890A-952519AD3F61", N_("OpenBSD data")),
++
++	/* QNX */
++	DEF_GUID("CEF5A9AD-73BC-4601-89F3-CDEEEEE321A1", N_("QNX6 file system")),
++
++	/* Plan 9 */
++	DEF_GUID("C91818F9-8025-47AF-89D2-F030D7000C2C", N_("Plan 9 partition"))
+ };
+ 
+ /* gpt_entry macros */
+-- 
+2.13.6
+
diff --git a/SOURCES/0130-lscpu-cleanup-DMI-detection-return-codes.patch b/SOURCES/0130-lscpu-cleanup-DMI-detection-return-codes.patch
new file mode 100644
index 0000000..d88f229
--- /dev/null
+++ b/SOURCES/0130-lscpu-cleanup-DMI-detection-return-codes.patch
@@ -0,0 +1,87 @@
+From 1b6deafbe0a671d4fd7b8b6e9cc23c8dfcd8683c Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 13 Jun 2017 12:15:11 +0200
+Subject: [PATCH 130/135] lscpu: cleanup DMI detection return codes
+
+Michal wrote:
+ There is weird mix of logic in lscpu-dmi.c which sometimes returns 0 and
+ sometimes -1 on error. Since most checks are if (rc) goto done; this
+ bails out early on error skipping some detection methods. Further, in
+ lscpu.c all following detections are guarder by if(hyper) so returning
+ -1 causes all following methods to be skipped.
+
+Upstream: http://github.com/karelzak/util-linux/commit/c972852b29391c35b1d5c7d3e1e6413e0cc86908
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1468646
+Reported-by: Michal Suchanek <msuchanek@suse.de>
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ sys-utils/lscpu-dmi.c | 21 +++++++++++++--------
+ 1 file changed, 13 insertions(+), 8 deletions(-)
+
+diff --git a/sys-utils/lscpu-dmi.c b/sys-utils/lscpu-dmi.c
+index a8298ff74..e4afd0b92 100644
+--- a/sys-utils/lscpu-dmi.c
++++ b/sys-utils/lscpu-dmi.c
+@@ -172,7 +172,7 @@ done:
+ static int hypervisor_decode_legacy(uint8_t *buf, const char *devmem)
+ {
+ 	if (!checksum(buf, 0x0F))
+-		return HYPER_NONE;
++		return -1;
+ 
+ 	return hypervisor_from_dmi_table(DWORD(buf + 0x08), WORD(buf + 0x06),
+ 			 WORD(buf + 0x0C),
+@@ -252,11 +252,15 @@ int read_hypervisor_dmi(void)
+ 	    || sizeof(uint16_t) != 2
+ 	    || sizeof(uint32_t) != 4
+ 	    || '\0' != 0)
+-		return rc;
++		goto done;
+ 
++	/* -1 : no DMI in /sys,
++	 *  0 : DMI exist, nothing detected (HYPER_NONE)
++	 * >0 : hypervisor detected
++	 */
+ 	rc = hypervisor_decode_sysfw();
+-	if (rc >= 0)
+-		return rc;
++	if (rc >= HYPER_NONE)
++		goto done;
+ 
+ 	/* First try EFI (ia64, Intel-based Mac) */
+ 	switch (address_from_efi(&fp)) {
+@@ -271,8 +275,9 @@ int read_hypervisor_dmi(void)
+ 		goto done;
+ 
+ 	rc = hypervisor_decode_smbios(buf, _PATH_DEV_MEM);
+-	if (rc)
++	if (rc >= HYPER_NONE)
+ 		goto done;
++
+ 	free(buf);
+ 	buf = NULL;
+ memory_scan:
+@@ -285,17 +290,17 @@ memory_scan:
+ 	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)
++			if (rc < 0)
+ 				fp += 16;
+ 
+ 		} else if (memcmp(buf + fp, "_DMI_", 5) == 0)
+ 			rc = hypervisor_decode_legacy(buf + fp, _PATH_DEV_MEM);
+ 
+-		if (rc >= 0)
++		if (rc >= HYPER_NONE)
+ 			break;
+ 	}
+ #endif
+ done:
+ 	free(buf);
+-	return rc;
++	return rc < 0 ? HYPER_NONE : rc;
+ }
+-- 
+2.13.6
+
diff --git a/SOURCES/0131-flock-zero-timeout-is-valid.patch b/SOURCES/0131-flock-zero-timeout-is-valid.patch
new file mode 100644
index 0000000..876da3a
--- /dev/null
+++ b/SOURCES/0131-flock-zero-timeout-is-valid.patch
@@ -0,0 +1,50 @@
+From 31568ef6a91b0f441c64fe79f7fa94a32be4dc97 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 7 Oct 2014 12:12:39 +0200
+Subject: [PATCH 131/135] flock: zero timeout is valid
+
+This patch reverts Sami's "timeout cannot be zero", introduced
+in commit 605325b23b36238c8f3ae165e37cab9064553cf7.
+
+The --timeout 0 has been originally interpreted as --nonblock. The
+patch also add hint about this behavior to the man page.
+
+Upstream: http://github.com/karelzak/util-linux/commit/c4604c38b503c8c46e50fc2048ebbcbcfcad3802
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1455398
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ sys-utils/flock.1 | 4 +++-
+ sys-utils/flock.c | 2 --
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/sys-utils/flock.1 b/sys-utils/flock.1
+index b28526f69..d5e85e082 100644
+--- a/sys-utils/flock.1
++++ b/sys-utils/flock.1
+@@ -83,7 +83,9 @@ Fail if the lock cannot be acquired within
+ Decimal fractional values are allowed.
+ See the
+ .I \-E
+-option for the exit code used.
++option for the exit code used. The zero number of
++.IR seconds
++is interpreted as \fB\-\-nonblock\fR.
+ .TP
+ \fB\-o\fP, \fB\-\-close\fP
+ Close the file descriptor on which the lock is held before executing
+diff --git a/sys-utils/flock.c b/sys-utils/flock.c
+index 18625a029..7dad46af0 100644
+--- a/sys-utils/flock.c
++++ b/sys-utils/flock.c
+@@ -175,8 +175,6 @@ int main(int argc, char *argv[])
+ 			have_timeout = 1;
+ 			strtotimeval_or_err(optarg, &timeout.it_value,
+ 				_("invalid timeout value"));
+-			if (timeout.it_value.tv_sec + timeout.it_value.tv_usec == 0)
+-				errx(EX_USAGE, _("timeout cannot be zero"));
+ 			break;
+ 		case 'E':
+ 			conflict_exit_code = strtos32_or_err(optarg,
+-- 
+2.13.6
+
diff --git a/SOURCES/0132-logger-add-man-page-note-about-the-default-tag.patch b/SOURCES/0132-logger-add-man-page-note-about-the-default-tag.patch
new file mode 100644
index 0000000..d1a5411
--- /dev/null
+++ b/SOURCES/0132-logger-add-man-page-note-about-the-default-tag.patch
@@ -0,0 +1,28 @@
+From b97b85baf6281745b7f720a35d9e4bcc26e9ddcb Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Mon, 16 May 2016 15:05:28 +0200
+Subject: [PATCH 132/135] logger: add man page note about the default --tag
+
+Upstream: http://github.com/karelzak/util-linux/commit/28b6c76f8a4ea1faa80fe779c2011bc433de28c6
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1336432
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ misc-utils/logger.1 | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/misc-utils/logger.1 b/misc-utils/logger.1
+index 57ca0d55a..3b55c8d7d 100644
+--- a/misc-utils/logger.1
++++ b/misc-utils/logger.1
+@@ -110,6 +110,8 @@ Output the message to standard error as well as to the system log.
+ \fB\-t\fR, \fB\-\-tag\fR \fItag\fR
+ Mark every line to be logged with the specified
+ .IR tag .
++The default tag is the name of the user logged in on the terminal (or a user
++name based on effective user ID).
+ .TP
+ \fB\-u\fR, \fB\-\-socket\fR \fIsocket\fR
+ Write to the specified
+-- 
+2.13.6
+
diff --git a/SOURCES/0133-script-use-all-io-to-write.patch b/SOURCES/0133-script-use-all-io-to-write.patch
new file mode 100644
index 0000000..090aa9f
--- /dev/null
+++ b/SOURCES/0133-script-use-all-io-to-write.patch
@@ -0,0 +1,61 @@
+From 214d0ef6ac63442c285dd5d9d54190c62faf50d7 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Mon, 16 Oct 2017 13:30:44 +0200
+Subject: [PATCH 133/135] script: use all-io to write
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1427500
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ term-utils/script.c | 12 ++++--------
+ 1 file changed, 4 insertions(+), 8 deletions(-)
+
+diff --git a/term-utils/script.c b/term-utils/script.c
+index 242b8154a..5840b600d 100644
+--- a/term-utils/script.c
++++ b/term-utils/script.c
+@@ -62,6 +62,7 @@
+ #include "closestream.h"
+ #include "nls.h"
+ #include "c.h"
++#include "all-io.h"
+ 
+ #if defined(HAVE_LIBUTIL) && defined(HAVE_PTY_H)
+ # include <pty.h>
+@@ -301,8 +302,7 @@ doinput(void) {
+ 
+ 	while (die == 0) {
+ 		if ((cc = read(STDIN_FILENO, ibuf, BUFSIZ)) > 0) {
+-			ssize_t wrt = write(master, ibuf, cc);
+-			if (wrt < 0) {
++			if (write_all(master, ibuf, cc)) {
+ 				warn (_("write failed"));
+ 				fail();
+ 			}
+@@ -355,8 +355,6 @@ dooutput(FILE *timingfd) {
+ 	struct timeval tv;
+ 	double oldtime=time(NULL), newtime;
+ 	int flgs = 0;
+-	ssize_t wrt;
+-	ssize_t fwrt;
+ 
+ 	close(STDIN_FILENO);
+ #ifdef HAVE_LIBUTIL
+@@ -393,13 +391,11 @@ dooutput(FILE *timingfd) {
+ 			fprintf(timingfd, "%f %zd\n", newtime - oldtime, cc);
+ 			oldtime = newtime;
+ 		}
+-		wrt = write(STDOUT_FILENO, obuf, cc);
+-		if (wrt < 0) {
++		if (write_all(STDOUT_FILENO, obuf, cc)) {
+ 			warn (_("write failed"));
+ 			fail();
+ 		}
+-		fwrt = fwrite(obuf, 1, cc, fscript);
+-		if (fwrt < cc) {
++		if (fwrite_all(obuf, 1, cc, fscript)) {
+ 			warn (_("cannot write script file"));
+ 			fail();
+ 		}
+-- 
+2.13.6
+
diff --git a/SOURCES/0134-logger-do-not-rely-only-getlogin-3-telling-who-ran-t.patch b/SOURCES/0134-logger-do-not-rely-only-getlogin-3-telling-who-ran-t.patch
new file mode 100644
index 0000000..c066d9a
--- /dev/null
+++ b/SOURCES/0134-logger-do-not-rely-only-getlogin-3-telling-who-ran-t.patch
@@ -0,0 +1,79 @@
+From 70ed51ccc2e8e6c4976d422af960e4232210fb99 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Mon, 16 Oct 2017 13:31:47 +0200
+Subject: [PATCH 134/135] logger: do not rely only getlogin(3) telling who ran
+ the command
+
+The getlogin(3) is known not to always work, and when that happens it
+is reasonable to try determine user of name by looking process owner
+and passwd information.
+
+Upstream: http://github.com/karelzak/util-linux/commit/019b97024fde3f07eaf541eef990762483369a11
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1336432
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ misc-utils/logger.c | 25 ++++++++++++++++---------
+ 1 file changed, 16 insertions(+), 9 deletions(-)
+
+diff --git a/misc-utils/logger.c b/misc-utils/logger.c
+index dfda01866..c1cec45e8 100644
+--- a/misc-utils/logger.c
++++ b/misc-utils/logger.c
+@@ -49,6 +49,8 @@
+ #include <arpa/inet.h>
+ #include <netdb.h>
+ #include <getopt.h>
++#include <sys/types.h>
++#include <pwd.h>
+ 
+ #include "c.h"
+ #include "closestream.h"
+@@ -183,9 +185,20 @@ inet_socket(const char *servername, const char *port, const int socket_type)
+ 	return fd;
+ }
+ 
++static char const *xgetlogin(void)
++{
++	char const *cp;
++	struct passwd *pw;
++
++	if (!(cp = getlogin()) || !*cp)
++		cp = (pw = getpwuid(geteuid()))? pw->pw_name : "<someone>";
++	return cp;
++}
++
+ static void
+ mysyslog(int fd, int logflags, int pri, char *tag, char *msg) {
+-       char *buf, pid[30], *cp, *tp;
++       char *buf, pid[30], *tp;
++       const char *cp;
+        time_t now;
+ 
+        if (fd > -1) {
+@@ -193,13 +206,7 @@ mysyslog(int fd, int logflags, int pri, char *tag, char *msg) {
+                        snprintf (pid, sizeof(pid), "[%d]", getpid());
+ 	       else
+ 		       pid[0] = 0;
+-               if (tag)
+-		       cp = tag;
+-	       else {
+-		       cp = getlogin();
+-		       if (!cp)
+-			       cp = "<someone>";
+-	       }
++	       cp = tag ? tag : xgetlogin();
+                (void)time(&now);
+ 	       tp = ctime(&now)+4;
+ 
+@@ -334,7 +341,7 @@ main(int argc, char **argv) {
+ 	else if (usock)
+ 		LogSock = unix_socket(usock, socket_type);
+ 	else
+-		openlog(tag ? tag : getlogin(), logflags, 0);
++		openlog(tag ? tag : xgetlogin(), logflags, 0);
+ 
+ 	buf = xcalloc(1, max_message_size);
+ 
+-- 
+2.13.6
+
diff --git a/SOURCES/0135-login-use-IPv4-on-IPv4-mapping-to-IPv6.patch b/SOURCES/0135-login-use-IPv4-on-IPv4-mapping-to-IPv6.patch
new file mode 100644
index 0000000..8d1c955
--- /dev/null
+++ b/SOURCES/0135-login-use-IPv4-on-IPv4-mapping-to-IPv6.patch
@@ -0,0 +1,52 @@
+From 7a1a825c7b77785f256e05b1e3ac7676c7485a5c Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 4 Jul 2017 12:50:39 +0200
+Subject: [PATCH 135/135] login: use IPv4 on IPv4-mapping-to-IPv6
+
+It seems that on some systems (e.g. RHEL7) the libc function
+getaddrinfo() is not able to translate ::ffff: address to IPv4. The
+result is 0.0.0.0 host address in the last(1) and utmpdump(1) output.
+
+ /sbin/login -h "::ffff:192.168.1.7"
+
+utmpdump:
+
+  [7] [03926] [1   ] [user1   ] [pts/1       ] [::ffff:192.168.1.7  ] [0.0.0.0        ] [Thu May 12 17:49:50 2016    ]
+
+Not sure if this is about order of the getaddrinfo() results, system
+configuration or libc version. It's irrelevant for login(1). We have
+to be robust enough to write usable address to log files everywhere.
+
+The solution is to detect IPv4-mapping-to-IPv6 and use IPv4 for utmp.
+
+Upstream: http://github.com/karelzak/util-linux/commit/1c8792f1ae7fa38cf1d4418ad99c207f65dfdb1a
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1296233
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ login-utils/login.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/login-utils/login.c b/login-utils/login.c
+index e0e960f88..5c36953ef 100644
+--- a/login-utils/login.c
++++ b/login-utils/login.c
+@@ -1101,8 +1101,15 @@ static void init_remote_info(struct login_context *cxt, char *remotehost)
+ 		} else if (info->ai_family == AF_INET6) {
+ 			struct sockaddr_in6 *sa =
+ 				     (struct sockaddr_in6 *) info->ai_addr;
++#ifdef IN6_IS_ADDR_V4MAPPED
++			if (IN6_IS_ADDR_V4MAPPED(&sa->sin6_addr)) {
++				const uint8_t *bytes = sa->sin6_addr.s6_addr;
++				struct in_addr addr = { *(const in_addr_t *) (bytes + 12) };
+ 
+-			memcpy(cxt->hostaddress, &(sa->sin6_addr), sizeof(sa->sin6_addr));
++				memcpy(cxt->hostaddress, &addr, sizeof(struct in_addr));
++			} else
++#endif
++				memcpy(cxt->hostaddress, &(sa->sin6_addr), sizeof(sa->sin6_addr));
+ 		}
+ 		freeaddrinfo(info);
+ 	}
+-- 
+2.13.6
+
diff --git a/SOURCES/0136-blkid-update-man-page-about-lsblk-and-ambivalent-pro.patch b/SOURCES/0136-blkid-update-man-page-about-lsblk-and-ambivalent-pro.patch
new file mode 100644
index 0000000..342f5d9
--- /dev/null
+++ b/SOURCES/0136-blkid-update-man-page-about-lsblk-and-ambivalent-pro.patch
@@ -0,0 +1,85 @@
+From d7725fb45fe8d4fcb67cb9fbc117bc1cf66fcd56 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 17 Oct 2017 10:44:01 +0200
+Subject: [PATCH 136/141] blkid: update man page about lsblk and ambivalent
+ probing
+
+Upstream: http://github.com/karelzak/util-linux/commit/12786a901520d7b30ff75ee8727221bf8a3089cb
+Upstream: http://github.com/karelzak/util-linux/commit/27fbfef33c1f23b5448b6cee856bcb3500b33c42
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1501953
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ misc-utils/blkid.8 | 39 +++++++++++++++++++++++++++------------
+ 1 file changed, 27 insertions(+), 12 deletions(-)
+
+diff --git a/misc-utils/blkid.8 b/misc-utils/blkid.8
+index a974b8e99..1f12d202a 100644
+--- a/misc-utils/blkid.8
++++ b/misc-utils/blkid.8
+@@ -61,6 +61,23 @@ library.  It can determine the type of content (e.g. filesystem or swap)
+ that a block device holds, and also the attributes (tokens, NAME=value pairs)
+ from the content metadata (e.g. LABEL or UUID fields).
+ .PP
++.B It is recommended to use
++.BR lsblk (8)
++.B command to get information about block devices, or lsblk --fs to get an overview of filesystems, or
++.BR findmnt (8)
++.B to search in already mounted filesystems.
++.PP
++.RS
++.BR lsblk (8)
++provides more information, better control on output formatting, easy to use in
++scripts and it does not require root permissions to get actual information.
++.B blkid
++reads information directly from devices and for non-root users
++it returns cached unverified information.
++.B blkid
++is mostly designed for system services and to test libblkid functionality.
++.RE
++.PP
+ When
+ .I device
+ is specified, tokens from only this device are displayed.
+@@ -71,21 +88,19 @@ If none is given, all devices which appear in
+ .I /proc/partitions
+ are shown, if they are recognized.
+ .PP
+-Note that
+-.B blkid
+-reads information directly from devices and for non-root users
+-it returns cached unverified information.  It is better to use
+-.B lsblk --fs
+-to get a user-friendly overview of filesystems and devices.
+-.BR lsblk (8)
+-is also easy to use in scripts.
+-.B blkid
+-is mostly designed for system services and to test libblkid functionality.
+-.PP
+ .B blkid
+ has two main forms of operation: either searching for a device with a
+ specific NAME=value pair, or displaying NAME=value pairs for one or
+ more specified devices.
++.PP
++For security reasons
++.B blkid
++silently ignores all devices where the probing result is ambivalent (multiple
++colliding filesystems are detected).  The low-level probing mode (\fB-p\fR)
++provides more information and extra return code in this case.
++It's recommended to use
++.BR wipefs (8)
++to get a detailed overview and to erase obsolete stuff (magic strings) from the device.
+ .SH OPTIONS
+ The \fIsize\fR and \fIoffset\fR arguments may be followed by the multiplicative
+ suffixes like KiB (=1024), MiB (=1024*1024), and so on for GiB, TiB, PiB, EiB, ZiB and YiB
+@@ -264,7 +279,7 @@ identified, an exit code of 2 is returned.
+ 
+ For usage or other errors, an exit code of 4 is returned.
+ 
+-If an ambivalent low-level probing result was detected, an exit code of 8 is
++If an ambivalent probing result was detected by low-level probing mode (\fB\-p\fR), an exit code of 8 is
+ returned.
+ .SH CONFIGURATION FILE
+ The standard location of the
+-- 
+2.13.6
+
diff --git a/SOURCES/0137-wipefs-fix-t-filter.patch b/SOURCES/0137-wipefs-fix-t-filter.patch
new file mode 100644
index 0000000..84e8954
--- /dev/null
+++ b/SOURCES/0137-wipefs-fix-t-filter.patch
@@ -0,0 +1,69 @@
+From df6302339ae99535d3c075712db8cadeedbb6c00 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 17 Oct 2017 11:07:56 +0200
+Subject: [PATCH 137/141] wipefs: fix -t filter
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1486777
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ misc-utils/wipefs.c | 15 ++++++++++++---
+ 1 file changed, 12 insertions(+), 3 deletions(-)
+
+diff --git a/misc-utils/wipefs.c b/misc-utils/wipefs.c
+index 0144c9ef8..a0852aa97 100644
+--- a/misc-utils/wipefs.c
++++ b/misc-utils/wipefs.c
+@@ -162,13 +162,16 @@ clone_offset(struct wipe_desc *wp0)
+ }
+ 
+ static struct wipe_desc *
+-get_desc_for_probe(struct wipe_desc *wp, blkid_probe pr)
++get_desc_for_probe(struct wipe_desc *wp, blkid_probe pr, int *found)
+ {
+ 	const char *off, *type, *mag, *p, *usage = NULL;
+ 	size_t len;
+ 	loff_t offset;
+ 	int rc, ispt = 0;
+ 
++	if (found)
++		*found = 0;
++
+ 	/* superblocks */
+ 	if (blkid_probe_lookup_value(pr, "TYPE", &type, NULL) == 0) {
+ 		rc = blkid_probe_lookup_value(pr, "SBMAGIC_OFFSET", &off, NULL);
+@@ -215,6 +218,8 @@ get_desc_for_probe(struct wipe_desc *wp, blkid_probe pr)
+ 	if (blkid_probe_lookup_value(pr, "UUID", &p, NULL) == 0)
+ 		wp->uuid = xstrdup(p);
+ 
++	if (found)
++		*found = 1;
+ 	return wp;
+ }
+ 
+@@ -266,7 +271,7 @@ read_offsets(struct wipe_desc *wp, const char *devname)
+ 		return NULL;
+ 
+ 	while (blkid_do_probe(pr) == 0) {
+-		wp = get_desc_for_probe(wp, pr);
++		wp = get_desc_for_probe(wp, pr, NULL);
+ 		if (!wp)
+ 			break;
+ 	}
+@@ -347,9 +352,13 @@ do_wipe(struct wipe_desc *wp, const char *devname, int noact, int all, int quiet
+ 	wp0 = clone_offset(wp);
+ 
+ 	while (blkid_do_probe(pr) == 0) {
+-		wp = get_desc_for_probe(wp, pr);
++		int found = 0;
++
++		wp = get_desc_for_probe(wp, pr, &found);
+ 		if (!wp)
+ 			break;
++		if (!found)
++			continue;
+ 
+ 		/* Check if offset is in provided list */
+ 		w = wp0;
+-- 
+2.13.6
+
diff --git a/SOURCES/0138-tests-backport-new-ts_scsi_debug_init.patch b/SOURCES/0138-tests-backport-new-ts_scsi_debug_init.patch
new file mode 100644
index 0000000..e3eba23
--- /dev/null
+++ b/SOURCES/0138-tests-backport-new-ts_scsi_debug_init.patch
@@ -0,0 +1,105 @@
+From 84995ef8ff7b76cff1cce438fc448f0afa560e23 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 17 Oct 2017 12:16:27 +0200
+Subject: [PATCH 138/141] tests: backport new ts_scsi_debug_init
+
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ tests/functions.sh | 76 +++++++++++++++++++++++++++++++++++++++++++++++-------
+ 1 file changed, 66 insertions(+), 10 deletions(-)
+
+diff --git a/tests/functions.sh b/tests/functions.sh
+index 0d1c9c88a..b930dfe7e 100644
+--- a/tests/functions.sh
++++ b/tests/functions.sh
+@@ -502,21 +502,77 @@ function ts_fdisk_clean {
+ }
+ 
+ function ts_scsi_debug_init {
++	local devname
++	local t
++	TS_DEVICE="none"
+ 
+-	modprobe --dry-run --quiet scsi_debug
+-	[ "$?" == 0 ] || ts_skip "missing scsi_debug module"
++	# dry run is not really reliable, real modprobe may still fail
++	modprobe --dry-run --quiet scsi_debug &>/dev/null \
++		|| ts_skip "missing scsi_debug module (dry-run)"
+ 
+-	rmmod scsi_debug &> /dev/null
+-	modprobe scsi_debug $*
+-	[ "$?" == 0 ] || ts_die "Cannot init device"
++	# skip if still in use or removal of modules not supported at all
++	# We don't want a slow timeout here so we don't use ts_scsi_debug_rmmod!
++	modprobe -r scsi_debug &>/dev/null \
++		|| ts_skip "cannot remove scsi_debug module (rmmod)"
+ 
+-	DEVNAME=$(grep --with-filename scsi_debug /sys/block/*/device/model | awk -F '/' '{print $4}')
+-	[ "x${DEVNAME}" == "x" ] && ts_die "Cannot find device"
++	modprobe -b scsi_debug "$@" &>/dev/null \
++		|| ts_skip "cannot load scsi_debug module (modprobe)"
+ 
+-	DEVICE="/dev/${DEVNAME}"
++	# it might be still not loaded, modprobe.conf or whatever
++	lsmod 2>/dev/null | grep -q "^scsi_debug " \
++		|| ts_skip "scsi_debug module not loaded (lsmod)"
+ 
+-	sleep 1
+ 	udevadm settle
+ 
+-	echo $DEVICE
++	# wait for device if udevadm settle does not work
++	for t in 0 0.02 0.05 0.1 1; do
++		sleep $t
++		devname=$(grep --with-filename scsi_debug /sys/block/*/device/model) && break
++	done
++	[ -n "${devname}" ] || ts_die "timeout waiting for scsi_debug device"
++
++	devname=$(echo $devname | awk -F '/' '{print $4}')
++	TS_DEVICE="/dev/${devname}"
++
++	# TODO validate that device is really up, for now just a warning on stderr
++	test -b $TS_DEVICE || echo "warning: scsi_debug device is still down" >&2
++}
++
++# automatically called once in ts_cleanup_on_exit()
++function ts_scsi_debug_rmmod {
++	local err=1
++	local t
++	local lastmsg
++
++	# Return early most importantly in case we are not root or the module does
++	# not exist at all.
++	[ $UID -eq 0 ] || return 0
++	[ -n "$TS_DEVICE" ] || return 0
++	lsmod 2>/dev/null | grep -q "^scsi_debug " || return 0
++
++	udevadm settle
++
++	# wait for successful rmmod if udevadm settle does not work
++	for t in 0 0.02 0.05 0.1 1; do
++		sleep $t
++		lastmsg="$(modprobe -r scsi_debug 2>&1)" && err=0 && break
++	done
++
++	if [ "$err" = "1" ]; then
++		ts_log "rmmod failed: '$lastmsg'"
++		ts_log "timeout removing scsi_debug module (rmmod)"
++		return 1
++	fi
++	if lsmod | grep -q "^scsi_debug "; then
++		ts_log "BUG! scsi_debug still loaded"
++		return 1
++	fi
++
++	# TODO Do we need to validate that all devices are gone?
++	udevadm settle
++	test -b "$TS_DEVICE" && echo "warning: scsi_debug device is still up" >&2
++
++	# TODO unset TS_DEVICE, check that nobody uses it later, e.g. ts_fdisk_clean
++
++	return 0
+ }
+-- 
+2.13.6
+
diff --git a/SOURCES/0139-tests-ts_scsi_debug_init-must-not-run-in-a-subshell.patch b/SOURCES/0139-tests-ts_scsi_debug_init-must-not-run-in-a-subshell.patch
new file mode 100644
index 0000000..a2356df
--- /dev/null
+++ b/SOURCES/0139-tests-ts_scsi_debug_init-must-not-run-in-a-subshell.patch
@@ -0,0 +1,558 @@
+From 9e643d190c1c3b39423c4d00f1ddc89e2b4cc09e Mon Sep 17 00:00:00 2001
+From: Ruediger Meier <ruediger.meier@ga-group.nl>
+Date: Sun, 11 May 2014 08:50:28 +0200
+Subject: [PATCH 139/141] tests: ts_scsi_debug_init must not run in a subshell
+
+ts_skip and ts_die won't work from subshell. Now we simply use
+TS_DEVICE which is globally set in that function.
+
+I've made sure that we never change TS_DEVICE variable after
+we've got it. So we could use it again for cleanup on exit in
+ts_{finalize,die,skip} functions.
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1454652
+Upstream: http://github.com/karelzak/util-linux/commit/f45df374ffc311220bd395da985b121eccfb4045
+Signed-off-by: Karel Zak <kzak@redhat.com>
+Signed-off-by: Ruediger Meier <ruediger.meier@ga-group.nl>
+---
+ tests/ts/blkid/md-raid1-part          | 25 +++++++++++++++-------
+ tests/ts/eject/umount                 | 39 ++++++++++++++++++-----------------
+ tests/ts/fdisk/align-512-4K           |  9 ++++----
+ tests/ts/fdisk/align-512-4K-63        |  9 ++++----
+ tests/ts/fdisk/align-512-4K-md        | 12 ++++++-----
+ tests/ts/fdisk/align-512-512-topology | 10 ++++-----
+ tests/ts/libmount/context             |  9 ++++----
+ tests/ts/libmount/context-utab        |  9 ++++----
+ tests/ts/libmount/tabfiles-tags       | 15 +++++++-------
+ tests/ts/mount/umount-alltargets      | 29 +++++++++++++-------------
+ tests/ts/mount/umount-recursive       | 21 ++++++++++---------
+ 11 files changed, 104 insertions(+), 83 deletions(-)
+
+diff --git a/tests/ts/blkid/md-raid1-part b/tests/ts/blkid/md-raid1-part
+index 46bde0ec8..20612ec21 100755
+--- a/tests/ts/blkid/md-raid1-part
++++ b/tests/ts/blkid/md-raid1-part
+@@ -23,10 +23,11 @@ TS_DESC="MD raid1 (last partition)"
+ ts_init "$*"
+ ts_skip_nonroot
+ 
+-DEVICE=$(ts_scsi_debug_init dev_size_mb=51 sector_size=512)
++# set global variable TS_DEVICE
++ts_scsi_debug_init dev_size_mb=51 sector_size=512
+ 
+ ts_log "Create partitions"
+-$TS_CMD_FDISK ${DEVICE} >> $TS_OUTPUT 2>&1 <<EOF
++$TS_CMD_FDISK ${TS_DEVICE} >> $TS_OUTPUT 2>&1 <<EOF
+ n
+ p
+ 1
+@@ -42,6 +43,16 @@ w
+ q
+ EOF
+ 
++# replace generated ID with something stable
++$TS_CMD_FDISK ${TS_DEVICE} &> /dev/null <<EOF
++x
++i
++0x1
++r
++w
++q
++EOF
++
+ udevadm settle
+ MD_DEVNAME=md8
+ MD_DEVICE=/dev/${MD_DEVNAME}
+@@ -49,24 +60,24 @@ MD_DEVICE=/dev/${MD_DEVNAME}
+ ts_log "Create RAID1 device"
+ /sbin/mdadm -q -S ${MD_DEVICE} &> /dev/null
+ /sbin/mdadm -q --create ${MD_DEVICE} --metadata=0.90 --chunk=64 --level=1 \
+-	    --raid-devices=2 ${DEVICE}1 ${DEVICE}2 >> $TS_OUTPUT 2>&1
++	    --raid-devices=2 ${TS_DEVICE}1 ${TS_DEVICE}2 >> $TS_OUTPUT 2>&1
+ udevadm settle
+ 
+ ts_log "Probe whole-disk"
+-$TS_CMD_BLKID -p -o udev ${DEVICE} 2>&1 | sort >> $TS_OUTPUT
++$TS_CMD_BLKID -p -o udev ${TS_DEVICE} 2>&1 | sort >> $TS_OUTPUT
+ 
+ ts_log "Probe first RAID member"
+-$TS_CMD_BLKID -p -o udev ${DEVICE}1 2>&1 | sort >> $TS_OUTPUT
++$TS_CMD_BLKID -p -o udev ${TS_DEVICE}1 2>&1 | sort >> $TS_OUTPUT
+ 
+ ts_log "Probe second RAID member"
+-$TS_CMD_BLKID -p -o udev ${DEVICE}2 2>&1 | sort >> $TS_OUTPUT
++$TS_CMD_BLKID -p -o udev ${TS_DEVICE}2 2>&1 | sort >> $TS_OUTPUT
+ 
+ /sbin/mdadm -q -S ${MD_DEVICE} >> $TS_OUTPUT 2>&1
+ 
+ udevadm settle
+ rmmod scsi_debug
+ 
+-ts_fdisk_clean $DEVICE
++ts_fdisk_clean $TS_DEVICE
+ # substitue UUIDs and major/minor number before comparison
+ sed -i \
+   -e         's/^\(ID_FS_UUID\)=.*/\1=__ts_uuid__/' \
+diff --git a/tests/ts/eject/umount b/tests/ts/eject/umount
+index 3c1f84edf..994ddb483 100755
+--- a/tests/ts/eject/umount
++++ b/tests/ts/eject/umount
+@@ -12,6 +12,7 @@ ts_skip_nonroot
+ # not removable device.
+ #
+ 
++# set global variable TS_DEVICE
+ function init_device {
+ 	ts_scsi_debug_init dev_size_mb=100
+ }
+@@ -47,50 +48,50 @@ function deinit_device {
+ 
+ 
+ ts_init_subtest "by-disk"
+-DEVICE=$(init_device)
+-$TS_CMD_EJECT --force $DEVICE && ts_log "Success"
++init_device
++$TS_CMD_EJECT --force $TS_DEVICE && ts_log "Success"
+ deinit_device
+ ts_finalize_subtest
+ 
+ ts_init_subtest "by-disk-mounted"
+-DEVICE=$(init_device)
+-mkfs.ext2 -q -F $DEVICE
++init_device
++mkfs.ext2 -q -F $TS_DEVICE
+ udevadm settle
+ mkdir -p $TS_MOUNTPOINT
+-mount $DEVICE $TS_MOUNTPOINT
+-$TS_CMD_EJECT --force $DEVICE && ts_log "Success"
++mount $TS_DEVICE $TS_MOUNTPOINT
++$TS_CMD_EJECT --force $TS_DEVICE && ts_log "Success"
+ deinit_device
+ ts_finalize_subtest
+ 
+ 
+ ts_init_subtest "by-disk-mounted-partition"
+-DEVICE=$(init_device)
+-init_partitions $DEVICE
++init_device
++init_partitions $TS_DEVICE
+ mkdir -p ${TS_MOUNTPOINT}1
+ mkdir -p ${TS_MOUNTPOINT}2
+-mount ${DEVICE}1 ${TS_MOUNTPOINT}1
+-mount ${DEVICE}2 ${TS_MOUNTPOINT}2
+-$TS_CMD_EJECT --force $DEVICE && ts_log "Success"
++mount ${TS_DEVICE}1 ${TS_MOUNTPOINT}1
++mount ${TS_DEVICE}2 ${TS_MOUNTPOINT}2
++$TS_CMD_EJECT --force $TS_DEVICE && ts_log "Success"
+ deinit_device
+ ts_finalize_subtest
+ 
+ 
+ ts_init_subtest "by-partition"
+-DEVICE=$(init_device)
+-init_partitions $DEVICE
+-$TS_CMD_EJECT --force ${DEVICE}1 && ts_log "Success"
++init_device
++init_partitions $TS_DEVICE
++$TS_CMD_EJECT --force ${TS_DEVICE}1 && ts_log "Success"
+ deinit_device
+ ts_finalize_subtest
+ 
+ 
+ ts_init_subtest "by-partition-mounted"
+-DEVICE=$(init_device)
+-init_partitions $DEVICE
++init_device
++init_partitions $TS_DEVICE
+ mkdir -p ${TS_MOUNTPOINT}1
+ mkdir -p ${TS_MOUNTPOINT}2
+-mount ${DEVICE}1 ${TS_MOUNTPOINT}1
+-mount ${DEVICE}2 ${TS_MOUNTPOINT}2
+-$TS_CMD_EJECT --force ${DEVICE}1 && ts_log "Success"
++mount ${TS_DEVICE}1 ${TS_MOUNTPOINT}1
++mount ${TS_DEVICE}2 ${TS_MOUNTPOINT}2
++$TS_CMD_EJECT --force ${TS_DEVICE}1 && ts_log "Success"
+ deinit_device
+ ts_finalize_subtest
+ 
+diff --git a/tests/ts/fdisk/align-512-4K b/tests/ts/fdisk/align-512-4K
+index c5ea72e7a..5608b1b65 100755
+--- a/tests/ts/fdisk/align-512-4K
++++ b/tests/ts/fdisk/align-512-4K
+@@ -27,11 +27,12 @@ TS_DESC="align 512/4K"
+ ts_init "$*"
+ ts_skip_nonroot
+ 
+-DEVICE=$(ts_scsi_debug_init dev_size_mb=50 sector_size=512 physblk_exp=3)
+-DEVNAME=$(basename $DEVICE)
++# set global variable TS_DEVICE
++ts_scsi_debug_init dev_size_mb=50 sector_size=512 physblk_exp=3
++DEVNAME=$(basename $TS_DEVICE)
+ 
+ ts_log "Create partitions"
+-$TS_CMD_FDISK ${DEVICE} >> $TS_OUTPUT 2>&1 <<EOF
++$TS_CMD_FDISK ${TS_DEVICE} >> $TS_OUTPUT 2>&1 <<EOF
+ n
+ p
+ 1
+@@ -71,6 +72,6 @@ cat /sys/block/${DEVNAME}/${DEVNAME}{1,2,3,4,5,6,7}/alignment_offset >> $TS_OUTP
+ 
+ rmmod scsi_debug
+ 
+-ts_fdisk_clean $DEVICE
++ts_fdisk_clean $TS_DEVICE
+ 
+ ts_finalize
+diff --git a/tests/ts/fdisk/align-512-4K-63 b/tests/ts/fdisk/align-512-4K-63
+index 4ec81982f..8199cf7b3 100755
+--- a/tests/ts/fdisk/align-512-4K-63
++++ b/tests/ts/fdisk/align-512-4K-63
+@@ -27,11 +27,12 @@ TS_DESC="align 512/4K +alignment_offset"
+ ts_init "$*"
+ ts_skip_nonroot
+ 
+-DEVICE=$(ts_scsi_debug_init dev_size_mb=50 sector_size=512 physblk_exp=3 lowest_aligned=7)
+-DEVNAME=$(basename $DEVICE)
++# set global variable TS_DEVICE
++ts_scsi_debug_init dev_size_mb=50 sector_size=512 physblk_exp=3 lowest_aligned=7
++DEVNAME=$(basename $TS_DEVICE)
+ 
+ ts_log "Create partitions"
+-$TS_CMD_FDISK ${DEVICE} >> $TS_OUTPUT 2>&1 <<EOF
++$TS_CMD_FDISK ${TS_DEVICE} >> $TS_OUTPUT 2>&1 <<EOF
+ n
+ p
+ 1
+@@ -71,6 +72,6 @@ cat /sys/block/${DEVNAME}/${DEVNAME}{1,2,3,4,5,6,7}/alignment_offset >> $TS_OUTP
+ 
+ rmmod scsi_debug
+ 
+-ts_fdisk_clean $DEVICE
++ts_fdisk_clean $TS_DEVICE
+ 
+ ts_finalize
+diff --git a/tests/ts/fdisk/align-512-4K-md b/tests/ts/fdisk/align-512-4K-md
+index 09947ff9e..ad662e0e8 100755
+--- a/tests/ts/fdisk/align-512-4K-md
++++ b/tests/ts/fdisk/align-512-4K-md
+@@ -27,11 +27,12 @@ TS_DESC="align 512/4K +MD"
+ ts_init "$*"
+ ts_skip_nonroot
+ 
+-DEVICE=$(ts_scsi_debug_init dev_size_mb=50 sector_size=512 physblk_exp=3)
+-DEVNAME=$(basename $DEVICE)
++# set global variable TS_DEVICE
++ts_scsi_debug_init dev_size_mb=50 sector_size=512 physblk_exp=3
++DEVNAME=$(basename $TS_DEVICE)
+ 
+ ts_log "Create partitions"
+-$TS_CMD_FDISK ${DEVICE} >> $TS_OUTPUT 2>&1 <<EOF
++$TS_CMD_FDISK ${TS_DEVICE} >> $TS_OUTPUT 2>&1 <<EOF
+ n
+ p
+ 1
+@@ -56,7 +57,7 @@ MD_DEVICE=/dev/${MD_DEVNAME}
+ 
+ /sbin/mdadm -q -S ${MD_DEVICE} &> /dev/null
+ /sbin/mdadm -q --create ${MD_DEVICE} --metadata=0.90 --chunk=64 \
+-	    --level=0 --raid-devices=2 ${DEVICE}1 ${DEVICE}2 >> $TS_OUTPUT 2>&1
++	    --level=0 --raid-devices=2 ${TS_DEVICE}1 ${TS_DEVICE}2 >> $TS_OUTPUT 2>&1
+ 
+ udevadm settle
+ ts_log "Create partitions (MD)"
+@@ -85,6 +86,7 @@ cat /sys/block/${MD_DEVNAME}/${MD_DEVNAME}p{1,2}/alignment_offset >> $TS_OUTPUT
+ udevadm settle
+ rmmod scsi_debug
+ 
+-ts_fdisk_clean $DEVICE
++ts_fdisk_clean $TS_DEVICE
++ts_fdisk_clean $MD_DEVICE
+ 
+ ts_finalize
+diff --git a/tests/ts/fdisk/align-512-512-topology b/tests/ts/fdisk/align-512-512-topology
+index 9354e45c7..65cb03f1d 100755
+--- a/tests/ts/fdisk/align-512-512-topology
++++ b/tests/ts/fdisk/align-512-512-topology
+@@ -27,12 +27,12 @@ TS_DESC="align 512/512 +topology"
+ ts_init "$*"
+ ts_skip_nonroot
+ 
+-
+-DEVICE=$(ts_scsi_debug_init dev_size_mb=50 sector_size=512)
+-DEVNAME=$(basename $DEVICE)
++# set global variable TS_DEVICE
++ts_scsi_debug_init dev_size_mb=50 sector_size=512
++DEVNAME=$(basename $TS_DEVICE)
+ 
+ ts_log "Create partitions"
+-$TS_CMD_FDISK ${DEVICE} >> $TS_OUTPUT 2>&1 <<EOF
++$TS_CMD_FDISK ${TS_DEVICE} >> $TS_OUTPUT 2>&1 <<EOF
+ n
+ p
+ 1
+@@ -72,6 +72,6 @@ cat /sys/block/${DEVNAME}/${DEVNAME}{1,2,3,4,5,6,7}/alignment_offset >> $TS_OUTP
+ 
+ rmmod scsi_debug
+ 
+-ts_fdisk_clean $DEVICE
++ts_fdisk_clean $TS_DEVICE
+ 
+ ts_finalize
+diff --git a/tests/ts/libmount/context b/tests/ts/libmount/context
+index 0c3bce986..873890378 100755
+--- a/tests/ts/libmount/context
++++ b/tests/ts/libmount/context
+@@ -21,11 +21,12 @@ TS_NOEXIST="$TS_OUTDIR/${TS_TESTNAME}-${TS_SUBNAME}-noex"
+ ts_log "Init device"
+ umount $MOUNTPOINT &> /dev/null
+ 
+-DEVICE=$(ts_scsi_debug_init dev_size_mb=100)
+-DEVNAME=$(basename $DEVICE)
++# set global variable TS_DEVICE
++ts_scsi_debug_init dev_size_mb=100
++DEVNAME=$(basename $TS_DEVICE)
+ 
+ ts_log "Create partitions"
+-$TS_CMD_FDISK ${DEVICE} &> /dev/null <<EOF
++$TS_CMD_FDISK ${TS_DEVICE} &> /dev/null <<EOF
+ n
+ p
+ 1
+@@ -35,7 +36,7 @@ w
+ q
+ EOF
+ 
+-DEVICE="${DEVICE}1"
++DEVICE="${TS_DEVICE}1"
+ 
+ sleep 1
+ udevadm settle
+diff --git a/tests/ts/libmount/context-utab b/tests/ts/libmount/context-utab
+index b2bfefc69..d57a64e6d 100755
+--- a/tests/ts/libmount/context-utab
++++ b/tests/ts/libmount/context-utab
+@@ -16,11 +16,12 @@ MOUNTPOINT="$TS_MOUNTPOINT"
+ 
+ [ -x $TESTPROG ] || ts_skip "test not compiled"
+ 
+-DEVICE=$(ts_scsi_debug_init dev_size_mb=100)
+-DEVNAME=$(basename $DEVICE)
++# set global variable TS_DEVICE
++ts_scsi_debug_init dev_size_mb=100
++DEVNAME=$(basename $TS_DEVICE)
+ 
+ ts_log "Create partitions"
+-$TS_CMD_FDISK ${DEVICE} &> /dev/null <<EOF
++$TS_CMD_FDISK ${TS_DEVICE} &> /dev/null <<EOF
+ n
+ p
+ 1
+@@ -30,7 +31,7 @@ w
+ q
+ EOF
+ 
+-DEVICE="${DEVICE}1"
++DEVICE="${TS_DEVICE}1"
+ 
+ sleep 1
+ udevadm settle
+diff --git a/tests/ts/libmount/tabfiles-tags b/tests/ts/libmount/tabfiles-tags
+index f52c4047c..fbd7daf47 100755
+--- a/tests/ts/libmount/tabfiles-tags
++++ b/tests/ts/libmount/tabfiles-tags
+@@ -11,17 +11,18 @@ TESTPROG="$TS_HELPER_LIBMOUNT_TAB"
+ 
+ [ -x $TESTPROG ] || ts_skip "test not compiled"
+ 
+-DEVICE=$(ts_scsi_debug_init dev_size_mb=50 sector_size=512)
++# set global variable TS_DEVICE
++ts_scsi_debug_init dev_size_mb=50 sector_size=512
+ LABEL="testLibmount"
+ UUID="de1bc6e9-34ab-4151-a1d7-900042eee8d9"
+ 
+ #
+ # Create filesystem
+ #
+-mkfs.ext3 -F -L $LABEL $DEVICE -U $UUID &> /dev/null || ts_die "Cannot make ext3 on $DEVICE" $DEVICE
++mkfs.ext3 -F -L $LABEL $TS_DEVICE -U $UUID &> /dev/null || ts_die "Cannot make ext3 on $TS_DEVICE" $TS_DEVICE
+ udevadm settle
+ 
+-ts_device_has_uuid $DEVICE || ts_die "Cannot find UUID on $DEVICE" $DEVICE
++ts_device_has_uuid $TS_DEVICE || ts_die "Cannot find UUID on $TS_DEVICE" $TS_DEVICE
+ 
+ FSTAB="$TS_OUTDIR/fstab"
+ 
+@@ -36,7 +37,7 @@ sed -i -e 's/fs: 0x.*/fs:/g' $TS_OUTPUT
+ ts_finalize_subtest
+ 
+ ts_init_subtest "fstab-label2dev"
+-ts_valgrind $TESTPROG --find-forward $FSTAB source $DEVICE &> $TS_OUTPUT
++ts_valgrind $TESTPROG --find-forward $FSTAB source $TS_DEVICE &> $TS_OUTPUT
+ sed -i -e 's/fs: 0x.*/fs:/g' $TS_OUTPUT
+ ts_finalize_subtest
+ 
+@@ -60,18 +61,18 @@ ts_finalize_subtest
+ 
+ ts_init_subtest "fstab-dev2label"
+ # has to return /mnt/mountpoint
+-ts_valgrind $TESTPROG --find-forward $FSTAB source $DEVICE &> $TS_OUTPUT
++ts_valgrind $TESTPROG --find-forward $FSTAB source $TS_DEVICE &> $TS_OUTPUT
+ sed -i -e 's/fs: 0x.*/fs:/g' $TS_OUTPUT
+ ts_finalize_subtest
+ 
+ #
+ # Add devname
+ #
+-echo "$DEVICE  /mnt/mountpoint3 auto defaults" >> $FSTAB
++echo "$TS_DEVICE  /mnt/mountpoint3 auto defaults" >> $FSTAB
+ 
+ ts_init_subtest "fstab-dev"
+ # has to return /mnt/mountpoint3
+-ts_valgrind $TESTPROG --find-forward $FSTAB source $DEVICE &> $TS_OUTPUT
++ts_valgrind $TESTPROG --find-forward $FSTAB source $TS_DEVICE &> $TS_OUTPUT
+ sed -i -e 's/fs: 0x.*/fs:/g' $TS_OUTPUT
+ sed -i -e 's/source: .*//g' $TS_OUTPUT		# devname is generated, remove it
+ ts_finalize_subtest
+diff --git a/tests/ts/mount/umount-alltargets b/tests/ts/mount/umount-alltargets
+index 434ecab2d..ae35e320a 100755
+--- a/tests/ts/mount/umount-alltargets
++++ b/tests/ts/mount/umount-alltargets
+@@ -12,10 +12,11 @@ ts_skip_nonroot
+ $TS_CMD_UMOUNT --help | grep -q all-targets
+ [ $? -eq 1 ] && ts_skip "all-targets unsupported"
+ 
+-DEVICE=$(ts_scsi_debug_init dev_size_mb=50)
++# set global variable TS_DEVICE
++ts_scsi_debug_init dev_size_mb=50
+ 
+ ts_log "Create partitions"
+-$TS_CMD_FDISK ${DEVICE} &> /dev/null <<EOF
++$TS_CMD_FDISK ${TS_DEVICE} &> /dev/null <<EOF
+ n
+ p
+ 1
+@@ -42,13 +43,13 @@ EOF
+ udevadm settle
+ 
+ ts_log "Create filesystem A"
+-mkfs.ext2 ${DEVICE}1 &> /dev/null
++mkfs.ext2 ${TS_DEVICE}1 &> /dev/null
+ ts_log "Create filesystem B"
+-mkfs.ext2 ${DEVICE}2 &> /dev/null
++mkfs.ext2 ${TS_DEVICE}2 &> /dev/null
+ ts_log "Create filesystem C"
+-mkfs.ext2 ${DEVICE}3 &> /dev/null
++mkfs.ext2 ${TS_DEVICE}3 &> /dev/null
+ ts_log "Create filesystem D"
+-mkfs.ext2 ${DEVICE}4 &> /dev/null
++mkfs.ext2 ${TS_DEVICE}4 &> /dev/null
+ 
+ udevadm settle
+ 
+@@ -76,7 +77,7 @@ MOUNTPOINT=$TS_MOUNTPOINT
+ # The same device mounted on more places, umount all by mountpoint name
+ #
+ ts_init_subtest "all-targets-mnt"
+-multi_mount ${DEVICE}1 $MOUNTPOINT
++multi_mount ${TS_DEVICE}1 $MOUNTPOINT
+ $TS_CMD_UMOUNT --all-targets ${MOUNTPOINT}1 >> $TS_OUTPUT 2>&1
+ [ $? == 0 ] || ts_log "umount failed"
+ ts_finalize_subtest
+@@ -85,8 +86,8 @@ ts_finalize_subtest
+ # The same device mounted on more places, umount all by device name
+ #
+ ts_init_subtest "all-targets-dev"
+-multi_mount ${DEVICE}1 $MOUNTPOINT
+-$TS_CMD_UMOUNT --all-targets ${DEVICE}1 >> $TS_OUTPUT 2>&1
++multi_mount ${TS_DEVICE}1 $MOUNTPOINT
++$TS_CMD_UMOUNT --all-targets ${TS_DEVICE}1 >> $TS_OUTPUT 2>&1
+ [ $? == 0 ] || ts_log "umount failed"
+ ts_finalize_subtest
+ 
+@@ -95,14 +96,14 @@ ts_finalize_subtest
+ # sub-mounts. Umount all by one umount all by top-level device name.
+ #
+ ts_init_subtest "all-targets-recursive"
+-multi_mount ${DEVICE}1 $MOUNTPOINT
++multi_mount ${TS_DEVICE}1 $MOUNTPOINT
+ [ -d "${MOUNTPOINT}1/subA" ] || mkdir -p ${MOUNTPOINT}1/subA
+-$TS_CMD_MOUNT ${DEVICE}2 ${MOUNTPOINT}1/subA
++$TS_CMD_MOUNT ${TS_DEVICE}2 ${MOUNTPOINT}1/subA
+ [ -d "${MOUNTPOINT}1/subA/subAB" ] || mkdir -p ${MOUNTPOINT}1/subA/subAB
+-$TS_CMD_MOUNT ${DEVICE}3 ${MOUNTPOINT}1/subA/subAB
++$TS_CMD_MOUNT ${TS_DEVICE}3 ${MOUNTPOINT}1/subA/subAB
+ [ -d "${MOUNTPOINT}1/subB" ] || mkdir -p ${MOUNTPOINT}1/subB
+-$TS_CMD_MOUNT ${DEVICE}4 ${MOUNTPOINT}1/subB
+-$TS_CMD_UMOUNT --recursive --all-targets ${DEVICE}1 >> $TS_OUTPUT 2>&1
++$TS_CMD_MOUNT ${TS_DEVICE}4 ${MOUNTPOINT}1/subB
++$TS_CMD_UMOUNT --recursive --all-targets ${TS_DEVICE}1 >> $TS_OUTPUT 2>&1
+ [ $? == 0 ] || ts_log "umount failed"
+ ts_finalize_subtest
+ 
+diff --git a/tests/ts/mount/umount-recursive b/tests/ts/mount/umount-recursive
+index 85e54df7a..9b9a7a1f1 100755
+--- a/tests/ts/mount/umount-recursive
++++ b/tests/ts/mount/umount-recursive
+@@ -13,10 +13,11 @@ $TS_CMD_UMOUNT --help | grep -q recursive
+ [ $? -eq 1 ] && ts_skip "recursive unsupported"
+ 
+ ts_log "Init device"
+-DEVICE=$(ts_scsi_debug_init dev_size_mb=50)
++# set global variable TS_DEVICE
++ts_scsi_debug_init dev_size_mb=50
+ 
+ ts_log "Create partitions"
+-$TS_CMD_FDISK ${DEVICE} &> /dev/null <<EOF
++$TS_CMD_FDISK ${TS_DEVICE} &> /dev/null <<EOF
+ n
+ p
+ 1
+@@ -43,13 +44,13 @@ EOF
+ udevadm settle
+ 
+ ts_log "Create filesystem A"
+-mkfs.ext2 ${DEVICE}1 &> /dev/null
++mkfs.ext2 ${TS_DEVICE}1 &> /dev/null
+ ts_log "Create filesystem B"
+-mkfs.ext2 ${DEVICE}2 &> /dev/null
++mkfs.ext2 ${TS_DEVICE}2 &> /dev/null
+ ts_log "Create filesystem C"
+-mkfs.ext2 ${DEVICE}3 &> /dev/null
++mkfs.ext2 ${TS_DEVICE}3 &> /dev/null
+ ts_log "Create filesystem D"
+-mkfs.ext2 ${DEVICE}4 &> /dev/null
++mkfs.ext2 ${TS_DEVICE}4 &> /dev/null
+ 
+ udevadm settle
+ 
+@@ -58,12 +59,12 @@ ts_log "Do tests..."
+ [ -d "$TS_MOUNTPOINT" ] || mkdir -p $TS_MOUNTPOINT
+ 
+ ts_log "A) Mount root"
+-$TS_CMD_MOUNT ${DEVICE}1 $TS_MOUNTPOINT >> $TS_OUTPUT 2>&1
++$TS_CMD_MOUNT ${TS_DEVICE}1 $TS_MOUNTPOINT >> $TS_OUTPUT 2>&1
+ $TS_CMD_MOUNT --make-shared $TS_MOUNTPOINT
+ 
+ ts_log "B) Mount child"
+ mkdir -p $TS_MOUNTPOINT/mntB
+-$TS_CMD_MOUNT ${DEVICE}2 $TS_MOUNTPOINT/mntB >> $TS_OUTPUT 2>&1
++$TS_CMD_MOUNT ${TS_DEVICE}2 $TS_MOUNTPOINT/mntB >> $TS_OUTPUT 2>&1
+ 
+ ts_log "B2) Mount child-bind"
+ mkdir -p $TS_MOUNTPOINT/bindB
+@@ -71,10 +72,10 @@ $TS_CMD_MOUNT --bind $TS_MOUNTPOINT/mntB $TS_MOUNTPOINT/bindB >> $TS_OUTPUT 2>&1
+ 
+ ts_log "C) Mount child/child"
+ mkdir -p $TS_MOUNTPOINT/mntB/mnt{C,D}
+-$TS_CMD_MOUNT ${DEVICE}3 $TS_MOUNTPOINT/mntB/mntC >> $TS_OUTPUT 2>&1
++$TS_CMD_MOUNT ${TS_DEVICE}3 $TS_MOUNTPOINT/mntB/mntC >> $TS_OUTPUT 2>&1
+ 
+ ts_log "D) Mount child/child"
+-$TS_CMD_MOUNT ${DEVICE}4 $TS_MOUNTPOINT/mntB/mntD >> $TS_OUTPUT 2>&1
++$TS_CMD_MOUNT ${TS_DEVICE}4 $TS_MOUNTPOINT/mntB/mntD >> $TS_OUTPUT 2>&1
+ 
+ ts_log "E) Mount child-bind"
+ mkdir -p $TS_MOUNTPOINT/bindC
+-- 
+2.13.6
+
diff --git a/SOURCES/0140-tests-cleanup-fdisk-outputs.patch b/SOURCES/0140-tests-cleanup-fdisk-outputs.patch
new file mode 100644
index 0000000..37d23a7
--- /dev/null
+++ b/SOURCES/0140-tests-cleanup-fdisk-outputs.patch
@@ -0,0 +1,86 @@
+From 0c4c724109d160e336d38f0a50fd82c9f5184ddb Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 17 Oct 2017 12:35:31 +0200
+Subject: [PATCH 140/141] tests: cleanup fdisk outputs
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1454652
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ tests/expected/fdisk/align-512-4K-md |  6 +++---
+ tests/expected/fdisk/align-512-512   | 16 ++++++++--------
+ tests/ts/fdisk/align-512-512         |  3 +--
+ 3 files changed, 12 insertions(+), 13 deletions(-)
+
+diff --git a/tests/expected/fdisk/align-512-4K-md b/tests/expected/fdisk/align-512-4K-md
+index e8f6ba161..336c9e019 100644
+--- a/tests/expected/fdisk/align-512-4K-md
++++ b/tests/expected/fdisk/align-512-4K-md
+@@ -69,7 +69,7 @@ Select (default p): Partition number (2-4, default 2): First sector (22528-10009
+ Last sector, +sectors or +size{K,M,G} (22528-100095, default 100095): Partition 2 of type Linux and of size 10 MiB is set
+ 
+ Command (m for help): 
+-Disk /dev/md8: 51 MB, 51249152 bytes, 100096 sectors
++Disk /dev/...: 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 / <removed> bytes
+@@ -77,8 +77,8 @@ Disk label type: dos
+ 
+ 
+     Device Boot      Start         End      Blocks   Id  System
+-/dev/md8p1            2048       22527       10240   83  Linux
+-/dev/md8p2           22528       43007       10240   83  Linux
++/dev/...p1            2048       22527       10240   83  Linux
++/dev/...p2           22528       43007       10240   83  Linux
+ 
+ Command (m for help): The partition table has been altered!
+ 
+diff --git a/tests/expected/fdisk/align-512-512 b/tests/expected/fdisk/align-512-512
+index 8e03d900d..f9cbb0e89 100644
+--- a/tests/expected/fdisk/align-512-512
++++ b/tests/expected/fdisk/align-512-512
+@@ -50,7 +50,7 @@ Last sector, +sectors or +size{K,M,G} (90112-102399, default 102399): Using defa
+ Partition 7 of type Linux and of size 6 MiB is set
+ 
+ Command (m for help): 
+-Disk /dev/loop0: 52 MB, 52428800 bytes, 102400 sectors
++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 / <removed> bytes
+@@ -58,12 +58,12 @@ Disk label type: dos
+ 
+ 
+       Device Boot      Start         End      Blocks   Id  System
+-/dev/loop0p1            2048       22527       10240   83  Linux
+-/dev/loop0p2           22528       43007       10240   83  Linux
+-/dev/loop0p3           43008       63487       10240   83  Linux
+-/dev/loop0p4           63488      102399       19456    5  Extended
+-/dev/loop0p5           65536       75775        5120   83  Linux
+-/dev/loop0p6           77824       88063        5120   83  Linux
+-/dev/loop0p7           90112      102399        6144   83  Linux
++/dev/...p1            2048       22527       10240   83  Linux
++/dev/...p2           22528       43007       10240   83  Linux
++/dev/...p3           43008       63487       10240   83  Linux
++/dev/...p4           63488      102399       19456    5  Extended
++/dev/...p5           65536       75775        5120   83  Linux
++/dev/...p6           77824       88063        5120   83  Linux
++/dev/...p7           90112      102399        6144   83  Linux
+ 
+ Command (m for help): 
+diff --git a/tests/ts/fdisk/align-512-512 b/tests/ts/fdisk/align-512-512
+index 82a6268cf..03133a6d1 100755
+--- a/tests/ts/fdisk/align-512-512
++++ b/tests/ts/fdisk/align-512-512
+@@ -64,7 +64,6 @@ q
+ EOF
+ 
+ ts_device_deinit $DEVICE
+-
+-ts_fdisk_clean
++ts_fdisk_clean $DEVICE
+ 
+ ts_finalize
+-- 
+2.13.6
+
diff --git a/SOURCES/0141-tests-check-for-mdadm.patch b/SOURCES/0141-tests-check-for-mdadm.patch
new file mode 100644
index 0000000..c2fc6c7
--- /dev/null
+++ b/SOURCES/0141-tests-check-for-mdadm.patch
@@ -0,0 +1,53 @@
+From 609177ec200592dce34bf0ee082c0d2ac8d01b8b Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 17 Oct 2017 12:35:31 +0200
+Subject: [PATCH 141/141] tests: check for mdadm
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1454652
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ tests/ts/blkid/md-raid1-part   | 1 +
+ tests/ts/eject/umount          | 2 +-
+ tests/ts/fdisk/align-512-4K-md | 1 +
+ 3 files changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/tests/ts/blkid/md-raid1-part b/tests/ts/blkid/md-raid1-part
+index 20612ec21..de21bca9a 100755
+--- a/tests/ts/blkid/md-raid1-part
++++ b/tests/ts/blkid/md-raid1-part
+@@ -22,6 +22,7 @@ TS_DESC="MD raid1 (last partition)"
+ . $TS_TOPDIR/functions.sh
+ ts_init "$*"
+ ts_skip_nonroot
++ts_check_prog "mdadm"
+ 
+ # set global variable TS_DEVICE
+ ts_scsi_debug_init dev_size_mb=51 sector_size=512
+diff --git a/tests/ts/eject/umount b/tests/ts/eject/umount
+index 994ddb483..e5cfe2b14 100755
+--- a/tests/ts/eject/umount
++++ b/tests/ts/eject/umount
+@@ -43,7 +43,7 @@ EOF
+ 
+ function deinit_device {
+ 	udevadm settle
+-	rmmod scsi_debug
++	ts_scsi_debug_rmmod
+ }
+ 
+ 
+diff --git a/tests/ts/fdisk/align-512-4K-md b/tests/ts/fdisk/align-512-4K-md
+index ad662e0e8..c45a0d43b 100755
+--- a/tests/ts/fdisk/align-512-4K-md
++++ b/tests/ts/fdisk/align-512-4K-md
+@@ -26,6 +26,7 @@ TS_DESC="align 512/4K +MD"
+ . $TS_TOPDIR/functions.sh
+ ts_init "$*"
+ ts_skip_nonroot
++ts_check_prog "mdadm"
+ 
+ # set global variable TS_DEVICE
+ ts_scsi_debug_init dev_size_mb=50 sector_size=512 physblk_exp=3
+-- 
+2.13.6
+
diff --git a/SOURCES/0142-lsmem-chmem-backport-new-commands.patch b/SOURCES/0142-lsmem-chmem-backport-new-commands.patch
new file mode 100644
index 0000000..c20edd1
--- /dev/null
+++ b/SOURCES/0142-lsmem-chmem-backport-new-commands.patch
@@ -0,0 +1,1608 @@
+From 4fde7a853f61fa025a9d42a7571161a69fdae162 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Mon, 23 Oct 2017 15:54:54 +0200
+Subject: [PATCH] lsmem, chmem: backport new commands
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1496421
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ configure.ac            |  19 ++
+ include/c.h             |  10 +
+ include/path.h          |   5 +-
+ include/strutils.h      |   1 +
+ lib/path.c              |  36 ++-
+ lib/strutils.c          |  17 +-
+ sys-utils/Makemodule.am |  14 +
+ sys-utils/chmem.8       | 114 ++++++++
+ sys-utils/chmem.c       | 447 +++++++++++++++++++++++++++++++
+ sys-utils/lsmem.1       |  95 +++++++
+ sys-utils/lsmem.c       | 687 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 11 files changed, 1432 insertions(+), 13 deletions(-)
+ create mode 100644 sys-utils/chmem.8
+ create mode 100644 sys-utils/chmem.c
+ create mode 100644 sys-utils/lsmem.1
+ create mode 100644 sys-utils/lsmem.c
+
+diff --git a/configure.ac b/configure.ac
+index 96c5838cf..d561e01d0 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1138,6 +1138,25 @@ UL_REQUIRES_SYSCALL_CHECK([pivot_root], [UL_CHECK_SYSCALL([pivot_root])])
+ AM_CONDITIONAL(BUILD_PIVOT_ROOT, test "x$build_pivot_root" = xyes)
+ 
+ 
++AC_ARG_ENABLE([lsmem],
++  AS_HELP_STRING([--disable-lsmem], [do not build lsmem]),
++  [], enable_lsmem=check
++)
++UL_BUILD_INIT([lsmem])
++UL_REQUIRES_LINUX([lsmem])
++UL_REQUIRES_BUILD([lsmem], [libsmartcols])
++AM_CONDITIONAL([BUILD_LSMEM], [test "x$build_lsmem" = xyes])
++
++
++AC_ARG_ENABLE([chmem],
++  AS_HELP_STRING([--disable-chmem], [do not build chmem]),
++  [], enable_chmem=check
++)
++UL_BUILD_INIT([chmem])
++UL_REQUIRES_LINUX([chmem])
++AM_CONDITIONAL([BUILD_CHMEM], [test "x$build_chmem" = xyes])
++
++
+ AC_ARG_ENABLE([elvtune],
+   AS_HELP_STRING([--enable-elvtune], [build elvtune (only works with 2.2 and 2.4 kernels)]),
+   [], enable_elvtune=no
+diff --git a/include/c.h b/include/c.h
+index 8ff61b484..124035ea5 100644
+--- a/include/c.h
++++ b/include/c.h
+@@ -302,6 +302,16 @@ static inline int usleep(useconds_t usec)
+ 
+ #define UTIL_LINUX_VERSION _("%s from %s\n"), program_invocation_short_name, PACKAGE_STRING
+ 
++/* backported to RHEL */
++#define USAGE_COLUMNS    _("\nAvailable output columns:\n")
++#define USAGE_OPTSTR_HELP     _("display this help")
++#define USAGE_OPTSTR_VERSION  _("display version")
++#define USAGE_HELP_OPTIONS(marg_dsc) \
++		"%-" #marg_dsc "s%s\n" \
++		"%-" #marg_dsc "s%s\n" \
++		, " -h, --help",    USAGE_OPTSTR_HELP \
++		, " -V, --version", USAGE_OPTSTR_VERSION
++
+ /*
+  * scanf modifiers for "strings allocation"
+  */
+diff --git a/include/path.h b/include/path.h
+index 45da692f8..1ab5724fc 100644
+--- a/include/path.h
++++ b/include/path.h
+@@ -4,6 +4,10 @@
+ #include <stdio.h>
+ #include <stdint.h>
+ 
++extern int path_set_prefix(const char *);
++
++extern const char *path_get(const char *path, ...);
++
+ 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, ...)
+@@ -27,7 +31,6 @@ extern cpu_set_t *path_read_cpuset(int, const char *path, ...)
+ 			      __attribute__ ((__format__ (__printf__, 2, 3)));
+ extern cpu_set_t *path_read_cpulist(int, const char *path, ...)
+ 			       __attribute__ ((__format__ (__printf__, 2, 3)));
+-extern void path_set_prefix(const char *);
+ #endif /* HAVE_CPU_SET_T */
+ 
+ #endif /* UTIL_LINUX_PATH_H */
+diff --git a/include/strutils.h b/include/strutils.h
+index aa7b95f96..1f028e4ed 100644
+--- a/include/strutils.h
++++ b/include/strutils.h
+@@ -25,6 +25,7 @@ extern uint32_t strtou32_or_err(const char *str, const char *errmesg);
+ 
+ extern int64_t strtos64_or_err(const char *str, const char *errmesg);
+ extern uint64_t strtou64_or_err(const char *str, const char *errmesg);
++extern uint64_t strtox64_or_err(const char *str, const char *errmesg);
+ 
+ extern double strtod_or_err(const char *str, const char *errmesg);
+ 
+diff --git a/lib/path.c b/lib/path.c
+index e47d31418..49ca9b5e0 100644
+--- a/lib/path.c
++++ b/lib/path.c
+@@ -38,6 +38,20 @@
+ static size_t prefixlen;
+ static char pathbuf[PATH_MAX];
+ 
++int
++path_set_prefix(const char *prefix)
++{
++	size_t len = strlen(prefix);
++
++	if (len >= sizeof(pathbuf) - 1) {
++		errno = ENAMETOOLONG;
++		return -1;
++	}
++	prefixlen = len;
++	strcpy(pathbuf, prefix);
++	return 0;
++}
++
+ static const char *
+ path_vcreate(const char *path, va_list ap)
+ {
+@@ -49,6 +63,19 @@ path_vcreate(const char *path, va_list ap)
+ 	return pathbuf;
+ }
+ 
++const char *
++path_get(const char *path, ...)
++{
++	const char *p;
++	va_list ap;
++
++	va_start(ap, path);
++	p = path_vcreate(path, ap);
++	va_end(ap);
++
++	return p;
++}
++
+ char *
+ path_strdup(const char *path, ...)
+ {
+@@ -246,13 +273,6 @@ path_read_cpulist(int maxcpus, const char *path, ...)
+ 
+ 	return set;
+ }
+-
+ #endif /* HAVE_CPU_SET_T */
+ 
+-void
+-path_set_prefix(const char *prefix)
+-{
+-	prefixlen = strlen(prefix);
+-	strncpy(pathbuf, prefix, sizeof(pathbuf));
+-	pathbuf[sizeof(pathbuf) - 1] = '\0';
+-}
++
+diff --git a/lib/strutils.c b/lib/strutils.c
+index 4b8a8130d..2458a2c2f 100644
+--- a/lib/strutils.c
++++ b/lib/strutils.c
+@@ -237,27 +237,36 @@ err:
+ 	errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
+ }
+ 
+-uint64_t strtou64_or_err(const char *str, const char *errmesg)
++static uint64_t _strtou64_or_err(const char *str, const char *errmesg, int base)
+ {
+ 	uintmax_t num;
+ 	char *end = NULL;
+ 
++	errno = 0;
+ 	if (str == NULL || *str == '\0')
+ 		goto err;
+-	errno = 0;
+-	num = strtoumax(str, &end, 10);
++	num = strtoumax(str, &end, base);
+ 
+ 	if (errno || str == end || (end && *end))
+ 		goto err;
+ 
+ 	return num;
+ err:
+-	if (errno)
++	if (errno == ERANGE)
+ 		err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
+ 
+ 	errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
+ }
+ 
++uint64_t strtou64_or_err(const char *str, const char *errmesg)
++{
++	return _strtou64_or_err(str, errmesg, 10);
++}
++
++uint64_t strtox64_or_err(const char *str, const char *errmesg)
++{
++	return _strtou64_or_err(str, errmesg, 16);
++}
+ 
+ double strtod_or_err(const char *str, const char *errmesg)
+ {
+diff --git a/sys-utils/Makemodule.am b/sys-utils/Makemodule.am
+index 0496b84e3..21585ce80 100644
+--- a/sys-utils/Makemodule.am
++++ b/sys-utils/Makemodule.am
+@@ -1,3 +1,17 @@
++if BUILD_LSMEM
++usrbin_exec_PROGRAMS += lsmem
++dist_man_MANS += sys-utils/lsmem.1
++lsmem_SOURCES = sys-utils/lsmem.c
++lsmem_LDADD = $(LDADD) libcommon.la libsmartcols.la
++lsmem_CFLAGS = $(AM_CFLAGS) -I$(ul_libsmartcols_incdir)
++endif
++
++if BUILD_CHMEM
++usrbin_exec_PROGRAMS += chmem
++dist_man_MANS += sys-utils/chmem.8
++chmem_SOURCES = sys-utils/chmem.c
++chmem_LDADD = $(LDADD) libcommon.la
++endif
+ 
+ usrbin_exec_PROGRAMS += flock
+ dist_man_MANS += sys-utils/flock.1
+diff --git a/sys-utils/chmem.8 b/sys-utils/chmem.8
+new file mode 100644
+index 000000000..dae7413d4
+--- /dev/null
++++ b/sys-utils/chmem.8
+@@ -0,0 +1,114 @@
++.TH CHMEM 8 "October 2016" "util-linux" "System Administration"
++.SH NAME
++chmem \- configure memory
++.SH SYNOPSIS
++.B chmem
++.RB [ \-h "] [" \-V "] [" \-v "] [" \-e | \-d "]"
++[\fISIZE\fP|\fIRANGE\fP|\fB\-b\fP \fIBLOCKRANGE\fP]
++[-z ZONE]
++.SH DESCRIPTION
++The chmem command sets a particular size or range of memory online or offline.
++.
++.IP "\(hy" 2
++Specify \fISIZE\fP as <size>[m|M|g|G]. With m or M, <size> specifies the memory
++size in MiB (1024 x 1024 bytes). With g or G, <size> specifies the memory size
++in GiB (1024 x 1024 x 1024 bytes). The default unit is MiB.
++.
++.IP "\(hy" 2
++Specify \fIRANGE\fP in the form 0x<start>-0x<end> as shown in the output of the
++\fBlsmem\fP command. <start> is the hexadecimal address of the first byte and <end>
++is the hexadecimal address of the last byte in the memory range.
++.
++.IP "\(hy" 2
++Specify \fIBLOCKRANGE\fP in the form <first>-<last> or <block> as shown in the
++output of the \fBlsmem\fP command. <first> is the number of the first memory block
++and <last> is the number of the last memory block in the memory
++range. Alternatively a single block can be specified. \fIBLOCKRANGE\fP requires
++the \fB--blocks\fP option.
++.
++.IP "\(hy" 2
++Specify \fIZONE\fP as the name of a memory zone, as shown in the output of the
++\fBlsmem -o +ZONES\fP command. The output shows one or more valid memory zones
++for each memory range. If multiple zones are shown, then the memory range
++currently belongs to the first zone. By default, chmem will set memory online
++to the zone Movable, if this is among the valid zones. This default can be
++changed by specifying the \fB--zone\fP option with another valid zone.
++For memory ballooning, it is recommended to select the zone Movable for memory
++online and offline, if possible. Memory in this zone is much more likely to be
++able to be offlined again, but it cannot be used for arbitrary kernel
++allocations, only for migratable pages (e.g. anonymous and page cache pages).
++Use the \fB\-\-help\fR option to see all available zones.
++.
++.PP
++\fISIZE\fP and \fIRANGE\fP must be aligned to the Linux memory block size, as
++shown in the output of the \fBlsmem\fP command.
++
++Setting memory online can fail for various reasons. On virtualized systems it
++can fail if the hypervisor does not have enough memory left, for example
++because memory was overcommitted. Setting memory offline can fail if Linux
++cannot free the memory. If only part of the requested memory can be set online
++or offline, a message tells you how much memory was set online or offline
++instead of the requested amount.
++
++When setting memory online \fBchmem\fP starts with the lowest memory block
++numbers. When setting memory offline \fBchmem\fP starts with the highest memory
++block numbers.
++.SH OPTIONS
++.TP
++.BR \-b ", " \-\-blocks
++Use a \fIBLOCKRANGE\fP parameter instead of \fIRANGE\fP or \fISIZE\fP for the
++\fB--enable\fP and \fB--disable\fP options.
++.TP
++.BR \-d ", " \-\-disable
++Set the specified \fIRANGE\fP, \fISIZE\fP, or \fIBLOCKRANGE\fP of memory offline.
++.TP
++.BR \-e ", " \-\-enable
++Set the specified \fIRANGE\fP, \fISIZE\fP, or \fIBLOCKRANGE\fP of memory online.
++.TP
++.BR \-z ", " \-\-zone
++Select the memory \fIZONE\fP where to set the specified \fIRANGE\fP, \fISIZE\fP,
++or \fIBLOCKRANGE\fP of memory online or offline. By default, memory will be set
++online to the zone Movable, if possible.
++.TP
++.BR \-h ", " \-\-help
++Print a short help text, then exit.
++.TP
++.BR \-v ", " \-\-verbose
++Verbose mode. Causes \fBchmem\fP to print debugging messages about it's
++progress.
++.TP
++.BR \-V ", " \-\-version
++Print the version number, then exit.
++.SH RETURN CODES
++.B chmem
++has the following return codes:
++.TP
++.BR 0
++success
++.TP
++.BR 1
++failure
++.TP
++.BR 64
++partial success
++.SH EXAMPLES
++.TP
++.B chmem --enable 1024
++This command requests 1024 MiB of memory to be set online.
++.TP
++.B chmem -e 2g
++This command requests 2 GiB of memory to be set online.
++.TP
++.B chmem --disable 0x00000000e4000000-0x00000000f3ffffff
++This command requests the memory range starting with 0x00000000e4000000
++and ending with 0x00000000f3ffffff to be set offline.
++.TP
++.B chmem -b -d 10
++This command requests the memory block number 10 to be set offline.
++.SH SEE ALSO
++.BR lsmem (1)
++.SH AVAILABILITY
++The \fBchmem\fP command is part of the util-linux package and is available from
++.UR https://\:www.kernel.org\:/pub\:/linux\:/utils\:/util-linux/
++Linux Kernel Archive
++.UE .
+diff --git a/sys-utils/chmem.c b/sys-utils/chmem.c
+new file mode 100644
+index 000000000..0e5e84727
+--- /dev/null
++++ b/sys-utils/chmem.c
+@@ -0,0 +1,447 @@
++/*
++ * chmem - Memory configuration tool
++ *
++ * Copyright IBM Corp. 2016
++ *
++ * 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 <unistd.h>
++#include <stdlib.h>
++#include <getopt.h>
++#include <assert.h>
++#include <dirent.h>
++#include <ctype.h>
++
++#include "c.h"
++#include "nls.h"
++#include "path.h"
++#include "strutils.h"
++#include "strv.h"
++#include "optutils.h"
++#include "closestream.h"
++#include "xalloc.h"
++
++/* partial success, otherwise we return regular EXIT_{SUCCESS,FAILURE} */
++#define CHMEM_EXIT_SOMEOK		64
++
++#define _PATH_SYS_MEMORY		"/sys/devices/system/memory"
++#define _PATH_SYS_MEMORY_BLOCK_SIZE	_PATH_SYS_MEMORY "/block_size_bytes"
++
++struct chmem_desc {
++	struct dirent	**dirs;
++	int		ndirs;
++	uint64_t	block_size;
++	uint64_t	start;
++	uint64_t	end;
++	uint64_t	size;
++	unsigned int	use_blocks : 1;
++	unsigned int	is_size	   : 1;
++	unsigned int	verbose	   : 1;
++	unsigned int	have_zones : 1;
++};
++
++enum {
++	CMD_MEMORY_ENABLE = 0,
++	CMD_MEMORY_DISABLE,
++	CMD_NONE
++};
++
++enum zone_id {
++	ZONE_DMA = 0,
++	ZONE_DMA32,
++	ZONE_NORMAL,
++	ZONE_HIGHMEM,
++	ZONE_MOVABLE,
++	ZONE_DEVICE,
++};
++
++static char *zone_names[] = {
++	[ZONE_DMA]	= "DMA",
++	[ZONE_DMA32]	= "DMA32",
++	[ZONE_NORMAL]	= "Normal",
++	[ZONE_HIGHMEM]	= "Highmem",
++	[ZONE_MOVABLE]	= "Movable",
++	[ZONE_DEVICE]	= "Device",
++};
++
++/*
++ * name must be null-terminated
++ */
++static int zone_name_to_id(const char *name)
++{
++	size_t i;
++
++	for (i = 0; i < ARRAY_SIZE(zone_names); i++) {
++		if (!strcasecmp(name, zone_names[i]))
++			return i;
++	}
++	return -1;
++}
++
++static void idxtostr(struct chmem_desc *desc, uint64_t idx, char *buf, size_t bufsz)
++{
++	uint64_t start, end;
++
++	start = idx * desc->block_size;
++	end = start + desc->block_size - 1;
++	snprintf(buf, bufsz,
++		 _("Memory Block %"PRIu64" (0x%016"PRIx64"-0x%016"PRIx64")"),
++		 idx, start, end);
++}
++
++static int chmem_size(struct chmem_desc *desc, int enable, int zone_id)
++{
++	char *name, *onoff, line[BUFSIZ], str[BUFSIZ];
++	uint64_t size, index;
++	const char *zn;
++	int i, rc;
++
++	size = desc->size;
++	onoff = enable ? "online" : "offline";
++	i = enable ? 0 : desc->ndirs - 1;
++
++	if (enable && zone_id >= 0) {
++		if (zone_id == ZONE_MOVABLE)
++			onoff = "online_movable";
++		else
++			onoff = "online_kernel";
++	}
++
++	for (; i >= 0 && i < desc->ndirs && size; i += enable ? 1 : -1) {
++		name = desc->dirs[i]->d_name;
++		index = strtou64_or_err(name + 6, _("Failed to parse index"));
++		path_read_str(line, sizeof(line), _PATH_SYS_MEMORY "/%s/state", name);
++		if (strncmp(onoff, line, 6) == 0)
++			continue;
++
++		if (desc->have_zones) {
++			path_read_str(line, sizeof(line),
++				      _PATH_SYS_MEMORY "/%s/valid_zones", name);
++			if (zone_id >= 0) {
++				zn = zone_names[zone_id];
++				if (enable && !strcasestr(line, zn))
++					continue;
++				if (!enable && strncasecmp(line, zn, strlen(zn)))
++					continue;
++			} else if (enable) {
++				/* By default, use zone Movable for online, if valid */
++				if (strcasestr(line, zone_names[ZONE_MOVABLE]))
++					onoff = "online_movable";
++				else
++					onoff = "online";
++			}
++		}
++
++		idxtostr(desc, index, str, sizeof(str));
++		rc = path_write_str(onoff, _PATH_SYS_MEMORY"/%s/state", name);
++		if (rc == -1 && desc->verbose) {
++			if (enable)
++				fprintf(stdout, _("%s enable failed\n"), str);
++			else
++				fprintf(stdout, _("%s disable failed\n"), str);
++		} else if (rc == 0 && desc->verbose) {
++			if (enable)
++				fprintf(stdout, _("%s enabled\n"), str);
++			else
++				fprintf(stdout, _("%s disabled\n"), str);
++		}
++		if (rc == 0)
++			size--;
++	}
++	if (size) {
++		uint64_t bytes;
++		char *sizestr;
++
++		bytes = (desc->size - size) * desc->block_size;
++		sizestr = size_to_human_string(SIZE_SUFFIX_1LETTER, bytes);
++		if (enable)
++			warnx(_("Could only enable %s of memory"), sizestr);
++		else
++			warnx(_("Could only disable %s of memory"), sizestr);
++		free(sizestr);
++	}
++	return size == 0 ? 0 : size == desc->size ? -1 : 1;
++}
++
++static int chmem_range(struct chmem_desc *desc, int enable, int zone_id)
++{
++	char *name, *onoff, line[BUFSIZ], str[BUFSIZ];
++	uint64_t index, todo;
++	const char *zn;
++	int i, rc;
++
++	todo = desc->end - desc->start + 1;
++	onoff = enable ? "online" : "offline";
++
++	if (enable && zone_id >= 0) {
++		if (zone_id == ZONE_MOVABLE)
++			onoff = "online_movable";
++		else
++			onoff = "online_kernel";
++	}
++
++	for (i = 0; i < desc->ndirs; i++) {
++		name = desc->dirs[i]->d_name;
++		index = strtou64_or_err(name + 6, _("Failed to parse index"));
++		if (index < desc->start)
++			continue;
++		if (index > desc->end)
++			break;
++		idxtostr(desc, index, str, sizeof(str));
++		path_read_str(line, sizeof(line), _PATH_SYS_MEMORY "/%s/state", name);
++		if (strncmp(onoff, line, 6) == 0) {
++			if (desc->verbose && enable)
++				fprintf(stdout, _("%s already enabled\n"), str);
++			else if (desc->verbose && !enable)
++				fprintf(stdout, _("%s already disabled\n"), str);
++			todo--;
++			continue;
++		}
++
++		if (desc->have_zones) {
++			path_read_str(line, sizeof(line),
++				      _PATH_SYS_MEMORY "/%s/valid_zones", name);
++			if (zone_id >= 0) {
++				zn = zone_names[zone_id];
++				if (enable && !strcasestr(line, zn)) {
++					warnx(_("%s enable failed: Zone mismatch"), str);
++					continue;
++				}
++				if (!enable && strncasecmp(line, zn, strlen(zn))) {
++					warnx(_("%s disable failed: Zone mismatch"), str);
++					continue;
++				}
++			} else if (enable) {
++				/* By default, use zone Movable for online, if valid */
++				if (strcasestr(line, zone_names[ZONE_MOVABLE]))
++					onoff = "online_movable";
++				else
++					onoff = "online";
++			}
++		}
++
++		rc = path_write_str(onoff, _PATH_SYS_MEMORY"/%s/state", name);
++		if (rc == -1) {
++			if (enable)
++				warn(_("%s enable failed"), str);
++			else
++				warn(_("%s disable failed"), str);
++		} else if (desc->verbose) {
++			if (enable)
++				fprintf(stdout, _("%s enabled\n"), str);
++			else
++				fprintf(stdout, _("%s disabled\n"), str);
++		}
++		if (rc == 0)
++			todo--;
++	}
++	return todo == 0 ? 0 : todo == desc->end - desc->start + 1 ? -1 : 1;
++}
++
++static int filter(const struct dirent *de)
++{
++	if (strncmp("memory", de->d_name, 6))
++		return 0;
++	return isdigit_string(de->d_name + 6);
++}
++
++static void read_info(struct chmem_desc *desc)
++{
++	char line[BUFSIZ];
++
++	desc->ndirs = scandir(_PATH_SYS_MEMORY, &desc->dirs, filter, versionsort);
++	if (desc->ndirs <= 0)
++		err(EXIT_FAILURE, _("Failed to read %s"), _PATH_SYS_MEMORY);
++	path_read_str(line, sizeof(line), _PATH_SYS_MEMORY_BLOCK_SIZE);
++	desc->block_size = strtoumax(line, NULL, 16);
++}
++
++static void parse_single_param(struct chmem_desc *desc, char *str)
++{
++	if (desc->use_blocks) {
++		desc->start = strtou64_or_err(str, _("Failed to parse block number"));
++		desc->end = desc->start;
++		return;
++	}
++	desc->is_size = 1;
++	desc->size = strtosize_or_err(str, _("Failed to parse size"));
++	if (isdigit(str[strlen(str) - 1]))
++		desc->size *= 1024*1024;
++	if (desc->size % desc->block_size) {
++		errx(EXIT_FAILURE, _("Size must be aligned to memory block size (%s)"),
++		     size_to_human_string(SIZE_SUFFIX_1LETTER, desc->block_size));
++	}
++	desc->size /= desc->block_size;
++}
++
++static void parse_range_param(struct chmem_desc *desc, char *start, char *end)
++{
++	if (desc->use_blocks) {
++		desc->start = strtou64_or_err(start, _("Failed to parse start"));
++		desc->end = strtou64_or_err(end, _("Failed to parse end"));
++		return;
++	}
++	if (strlen(start) < 2 || start[1] != 'x')
++		errx(EXIT_FAILURE, _("Invalid start address format: %s"), start);
++	if (strlen(end) < 2 || end[1] != 'x')
++		errx(EXIT_FAILURE, _("Invalid end address format: %s"), end);
++	desc->start = strtox64_or_err(start, _("Failed to parse start address"));
++	desc->end = strtox64_or_err(end, _("Failed to parse end address"));
++	if (desc->start % desc->block_size || (desc->end + 1) % desc->block_size) {
++		errx(EXIT_FAILURE,
++		     _("Start address and (end address + 1) must be aligned to "
++		       "memory block size (%s)"),
++		     size_to_human_string(SIZE_SUFFIX_1LETTER, desc->block_size));
++	}
++	desc->start /= desc->block_size;
++	desc->end /= desc->block_size;
++}
++
++static void parse_parameter(struct chmem_desc *desc, char *param)
++{
++	char **split;
++
++	split = strv_split(param, "-");
++	if (strv_length(split) > 2)
++		errx(EXIT_FAILURE, _("Invalid parameter: %s"), param);
++	if (strv_length(split) == 1)
++		parse_single_param(desc, split[0]);
++	else
++		parse_range_param(desc, split[0], split[1]);
++	strv_free(split);
++	if (desc->start > desc->end)
++		errx(EXIT_FAILURE, _("Invalid range: %s"), param);
++}
++
++static void __attribute__((__noreturn__)) usage(void)
++{
++	FILE *out = stdout;
++	size_t i;
++
++	fputs(USAGE_HEADER, out);
++	fprintf(out, _(" %s [options] [SIZE|RANGE|BLOCKRANGE]\n"), program_invocation_short_name);
++
++	fputs(USAGE_SEPARATOR, out);
++	fputs(_("Set a particular size or range of memory online or offline.\n"), out);
++
++	fputs(USAGE_OPTIONS, out);
++	fputs(_(" -e, --enable       enable memory\n"), out);
++	fputs(_(" -d, --disable      disable memory\n"), out);
++	fputs(_(" -b, --blocks       use memory blocks\n"), out);
++	fputs(_(" -z, --zone <name>  select memory zone (see below)\n"), out);
++	fputs(_(" -v, --verbose      verbose output\n"), out);
++	printf(USAGE_HELP_OPTIONS(20));
++
++	fputs(_("\nSupported zones:\n"), out);
++	for (i = 0; i < ARRAY_SIZE(zone_names); i++)
++		fprintf(out, " %s\n", zone_names[i]);
++
++	printf(USAGE_MAN_TAIL("chmem(8)"));
++
++	exit(EXIT_SUCCESS);
++}
++
++int main(int argc, char **argv)
++{
++	struct chmem_desc _desc = { }, *desc = &_desc;
++	int cmd = CMD_NONE, zone_id = -1;
++	char *zone = NULL;
++	int c, rc;
++
++	static const struct option longopts[] = {
++		{"block",	no_argument,		NULL, 'b'},
++		{"disable",	no_argument,		NULL, 'd'},
++		{"enable",	no_argument,		NULL, 'e'},
++		{"help",	no_argument,		NULL, 'h'},
++		{"verbose",	no_argument,		NULL, 'v'},
++		{"version",	no_argument,		NULL, 'V'},
++		{"zone",	required_argument,	NULL, 'z'},
++		{NULL,		0,			NULL, 0}
++	};
++
++	static const ul_excl_t excl[] = {	/* rows and cols in ASCII order */
++		{ 'd','e' },
++		{ 0 }
++	};
++	int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
++
++	setlocale(LC_ALL, "");
++	bindtextdomain(PACKAGE, LOCALEDIR);
++	textdomain(PACKAGE);
++	atexit(close_stdout);
++
++	read_info(desc);
++
++	while ((c = getopt_long(argc, argv, "bdehvVz:", longopts, NULL)) != -1) {
++
++		err_exclusive_options(c, longopts, excl, excl_st);
++
++		switch (c) {
++		case 'd':
++			cmd = CMD_MEMORY_DISABLE;
++			break;
++		case 'e':
++			cmd = CMD_MEMORY_ENABLE;
++			break;
++		case 'b':
++			desc->use_blocks = 1;
++			break;
++		case 'h':
++			usage();
++			break;
++		case 'v':
++			desc->verbose = 1;
++			break;
++		case 'V':
++			printf(UTIL_LINUX_VERSION);
++			return EXIT_SUCCESS;
++		case 'z':
++			zone = xstrdup(optarg);
++			break;
++		default:
++			errtryhelp(EXIT_FAILURE);
++		}
++	}
++
++	if ((argc == 1) || (argc != optind + 1) || (cmd == CMD_NONE)) {
++		warnx(_("bad usage"));
++		errtryhelp(EXIT_FAILURE);
++	}
++
++	parse_parameter(desc, argv[optind]);
++
++	/* The valid_zones sysfs attribute was introduced with kernel 3.18 */
++	if (path_exist(_PATH_SYS_MEMORY "/memory0/valid_zones"))
++		desc->have_zones = 1;
++	else if (zone)
++		warnx(_("zone ignored, no valid_zones sysfs attribute present"));
++
++	if (zone && desc->have_zones) {
++		zone_id = zone_name_to_id(zone);
++		if (zone_id == -1) {
++			warnx(_("unknown memory zone: %s"), zone);
++			errtryhelp(EXIT_FAILURE);
++		}
++	}
++
++	if (desc->is_size)
++		rc = chmem_size(desc, cmd == CMD_MEMORY_ENABLE ? 1 : 0, zone_id);
++	else
++		rc = chmem_range(desc, cmd == CMD_MEMORY_ENABLE ? 1 : 0, zone_id);
++
++	return rc == 0 ? EXIT_SUCCESS :
++		rc < 0 ? EXIT_FAILURE : CHMEM_EXIT_SOMEOK;
++}
+diff --git a/sys-utils/lsmem.1 b/sys-utils/lsmem.1
+new file mode 100644
+index 000000000..3f5cd7d4b
+--- /dev/null
++++ b/sys-utils/lsmem.1
+@@ -0,0 +1,95 @@
++.TH LSMEM 1 "October 2016" "util-linux" "User Commands"
++.SH NAME
++lsmem \- list the ranges of available memory with their online status
++.SH SYNOPSIS
++.B lsmem
++[options]
++.SH DESCRIPTION
++The \fBlsmem\fP command lists the ranges of available memory with their online
++status. The listed memory blocks correspond to the memory block representation
++in sysfs. The command also shows the memory block size and the amount of memory
++in online and offline state.
++
++The default output compatible with original implementation from s390-tools, but
++it's strongly recommended to 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.
++
++The \fBlsmem\fP command lists a new memory range always when the current memory
++block distinguish from the previous block by STATE, REMOVABLE, NODE or ZONES
++attribute.  This default behavior is possible to override by the
++\fB\-\-split\fR option (e.g. \fBlsmem \-\-split=STATE,ZONES\fR).  The special
++word "none" may be used to ignore all differences between memory blocks and to
++create as large as possible continuous ranges.  The opposite semantic is
++\fB\-\-all\fR to list individual memory blocks.  The default split policy is
++subject to change.  Always explicitly use \fB\-\-split\fR in environments where
++a stable output is required.
++
++Note that some output columns may provide inaccurate information if a split policy
++forces \fBlsmem\fP to ignore diffrences in some attributes. For example if you
++merge removable and non-removable memory blocks to the one range than all
++the range will be marked as non-removable on \fBlsmem\fP output.
++
++Not all columns are supported on all systems.  If an unsupported column is
++specified, \fBlsmem\fP prints the column but does not provide any data for it.
++
++Use the \fB\-\-help\fR option to see the columns description.
++
++.SH OPTIONS
++.TP
++.BR \-a ", " \-\-all
++List each individual memory block, instead of combining memory blocks with
++similar attributes.
++.TP
++.BR \-b , " \-\-bytes"
++Print the SIZE column in bytes rather than in a human-readable format.
++.TP
++.BR \-h ", " \-\-help
++Display help text and exit.
++.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. \fBlsmem \-o +NODE\fP).
++.TP
++.BR \-P , " \-\-pairs"
++Produce output in the form of key="value" pairs.
++All potentially unsafe characters are hex-escaped (\\x<code>).
++.TP
++.BR \-r , " \-\-raw"
++Produce output in raw format.  All potentially unsafe characters are hex-escaped
++(\\x<code>).
++.TP
++.BR \-S , " \-\-split " \fIlist\fP
++Specify which columns (attributes) use to split memory blocks to ranges.  The
++supported columns are STATE, REMOVABLE, NODE and ZONES, or "none". The another columns are
++silently ignored. For more details see DESCRIPTION above.
++.TP
++.BR \-s , " \-\-sysroot " \fIdirectory\fP
++Gather memory data for a Linux instance other than the instance from which the
++\fBlsmem\fP command is issued.  The specified \fIdirectory\fP is the system
++root of the Linux instance to be inspected.
++.TP
++.BR \-V ", " \-\-version
++Display version information and exit.
++.TP
++\fB\-\-summary\fR[=\fIwhen\fR]
++This option controls summary lines output.  The optional argument \fIwhen\fP can be
++\fBnever\fR, \fBalways\fR or \fBonly\fR.  If the \fIwhen\fR argument is
++omitted, it defaults to \fB"only"\fR. The summary output is suppresed for
++\fB\-\-raw\fR and \fB\-\-pairs\fR.
++.SH AUTHOR
++.B lsmem
++was originally written by Gerald Schaefer for s390-tools in Perl. The C version
++for util-linux was written by Clemens von Mann, Heiko Carstens and Karel Zak.
++.SH SEE ALSO
++.BR chmem (8)
++.SH AVAILABILITY
++The \fBlsmem\fP command is part of the util-linux package and is available from
++.UR https://\:www.kernel.org\:/pub\:/linux\:/utils\:/util-linux/
++Linux Kernel Archive
++.UE .
+diff --git a/sys-utils/lsmem.c b/sys-utils/lsmem.c
+new file mode 100644
+index 000000000..34a2847af
+--- /dev/null
++++ b/sys-utils/lsmem.c
+@@ -0,0 +1,687 @@
++/*
++ * lsmem - Show memory configuration
++ *
++ * Copyright IBM Corp. 2016
++ * Copyright (C) 2016 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 <c.h>
++#include <nls.h>
++#include <path.h>
++#include <strutils.h>
++#include <closestream.h>
++#include <xalloc.h>
++#include <getopt.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <dirent.h>
++#include <fcntl.h>
++#include <inttypes.h>
++#include <assert.h>
++#include <optutils.h>
++#include <libsmartcols.h>
++
++#define _PATH_SYS_MEMORY		"/sys/devices/system/memory"
++#define _PATH_SYS_MEMORY_BLOCK_SIZE	_PATH_SYS_MEMORY "/block_size_bytes"
++
++#define MEMORY_STATE_ONLINE		0
++#define MEMORY_STATE_OFFLINE		1
++#define MEMORY_STATE_GOING_OFFLINE	2
++#define MEMORY_STATE_UNKNOWN		3
++
++enum zone_id {
++	ZONE_DMA = 0,
++	ZONE_DMA32,
++	ZONE_NORMAL,
++	ZONE_HIGHMEM,
++	ZONE_MOVABLE,
++	ZONE_DEVICE,
++	ZONE_NONE,
++	ZONE_UNKNOWN,
++	MAX_NR_ZONES,
++};
++
++struct memory_block {
++	uint64_t	index;
++	uint64_t	count;
++	int		state;
++	int		node;
++	int		nr_zones;
++	int		zones[MAX_NR_ZONES];
++	unsigned int	removable:1;
++};
++
++struct lsmem {
++	struct dirent		**dirs;
++	int			ndirs;
++	struct memory_block	*blocks;
++	int			nblocks;
++	uint64_t		block_size;
++	uint64_t		mem_online;
++	uint64_t		mem_offline;
++
++	struct libscols_table	*table;
++	unsigned int		have_nodes : 1,
++				raw : 1,
++				export : 1,
++				noheadings : 1,
++				summary : 1,
++				list_all : 1,
++				bytes : 1,
++				want_summary : 1,
++				want_table : 1,
++				split_by_node : 1,
++				split_by_state : 1,
++				split_by_removable : 1,
++				split_by_zones : 1,
++				have_zones : 1;
++};
++
++
++enum {
++	COL_RANGE,
++	COL_SIZE,
++	COL_STATE,
++	COL_REMOVABLE,
++	COL_BLOCK,
++	COL_NODE,
++	COL_ZONES,
++};
++
++static char *zone_names[] = {
++	[ZONE_DMA]	= "DMA",
++	[ZONE_DMA32]	= "DMA32",
++	[ZONE_NORMAL]	= "Normal",
++	[ZONE_HIGHMEM]	= "Highmem",
++	[ZONE_MOVABLE]	= "Movable",
++	[ZONE_DEVICE]	= "Device",
++	[ZONE_NONE]	= "None",	/* block contains more than one zone, can't be offlined */
++	[ZONE_UNKNOWN]	= "Unknown",
++};
++
++/* column names */
++struct coldesc {
++	const char	*name;		/* header */
++	double		whint;		/* width hint (N < 1 is in percent of termwidth) */
++	int		flags;		/* SCOLS_FL_* */
++	const char      *help;
++
++	int	sort_type;		/* SORT_* */
++};
++
++/* columns descriptions */
++static struct coldesc coldescs[] = {
++	[COL_RANGE]	= { "RANGE", 0, 0, N_("start and end address of the memory range")},
++	[COL_SIZE]	= { "SIZE", 5, SCOLS_FL_RIGHT, N_("size of the memory range")},
++	[COL_STATE]	= { "STATE", 0, SCOLS_FL_RIGHT, N_("online status of the memory range")},
++	[COL_REMOVABLE]	= { "REMOVABLE", 0, SCOLS_FL_RIGHT, N_("memory is removable")},
++	[COL_BLOCK]	= { "BLOCK", 0, SCOLS_FL_RIGHT, N_("memory block number or blocks range")},
++	[COL_NODE]	= { "NODE", 0, SCOLS_FL_RIGHT, N_("numa node of memory")},
++	[COL_ZONES]	= { "ZONES", 0, SCOLS_FL_RIGHT, N_("valid zones for the memory range")},
++};
++
++/* 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;
++}
++
++/*
++ * name must be null-terminated
++ */
++static int zone_name_to_id(const char *name)
++{
++	size_t i;
++
++	for (i = 0; i < ARRAY_SIZE(zone_names); i++) {
++		if (!strcasecmp(name, zone_names[i]))
++			return i;
++	}
++	return ZONE_UNKNOWN;
++}
++
++#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))
++			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(coldescs));
++
++	return columns[num];
++}
++
++static inline struct coldesc *get_column_desc(int num)
++{
++	return &coldescs[ get_column_id(num) ];
++}
++
++static inline void reset_split_policy(struct lsmem *l, int enable)
++{
++	l->split_by_state = enable;
++	l->split_by_node = enable;
++	l->split_by_removable = enable;
++	l->split_by_zones = enable;
++}
++
++static void add_scols_line(struct lsmem *lsmem, struct memory_block *blk)
++{
++	size_t i;
++	struct libscols_line *line;
++
++	line = scols_table_new_line(lsmem->table, NULL);
++	if (!line)
++		err_oom();
++
++	for (i = 0; i < ncolumns; i++) {
++		char *str = NULL;
++
++		switch (get_column_id(i)) {
++		case COL_RANGE:
++		{
++			uint64_t start = blk->index * lsmem->block_size;
++			uint64_t size = blk->count * lsmem->block_size;
++			xasprintf(&str, "0x%016"PRIx64"-0x%016"PRIx64, start, start + size - 1);
++			break;
++		}
++		case COL_SIZE:
++			if (lsmem->bytes)
++				xasprintf(&str, "%"PRId64, (uint64_t) blk->count * lsmem->block_size);
++			else
++				str = size_to_human_string(SIZE_SUFFIX_1LETTER,
++						(uint64_t) blk->count * lsmem->block_size);
++			break;
++		case COL_STATE:
++			str = xstrdup(
++				blk->state == MEMORY_STATE_ONLINE ? _("online") :
++				blk->state == MEMORY_STATE_OFFLINE ? _("offline") :
++				blk->state == MEMORY_STATE_GOING_OFFLINE ? _("on->off") :
++				"?");
++			break;
++		case COL_REMOVABLE:
++			if (blk->state == MEMORY_STATE_ONLINE)
++				str = xstrdup(blk->removable ? _("yes") : _("no"));
++			else
++				str = xstrdup("-");
++			break;
++		case COL_BLOCK:
++			if (blk->count == 1)
++				xasprintf(&str, "%"PRId64, blk->index);
++			else
++				xasprintf(&str, "%"PRId64"-%"PRId64,
++					 blk->index, blk->index + blk->count - 1);
++			break;
++		case COL_NODE:
++			if (lsmem->have_nodes)
++				xasprintf(&str, "%d", blk->node);
++			else
++				str = xstrdup("-");
++			break;
++		case COL_ZONES:
++			if (lsmem->have_zones) {
++				char valid_zones[BUFSIZ];
++				int j, zone_id;
++
++				valid_zones[0] = '\0';
++				for (j = 0; j < blk->nr_zones; j++) {
++					zone_id = blk->zones[j];
++					if (strlen(valid_zones) +
++					    strlen(zone_names[zone_id]) > BUFSIZ - 2)
++						break;
++					strcat(valid_zones, zone_names[zone_id]);
++					if (j + 1 < blk->nr_zones)
++						strcat(valid_zones, "/");
++				}
++				str = xstrdup(valid_zones);
++			} else
++				str = xstrdup("-");
++			break;
++		}
++
++		if (str && scols_line_refer_data(line, i, str) != 0)
++			err_oom();
++	}
++}
++
++static void fill_scols_table(struct lsmem *lsmem)
++{
++	int i;
++
++	for (i = 0; i < lsmem->nblocks; i++)
++		add_scols_line(lsmem, &lsmem->blocks[i]);
++}
++
++static void print_summary(struct lsmem *lsmem)
++{
++	if (lsmem->bytes) {
++		printf("%-23s %15"PRId64"\n",_("Memory block size:"), lsmem->block_size);
++		printf("%-23s %15"PRId64"\n",_("Total online memory:"), lsmem->mem_online);
++		printf("%-23s %15"PRId64"\n",_("Total offline memory:"), lsmem->mem_offline);
++	} else {
++		printf("%-23s %5s\n",_("Memory block size:"),
++			size_to_human_string(SIZE_SUFFIX_1LETTER, lsmem->block_size));
++		printf("%-23s %5s\n",_("Total online memory:"),
++			size_to_human_string(SIZE_SUFFIX_1LETTER, lsmem->mem_online));
++		printf("%-23s %5s\n",_("Total offline memory:"),
++			size_to_human_string(SIZE_SUFFIX_1LETTER, lsmem->mem_offline));
++	}
++}
++
++static int memory_block_get_node(char *name)
++{
++	struct dirent *de;
++	const char *path;
++	DIR *dir;
++	int node;
++
++	path = path_get(_PATH_SYS_MEMORY"/%s", name);
++	if (!path || !(dir= opendir(path)))
++		err(EXIT_FAILURE, _("Failed to open %s"), path ? path : name);
++
++	node = -1;
++	while ((de = readdir(dir)) != NULL) {
++		if (strncmp("node", de->d_name, 4))
++			continue;
++		if (!isdigit_string(de->d_name + 4))
++			continue;
++		node = strtol(de->d_name + 4, NULL, 10);
++		break;
++	}
++	closedir(dir);
++	return node;
++}
++
++static void memory_block_read_attrs(struct lsmem *lsmem, char *name,
++				    struct memory_block *blk)
++{
++	char *token = NULL;
++	char line[BUFSIZ];
++	int i;
++
++	blk->count = 1;
++	blk->index = strtoumax(name + 6, NULL, 10); /* get <num> of "memory<num>" */
++	blk->removable = path_read_u64(_PATH_SYS_MEMORY"/%s/removable", name);
++	blk->state = MEMORY_STATE_UNKNOWN;
++
++	path_read_str(line, sizeof(line), _PATH_SYS_MEMORY"/%s/state", name);
++	if (strcmp(line, "offline") == 0)
++		blk->state = MEMORY_STATE_OFFLINE;
++	else if (strcmp(line, "online") == 0)
++		blk->state = MEMORY_STATE_ONLINE;
++	else if (strcmp(line, "going-offline") == 0)
++		blk->state = MEMORY_STATE_GOING_OFFLINE;
++
++	if (lsmem->have_nodes)
++		blk->node = memory_block_get_node(name);
++
++	blk->nr_zones = 0;
++	if (lsmem->have_zones) {
++		path_read_str(line, sizeof(line), _PATH_SYS_MEMORY"/%s/valid_zones", name);
++		token = strtok(line, " ");
++	}
++	for (i = 0; i < MAX_NR_ZONES; i++) {
++		if (token) {
++			blk->zones[i] = zone_name_to_id(token);
++			blk->nr_zones++;
++			token = strtok(NULL, " ");
++		}
++	}
++}
++
++static int is_mergeable(struct lsmem *lsmem, struct memory_block *blk)
++{
++	struct memory_block *curr;
++	int i;
++
++	if (!lsmem->nblocks)
++		return 0;
++	curr = &lsmem->blocks[lsmem->nblocks - 1];
++	if (lsmem->list_all)
++		return 0;
++	if (curr->index + curr->count != blk->index)
++		return 0;
++	if (lsmem->split_by_state && curr->state != blk->state)
++		return 0;
++	if (lsmem->split_by_removable && curr->removable != blk->removable)
++		return 0;
++	if (lsmem->split_by_node && lsmem->have_nodes) {
++		if (curr->node != blk->node)
++			return 0;
++	}
++	if (lsmem->split_by_zones && lsmem->have_zones) {
++		if (curr->nr_zones != blk->nr_zones)
++			return 0;
++		for (i = 0; i < curr->nr_zones; i++) {
++			if (curr->zones[i] == ZONE_UNKNOWN ||
++			    curr->zones[i] != blk->zones[i])
++				return 0;
++		}
++	}
++	return 1;
++}
++
++static void read_info(struct lsmem *lsmem)
++{
++	struct memory_block blk;
++	char line[BUFSIZ];
++	int i;
++
++	path_read_str(line, sizeof(line), _PATH_SYS_MEMORY_BLOCK_SIZE);
++	lsmem->block_size = strtoumax(line, NULL, 16);
++
++	for (i = 0; i < lsmem->ndirs; i++) {
++		memory_block_read_attrs(lsmem, lsmem->dirs[i]->d_name, &blk);
++		if (is_mergeable(lsmem, &blk)) {
++			lsmem->blocks[lsmem->nblocks - 1].count++;
++			continue;
++		}
++		lsmem->nblocks++;
++		lsmem->blocks = xrealloc(lsmem->blocks, lsmem->nblocks * sizeof(blk));
++		*&lsmem->blocks[lsmem->nblocks - 1] = blk;
++	}
++	for (i = 0; i < lsmem->nblocks; i++) {
++		if (lsmem->blocks[i].state == MEMORY_STATE_ONLINE)
++			lsmem->mem_online += lsmem->block_size * lsmem->blocks[i].count;
++		else
++			lsmem->mem_offline += lsmem->block_size * lsmem->blocks[i].count;
++	}
++}
++
++static int memory_block_filter(const struct dirent *de)
++{
++	if (strncmp("memory", de->d_name, 6))
++		return 0;
++	return isdigit_string(de->d_name + 6);
++}
++
++static void read_basic_info(struct lsmem *lsmem)
++{
++	const char *dir;
++
++	if (!path_exist(_PATH_SYS_MEMORY_BLOCK_SIZE))
++		errx(EXIT_FAILURE, _("This system does not support memory blocks"));
++
++	dir = path_get(_PATH_SYS_MEMORY);
++	if (!dir)
++		err(EXIT_FAILURE, _("Failed to read %s"), _PATH_SYS_MEMORY);
++
++	lsmem->ndirs = scandir(dir, &lsmem->dirs, memory_block_filter, versionsort);
++	if (lsmem->ndirs <= 0)
++		err(EXIT_FAILURE, _("Failed to read %s"), _PATH_SYS_MEMORY);
++
++	if (memory_block_get_node(lsmem->dirs[0]->d_name) != -1)
++		lsmem->have_nodes = 1;
++
++	/* The valid_zones sysfs attribute was introduced with kernel 3.18 */
++	if (path_exist(_PATH_SYS_MEMORY "/memory0/valid_zones"))
++		lsmem->have_zones = 1;
++}
++
++static void __attribute__((__noreturn__)) usage(void)
++{
++	FILE *out = stdout;
++	size_t i;
++
++	fputs(USAGE_HEADER, out);
++	fprintf(out, _(" %s [options]\n"), program_invocation_short_name);
++
++	fputs(USAGE_SEPARATOR, out);
++	fputs(_("List the ranges of available memory with their online status.\n"), out);
++
++	fputs(USAGE_OPTIONS, out);
++	fputs(_(" -P, --pairs          use key=\"value\" output format\n"), out);
++	fputs(_(" -a, --all            list each individual memory block\n"), out);
++	fputs(_(" -b, --bytes          print SIZE in bytes rather than in human readable format\n"), out);
++	fputs(_(" -n, --noheadings     don't print headings\n"), out);
++	fputs(_(" -o, --output <list>  output columns\n"), out);
++	fputs(_(" -r, --raw            use raw output format\n"), out);
++	fputs(_(" -S, --split <list>   split ranges by specified columns\n"), out);
++	fputs(_(" -s, --sysroot <dir>  use the specified directory as system root\n"), out);
++	fputs(_("     --summary[=when] print summary information (never,always or only)\n"), out);
++
++	fputs(USAGE_SEPARATOR, out);
++	printf(USAGE_HELP_OPTIONS(22));
++
++	fputs(USAGE_COLUMNS, out);
++	for (i = 0; i < ARRAY_SIZE(coldescs); i++)
++		fprintf(out, " %10s  %s\n", coldescs[i].name, _(coldescs[i].help));
++
++	printf(USAGE_MAN_TAIL("lsmem(1)"));
++
++	exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
++}
++
++int main(int argc, char **argv)
++{
++	struct lsmem _lsmem = {
++			.want_table = 1,
++			.want_summary = 1
++		}, *lsmem = &_lsmem;
++
++	const char *outarg = NULL, *splitarg = NULL;
++	int c;
++	size_t i;
++
++	enum {
++		LSMEM_OPT_SUMARRY = CHAR_MAX + 1
++	};
++
++	static const struct option longopts[] = {
++		{"all",		no_argument,		NULL, 'a'},
++		{"bytes",	no_argument,		NULL, 'b'},
++		{"help",	no_argument,		NULL, 'h'},
++		{"noheadings",	no_argument,		NULL, 'n'},
++		{"output",	required_argument,	NULL, 'o'},
++		{"pairs",	no_argument,		NULL, 'P'},
++		{"raw",		no_argument,		NULL, 'r'},
++		{"sysroot",	required_argument,	NULL, 's'},
++		{"split",       required_argument,      NULL, 'S'},
++		{"version",	no_argument,		NULL, 'V'},
++		{"summary",     optional_argument,	NULL, LSMEM_OPT_SUMARRY },
++		{NULL,		0,			NULL, 0}
++	};
++	static const ul_excl_t excl[] = {	/* rows and cols in ASCII order */
++		{ 'J', 'P', 'r' },
++		{ 'S', 'a' },
++		{ 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, "abhJno:PrS:s:V", longopts, NULL)) != -1) {
++
++		err_exclusive_options(c, longopts, excl, excl_st);
++
++		switch (c) {
++		case 'a':
++			lsmem->list_all = 1;
++			break;
++		case 'b':
++			lsmem->bytes = 1;
++			break;
++		case 'h':
++			usage();
++			break;
++		case 'n':
++			lsmem->noheadings = 1;
++			break;
++		case 'o':
++			outarg = optarg;
++			break;
++		case 'P':
++			lsmem->export = 1;
++			lsmem->want_summary = 0;
++			break;
++		case 'r':
++			lsmem->raw = 1;
++			lsmem->want_summary = 0;
++			break;
++		case 's':
++			if(path_set_prefix(optarg))
++				err(EXIT_FAILURE, _("invalid argument to %s"), "--sysroot");
++			break;
++		case 'S':
++			splitarg = optarg;
++			break;
++		case 'V':
++			printf(UTIL_LINUX_VERSION);
++			return 0;
++		case LSMEM_OPT_SUMARRY:
++			if (optarg) {
++				if (strcmp(optarg, "never") == 0)
++					lsmem->want_summary = 0;
++				else if (strcmp(optarg, "only") == 0)
++					lsmem->want_table = 0;
++				else if (strcmp(optarg, "always") == 0)
++					lsmem->want_summary = 1;
++				else
++					errx(EXIT_FAILURE, _("unsupported --summary argument"));
++			} else
++				lsmem->want_table = 0;
++			break;
++		default:
++			errtryhelp(EXIT_FAILURE);
++		}
++	}
++
++	if (argc != optind) {
++		warnx(_("bad usage"));
++		errtryhelp(EXIT_FAILURE);
++	}
++
++	if (lsmem->want_table + lsmem->want_summary == 0)
++		errx(EXIT_FAILURE, _("options --{raw,pairs} and --summary=only are mutually exclusive"));
++
++	/* Shortcut to avoid scols machinery on --summary=only */
++	if (lsmem->want_table == 0 && lsmem->want_summary) {
++		read_basic_info(lsmem);
++		read_info(lsmem);
++		print_summary(lsmem);
++		return EXIT_SUCCESS;
++	}
++
++	/*
++	 * Default columns
++	 */
++	if (!ncolumns) {
++		add_column(columns, ncolumns++, COL_RANGE);
++		add_column(columns, ncolumns++, COL_SIZE);
++		add_column(columns, ncolumns++, COL_STATE);
++		add_column(columns, ncolumns++, COL_REMOVABLE);
++		add_column(columns, ncolumns++, COL_BLOCK);
++	}
++
++	if (outarg && string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns),
++					 (int *) &ncolumns, column_name_to_id) < 0)
++		return EXIT_FAILURE;
++
++	/*
++	 * Initialize output
++	 */
++	scols_init_debug(0);
++
++	if (!(lsmem->table = scols_new_table()))
++		errx(EXIT_FAILURE, _("failed to initialize output table"));
++	scols_table_enable_raw(lsmem->table, lsmem->raw);
++	scols_table_enable_export(lsmem->table, lsmem->export);
++	scols_table_enable_noheadings(lsmem->table, lsmem->noheadings);
++
++	for (i = 0; i < ncolumns; i++) {
++		struct coldesc *ci = get_column_desc(i);
++		if (!scols_table_new_column(lsmem->table, ci->name, ci->whint, ci->flags))
++			err(EXIT_FAILURE, _("Failed to initialize output column"));
++	}
++
++	if (splitarg) {
++		int split[ARRAY_SIZE(coldescs)] = { 0 };
++		static size_t nsplits = 0;
++
++		reset_split_policy(lsmem, 0);	/* disable all */
++
++		if (strcasecmp(splitarg, "none") == 0)
++			;
++		else if (string_add_to_idarray(splitarg, split, ARRAY_SIZE(split),
++					(int *) &nsplits, column_name_to_id) < 0)
++			return EXIT_FAILURE;
++
++		for (i = 0; i < nsplits; i++) {
++			switch (split[i]) {
++			case COL_STATE:
++				lsmem->split_by_state = 1;
++				break;
++			case COL_NODE:
++				lsmem->split_by_node = 1;
++				break;
++			case COL_REMOVABLE:
++				lsmem->split_by_removable = 1;
++				break;
++			case COL_ZONES:
++				lsmem->split_by_zones = 1;
++				break;
++			}
++		}
++	} else
++		reset_split_policy(lsmem, 1); /* enable all */
++
++	/*
++	 * Read data and print output
++	 */
++	read_basic_info(lsmem);
++	read_info(lsmem);
++
++	if (lsmem->want_table) {
++		fill_scols_table(lsmem);
++		scols_print_table(lsmem->table);
++
++		if (lsmem->want_summary)
++			fputc('\n', stdout);
++	}
++
++	if (lsmem->want_summary)
++		print_summary(lsmem);
++
++	scols_unref_table(lsmem->table);
++	return 0;
++}
+-- 
+2.13.6
+
diff --git a/SOURCES/0143-lsmem-make-split-optional-follow-output-by-default.patch b/SOURCES/0143-lsmem-make-split-optional-follow-output-by-default.patch
new file mode 100644
index 0000000..ec94d77
--- /dev/null
+++ b/SOURCES/0143-lsmem-make-split-optional-follow-output-by-default.patch
@@ -0,0 +1,119 @@
+From 66d819dc82080e9dba609b3bfff45c14d7c3ba3c Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Fri, 3 Nov 2017 10:58:33 +0100
+Subject: [PATCH] lsmem: make --split optional, follow output by default
+
+Let's keep lsmem backwardly compatible (<=v2.30) and create ranges
+according to the output columns by default. This default behavior may
+be modified by --split command line option.
+
+Upstream: http://github.com/karelzak/util-linux/commit/96cbe362c034305e5f12a912b4247b3321420ee7
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1496421
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ sys-utils/lsmem.1 | 14 ++++++--------
+ sys-utils/lsmem.c | 49 ++++++++++++++++++++++++++++++-------------------
+ 2 files changed, 36 insertions(+), 27 deletions(-)
+
+diff --git a/sys-utils/lsmem.1 b/sys-utils/lsmem.1
+index 3f5cd7d4b..bfe312bfc 100644
+--- a/sys-utils/lsmem.1
++++ b/sys-utils/lsmem.1
+@@ -16,14 +16,12 @@ 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.
+ 
+ The \fBlsmem\fP command lists a new memory range always when the current memory
+-block distinguish from the previous block by STATE, REMOVABLE, NODE or ZONES
+-attribute.  This default behavior is possible to override by the
+-\fB\-\-split\fR option (e.g. \fBlsmem \-\-split=STATE,ZONES\fR).  The special
+-word "none" may be used to ignore all differences between memory blocks and to
+-create as large as possible continuous ranges.  The opposite semantic is
+-\fB\-\-all\fR to list individual memory blocks.  The default split policy is
+-subject to change.  Always explicitly use \fB\-\-split\fR in environments where
+-a stable output is required.
++block distinguish from the previous block by some output column.  This default
++behavior is possible to override by the \fB\-\-split\fR option (e.g. \fBlsmem
++\-\-split=ZONES\fR).  The special word "none" may be used to ignore all
++differences between memory blocks and to create as large as possible continuous
++ranges.  The opposite semantic is \fB\-\-all\fR to list individual memory
++blocks.
+ 
+ Note that some output columns may provide inaccurate information if a split policy
+ forces \fBlsmem\fP to ignore diffrences in some attributes. For example if you
+diff --git a/sys-utils/lsmem.c b/sys-utils/lsmem.c
+index 34a2847af..aaf7374fc 100644
+--- a/sys-utils/lsmem.c
++++ b/sys-utils/lsmem.c
+@@ -202,6 +202,32 @@ static inline void reset_split_policy(struct lsmem *l, int enable)
+ 	l->split_by_zones = enable;
+ }
+ 
++static void set_split_policy(struct lsmem *l, int cols[], size_t ncols)
++{
++	size_t i;
++
++	reset_split_policy(l, 0);
++
++	for (i = 0; i < ncols; i++) {
++		switch (cols[i]) {
++		case COL_STATE:
++			l->split_by_state = 1;
++			break;
++		case COL_NODE:
++			l->split_by_node = 1;
++			break;
++		case COL_REMOVABLE:
++			l->split_by_removable = 1;
++			break;
++		case COL_ZONES:
++			l->split_by_zones = 1;
++			break;
++		default:
++			break;
++		}
++	}
++}
++
+ static void add_scols_line(struct lsmem *lsmem, struct memory_block *blk)
+ {
+ 	size_t i;
+@@ -638,32 +664,17 @@ int main(int argc, char **argv)
+ 		int split[ARRAY_SIZE(coldescs)] = { 0 };
+ 		static size_t nsplits = 0;
+ 
+-		reset_split_policy(lsmem, 0);	/* disable all */
+-
+ 		if (strcasecmp(splitarg, "none") == 0)
+ 			;
+ 		else if (string_add_to_idarray(splitarg, split, ARRAY_SIZE(split),
+ 					(int *) &nsplits, column_name_to_id) < 0)
+ 			return EXIT_FAILURE;
+ 
+-		for (i = 0; i < nsplits; i++) {
+-			switch (split[i]) {
+-			case COL_STATE:
+-				lsmem->split_by_state = 1;
+-				break;
+-			case COL_NODE:
+-				lsmem->split_by_node = 1;
+-				break;
+-			case COL_REMOVABLE:
+-				lsmem->split_by_removable = 1;
+-				break;
+-			case COL_ZONES:
+-				lsmem->split_by_zones = 1;
+-				break;
+-			}
+-		}
++		set_split_policy(lsmem, split, nsplits);
++
+ 	} else
+-		reset_split_policy(lsmem, 1); /* enable all */
++		/* follow output columns */
++		set_split_policy(lsmem, columns, ncolumns);
+ 
+ 	/*
+ 	 * Read data and print output
+-- 
+2.13.6
+
diff --git a/SOURCES/0144-libmount-fix-access-utab-write-test.patch b/SOURCES/0144-libmount-fix-access-utab-write-test.patch
new file mode 100644
index 0000000..50dccbd
--- /dev/null
+++ b/SOURCES/0144-libmount-fix-access-utab-write-test.patch
@@ -0,0 +1,226 @@
+From 5d238002ff22241a7d04608102a2182aa74d2b69 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/0145-login-add-LOGIN_PLAIN_PROMPT-to-login.defs.patch b/SOURCES/0145-login-add-LOGIN_PLAIN_PROMPT-to-login.defs.patch
new file mode 100644
index 0000000..58c0242
--- /dev/null
+++ b/SOURCES/0145-login-add-LOGIN_PLAIN_PROMPT-to-login.defs.patch
@@ -0,0 +1,86 @@
+From a8427f41c91ac12f0b208fe7eaf4e535b8a56464 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Mon, 4 Dec 2017 12:31:29 +0100
+Subject: [PATCH 145/146] login: add LOGIN_PLAIN_PROMPT to login.defs
+
+We have command line option -H to disable hostname in login prompt.
+Unfortunately, in same cases (e.g. telnetd) it's impossible to specify
+login(1) command line options due to hardcoded execl()...
+
+This patch introduces LOGIN_PLAIN_PROMPT boolean for /etc/login.defs
+to suppress hostname in the prompt.
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1520906
+Upstream: http://github.com/karelzak/util-linux/commit/e6b32e7d1adf2a0c09743d71dfdbe2742c5884ac
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ login-utils/login.1 | 12 ++++++++++++
+ login-utils/login.c | 12 +++++++++---
+ 2 files changed, 21 insertions(+), 3 deletions(-)
+
+diff --git a/login-utils/login.1 b/login-utils/login.1
+index 216645ebe..ec636fd74 100644
+--- a/login-utils/login.1
++++ b/login-utils/login.1
+@@ -130,6 +130,9 @@ Used by other servers (i.e.,
+ to tell
+ .B login
+ that printing the hostname should be suppressed in the login: prompt.
++See also LOGIN_PLAIN_PROMPT below if your server does not allow to configure
++.B login
++command line.
+ .TP
+ .B \-V
+ Print version and exit.
+@@ -157,6 +160,15 @@ by
+ PAM module.
+ .RE
+ .PP
++.B LOGIN_PLAIN_PROMPT
++(boolean)
++.RS 4
++Tell login that printing the hostname should be suppressed in the login:
++prompt.  This is alternative to the \fB\-H\fR command line option.  The default
++value is
++.IR no .
++.RE
++.PP
+ .B LOGIN_TIMEOUT
+ (number)
+ .RS 4
+diff --git a/login-utils/login.c b/login-utils/login.c
+index 5c36953ef..eee3f7bd1 100644
+--- a/login-utils/login.c
++++ b/login-utils/login.c
+@@ -709,7 +709,8 @@ static void loginpam_err(pam_handle_t *pamh, int retcode)
+ }
+ 
+ /*
+- * Composes "<host> login: " string; or returns "login: " is -H is given
++ * Composes "<host> login: " string; or returns "login: " if -H is given or
++ * LOGIN_PLAIN_PROMPT=yes configured.
+  */
+ static const char *loginpam_get_prompt(struct login_context *cxt)
+ {
+@@ -717,11 +718,16 @@ static const char *loginpam_get_prompt(struct login_context *cxt)
+ 	char *prompt, *dflt_prompt = _("login: ");
+ 	size_t sz;
+ 
+-	if (cxt->nohost || !(host = get_thishost(cxt, NULL)))
++	if (cxt->nohost)
++		return dflt_prompt;	/* -H on command line */
++
++	if (getlogindefs_bool("LOGIN_PLAIN_PROMPT", 0) == 1)
+ 		return dflt_prompt;
+ 
+-	sz = strlen(host) + 1 + strlen(dflt_prompt) + 1;
++	if (!(host = get_thishost(cxt, NULL)))
++		return dflt_prompt;
+ 
++	sz = strlen(host) + 1 + strlen(dflt_prompt) + 1;
+ 	prompt = xmalloc(sz);
+ 	snprintf(prompt, sz, "%s %s", host, dflt_prompt);
+ 
+-- 
+2.13.6
+
diff --git a/SOURCES/0146-libblkid-Add-VDO-superblock-information-into-blkid.patch b/SOURCES/0146-libblkid-Add-VDO-superblock-information-into-blkid.patch
new file mode 100644
index 0000000..22ee16c
--- /dev/null
+++ b/SOURCES/0146-libblkid-Add-VDO-superblock-information-into-blkid.patch
@@ -0,0 +1,114 @@
+From e8c8b5f97c864f0fd65378ccde0c45526e6916c9 Mon Sep 17 00:00:00 2001
+From: Sweet Tea Dorminy <sweettea@mit.edu>
+Date: Wed, 6 Dec 2017 18:26:59 -0500
+Subject: [PATCH 146/146] libblkid: Add VDO superblock information into blkid
+
+[kzak@redhat.com: - add tests/expected/blkid/low-probe-vdo
+                  - enlarge the image (must be > 1024)]
+
+[RHEL7: exclude vdo regression test doe to binary stuff in the patch]
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1521163
+Upstream: http://github.com/karelzak/util-linux/commit/6418cba457a701d44294d934c2bc4b766bbcfa2b
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libblkid/src/Makemodule.am             |   1 +
+ libblkid/src/superblocks/superblocks.c |   1 +
+ libblkid/src/superblocks/superblocks.h |   1 +
+ libblkid/src/superblocks/vdo.c         |  48 +++++++++++++++++++++++++++++++++
+ 4 files changed, 55 insertions(+)
+ create mode 100644 libblkid/src/superblocks/vdo.c
+
+diff --git a/libblkid/src/Makemodule.am b/libblkid/src/Makemodule.am
+index 15639768a..791d7cbe8 100644
+--- a/libblkid/src/Makemodule.am
++++ b/libblkid/src/Makemodule.am
+@@ -88,6 +88,7 @@ libblkid_la_SOURCES = \
+ 	libblkid/src/superblocks/ubifs.c \
+ 	libblkid/src/superblocks/udf.c \
+ 	libblkid/src/superblocks/ufs.c \
++	libblkid/src/superblocks/vdo.c \
+ 	libblkid/src/superblocks/vfat.c \
+ 	libblkid/src/superblocks/via_raid.c \
+ 	libblkid/src/superblocks/vmfs.c \
+diff --git a/libblkid/src/superblocks/superblocks.c b/libblkid/src/superblocks/superblocks.c
+index 3721544ff..8210fc17b 100644
+--- a/libblkid/src/superblocks/superblocks.c
++++ b/libblkid/src/superblocks/superblocks.c
+@@ -109,6 +109,7 @@ static const struct blkid_idinfo *idinfos[] =
+ 	&verity_hash_idinfo,
+ 	&luks_idinfo,
+ 	&vmfs_volume_idinfo,
++	&vdo_idinfo,
+ 
+ 	/* Filesystems */
+ 	&vfat_idinfo,
+diff --git a/libblkid/src/superblocks/superblocks.h b/libblkid/src/superblocks/superblocks.h
+index 90847151b..487fe38c2 100644
+--- a/libblkid/src/superblocks/superblocks.h
++++ b/libblkid/src/superblocks/superblocks.h
+@@ -72,6 +72,7 @@ extern const struct blkid_idinfo befs_idinfo;
+ extern const struct blkid_idinfo nilfs2_idinfo;
+ extern const struct blkid_idinfo exfat_idinfo;
+ extern const struct blkid_idinfo f2fs_idinfo;
++extern const struct blkid_idinfo vdo_idinfo;
+ 
+ /*
+  * superblock functions
+diff --git a/libblkid/src/superblocks/vdo.c b/libblkid/src/superblocks/vdo.c
+new file mode 100644
+index 000000000..bec686f4f
+--- /dev/null
++++ b/libblkid/src/superblocks/vdo.c
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2017 Red Hat, Inc.
++ *
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <errno.h>
++#include <ctype.h>
++#include <stdint.h>
++
++#include "superblocks.h"
++
++struct vdo_super_block {
++	char magic[8];			/* magic number 'dmvdo001'*/
++	char unused[32];		/* 32 bytes of unimportant space */
++	unsigned char sb_uuid[16];	/* vdo unique id */
++
++	/* this is not all... but enough for libblkid */
++} __attribute__((packed));
++
++static int probe_vdo(blkid_probe pr, const struct blkid_idmag *mag)
++{
++	struct vdo_super_block *vsb;
++
++	vsb = blkid_probe_get_sb(pr, mag, struct vdo_super_block);
++	if (!vsb)
++		return errno ? -errno : 1;
++
++	blkid_probe_set_uuid(pr, vsb->sb_uuid);
++	return 0;
++}
++
++const struct blkid_idinfo vdo_idinfo =
++{
++	.name		= "vdo",
++	.usage		= BLKID_USAGE_OTHER,
++	.probefunc	= probe_vdo,
++	.magics		=
++	{
++		{ .magic = "dmvdo001", .len = 8 },
++		{ NULL }
++	}
++};
+-- 
+2.13.6
+
diff --git a/SOURCES/0147-include-debug-don-t-print-pointer-address-for-SUID-p.patch b/SOURCES/0147-include-debug-don-t-print-pointer-address-for-SUID-p.patch
new file mode 100644
index 0000000..296753c
--- /dev/null
+++ b/SOURCES/0147-include-debug-don-t-print-pointer-address-for-SUID-p.patch
@@ -0,0 +1,406 @@
+From 3fcd52706b6818e785a104ed6c4f2b46e5d1ab2f Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Fri, 12 Jan 2018 11:01:26 +0100
+Subject: [PATCH] include/debug: don't print pointer address for SUID programs
+
+* introduce new flag __UL_DEBUG_FL_NOADDR to suppress pointer address printing
+  (and MNT_DEBUG_FL_NOADDR for libmount)
+
+* use __UL_DEBUG_FL_NOADDR when SUID
+
+* move ul_debugobj() to debugobj.h, and require UL_DEBUG_CURRENT_MASK
+  to provide access to the current mask from ul_debugobj(). It's better
+  than modify all ul_debugobj() calls and use the global mask as
+  argument.
+
+* remove never used UL_DEBUG_DEFINE_FLAG
+
+* remove %p from another libmount and libblkid debug messages
+
+Upstream: http://github.com/karelzak/util-linux/commit/6d00cfb2330cb47d00d350eedfbffbbf5991a743
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1534893
+Reported-by: halfdog <me@halfdog.net>
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ include/Makemodule.am                |  2 ++
+ include/debug.h                      | 29 +++++++++++------------------
+ include/debugobj.h                   | 22 ++++++++++++++++++++++
+ lib/loopdev.c                        |  2 +-
+ libblkid/src/partitions/partitions.c | 20 ++++++++++----------
+ libblkid/src/probe.c                 | 21 ++++++++++-----------
+ libmount/src/fs.c                    |  2 +-
+ libmount/src/init.c                  |  5 +++++
+ libmount/src/mountP.h                |  4 +++-
+ libmount/src/tab_diff.c              |  6 +++---
+ libmount/src/tab_update.c            |  4 ++--
+ libsmartcols/src/smartcolsP.h        |  3 +++
+ sys-utils/lsns.c                     |  3 +++
+ 13 files changed, 76 insertions(+), 47 deletions(-)
+ create mode 100644 include/debugobj.h
+
+diff --git a/include/Makemodule.am b/include/Makemodule.am
+index 168029683..bd4aa8cea 100644
+--- a/include/Makemodule.am
++++ b/include/Makemodule.am
+@@ -11,6 +11,8 @@ dist_noinst_HEADERS += \
+ 	include/colors.h \
+ 	include/cpuset.h \
+ 	include/crc32.h \
++	include/debug.h \
++	include/debugobj.h \
+ 	include/env.h \
+ 	include/exec_shell.h \
+ 	include/exitcodes.h \
+diff --git a/include/debug.h b/include/debug.h
+index 848e47456..1c7ed8037 100644
+--- a/include/debug.h
++++ b/include/debug.h
+@@ -13,12 +13,15 @@
+ 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_MASK(m)         m ## _debug_mask
++#define UL_DEBUG_DEFINE_MASK(m)  int UL_DEBUG_MASK(m)
+ #define UL_DEBUG_DECLARE_MASK(m) extern UL_DEBUG_DEFINE_MASK(m)
+ #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
++/*
++ * Internal mask flags (above 0xffffff)
++ */
++#define __UL_DEBUG_FL_NOADDR   (1 << 24)       /* Don't print object address */
+ 
+ /* l - library name, p - flag prefix, m - flag postfix, x - function */
+ #define __UL_DBG(l, p, m, x) \
+@@ -55,6 +58,10 @@ struct dbg_mask { char *mname; int val; };
+ 				lib ## _debug_mask = parse_envmask(lib ## _masknames, str); \
+ 		} else \
+ 			lib ## _debug_mask = mask; \
++		if (lib ## _debug_mask) { \
++			if (getuid() != geteuid() || getgid() != getegid()) \
++				lib ## _debug_mask |= __UL_DEBUG_FL_NOADDR; \
++		} \
+ 		lib ## _debug_mask |= pref ## INIT; \
+ 		if (lib ## _debug_mask != pref ## INIT) { \
+ 			__UL_DBG(lib, pref, INIT, ul_debug("library debug mask: 0x%04x", \
+@@ -72,21 +79,7 @@ ul_debug(const char *mesg, ...)
+ 	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[],
++static inline int parse_envmask(const struct dbg_mask flagnames[],
+ 				const char *mask)
+ {
+ 	int res;
+diff --git a/include/debugobj.h b/include/debugobj.h
+new file mode 100644
+index 000000000..73b70b8df
+--- /dev/null
++++ b/include/debugobj.h
+@@ -0,0 +1,22 @@
++#ifndef UTIL_LINUX_DEBUGOBJ_H
++#define UTIL_LINUX_DEBUGOBJ_H
++
++/*
++ * Include *after* debug.h and after UL_DEBUG_CURRENT_MASK define.
++ */
++
++static inline void __attribute__ ((__format__ (__printf__, 2, 3)))
++ul_debugobj(const void *handler, const char *mesg, ...)
++{
++	va_list ap;
++
++	if (handler && !(UL_DEBUG_CURRENT_MASK & __UL_DEBUG_FL_NOADDR))
++		fprintf(stderr, "[%p]: ", handler);
++
++	va_start(ap, mesg);
++	vfprintf(stderr, mesg, ap);
++	va_end(ap);
++	fputc('\n', stderr);
++}
++
++#endif /* UTIL_LINUX_DEBUGOBJ_H */
+diff --git a/lib/loopdev.c b/lib/loopdev.c
+index db5463698..daf0a81e8 100644
+--- a/lib/loopdev.c
++++ b/lib/loopdev.c
+@@ -50,7 +50,7 @@
+ 
+ # define DBG(l,x)	do { \
+ 				if ((l)->debug) {\
+-					fprintf(stderr, "loopdev:  [%p]: ", (l)); \
++					fprintf(stderr, "loopdev: "); \
+ 					x; \
+ 				} \
+ 			} while(0)
+diff --git a/libblkid/src/partitions/partitions.c b/libblkid/src/partitions/partitions.c
+index 9d846ff85..2d0d70d81 100644
+--- a/libblkid/src/partitions/partitions.c
++++ b/libblkid/src/partitions/partitions.c
+@@ -381,8 +381,8 @@ static blkid_partlist partitions_init_data(struct blkid_chain *chn)
+ 
+ 	reset_partlist(ls);
+ 
+-	DBG(LOWPROBE, blkid_debug("parts: initialized partitions list (%p, size=%d)",
+-		ls, ls->nparts_max));
++	DBG(LOWPROBE, blkid_debug("parts: initialized partitions list (size=%d)",
++		ls->nparts_max));
+ 	return ls;
+ }
+ 
+@@ -417,7 +417,7 @@ blkid_parttable blkid_partlist_new_parttable(blkid_partlist ls,
+ 	list_add_tail(&tab->t_tabs, &ls->l_tabs);
+ 
+ 	DBG(LOWPROBE, blkid_debug("parts: create a new partition table "
+-		       "(%p, type=%s, offset=%"PRId64")", tab, type, offset));
++		       "(type=%s, offset=%"PRId64")", type, offset));
+ 	return tab;
+ }
+ 
+@@ -458,9 +458,9 @@ blkid_partition blkid_partlist_add_partition(blkid_partlist ls,
+ 	par->start = start;
+ 	par->size = size;
+ 
+-	DBG(LOWPROBE, blkid_debug("parts: add partition (%p start=%"
+-		PRId64 ", size=%" PRId64 ", table=%p)",
+-		par, par->start, par->size, tab));
++	DBG(LOWPROBE, blkid_debug("parts: add partition (start=%"
++		PRId64 ", size=%" PRId64 ")",
++		par->start, par->size));
+ 	return par;
+ }
+ 
+@@ -662,8 +662,8 @@ int blkid_partitions_do_subprobe(blkid_probe pr, blkid_partition parent,
+ 	blkid_loff_t sz, off;
+ 
+ 	DBG(LOWPROBE, blkid_debug(
+-		"parts: ----> %s subprobe requested (parent=%p)",
+-		id->name, parent));
++		"parts: ----> %s subprobe requested)",
++		id->name));
+ 
+ 	if (!pr || !parent || !parent->size)
+ 		return -EINVAL;
+@@ -709,8 +709,8 @@ int blkid_partitions_do_subprobe(blkid_probe pr, blkid_partition parent,
+ 	blkid_free_probe(prc);	/* free cloned prober */
+ 
+ 	DBG(LOWPROBE, blkid_debug(
+-		"parts: <---- %s subprobe done (parent=%p, rc=%d)",
+-		id->name, parent, rc));
++		"parts: <---- %s subprobe done (rc=%d)",
++		id->name, rc));
+ 
+ 	return rc;
+ }
+diff --git a/libblkid/src/probe.c b/libblkid/src/probe.c
+index 9cf099ae4..07b08441f 100644
+--- a/libblkid/src/probe.c
++++ b/libblkid/src/probe.c
+@@ -145,7 +145,7 @@ blkid_probe blkid_new_probe(void)
+ 	if (!pr)
+ 		return NULL;
+ 
+-	DBG(LOWPROBE, blkid_debug("allocate a new probe %p", pr));
++	DBG(LOWPROBE, blkid_debug("allocate a new probe"));
+ 
+ 	/* initialize chains */
+ 	for (i = 0; i < BLKID_NCHAINS; i++) {
+@@ -260,7 +260,7 @@ void blkid_free_probe(blkid_probe pr)
+ 	blkid_probe_reset_buffer(pr);
+ 	blkid_free_probe(pr->disk_probe);
+ 
+-	DBG(LOWPROBE, blkid_debug("free probe %p", pr));
++	DBG(LOWPROBE, blkid_debug("free probe"));
+ 	free(pr);
+ }
+ 
+@@ -552,8 +552,8 @@ unsigned char *blkid_probe_get_buffer(blkid_probe pr,
+ 				list_entry(p, struct blkid_bufinfo, bufs);
+ 
+ 		if (x->off <= off && off + len <= x->off + x->len) {
+-			DBG(LOWPROBE, blkid_debug("\treuse buffer: off=%jd len=%jd pr=%p",
+-							x->off, x->len, pr));
++			DBG(LOWPROBE, blkid_debug("\treuse buffer: off=%jd len=%jd",
++							x->off, x->len));
+ 			bf = x;
+ 			break;
+ 		}
+@@ -584,8 +584,8 @@ unsigned char *blkid_probe_get_buffer(blkid_probe pr,
+ 		bf->off = off;
+ 		INIT_LIST_HEAD(&bf->bufs);
+ 
+-		DBG(LOWPROBE, blkid_debug("\tbuffer read: off=%jd len=%jd pr=%p",
+-				off, len, pr));
++		DBG(LOWPROBE, blkid_debug("\tbuffer read: off=%jd len=%jd",
++				off, len));
+ 
+ 		ret = read(pr->fd, bf->data, len);
+ 		if (ret != (ssize_t) len) {
+@@ -609,7 +609,7 @@ static void blkid_probe_reset_buffer(blkid_probe pr)
+ 	if (!pr || list_empty(&pr->buffers))
+ 		return;
+ 
+-	DBG(LOWPROBE, blkid_debug("reseting probing buffers pr=%p", pr));
++	DBG(LOWPROBE, blkid_debug("reseting probing buffers"));
+ 
+ 	while (!list_empty(&pr->buffers)) {
+ 		struct blkid_bufinfo *bf = list_entry(pr->buffers.next,
+@@ -766,9 +766,8 @@ int blkid_probe_set_dimension(blkid_probe pr,
+ 		return -1;
+ 
+ 	DBG(LOWPROBE, blkid_debug(
+-		"changing probing area pr=%p: size=%llu, off=%llu "
++		"changing probing area: size=%llu, off=%llu "
+ 		"-to-> size=%llu, off=%llu",
+-		pr,
+ 		(unsigned long long) pr->size,
+ 		(unsigned long long) pr->off,
+ 		(unsigned long long) size,
+@@ -840,7 +839,7 @@ int blkid_probe_get_idmag(blkid_probe pr, const struct blkid_idinfo *id,
+ static inline void blkid_probe_start(blkid_probe pr)
+ {
+ 	if (pr) {
+-		DBG(LOWPROBE, blkid_debug("%p: start probe", pr));
++		DBG(LOWPROBE, blkid_debug("start probe"));
+ 		pr->cur_chain = NULL;
+ 		pr->prob_flags = 0;
+ 		blkid_probe_set_wiper(pr, 0, 0);
+@@ -850,7 +849,7 @@ static inline void blkid_probe_start(blkid_probe pr)
+ static inline void blkid_probe_end(blkid_probe pr)
+ {
+ 	if (pr) {
+-		DBG(LOWPROBE, blkid_debug("%p: end probe", pr));
++		DBG(LOWPROBE, blkid_debug("end probe"));
+ 		pr->cur_chain = NULL;
+ 		pr->prob_flags = 0;
+ 		blkid_probe_set_wiper(pr, 0, 0);
+diff --git a/libmount/src/fs.c b/libmount/src/fs.c
+index 75e3bbb26..e46ee0c0e 100644
+--- a/libmount/src/fs.c
++++ b/libmount/src/fs.c
+@@ -1451,7 +1451,7 @@ int mnt_fs_print_debug(struct libmnt_fs *fs, FILE *file)
+ {
+ 	if (!fs || !file)
+ 		return -EINVAL;
+-	fprintf(file, "------ fs: %p\n", fs);
++	fprintf(file, "------ fs\n");
+ 	fprintf(file, "source: %s\n", mnt_fs_get_source(fs));
+ 	fprintf(file, "target: %s\n", mnt_fs_get_target(fs));
+ 	fprintf(file, "fstype: %s\n", mnt_fs_get_fstype(fs));
+diff --git a/libmount/src/init.c b/libmount/src/init.c
+index 4e5f489c4..e5e6925f5 100644
+--- a/libmount/src/init.c
++++ b/libmount/src/init.c
+@@ -38,6 +38,11 @@ void mnt_init_debug(int mask)
+ 	} else
+ 		libmount_debug_mask = mask;
+ 
++	if (libmount_debug_mask) {
++		if (getuid() != geteuid() || getgid() != getegid())
++			libmount_debug_mask |= MNT_DEBUG_FL_NOADDR;
++	}
++
+ 	libmount_debug_mask |= MNT_DEBUG_INIT;
+ 
+ 	if (libmount_debug_mask && libmount_debug_mask != MNT_DEBUG_INIT) {
+diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h
+index 8b3f92e17..dc3ed3f49 100644
+--- a/libmount/src/mountP.h
++++ b/libmount/src/mountP.h
+@@ -51,6 +51,8 @@
+ #define MNT_DEBUG_DIFF		(1 << 11)
+ #define MNT_DEBUG_ALL		0xFFFF
+ 
++#define MNT_DEBUG_FL_NOADDR	(1 << 24)
++
+ #ifdef CONFIG_LIBMOUNT_DEBUG
+ # include <stdio.h>
+ # include <stdarg.h>
+@@ -91,7 +93,7 @@ mnt_debug_h(void *handler, const char *mesg, ...)
+ {
+ 	va_list ap;
+ 
+-	if (handler)
++	if (handler && !(libmount_debug_mask & MNT_DEBUG_FL_NOADDR))
+ 		fprintf(stderr, "[%p]: ", handler);
+ 	va_start(ap, mesg);
+ 	vfprintf(stderr, mesg, ap);
+diff --git a/libmount/src/tab_diff.c b/libmount/src/tab_diff.c
+index f01f889f8..0a69f402c 100644
+--- a/libmount/src/tab_diff.c
++++ b/libmount/src/tab_diff.c
+@@ -229,9 +229,9 @@ int mnt_diff_tables(struct libmnt_tabdiff *df, struct libmnt_table *old_tab,
+ 	if (!no && !nn)			/* both tables are empty */
+ 		return 0;
+ 
+-	DBG(DIFF, mnt_debug_h(df, "analyze new=%p (%d entries), "
+-				          "old=%p (%d entries)",
+-				new_tab, nn, old_tab, no));
++	DBG(DIFF, mnt_debug_h(df, "analyze new (%d entries), "
++				          "old (%d entries)",
++				nn, no));
+ 
+ 	mnt_reset_iter(&itr, MNT_ITER_FORWARD);
+ 
+diff --git a/libmount/src/tab_update.c b/libmount/src/tab_update.c
+index 5f503cad7..b45c4a92c 100644
+--- a/libmount/src/tab_update.c
++++ b/libmount/src/tab_update.c
+@@ -173,8 +173,8 @@ int mnt_update_set_fs(struct libmnt_update *upd, unsigned long mountflags,
+ 		return -EINVAL;
+ 
+ 	DBG(UPDATE, mnt_debug_h(upd,
+-			"resetting FS [fs=0x%p, target=%s, flags=0x%08lx]",
+-			fs, target, mountflags));
++			"resetting FS [target=%s, flags=0x%08lx]",
++			target, mountflags));
+ 	if (fs) {
+ 		DBG(UPDATE, mnt_debug_h(upd, "FS template:"));
+ 		DBG(UPDATE, mnt_fs_print_debug(fs, stderr));
+diff --git a/libsmartcols/src/smartcolsP.h b/libsmartcols/src/smartcolsP.h
+index 28246c14f..cea4f3101 100644
+--- a/libsmartcols/src/smartcolsP.h
++++ b/libsmartcols/src/smartcolsP.h
+@@ -43,6 +43,9 @@ UL_DEBUG_DECLARE_MASK(libsmartcols);
+ #define ON_DBG(m, x)	__UL_DBG_CALL(libsmartcols, SCOLS_DEBUG_, m, x)
+ #define DBG_FLUSH	__UL_DBG_FLUSH(libsmartcols, SCOLS_DEBUG_)
+ 
++#define UL_DEBUG_CURRENT_MASK  UL_DEBUG_MASK(libsmartcols)
++#include "debugobj.h"
++
+ /*
+  * Generic iterator
+  */
+diff --git a/sys-utils/lsns.c b/sys-utils/lsns.c
+index 5ee298172..fb53a16a4 100644
+--- a/sys-utils/lsns.c
++++ b/sys-utils/lsns.c
+@@ -55,6 +55,9 @@ UL_DEBUG_DEFINE_MASKNAMES(lsns) = UL_DEBUG_EMPTY_MASKNAMES;
+ #define DBG(m, x)       __UL_DBG(lsns, LSNS_DEBUG_, m, x)
+ #define ON_DBG(m, x)    __UL_DBG_CALL(lsns, LSNS_DEBUG_, m, x)
+ 
++#define UL_DEBUG_CURRENT_MASK  UL_DEBUG_MASK(lsns)
++#include "debugobj.h"
++
+ struct idcache *uid_cache = NULL;
+ 
+ /* column IDs */
+-- 
+2.13.6
+
diff --git a/SOURCES/0148-mkswap-tolerate-ENOTSUP-when-failing-to-relabel.patch b/SOURCES/0148-mkswap-tolerate-ENOTSUP-when-failing-to-relabel.patch
new file mode 100644
index 0000000..d1f36df
--- /dev/null
+++ b/SOURCES/0148-mkswap-tolerate-ENOTSUP-when-failing-to-relabel.patch
@@ -0,0 +1,34 @@
+From a656eda4cf268f555563d45808df4bb1df54c95f Mon Sep 17 00:00:00 2001
+From: Lubomir Rintel <lkundrak@v3.sk>
+Date: Mon, 18 Apr 2016 09:01:23 +0200
+Subject: [PATCH] mkswap: tolerate ENOTSUP when failing to relabel
+
+It might be that the underlying filesystem just doesn't support SELinux
+labeling. This fixes creating swap on vfat live media:
+
+  # livecd-iso-to-disk.sh --msdos --swap-size-mb 666 ...
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1538545
+Upstream: http://github.com/karelzak/util-linux/commit/d97dc0ee2505e80c8e9fca89aa2001b2ec2c3695
+Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ disk-utils/mkswap.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/disk-utils/mkswap.c b/disk-utils/mkswap.c
+index ec6fc5f99..ff47f2038 100644
+--- a/disk-utils/mkswap.c
++++ b/disk-utils/mkswap.c
+@@ -656,7 +656,7 @@ main(int argc, char **argv) {
+ 		context_string = context_str(newcontext);
+ 
+ 		if (strcmp(context_string, oldcontext)!=0) {
+-			if (fsetfilecon(DEV, context_string))
++			if (fsetfilecon(DEV, context_string) && errno != ENOTSUP)
+ 				err(EXIT_FAILURE, _("unable to relabel %s to %s"),
+ 						device_name, context_string);
+ 		}
+-- 
+2.13.6
+
diff --git a/SOURCES/0149-libmount-fix-debug-message.patch b/SOURCES/0149-libmount-fix-debug-message.patch
new file mode 100644
index 0000000..c3e2be7
--- /dev/null
+++ b/SOURCES/0149-libmount-fix-debug-message.patch
@@ -0,0 +1,28 @@
+From c817652429d4326bb43a8d975611927170447805 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Thu, 1 Feb 2018 16:52:14 +0100
+Subject: [PATCH] libmount: fix debug message
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1534893
+Upstream: http://github.com/karelzak/util-linux/commit/b058f473d175450c48a65031f1abc8d8b90b2b7b
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ libmount/src/fs.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/libmount/src/fs.c b/libmount/src/fs.c
+index e46ee0c0e..e5c38c1b6 100644
+--- a/libmount/src/fs.c
++++ b/libmount/src/fs.c
+@@ -1451,7 +1451,7 @@ int mnt_fs_print_debug(struct libmnt_fs *fs, FILE *file)
+ {
+ 	if (!fs || !file)
+ 		return -EINVAL;
+-	fprintf(file, "------ fs\n");
++	fprintf(file, "------ fs:\n");
+ 	fprintf(file, "source: %s\n", mnt_fs_get_source(fs));
+ 	fprintf(file, "target: %s\n", mnt_fs_get_target(fs));
+ 	fprintf(file, "fstype: %s\n", mnt_fs_get_fstype(fs));
+-- 
+2.14.3
+
diff --git a/SPECS/util-linux.spec b/SPECS/util-linux.spec
index 7ddf276..48100e4 100644
--- a/SPECS/util-linux.spec
+++ b/SPECS/util-linux.spec
@@ -2,7 +2,7 @@
 Summary: A collection of basic system utilities
 Name: util-linux
 Version: 2.23.2
-Release: 43%{?dist}.2
+Release: 52%{?dist}
 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
@@ -57,6 +57,9 @@ Conflicts: e2fsprogs < 1.41.8-5
 Obsoletes: util-linux-ng < 2.19
 Provides: util-linux-ng = %{version}-%{release}
 Conflicts: filesystem < 3
+# lsmem and chmem from s390utils
+Conflicts: s390utils-base < 2:1.23.0-33
+
 Provides: /bin/dmesg
 Provides: /bin/kill
 Provides: /bin/more
@@ -335,10 +338,53 @@ 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
+#
+# RHEL7.5
+#
 # 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
+# 1498462 - agetty not parsing /etc/os-release correctly when processing /etc/issue
+Patch127: 0127-agetty-fix-etc-os-release-parsing.patch
+# 1490984 - Please update fdisk's manual page
+Patch128: 0128-fdisk-remove-obsolete-info-about-GPT-from-man-page.patch
+# 1487031 - [GSS][RFE]The Ceph disk type is unknown then we run the command "fdisk -l"
+Patch129: 0129-libfdisk-gpt-sync-type-UUIDs-with-upstream.patch
+# 1468646 - lscpu output missing Hypervisor
+Patch130: 0130-lscpu-cleanup-DMI-detection-return-codes.patch
+# 1455398 - flock --timeout=0 doesn't work on RHEL7
+Patch131: 0131-flock-zero-timeout-is-valid.patch
+# 1336432 - journald: SYSLOG_IDENTIFIER is invalid when running logger
+Patch132: 0132-logger-add-man-page-note-about-the-default-tag.patch
+# 1427500 - util-linux: script does not retry on EINTR when logging command output
+Patch133: 0133-script-use-all-io-to-write.patch
+# 1336432 - journald: SYSLOG_IDENTIFIER is invalid when running logger
+Patch134: 0134-logger-do-not-rely-only-getlogin-3-telling-who-ran-t.patch
+# 1296233 - login(1) writes 0.0.0.0 IP address to wtmp when executed with "-h <ipv4-mapping-to-ipv6>" hostname
+Patch135: 0135-login-use-IPv4-on-IPv4-mapping-to-IPv6.patch
+# 1501953 - blkid shows wrong return code on failure with ambivalent results
+Patch136: 0136-blkid-update-man-page-about-lsblk-and-ambivalent-pro.patch
+# 1486777 - wipefs printing duplicate gpt clear messages
+Patch137: 0137-wipefs-fix-t-filter.patch
+# 1454652 - fix test suite
+Patch138: 0138-tests-backport-new-ts_scsi_debug_init.patch
+Patch139: 0139-tests-ts_scsi_debug_init-must-not-run-in-a-subshell.patch
+Patch140: 0140-tests-cleanup-fdisk-outputs.patch
+Patch141: 0141-tests-check-for-mdadm.patch
+# 1496421 - [Pegas1.1 FEAT] z Systems: Move lsmem and chmem to util-linux (through rebase >= 2.30)
+Patch142: 0142-lsmem-chmem-backport-new-commands.patch
+Patch143: 0143-lsmem-make-split-optional-follow-output-by-default.patch
+# 1499760 - gvfs-udisks2-volume-monitor generates huge amount of audit log with access denied messages
+Patch144: 0144-libmount-fix-access-utab-write-test.patch
+# 1520906 - make hostname in login(1) prompt optional [rhel-7.5]
+Patch145: 0145-login-add-LOGIN_PLAIN_PROMPT-to-login.defs.patch
+# 1521163 - [RFE] blkid can identify magic number and UUID of VDO volume
+Patch146: 0146-libblkid-Add-VDO-superblock-information-into-blkid.patch
+# 1534893 - RHEL7: util-linux: mount/unmount ASLR bypass via environment variable in libmount
+Patch147: 0147-include-debug-don-t-print-pointer-address-for-SUID-p.patch
+# 1538545 - SELinux error creating swap file
+Patch148: 0148-mkswap-tolerate-ENOTSUP-when-failing-to-relabel.patch
+# 1534893 - RHEL7: util-linux: mount/unmount ASLR bypass via environment variable in libmount
+Patch149: 0149-libmount-fix-debug-message.patch
 
 %description
 The util-linux package contains a large variety of low-level system
@@ -595,8 +641,7 @@ 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
-
+ln -sf ../proc/self/mounts %{buildroot}/etc/mtab
 
 # remove static libs
 rm -f $RPM_BUILD_ROOT%{_libdir}/lib{uuid,blkid,mount}.a
@@ -634,7 +679,7 @@ if [ -x /usr/sbin/selinuxenabled ] && /usr/sbin/selinuxenabled; then
 	fi
 fi
 if [ ! -L /etc/mtab ]; then
-	ln -fs /proc/mounts /etc/mtab
+	ln -sf ../proc/self/mounts /etc/mtab || :
 fi
 
 %post -n libblkid
@@ -719,6 +764,7 @@ fi
 %{_bindir}/colcrt
 %{_bindir}/colrm
 %{_bindir}/column
+%{_bindir}/chmem
 %{_bindir}/dmesg
 %{_bindir}/eject
 %{_bindir}/fallocate
@@ -734,6 +780,7 @@ fi
 %{_bindir}/kill
 %{_bindir}/lsipc
 %{_bindir}/lsns
+%{_bindir}/lsmem
 %{_bindir}/logger
 %{_bindir}/look
 %{_bindir}/lsblk
@@ -788,6 +835,7 @@ fi
 %{_mandir}/man1/look.1*
 %{_mandir}/man1/lscpu.1*
 %{_mandir}/man1/lslogins.1*
+%{_mandir}/man1/lsmem.1*
 %{_mandir}/man1/lsipc.1*
 %{_mandir}/man1/mcookie.1*
 %{_mandir}/man1/more.1*
@@ -820,6 +868,7 @@ fi
 %{_mandir}/man8/blkid.8*
 %{_mandir}/man8/blockdev.8*
 %{_mandir}/man8/chcpu.8*
+%{_mandir}/man8/chmem.8*
 %{_mandir}/man8/ctrlaltdel.8*
 %{_mandir}/man8/delpart.8*
 %{_mandir}/man8/fdisk.8*
@@ -1069,11 +1118,45 @@ fi
 %{_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)
+* Fri Feb 02 2018 Karel Zak <kzak@redhat.com> 2.23.2-52
+- fix #1534893 - RHEL7: util-linux: mount/unmount ASLR bypass via environment variable in libmount
+
+* Wed Jan 31 2018 Karel Zak <kzak@redhat.com> 2.23.2-51
+- fix #1538545 - SELinux error creating swap file
+
+* Tue Jan 23 2018 Karel Zak <kzak@redhat.com> 2.23.2-50
+- fix #1534893 - RHEL7: util-linux: mount/unmount ASLR bypass via environment variable in libmount
+
+* Mon Dec 11 2017 Karel Zak <kzak@redhat.com> 2.23.2-49
+- fix #1520906 - make hostname in login(1) prompt optional
+- fix #1521163 - [RFE] blkid can identify magic number and UUID of VDO volume
+
+* Thu Nov 09 2017 Karel Zak <kzak@redhat.com> 2.23.2-48
+- improve libmount eaccess test (#1499760)
+
+* Wed Nov 08 2017 Karel Zak <kzak@redhat.com> 2.23.2-47
+- improve lsmem (#1496421)
+
+* Mon Oct 23 2017 Karel Zak <kzak@redhat.com> 2.23.2-46
+- fix #1496421 - Move lsmem and chmem to util-linux
+
+* Tue Oct 17 2017 Karel Zak <kzak@redhat.com> 2.23.2-45
+- fix #1501953 - blkid shows wrong return code on failure with ambivalent results
+- fix #1486777 - wipefs printing duplicate gpt clear messages
+- fix #1454652 - fix test suite
 
-* Mon Oct 30 2017 Karel Zak <kzak@redhat.com> 2.23.2-43.el7_4.1
+* Mon Oct 16 2017 Karel Zak <kzak@redhat.com> 2.23.2-44
+- fix #1478002 - systemd read-only container produces errors
 - fix #1499760 - gvfs-udisks2-volume-monitor generates huge amount of audit log with access denied messages
+- fix #1498462 - agetty not parsing /etc/os-release correctly when processing /etc/issue
+- fix #1490984 - Please update fdisk's manual page
+- fix #1487031 - [GSS][RFE]The Ceph disk type is unknown then we run the command "fdisk -l"
+- fix #1468646 - lscpu output missing Hypervisor
+- fix #1455398 - flock --timeout=0 doesn't work on RHEL7
+- fix #1336432 - journald: SYSLOG_IDENTIFIER is invalid when running logger
+- fix #1427500 - util-linux: script does not retry on EINTR when logging command output
+- fix #1336432 - journald: SYSLOG_IDENTIFIER is invalid when running logger
+- fix #1296233 - login(1) writes 0.0.0.0 IP address to wtmp when executed with "-h <ipv4-mapping-to-ipv6>" hostname
 
 * 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