diff --git a/SOURCES/0089-fdisk-fix-Blocks-column-calculation.patch b/SOURCES/0089-fdisk-fix-Blocks-column-calculation.patch new file mode 100644 index 0000000..5e9aec0 --- /dev/null +++ b/SOURCES/0089-fdisk-fix-Blocks-column-calculation.patch @@ -0,0 +1,27 @@ +From acf8de63d2a797850935feeaf6bac2dd21c9b496 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Wed, 15 Mar 2017 13:23:56 +0100 +Subject: [PATCH 089/116] fdisk: fix Blocks column calculation + +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1344102 +Signed-off-by: Karel Zak +--- + fdisks/fdiskdoslabel.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fdisks/fdiskdoslabel.c b/fdisks/fdiskdoslabel.c +index b7eb35a..6375692 100644 +--- a/fdisks/fdiskdoslabel.c ++++ b/fdisks/fdiskdoslabel.c +@@ -1202,7 +1202,7 @@ int dos_list_table(struct fdisk_context *cxt, + p = pe->part_table; + if (p && !is_cleared_partition(p)) { + unsigned int psects = get_nr_sects(p); +- unsigned int pblocks = psects; ++ unsigned long pblocks = psects; + unsigned int podd = 0; + struct fdisk_parttype *type = + fdisk_get_parttype_from_code(cxt, p->sys_ind); +-- +2.9.3 + diff --git a/SOURCES/0090-fdisk-fix-menu-for-GPT.patch b/SOURCES/0090-fdisk-fix-menu-for-GPT.patch new file mode 100644 index 0000000..efd40e2 --- /dev/null +++ b/SOURCES/0090-fdisk-fix-menu-for-GPT.patch @@ -0,0 +1,45 @@ +From 64107c0347dde0b7207b31132837864bd5f4c714 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Wed, 15 Mar 2017 14:16:25 +0100 +Subject: [PATCH 090/116] fdisk: fix menu for GPT + +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1344720 +Signed-off-by: Karel Zak +--- + fdisks/fdisk.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/fdisks/fdisk.c b/fdisks/fdisk.c +index 2656711..0ec9909 100644 +--- a/fdisks/fdisk.c ++++ b/fdisks/fdisk.c +@@ -87,18 +87,21 @@ static const struct menulist_descr menulist[] = { + {'n', N_("add a new partition"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF | FDISK_DISKLABEL_GPT, 0}}, + {'o', N_("change rotation speed (rpm)"), {0, FDISK_DISKLABEL_SUN}}, + {'o', N_("create a new empty DOS partition table"), {~FDISK_DISKLABEL_OSF, 0}}, +- {'p', N_("print the partition table"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF, FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN}}, ++ {'p', N_("print the partition table"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF | FDISK_DISKLABEL_GPT, ++ FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_GPT }}, + {'q', N_("quit without saving changes"), {FDISK_DISKLABEL_ANY, FDISK_DISKLABEL_ANY}}, +- {'r', N_("return to main menu"), {FDISK_DISKLABEL_OSF, FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF}}, ++ {'r', N_("return to main menu"), {FDISK_DISKLABEL_OSF, FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF | FDISK_DISKLABEL_GPT}}, + {'s', N_("change number of sectors/track"), {0, FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN}}, + {'s', N_("create a new empty Sun disklabel"), {~FDISK_DISKLABEL_OSF, 0}}, + {'s', N_("show complete disklabel"), {FDISK_DISKLABEL_OSF, 0}}, + {'t', N_("change a partition's system id"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF, 0}}, + {'u', N_("change display/entry units"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF, 0}}, +- {'v', N_("verify the partition table"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI, FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI}}, ++ {'v', N_("verify the partition table"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_GPT, ++ FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_GPT}}, + {'w', N_("write disklabel to disk"), {FDISK_DISKLABEL_OSF, 0}}, +- {'w', N_("write table to disk and exit"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_GPT, FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI}}, +- {'x', N_("extra functionality (experts only)"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI, 0}}, ++ {'w', N_("write table to disk and exit"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_GPT, ++ FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_GPT}}, ++ {'x', N_("extra functionality (experts only)"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_GPT, 0}}, + #if !defined (__alpha__) + {'x', N_("link BSD partition to non-BSD partition"), {FDISK_DISKLABEL_OSF, 0}}, + #endif +-- +2.9.3 + diff --git a/SOURCES/0091-logger-backport-size.patch b/SOURCES/0091-logger-backport-size.patch new file mode 100644 index 0000000..41d6ec5 --- /dev/null +++ b/SOURCES/0091-logger-backport-size.patch @@ -0,0 +1,165 @@ +From 1e0289af99737049de97b8cfe342b56d380560bf Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Thu, 16 Mar 2017 12:20:58 +0100 +Subject: [PATCH 091/116] logger: backport --size + +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1323916 +Signed-off-by: Karel Zak +--- + misc-utils/logger.1 | 6 ++++++ + misc-utils/logger.c | 34 ++++++++++++++++++++++++---------- + 2 files changed, 30 insertions(+), 10 deletions(-) + +diff --git a/misc-utils/logger.1 b/misc-utils/logger.1 +index 8c4faca..57ca0d5 100644 +--- a/misc-utils/logger.1 ++++ b/misc-utils/logger.1 +@@ -98,6 +98,12 @@ logs the message as informational in the local3 facility. + The default is + .IR user.notice . + .TP ++\fB\-S\fR, \fB\-\-size\fR \fIsize\fR ++Sets the maximum permitted message size. The default is 1KiB, which is ++the limit traditionally used and specified in RFC 3164. When selecting a ++maximum message size, it is important to ensure that the receiver supports ++the max size as well, otherwise messages may become truncated. ++.TP + \fB\-s\fR, \fB\-\-stderr\fR + Output the message to standard error as well as to the system log. + .TP +diff --git a/misc-utils/logger.c b/misc-utils/logger.c +index a331869..dfda018 100644 +--- a/misc-utils/logger.c ++++ b/misc-utils/logger.c +@@ -54,6 +54,8 @@ + #include "closestream.h" + #include "nls.h" + #include "strutils.h" ++#include "xalloc.h" ++#include "all-io.h" + + #define SYSLOG_NAMES + #include +@@ -183,7 +185,7 @@ inet_socket(const char *servername, const char *port, const int socket_type) + + static void + mysyslog(int fd, int logflags, int pri, char *tag, char *msg) { +- char buf[1000], pid[30], *cp, *tp; ++ char *buf, pid[30], *cp, *tp; + time_t now; + + if (fd > -1) { +@@ -201,11 +203,11 @@ mysyslog(int fd, int logflags, int pri, char *tag, char *msg) { + (void)time(&now); + tp = ctime(&now)+4; + +- snprintf(buf, sizeof(buf), "<%d>%.15s %.200s%s: %.400s", ++ xasprintf(&buf, "<%d>%.15s %.200s%s: %s", + pri, tp, cp, pid, msg); + +- if (write(fd, buf, strlen(buf)+1) < 0) +- return; /* error */ ++ write_all(fd, buf, strlen(buf)+1); ++ free(buf); + } + } + +@@ -221,6 +223,7 @@ static void __attribute__ ((__noreturn__)) usage(FILE *out) + " -i, --id log the process ID too\n" + " -f, --file log the contents of this file\n" + " -h, --help display this help text and exit\n"), out); ++ fputs(_(" -S, --size maximum size for a single message (default 1024)\n"), out); + fputs(_(" -n, --server write to this remote syslog server\n" + " -P, --port use this port for UDP or TCP connection\n" + " -p, --priority mark given message with this priority\n" +@@ -241,11 +244,12 @@ static void __attribute__ ((__noreturn__)) usage(FILE *out) + int + main(int argc, char **argv) { + int ch, logflags, pri; +- char *tag, buf[1024]; ++ char *tag, *buf; + char *usock = NULL; + char *server = NULL; + char *port = NULL; + int LogSock = -1, socket_type = ALL_TYPES; ++ size_t max_message_size = 1024; + + static const struct option longopts[] = { + { "id", no_argument, 0, 'i' }, +@@ -253,6 +257,7 @@ main(int argc, char **argv) { + { "file", required_argument, 0, 'f' }, + { "priority", required_argument, 0, 'p' }, + { "tag", required_argument, 0, 't' }, ++ { "size", required_argument, 0, 'S' }, + { "socket", required_argument, 0, 'u' }, + { "udp", no_argument, 0, 'd' }, + { "tcp", no_argument, 0, 'T' }, +@@ -271,7 +276,7 @@ main(int argc, char **argv) { + tag = NULL; + pri = LOG_NOTICE; + logflags = 0; +- while ((ch = getopt_long(argc, argv, "f:ip:st:u:dTn:P:Vh", ++ while ((ch = getopt_long(argc, argv, "f:ip:st:u:dTn:P:S:Vh", + longopts, NULL)) != -1) { + switch((char)ch) { + case 'f': /* file to log */ +@@ -297,6 +302,10 @@ main(int argc, char **argv) { + case 'd': + socket_type = TYPE_UDP; + break; ++ case 'S': ++ max_message_size = strtosize_or_err(optarg, ++ _("failed to parse message size")); ++ break; + case 'T': + socket_type = TYPE_TCP; + break; +@@ -327,21 +336,23 @@ main(int argc, char **argv) { + else + openlog(tag ? tag : getlogin(), logflags, 0); + ++ buf = xcalloc(1, max_message_size); ++ + /* log input line if appropriate */ + if (argc > 0) { + register char *p, *endp; + size_t len; + +- for (p = buf, endp = buf + sizeof(buf) - 2; *argv;) { ++ for (p = buf, endp = buf + max_message_size - 2; *argv;) { + len = strlen(*argv); + if (p + len > endp && p > buf) { + if (!usock && !server) + syslog(pri, "%s", buf); + else + mysyslog(LogSock, logflags, pri, tag, buf); +- p = buf; ++ p = buf; + } +- if (len > sizeof(buf) - 1) { ++ if (len > max_message_size - 1) { + if (!usock && !server) + syslog(pri, "%s", *argv++); + else +@@ -360,7 +371,7 @@ main(int argc, char **argv) { + mysyslog(LogSock, logflags, pri, tag, buf); + } + } else { +- while (fgets(buf, sizeof(buf), stdin) != NULL) { ++ while (fgets(buf, max_message_size, stdin) != NULL) { + /* glibc is buggy and adds an additional newline, + so we have to remove it here until glibc is fixed */ + int len = strlen(buf); +@@ -374,6 +385,9 @@ main(int argc, char **argv) { + mysyslog(LogSock, logflags, pri, tag, buf); + } + } ++ ++ free(buf); ++ + if (!usock && !server) + closelog(); + else +-- +2.9.3 + diff --git a/SOURCES/0092-fdisk-print-header-UUID-for-GPT.patch b/SOURCES/0092-fdisk-print-header-UUID-for-GPT.patch new file mode 100644 index 0000000..d7f91ed --- /dev/null +++ b/SOURCES/0092-fdisk-print-header-UUID-for-GPT.patch @@ -0,0 +1,70 @@ +From 6f768ec049944ab39c79fcaa7bdf9622385b7672 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Thu, 16 Mar 2017 13:29:50 +0100 +Subject: [PATCH 092/116] fdisk: print header UUID for GPT + +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1344726 +Signed-off-by: Karel Zak +--- + fdisks/fdisk.c | 2 ++ + libfdisk/src/fdiskP.h | 1 + + libfdisk/src/gpt.c | 18 ++++++++++++++++++ + 3 files changed, 21 insertions(+) + +diff --git a/fdisks/fdisk.c b/fdisks/fdisk.c +index 0ec9909..974d735 100644 +--- a/fdisks/fdisk.c ++++ b/fdisks/fdisk.c +@@ -657,6 +657,8 @@ list_disk_geometry(struct fdisk_context *cxt) { + printf(_("Disk label type: %s\n"), cxt->label->name); + if (fdisk_is_disklabel(cxt, DOS)) + dos_print_mbr_id(cxt); ++ if (fdisk_is_disklabel(cxt, GPT)) ++ gpt_print_header_id(cxt); + printf("\n"); + } + +diff --git a/libfdisk/src/fdiskP.h b/libfdisk/src/fdiskP.h +index ce42860..6711ab8 100644 +--- a/libfdisk/src/fdiskP.h ++++ b/libfdisk/src/fdiskP.h +@@ -315,6 +315,7 @@ extern void fdisk_deinit_label(struct fdisk_label *lb); + + /* gpt.c -- temporary bypass library API... */ + extern void gpt_list_table(struct fdisk_context *cxt, int xtra); ++extern void gpt_print_header_id(struct fdisk_context *cxt); + + /* ask.c */ + extern int fdisk_ask_partnum(struct fdisk_context *cxt, size_t *partnum, int wantnew); +diff --git a/libfdisk/src/gpt.c b/libfdisk/src/gpt.c +index d3bdc2d..899e1b2 100644 +--- a/libfdisk/src/gpt.c ++++ b/libfdisk/src/gpt.c +@@ -341,6 +341,24 @@ static inline int partition_unused(const struct gpt_entry *e) + sizeof(struct gpt_guid)); + } + ++void gpt_print_header_id(struct fdisk_context *cxt) ++{ ++ char str[37]; ++ struct gpt_header *header; ++ struct fdisk_gpt_label *gpt; ++ ++ assert(cxt); ++ assert(cxt->label); ++ assert(fdisk_is_disklabel(cxt, GPT)); ++ ++ gpt = self_label(cxt); ++ header = gpt->pheader ? gpt->pheader : gpt->bheader; ++ ++ guid_to_string(&header->disk_guid, str); ++ ++ printf("Disk identifier: %s\n", str); ++} ++ + /* + * Builds a clean new valid protective MBR - will wipe out any existing data. + * Returns 0 on success, otherwise < 0 on error. +-- +2.9.3 + diff --git a/SOURCES/0093-fdisk-improve-l-error-handling.patch b/SOURCES/0093-fdisk-improve-l-error-handling.patch new file mode 100644 index 0000000..8471c1a --- /dev/null +++ b/SOURCES/0093-fdisk-improve-l-error-handling.patch @@ -0,0 +1,76 @@ +From e4f26d51bd06910634c2aaeccfecc7e6cd61ef0a Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Fri, 17 Mar 2017 11:47:00 +0100 +Subject: [PATCH 093/116] fdisk: improve -l error handling + +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1362662 +Signed-off-by: Karel Zak +--- + fdisks/fdisk.c | 23 ++++++++++++++++------- + 1 file changed, 16 insertions(+), 7 deletions(-) + +diff --git a/fdisks/fdisk.c b/fdisks/fdisk.c +index 974d735..177921a 100644 +--- a/fdisks/fdisk.c ++++ b/fdisks/fdisk.c +@@ -924,11 +924,15 @@ static int is_ide_cdrom_or_tape(char *device) + } + + /* Print disk geometry and partition table of a specified device (-l option) */ +-static void print_partition_table_from_option(struct fdisk_context *cxt, +- char *device, unsigned long sector_size) ++static int print_partition_table_from_option(struct fdisk_context *cxt, ++ char *device, unsigned long sector_size, ++ int warnme) + { +- if (fdisk_context_assign_device(cxt, device, 1) != 0) /* read-only */ +- err(EXIT_FAILURE, _("cannot open %s"), device); ++ if (fdisk_context_assign_device(cxt, device, 1) != 0) { /* read-only */ ++ if (warnme || errno == EACCES) ++ warn(_("cannot open %s"), device); ++ return -1; ++ } + + if (sector_size) /* passed -b option, override autodiscovery */ + fdisk_override_sector_size(cxt, sector_size); +@@ -941,6 +945,8 @@ static void print_partition_table_from_option(struct fdisk_context *cxt, + list_table(cxt, 0); + else + list_disk_geometry(cxt); ++ ++ return 0; + } + + /* +@@ -971,7 +977,7 @@ print_all_partition_table_from_option(struct fdisk_context *cxt, + char *cn = canonicalize_path(devname); + if (cn) { + if (!is_ide_cdrom_or_tape(cn)) +- print_partition_table_from_option(cxt, cn, sector_size); ++ print_partition_table_from_option(cxt, cn, sector_size, 0); + free(cn); + } + } +@@ -1223,14 +1229,17 @@ int main(int argc, char **argv) + " be used with one specified device\n")); + + if (optl) { ++ int rc = 0; ++ + nowarn = 1; + if (argc > optind) { + int k; + for (k = optind; k < argc; k++) +- print_partition_table_from_option(cxt, argv[k], sector_size); ++ rc += print_partition_table_from_option(cxt, argv[k], sector_size, 1); + } else + print_all_partition_table_from_option(cxt, sector_size); +- exit(EXIT_SUCCESS); ++ ++ exit(rc ? EXIT_FAILURE : EXIT_SUCCESS); + } + + if (opts) { +-- +2.9.3 + diff --git a/SOURCES/0094-losetup-improve-man-page-SYNOPSIS.patch b/SOURCES/0094-losetup-improve-man-page-SYNOPSIS.patch new file mode 100644 index 0000000..df5427a --- /dev/null +++ b/SOURCES/0094-losetup-improve-man-page-SYNOPSIS.patch @@ -0,0 +1,42 @@ +From 38899e30a9a195adb4732185ed62d55a03ecc96d Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Fri, 17 Mar 2017 14:02:39 +0100 +Subject: [PATCH 094/116] losetup: improve man page SYNOPSIS + +and remove obsolete "-p fd" from the man page. + +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1369436 +Signed-off-by: Karel Zak +--- + sys-utils/losetup.8 | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/sys-utils/losetup.8 b/sys-utils/losetup.8 +index bd73518..9a8c1d5 100644 +--- a/sys-utils/losetup.8 ++++ b/sys-utils/losetup.8 +@@ -37,7 +37,7 @@ Print name of first unused loop device: + .B "losetup \-f" + .sp + .in -5 +-Setup loop device: ++Set up a loop device: + .sp + .in +5 + .B losetup +@@ -46,10 +46,8 @@ Setup loop device: + .RB [ \-\-sizelimit + .IR size ] + .in +8 +-.RB [ \-p +-.IR pfd ] +-.RB [ \-rP ] +-.RB { \-f [ \-\-show ]| \fIloopdev\fP } ++.RB [ \-Pr ] ++.RB [ \-\-show ] " \-f" | \fIloopdev\fP + .I file + .sp + .in -13 +-- +2.9.3 + diff --git a/SOURCES/0095-libblkid-fix-potential-bufer-overflows.patch b/SOURCES/0095-libblkid-fix-potential-bufer-overflows.patch new file mode 100644 index 0000000..5eceb9a --- /dev/null +++ b/SOURCES/0095-libblkid-fix-potential-bufer-overflows.patch @@ -0,0 +1,103 @@ +From 55540ea3dfdc707dc998333fd0715549522464fb Mon Sep 17 00:00:00 2001 +From: Sebastian Krahmer +Date: Fri, 5 Dec 2014 10:06:42 +0100 +Subject: [PATCH 095/116] libblkid: fix potential bufer overflows + +While digging deeper into libblk probing, I found that some +computations might wrap and allocate too few buffer space which then +overflows. In particular on 32bit systems (chromebook) where size_t is +32bit, this is problematic (for 64bit the result fits into the calloc +size_t). + +Upstream: Upstream: https://github.com/karelzak/util-linux/commit/109df14fad4e9570e26950913ebace6c79289400 +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1392656 +Signed-off-by: Karel Zak +--- + libblkid/src/partitions/gpt.c | 12 ++++++++---- + libblkid/src/probe.c | 7 +++++++ + libblkid/src/superblocks/zfs.c | 3 +++ + 3 files changed, 18 insertions(+), 4 deletions(-) + +diff --git a/libblkid/src/partitions/gpt.c b/libblkid/src/partitions/gpt.c +index 6ab0dc6..e801ea3 100644 +--- a/libblkid/src/partitions/gpt.c ++++ b/libblkid/src/partitions/gpt.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + + #include "partitions.h" + #include "crc32.h" +@@ -266,14 +267,17 @@ static struct gpt_header *get_gpt_header( + return NULL; + } + +- /* Size of blocks with GPT entries */ +- esz = le32_to_cpu(h->num_partition_entries) * +- le32_to_cpu(h->sizeof_partition_entry); +- if (!esz) { ++ if (le32_to_cpu(h->num_partition_entries) == 0 || ++ le32_to_cpu(h->sizeof_partition_entry) == 0 || ++ ULONG_MAX / le32_to_cpu(h->num_partition_entries) < le32_to_cpu(h->sizeof_partition_entry)) { + DBG(LOWPROBE, blkid_debug("GPT entries undefined")); + return NULL; + } + ++ /* Size of blocks with GPT entries */ ++ esz = le32_to_cpu(h->num_partition_entries) * ++ le32_to_cpu(h->sizeof_partition_entry); ++ + /* The header seems valid, save it + * (we don't care about zeros in hdr->reserved2 area) */ + memcpy(hdr, h, sizeof(*h)); +diff --git a/libblkid/src/probe.c b/libblkid/src/probe.c +index f9fab5b..9cf099a 100644 +--- a/libblkid/src/probe.c ++++ b/libblkid/src/probe.c +@@ -103,6 +103,7 @@ + #include + #include + #include ++#include + + #ifdef HAVE_LIBUUID + # include +@@ -565,6 +566,12 @@ unsigned char *blkid_probe_get_buffer(blkid_probe pr, + return NULL; + } + ++ /* someone trying to overflow some buffers? */ ++ if (len > ULONG_MAX - sizeof(struct blkid_bufinfo)) { ++ errno = ENOMEM; ++ return NULL; ++ } ++ + /* allocate info and space for data by why call */ + bf = calloc(1, sizeof(struct blkid_bufinfo) + len); + if (!bf) { +diff --git a/libblkid/src/superblocks/zfs.c b/libblkid/src/superblocks/zfs.c +index 406ba2b..56ee472 100644 +--- a/libblkid/src/superblocks/zfs.c ++++ b/libblkid/src/superblocks/zfs.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + + #include "superblocks.h" + +@@ -108,6 +109,8 @@ static void zfs_extract_guid_name(blkid_probe pr, loff_t offset) + + nvs->nvs_type = be32_to_cpu(nvs->nvs_type); + nvs->nvs_strlen = be32_to_cpu(nvs->nvs_strlen); ++ if (nvs->nvs_strlen > UINT_MAX - sizeof(*nvs)) ++ break; + avail -= nvs->nvs_strlen + sizeof(*nvs); + nvdebug("nvstring: type %u string %*s\n", nvs->nvs_type, + nvs->nvs_strlen, nvs->nvs_string); +-- +2.9.3 + diff --git a/SOURCES/0096-umount-fix-obsolete-info-about-loop-in-umount.8.patch b/SOURCES/0096-umount-fix-obsolete-info-about-loop-in-umount.8.patch new file mode 100644 index 0000000..7d03314 --- /dev/null +++ b/SOURCES/0096-umount-fix-obsolete-info-about-loop-in-umount.8.patch @@ -0,0 +1,53 @@ +From ad1c931f24e81b169127d611eb8aac72665c4bf2 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Tue, 30 Aug 2016 10:25:44 +0200 +Subject: [PATCH 096/116] umount: fix obsolete info about loop= in umount.8 + +Upstream: Upstream: Upstream: https://github.com/karelzak/util-linux/commit/d00eb87ba284635e72b10880dfcf409276fa41b0 +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1370959 +Signed-off-by: Karel Zak +--- + sys-utils/umount.8 | 20 ++++++++++++-------- + 1 file changed, 12 insertions(+), 8 deletions(-) + +diff --git a/sys-utils/umount.8 b/sys-utils/umount.8 +index 1fa653c..f0a712b 100644 +--- a/sys-utils/umount.8 ++++ b/sys-utils/umount.8 +@@ -78,8 +78,10 @@ Do not canonicalize paths. For more details about this option see the + man page. + .TP + \fB\-d\fR, \fB\-\-detach\-loop\fR +-In case the unmounted device was a loop device, also free this loop +-device. ++When the unmounted device was a loop device, also free this loop ++device. This option is unnecessary for devices initialized by ++.BR mount (8), ++in this case "autoclear" functionality is enabled by default. + .TP + \fB\-\-fake\fP + Causes everything to be done except for the actual system call; this 'fakes' +@@ -145,12 +147,14 @@ Print version and exit. + .SH "THE LOOP DEVICE" + The + .B umount +-command will free the loop device (if any) associated with the mount, in +-case it finds the option 'loop=...' in +-.IR /etc/mtab , +-or when the \-d option was given. Any pending loop devices can be freed +-using 'losetup -d', see +-.BR losetup (8). ++command will automatically detach loop device previously initialized by ++.BR mount (8) ++command independently of /etc/mtab. ++ ++In this case the device is initialized with "autoclear" flag (see ++.BR losetup (8) ++output for more details), otherwise it's necessary to use the option \fB \-\-detach\-loop\fR ++or call \fBlosetup -d \fR. The autoclear feature is supported since Linux 2.6.25. + .SH NOTES + The syntax of external umount helpers is: + .PP +-- +2.9.3 + diff --git a/SOURCES/0097-mount-fix-all-and-nofail-return-code.patch b/SOURCES/0097-mount-fix-all-and-nofail-return-code.patch new file mode 100644 index 0000000..0863b88 --- /dev/null +++ b/SOURCES/0097-mount-fix-all-and-nofail-return-code.patch @@ -0,0 +1,43 @@ +From d94c73b186ea4fec6333d1fb6cced1b4b8515d58 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Mon, 7 Apr 2014 11:53:05 +0200 +Subject: [PATCH 097/116] mount: fix --all and nofail return code + +Now the "nofail" affects warnings warning messages only. That's wrong +and regression (against original non-libmount version). The nofail has +to control return code too. + +Upstream: https://github.com/karelzak/util-linux/commit/8ab82185eed76bc20694a197fe10c5f9fb795b80 +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1357746 +Reported-by: Patrick McLean +Signed-off-by: Karel Zak +--- + sys-utils/mount.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/sys-utils/mount.c b/sys-utils/mount.c +index f332070..44e2b7c 100644 +--- a/sys-utils/mount.c ++++ b/sys-utils/mount.c +@@ -197,12 +197,14 @@ static int mount_all(struct libmnt_context *cxt) + if (mnt_context_is_verbose(cxt)) + printf("%-25s: mount successfully forked\n", tgt); + } else { +- mk_exit_code(cxt, mntrc); /* to print warnings */ +- +- if (mnt_context_get_status(cxt)) { ++ if (mk_exit_code(cxt, mntrc) == MOUNT_EX_SUCCESS) { + nsucc++; + +- if (mnt_context_is_verbose(cxt)) ++ /* Note that MOUNT_EX_SUCCESS return code does ++ * not mean that FS has been really mounted ++ * (e.g. nofail option) */ ++ if (mnt_context_get_status(cxt) ++ && mnt_context_is_verbose(cxt)) + printf("%-25s: successfully mounted\n", tgt); + } else + nerrs++; +-- +2.9.3 + diff --git a/SOURCES/0098-umount-exclude-selinuxfs-from-all.patch b/SOURCES/0098-umount-exclude-selinuxfs-from-all.patch new file mode 100644 index 0000000..aeb6279 --- /dev/null +++ b/SOURCES/0098-umount-exclude-selinuxfs-from-all.patch @@ -0,0 +1,28 @@ +From 92da0dea47ffceffb4a049a0a1094e41e212ceee Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Thu, 9 Feb 2017 11:21:49 +0100 +Subject: [PATCH 098/116] umount: exclude selinuxfs from --all + +Upstream: https://github.com/karelzak/util-linux/commit/9e66fd30d7bfbd7279db6100830aa9045d0255ca +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1417722 +Signed-off-by: Karel Zak +--- + sys-utils/umount.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sys-utils/umount.c b/sys-utils/umount.c +index 9c47744..48483dc 100644 +--- a/sys-utils/umount.c ++++ b/sys-utils/umount.c +@@ -605,7 +605,7 @@ int main(int argc, char **argv) + + if (all) { + if (!types) +- types = "noproc,nodevfs,nodevpts,nosysfs,norpc_pipefs,nonfsd"; ++ types = "noproc,nodevfs,nodevpts,nosysfs,norpc_pipefs,nonfsd,noselinuxfs"; + + mnt_context_set_fstype_pattern(cxt, types); + rc = umount_all(cxt); +-- +2.9.3 + diff --git a/SOURCES/0099-sfdisk-remove-useless-CDROM-detection-for-s.patch b/SOURCES/0099-sfdisk-remove-useless-CDROM-detection-for-s.patch new file mode 100644 index 0000000..deca6be --- /dev/null +++ b/SOURCES/0099-sfdisk-remove-useless-CDROM-detection-for-s.patch @@ -0,0 +1,61 @@ +From 8229770ff79a383d7e5b133f94609e861aae4283 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Fri, 17 Mar 2017 15:03:28 +0100 +Subject: [PATCH 099/116] sfdisk: remove useless CDROM detection for -s + +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1402825 +Signed-off-by: Karel Zak +--- + fdisks/sfdisk.c | 16 ++++++---------- + 1 file changed, 6 insertions(+), 10 deletions(-) + +diff --git a/fdisks/sfdisk.c b/fdisks/sfdisk.c +index 93bca27..afb15fc 100644 +--- a/fdisks/sfdisk.c ++++ b/fdisks/sfdisk.c +@@ -2905,36 +2905,32 @@ do_pt_geom(char *dev, int silent) { + /* for compatibility with earlier fdisk: provide option -s */ + static void + do_size(char *dev, int silent) { +- int fd; ++ int fd, rc; + unsigned long long size; + + fd = my_open(dev, 0, silent); + if (fd < 0) + return; + +- if (blkdev_get_sectors(fd, &size) == -1) { ++ rc = blkdev_get_sectors(fd, &size); ++ close(fd); ++ ++ if (rc == -1) { + if (!silent) { + perror(dev); + errx(EXIT_FAILURE, _("Cannot get size of %s"), dev); + } +- goto done; ++ return; + } + + size /= 2; /* convert sectors to blocks */ + +- /* a CDROM drive without mounted CD yields MAXINT */ +- if (silent && size == ((1 << 30) - 1)) +- goto done; +- + if (silent) + printf("%s: %9llu\n", dev, size); + else + printf("%llu\n", size); + + total_size += size; +- +-done: +- close(fd); + } + + /* +-- +2.9.3 + diff --git a/SOURCES/0100-more-fix-repeat-search-crash.patch b/SOURCES/0100-more-fix-repeat-search-crash.patch new file mode 100644 index 0000000..edfd77f --- /dev/null +++ b/SOURCES/0100-more-fix-repeat-search-crash.patch @@ -0,0 +1,41 @@ +From d7e6a773863ad47dbdab9244b6629590d4b46f0e Mon Sep 17 00:00:00 2001 +From: Sami Kerola +Date: Tue, 27 Jan 2015 22:28:57 +0000 +Subject: [PATCH 100/116] more: fix repeat search crash + +Repeating a search for a pattern that did not found made more(1) to +crash. To reproduce 'more /etc/services' and search for 'doom'; you will +find a service in port 666 - pressing '.' after that result used to cause +core dump. + +Upstream: https://github.com/karelzak/util-linux/commit/bc1ed338814f69473629b04c5e9efae5d7db3b72 +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1403973 +Signed-off-by: Sami Kerola +--- + text-utils/more.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/text-utils/more.c b/text-utils/more.c +index 496b116..0e9c2bd 100644 +--- a/text-utils/more.c ++++ b/text-utils/more.c +@@ -1588,6 +1588,8 @@ void search(char buf[], FILE *file, register int n) + context.line = saveln = Currline; + context.chrctr = startline; + lncount = 0; ++ if (!buf) ++ goto notfound; + if ((rc = regcomp(&re, buf, REG_NOSUB)) != 0) { + char s[REGERR_BUF]; + regerror(rc, &re, s, sizeof s); +@@ -1644,6 +1646,7 @@ void search(char buf[], FILE *file, register int n) + } + free(previousre); + previousre = NULL; ++notfound: + more_error(_("Pattern not found")); + } + } +-- +2.9.3 + diff --git a/SOURCES/0101-more-avoid-double-free-on-exit.patch b/SOURCES/0101-more-avoid-double-free-on-exit.patch new file mode 100644 index 0000000..87d1c36 --- /dev/null +++ b/SOURCES/0101-more-avoid-double-free-on-exit.patch @@ -0,0 +1,42 @@ +From f98c5f53d4661ec22097d36f5debd195491ec3c6 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Thu, 15 Dec 2016 14:40:26 +0100 +Subject: [PATCH 101/116] more: avoid double free() on exit + +On 'q' command more(1) calls end_it() function with _exit(). The +_exit() may suspend program execution due to pending I/O on very +loaded server. In this time SIGINT may be delivered due to impatient +user who will press ^C. + +And then end_it() cleanup function may be executed by signal handler +too. The result is double free()... + +Upstream: https://github.com/karelzak/util-linux/commit/0ed2a954714992938b35893b70197090a61b3b2e +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1403971 +Signed-off-by: Karel Zak +--- + text-utils/more.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/text-utils/more.c b/text-utils/more.c +index 0e9c2bd..f98cb14 100644 +--- a/text-utils/more.c ++++ b/text-utils/more.c +@@ -763,6 +763,14 @@ void chgwinsz(int dummy __attribute__((__unused__))) + /* Clean up terminal state and exit. Also come here if interrupt signal received */ + void __attribute__((__noreturn__)) end_it(int dummy __attribute__((__unused__))) + { ++ /* May be executed as a signal handler as well as by main process. ++ * ++ * The _exit() may wait for pending I/O for really long time, be sure ++ * that signal handler is not executed in this time to avoid double ++ * de-initialization (free() calls, etc.). ++ */ ++ signal(SIGINT, SIG_IGN); ++ + reset_tty(); + if (clreol) { + putchar('\r'); +-- +2.9.3 + diff --git a/SOURCES/0102-ipcs-show-gid-instead-of-uid.patch b/SOURCES/0102-ipcs-show-gid-instead-of-uid.patch new file mode 100644 index 0000000..b549099 --- /dev/null +++ b/SOURCES/0102-ipcs-show-gid-instead-of-uid.patch @@ -0,0 +1,48 @@ +From a04fe4b347e563d7ff8d116fde6c6f26646ffadd Mon Sep 17 00:00:00 2001 +From: Hushan Jia +Date: Sun, 21 Feb 2016 21:10:24 -0800 +Subject: [PATCH 102/116] ipcs: show gid instead of uid + +ipcs -i incorrectly used uid where it should be gid + +Upstream: https://github.com/karelzak/util-linux/commit/e0bbe3d6ffed13ca5e4af450b8de775ddc5b30f3 +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1358095 +Signed-off-by: Hushan Jia +--- + sys-utils/ipcs.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/sys-utils/ipcs.c b/sys-utils/ipcs.c +index 1843cd5..1db7fd0 100644 +--- a/sys-utils/ipcs.c ++++ b/sys-utils/ipcs.c +@@ -564,7 +564,7 @@ static void print_shm(int shmid, int unit) + + printf(_("\nShared memory Segment shmid=%d\n"), shmid); + printf(_("uid=%u\tgid=%u\tcuid=%u\tcgid=%u\n"), +- shmdata->shm_perm.uid, shmdata->shm_perm.uid, ++ shmdata->shm_perm.uid, shmdata->shm_perm.gid, + shmdata->shm_perm.cuid, shmdata->shm_perm.cgid); + printf(_("mode=%#o\taccess_perms=%#o\n"), shmdata->shm_perm.mode, + shmdata->shm_perm.mode & 0777); +@@ -594,7 +594,7 @@ void print_msg(int msgid, int unit) + + printf(_("\nMessage Queue msqid=%d\n"), msgid); + printf(_("uid=%u\tgid=%u\tcuid=%u\tcgid=%u\tmode=%#o\n"), +- msgdata->msg_perm.uid, msgdata->msg_perm.uid, ++ msgdata->msg_perm.uid, msgdata->msg_perm.gid, + msgdata->msg_perm.cuid, msgdata->msg_perm.cgid, + msgdata->msg_perm.mode); + ipc_print_size(unit, unit == IPC_UNIT_HUMAN ? _("csize=") : _("cbytes="), +@@ -627,7 +627,7 @@ static void print_sem(int semid) + + printf(_("\nSemaphore Array semid=%d\n"), semid); + printf(_("uid=%u\t gid=%u\t cuid=%u\t cgid=%u\n"), +- semdata->sem_perm.uid, semdata->sem_perm.uid, ++ semdata->sem_perm.uid, semdata->sem_perm.gid, + semdata->sem_perm.cuid, semdata->sem_perm.cgid); + printf(_("mode=%#o, access_perms=%#o\n"), + semdata->sem_perm.mode, semdata->sem_perm.mode & 0777); +-- +2.9.3 + diff --git a/SOURCES/0103-ipcs-fix-JP-status-message.patch b/SOURCES/0103-ipcs-fix-JP-status-message.patch new file mode 100644 index 0000000..91260b0 --- /dev/null +++ b/SOURCES/0103-ipcs-fix-JP-status-message.patch @@ -0,0 +1,27 @@ +From 68e4765ff497c6274c337a03874d2e4e8b04166d Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Mon, 20 Mar 2017 11:47:02 +0100 +Subject: [PATCH 103/116] ipcs: fix JP status message + +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1358097 +Signed-off-by: Karel Zak +--- + po/ja.po | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/po/ja.po b/po/ja.po +index 4c748de..f0d3645 100644 +--- a/po/ja.po ++++ b/po/ja.po +@@ -13013,7 +13013,7 @@ msgstr "セットされていません" + + #: sys-utils/ipcs.c:327 + msgid "dest" +-msgstr "対象" ++msgstr "削除" + + #: sys-utils/ipcs.c:328 + msgid "locked" +-- +2.9.3 + diff --git a/SOURCES/0104-swapon-fix-discard-option-parsing.patch b/SOURCES/0104-swapon-fix-discard-option-parsing.patch new file mode 100644 index 0000000..4de1ff6 --- /dev/null +++ b/SOURCES/0104-swapon-fix-discard-option-parsing.patch @@ -0,0 +1,44 @@ +From 294a277fceb5cd6640a9b7a6e8af7b2567150f34 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Mon, 20 Mar 2017 12:03:40 +0100 +Subject: [PATCH 104/116] swapon: fix discard option parsing + +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1378100 +Upstream: https://github.com/karelzak/util-linux/commit/07332bfa1ec122a251194a62f91319841121d5aa +Signed-off-by: Karel Zak +--- + sys-utils/swapon.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/sys-utils/swapon.c b/sys-utils/swapon.c +index d85b910..d4f2c08 100644 +--- a/sys-utils/swapon.c ++++ b/sys-utils/swapon.c +@@ -632,20 +632,21 @@ static int swapon_all(void) + + while (mnt_table_find_next_fs(tb, itr, match_swap, NULL, &fs) == 0) { + /* defaults */ ++ size_t argsz = 0; + int pri = priority, dsc = discard, nofail = ifexists; + char *p, *src, *dscarg; + + if (mnt_fs_get_option(fs, "noauto", NULL, NULL) == 0) + continue; +- if (mnt_fs_get_option(fs, "discard", &dscarg, NULL) == 0) { ++ if (mnt_fs_get_option(fs, "discard", &dscarg, &argsz) == 0) { + dsc |= SWAP_FLAG_DISCARD; + if (dscarg) { + /* only single-time discards are wanted */ +- if (strcmp(dscarg, "once") == 0) ++ if (strncmp(dscarg, "once", argsz) == 0) + dsc |= SWAP_FLAG_DISCARD_ONCE; + + /* do discard for every released swap page */ +- if (strcmp(dscarg, "pages") == 0) ++ if (strncmp(dscarg, "pages", argsz) == 0) + dsc |= SWAP_FLAG_DISCARD_PAGES; + } + } +-- +2.9.3 + diff --git a/SOURCES/0105-fallocate-Added-posix_fallocate-support.patch b/SOURCES/0105-fallocate-Added-posix_fallocate-support.patch new file mode 100644 index 0000000..f200f20 --- /dev/null +++ b/SOURCES/0105-fallocate-Added-posix_fallocate-support.patch @@ -0,0 +1,207 @@ +From e3cfe198ebff9721efe6dd063da4b7b2dfe1d8b9 Mon Sep 17 00:00:00 2001 +From: Denis Chaplygin +Date: Tue, 31 Jan 2017 12:51:28 +0100 +Subject: [PATCH 105/116] fallocate: Added posix_fallocate() support. + +No all filesystems support Linux fallocate. The new option allow use +posix implementation if necessary. + +Upstream: https://github.com/karelzak/util-linux/commit/833f9a7aae713278eec5f85266597482f18c7370 +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1416467 +Signed-off-by: Karel Zak +--- + AUTHORS | 1 + + configure.ac | 28 ++++++++++++++++++++++++++++ + sys-utils/fallocate.1 | 10 ++++++++++ + sys-utils/fallocate.c | 44 ++++++++++++++++++++++++++++++++++++++++++-- + 4 files changed, 81 insertions(+), 2 deletions(-) + +diff --git a/AUTHORS b/AUTHORS +index cd40985..3e02181 100644 +--- a/AUTHORS ++++ b/AUTHORS +@@ -148,6 +148,7 @@ CONTRIBUTORS: + David Miller + David Prévot + David Woodhouse ++ Denis Chaplygin + Denis ChengRq + Dennis Gilmore + Dennis Jensen +diff --git a/configure.ac b/configure.ac +index 266ef08..f87a885 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -917,6 +917,34 @@ if test "x$build_fallocate" = xyes; then + AC_MSG_RESULT([no])]) + fi + ++AS_IF([test "x$build_fallocate" = xyes], [ ++ dnl check for valid posix_fallocate() function ++ AC_MSG_CHECKING([for valid posix_fallocate() function]) ++ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ ++#ifdef HAVE_UNISTD_H ++# include ++#endif ++#ifdef HAVE_SYS_TYPES_H ++# include ++#endif ++#ifdef HAVE_LINUX_FALLOC_H ++# include ++#endif ++#ifdef HAVE_FCNTL_H ++# include ++#endif ++]],[[ ++ long ret; ++ ret = posix_fallocate(0, 0xfffffffful, 0xfffffffful); ++ if (ret != 0) { ++ return 1; ++ } ++ ]])],[ ++ AC_MSG_RESULT([yes]) ++ AC_DEFINE([HAVE_POSIX_FALLOCATE], [1], [Have valid posix_fallocate() function])],[ ++ AC_MSG_RESULT([no])]) ++]) ++ + + AC_ARG_ENABLE([unshare], + AS_HELP_STRING([--disable-unshare], [do not build unshare]), +diff --git a/sys-utils/fallocate.1 b/sys-utils/fallocate.1 +index 49d26e4..3763530 100644 +--- a/sys-utils/fallocate.1 ++++ b/sys-utils/fallocate.1 +@@ -11,6 +11,13 @@ fallocate \- preallocate space to a file + .B \-l + .IR length + .I filename ++.PP ++.B fallocate \-x ++.RB [ \-o ++.IR offset ] ++.RB \-l ++.IR length ++.I filename + .SH DESCRIPTION + .B fallocate + is used to preallocate blocks to a file. For filesystems which support the +@@ -39,6 +46,9 @@ Punch holes in the file, the range should not exceed the length of the file. + Specifies the beginning offset of the allocation, in bytes. + .IP "\fB\-l, \-\-length\fP \fIlength\fP + Specifies the length of the allocation, in bytes. ++.IP "\fB\-x , \-\-posix\fP ++Enable POSIX operation mode. In that mode allocation operation always completes, ++but it may take longer time when fast allocation is not supported by the underlying filesystem. + .IP "\fB\-h, \-\-help\fP" + Print help and exit. + .IP "\fB-V, \-\-version" +diff --git a/sys-utils/fallocate.c b/sys-utils/fallocate.c +index ff0f9e6..17ae5fe 100644 +--- a/sys-utils/fallocate.c ++++ b/sys-utils/fallocate.c +@@ -52,6 +52,7 @@ + #include "strutils.h" + #include "c.h" + #include "closestream.h" ++#include "optutils.h" + + static void __attribute__((__noreturn__)) usage(FILE *out) + { +@@ -63,6 +64,9 @@ static void __attribute__((__noreturn__)) usage(FILE *out) + " -p, --punch-hole punch holes in the file\n" + " -o, --offset offset of the allocation, in bytes\n" + " -l, --length length of the allocation, in bytes\n"), out); ++#ifdef HAVE_POSIX_FALLOCATE ++ fputs(_(" -x, --posix use posix_fallocate(3) instead of fallocate(2)\n"), out); ++#endif + fputs(USAGE_SEPARATOR, out); + fputs(USAGE_HELP, out); + fputs(USAGE_VERSION, out); +@@ -71,6 +75,18 @@ static void __attribute__((__noreturn__)) usage(FILE *out) + exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); + } + ++ ++#ifdef HAVE_POSIX_FALLOCATE ++static void xposix_fallocate(int fd, off_t offset, off_t length) ++{ ++ int error = posix_fallocate(fd, offset, length); ++ if (error < 0) { ++ err(EXIT_FAILURE, _("fallocate failed")); ++ } ++} ++#endif ++ ++ + static loff_t cvtnum(char *s) + { + uintmax_t x; +@@ -85,9 +101,10 @@ int main(int argc, char **argv) + { + char *fname; + int c; +- int error; ++ int error = 0; + int fd; + int mode = 0; ++ int posix = 0; + loff_t length = -2LL; + loff_t offset = 0; + +@@ -98,15 +115,25 @@ int main(int argc, char **argv) + { "punch-hole", 0, 0, 'p' }, + { "offset", 1, 0, 'o' }, + { "length", 1, 0, 'l' }, ++ { "posix", 0, 0, 'x' }, + { NULL, 0, 0, 0 } + }; + ++ static const ul_excl_t excl[] = { /* rows and cols in ASCII order */ ++ { 'x', 'n', 'p' }, ++ { 0 } ++ }; ++ int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT; ++ + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + atexit(close_stdout); + +- while ((c = getopt_long(argc, argv, "hVnpl:o:", longopts, NULL)) != -1) { ++ while ((c = getopt_long(argc, argv, "hVnpl:o:x", longopts, NULL)) != -1) { ++ ++ err_exclusive_options(c, longopts, excl, excl_st); ++ + switch(c) { + case 'h': + usage(stdout); +@@ -126,6 +153,13 @@ int main(int argc, char **argv) + case 'o': + offset = cvtnum(optarg); + break; ++ case 'x': ++#ifdef HAVE_POSIX_FALLOCATE ++ posix = 1; ++ break; ++#else ++ errx(EXIT_FAILURE, _("posix_fallocate support is not compiled")) ++#endif + default: + usage(stderr); + break; +@@ -152,6 +186,12 @@ int main(int argc, char **argv) + if (fd < 0) + err(EXIT_FAILURE, _("cannot open %s"), fname); + ++#ifdef HAVE_POSIX_FALLOCATE ++ if (posix) ++ xposix_fallocate(fd, offset, length); ++ else ++#endif ++ + #ifdef HAVE_FALLOCATE + error = fallocate(fd, mode, offset, length); + #else +-- +2.9.3 + diff --git a/SOURCES/0106-zramctl-backport-from-v2.29.patch b/SOURCES/0106-zramctl-backport-from-v2.29.patch new file mode 100644 index 0000000..2f87a48 --- /dev/null +++ b/SOURCES/0106-zramctl-backport-from-v2.29.patch @@ -0,0 +1,1723 @@ +From c43588bf03cc05b2eae724751b6652949e5c9caa Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Tue, 21 Mar 2017 13:04:17 +0100 +Subject: [PATCH 106/116] zramctl: backport from v2.29 + +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1358755 +Signed-off-by: Karel Zak +--- + .gitignore | 1 + + configure.ac | 6 + + include/Makemodule.am | 1 + + include/c.h | 8 + + include/strutils.h | 9 + + include/strv.h | 55 ++++ + include/sysfs.h | 3 + + lib/Makemodule.am | 3 +- + lib/strutils.c | 129 +++++++++ + lib/strv.c | 403 ++++++++++++++++++++++++++ + lib/sysfs.c | 45 ++- + sys-utils/Makemodule.am | 7 + + sys-utils/zramctl.8 | 123 ++++++++ + sys-utils/zramctl.c | 736 ++++++++++++++++++++++++++++++++++++++++++++++++ + 14 files changed, 1524 insertions(+), 5 deletions(-) + create mode 100644 include/strv.h + create mode 100644 lib/strv.c + create mode 100644 sys-utils/zramctl.8 + create mode 100644 sys-utils/zramctl.c + +diff --git a/configure.ac b/configure.ac +index f87a885..db7095a 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -826,6 +826,12 @@ UL_REQUIRES_LINUX([losetup]) + AM_CONDITIONAL(BUILD_LOSETUP, test "x$build_losetup" = xyes) + + ++UL_BUILD_INIT([zramctl], [check]) ++UL_REQUIRES_LINUX([zramctl]) ++UL_REQUIRES_BUILD([zramctl], [libsmartcols]) ++AM_CONDITIONAL([BUILD_ZRAMCTL], [test "x$build_zramctl" = xyes]) ++ ++ + AC_ARG_ENABLE([cytune], + AS_HELP_STRING([--disable-cytune], [do not build cytune]), + [], enable_cytune=check +diff --git a/include/Makemodule.am b/include/Makemodule.am +index 757f317..1680296 100644 +--- a/include/Makemodule.am ++++ b/include/Makemodule.am +@@ -39,6 +39,7 @@ dist_noinst_HEADERS += \ + include/readutmp.h \ + include/setproctitle.h \ + include/strutils.h \ ++ include/strv.h \ + include/swapheader.h \ + include/sysfs.h \ + include/timer.h \ +diff --git a/include/c.h b/include/c.h +index a2779a5..3754e75 100644 +--- a/include/c.h ++++ b/include/c.h +@@ -309,6 +309,14 @@ static inline int usleep(useconds_t usec) + #endif + + /* ++ * Macros to convert #define'itions to strings, for example ++ * #define XYXXY 42 ++ * printf ("%s=%s\n", stringify(XYXXY), stringify_value(XYXXY)); ++ */ ++#define stringify_value(s) stringify(s) ++#define stringify(s) #s ++ ++/* + * Note that sysconf(_SC_GETPW_R_SIZE_MAX) returns *initial* suggested size for + * pwd buffer and in some cases it is not large enough. See POSIX and + * getpwnam_r man page for more details. +diff --git a/include/strutils.h b/include/strutils.h +index 709fcad..aa7b95f 100644 +--- a/include/strutils.h ++++ b/include/strutils.h +@@ -5,6 +5,7 @@ + #include + #include + #include ++#include + + /* default strtoxx_or_err() exit code */ + #ifndef STRTOXX_EXIT_CODE +@@ -102,4 +103,12 @@ extern int parse_range(const char *str, int *lower, int *upper, int def); + + extern int streq_except_trailing_slash(const char *s1, const char *s2); + ++extern char *strnappend(const char *s, const char *suffix, size_t b); ++extern char *strappend(const char *s, const char *suffix); ++extern char *strfappend(const char *s, const char *format, ...) ++ __attribute__ ((__format__ (__printf__, 2, 0))); ++extern const char *split(const char **state, size_t *l, const char *separator, int quoted); ++ ++extern int skip_fline(FILE *fp); ++ + #endif +diff --git a/include/strv.h b/include/strv.h +new file mode 100644 +index 0000000..260ad12 +--- /dev/null ++++ b/include/strv.h +@@ -0,0 +1,55 @@ ++#ifndef UTIL_LINUX_STRV ++#define UTIL_LINUX_STRV ++ ++#include ++ ++#include "c.h" ++ ++char **strv_free(char **l); ++void strv_clear(char **l); ++char **strv_copy(char * const *l); ++unsigned strv_length(char * const *l); ++ ++int strv_extend_strv(char ***a, char **b); ++int strv_extend_strv_concat(char ***a, char **b, const char *suffix); ++int strv_extend(char ***l, const char *value); ++int strv_extendv(char ***l, const char *format, va_list ap); ++int strv_extendf(char ***l, const char *format, ...) ++ __attribute__ ((__format__ (__printf__, 2, 0))); ++int strv_push(char ***l, char *value); ++int strv_push_prepend(char ***l, char *value); ++int strv_consume(char ***l, char *value); ++int strv_consume_prepend(char ***l, char *value); ++ ++char **strv_remove(char **l, const char *s); ++ ++char **strv_new(const char *x, ...); ++char **strv_new_ap(const char *x, va_list ap); ++ ++static inline const char* STRV_IFNOTNULL(const char *x) { ++ return x ? x : (const char *) -1; ++} ++ ++static inline int strv_isempty(char * const *l) { ++ return !l || !*l; ++} ++ ++char **strv_split(const char *s, const char *separator); ++char *strv_join(char **l, const char *separator); ++ ++#define STRV_FOREACH(s, l) \ ++ for ((s) = (l); (s) && *(s); (s)++) ++ ++#define STRV_FOREACH_BACKWARDS(s, l) \ ++ STRV_FOREACH(s, l) \ ++ ; \ ++ for ((s)--; (l) && ((s) >= (l)); (s)--) ++ ++ ++#define STRV_MAKE_EMPTY ((char*[1]) { NULL }) ++ ++char **strv_reverse(char **l); ++ ++#endif /* UTIL_LINUX_STRV */ ++ ++ +diff --git a/include/sysfs.h b/include/sysfs.h +index 0a9c218..a547005 100644 +--- a/include/sysfs.h ++++ b/include/sysfs.h +@@ -58,6 +58,9 @@ extern int sysfs_read_s64(struct sysfs_cxt *cxt, const char *attr, int64_t *res) + extern int sysfs_read_u64(struct sysfs_cxt *cxt, const char *attr, uint64_t *res); + extern int sysfs_read_int(struct sysfs_cxt *cxt, const char *attr, int *res); + ++extern int sysfs_write_string(struct sysfs_cxt *cxt, const char *attr, const char *str); ++extern int sysfs_write_u64(struct sysfs_cxt *cxt, const char *attr, uint64_t num); ++ + extern char *sysfs_get_devname(struct sysfs_cxt *cxt, char *buf, size_t bufsiz); + + extern char *sysfs_strdup(struct sysfs_cxt *cxt, const char *attr); +diff --git a/lib/Makemodule.am b/lib/Makemodule.am +index 73280f9..faf9d74 100644 +--- a/lib/Makemodule.am ++++ b/lib/Makemodule.am +@@ -27,7 +27,8 @@ libcommon_la_SOURCES = \ + lib/ttyutils.c \ + lib/xgetpass.c \ + lib/exec_shell.c \ +- lib/readutmp.c ++ lib/readutmp.c \ ++ lib/strv.c + + if LINUX + libcommon_la_SOURCES += \ +diff --git a/lib/strutils.c b/lib/strutils.c +index f9cdcbb..4b8a813 100644 +--- a/lib/strutils.c ++++ b/lib/strutils.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + #include "c.h" + #include "nls.h" +@@ -687,6 +688,134 @@ int streq_except_trailing_slash(const char *s1, const char *s2) + return equal; + } + ++char *strnappend(const char *s, const char *suffix, size_t b) ++{ ++ size_t a; ++ char *r; ++ ++ if (!s && !suffix) ++ return strdup(""); ++ if (!s) ++ return strndup(suffix, b); ++ if (!suffix) ++ return strdup(s); ++ ++ assert(s); ++ assert(suffix); ++ ++ a = strlen(s); ++ if (b > ((size_t) -1) - a) ++ return NULL; ++ ++ r = malloc(a + b + 1); ++ if (!r) ++ return NULL; ++ ++ memcpy(r, s, a); ++ memcpy(r + a, suffix, b); ++ r[a+b] = 0; ++ ++ return r; ++} ++ ++char *strappend(const char *s, const char *suffix) ++{ ++ return strnappend(s, suffix, suffix ? strlen(suffix) : 0); ++} ++ ++char *strfappend(const char *s, const char *format, ...) ++{ ++ va_list ap; ++ char *val, *res; ++ int sz; ++ ++ va_start(ap, format); ++ sz = vasprintf(&val, format, ap); ++ va_end(ap); ++ ++ if (sz < 0) ++ return NULL; ++ ++ res = strnappend(s, val, sz); ++ free(val); ++ return res; ++} ++ ++static size_t strcspn_escaped(const char *s, const char *reject) ++{ ++ int escaped = 0; ++ int n; ++ ++ for (n=0; s[n]; n++) { ++ if (escaped) ++ escaped = 0; ++ else if (s[n] == '\\') ++ escaped = 1; ++ else if (strchr(reject, s[n])) ++ break; ++ } ++ ++ /* if s ends in \, return index of previous char */ ++ return n - escaped; ++} ++ ++/* Split a string into words. */ ++const char *split(const char **state, size_t *l, const char *separator, int quoted) ++{ ++ const char *current; ++ ++ current = *state; ++ ++ if (!*current) { ++ assert(**state == '\0'); ++ return NULL; ++ } ++ ++ current += strspn(current, separator); ++ if (!*current) { ++ *state = current; ++ return NULL; ++ } ++ ++ if (quoted && strchr("\'\"", *current)) { ++ char quotechars[2] = {*current, '\0'}; ++ ++ *l = strcspn_escaped(current + 1, quotechars); ++ if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] || ++ (current[*l + 2] && !strchr(separator, current[*l + 2]))) { ++ /* right quote missing or garbage at the end */ ++ *state = current; ++ return NULL; ++ } ++ *state = current++ + *l + 2; ++ } else if (quoted) { ++ *l = strcspn_escaped(current, separator); ++ if (current[*l] && !strchr(separator, current[*l])) { ++ /* unfinished escape */ ++ *state = current; ++ return NULL; ++ } ++ *state = current + *l; ++ } else { ++ *l = strcspn(current, separator); ++ *state = current + *l; ++ } ++ ++ return current; ++} ++ ++/* Rewind file pointer forward to new line. */ ++int skip_fline(FILE *fp) ++{ ++ int ch; ++ ++ do { ++ if ((ch = fgetc(fp)) == EOF) ++ return 1; ++ if (ch == '\n') ++ return 0; ++ } while (1); ++} + + #ifdef TEST_PROGRAM + +diff --git a/lib/strv.c b/lib/strv.c +new file mode 100644 +index 0000000..ddc2a0c +--- /dev/null ++++ b/lib/strv.c +@@ -0,0 +1,403 @@ ++/* ++ * ++ * Copyright 2010 Lennart Poettering ++ * ++ * This is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU Lesser General Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. ++ * ++ * ++ * Copyright (C) 2015 Karel Zak ++ * Modified the original version from systemd project for util-linux. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "strutils.h" ++#include "strv.h" ++ ++void strv_clear(char **l) { ++ char **k; ++ ++ if (!l) ++ return; ++ ++ for (k = l; *k; k++) ++ free(*k); ++ ++ *l = NULL; ++} ++ ++char **strv_free(char **l) { ++ strv_clear(l); ++ free(l); ++ return NULL; ++} ++ ++char **strv_copy(char * const *l) { ++ char **r, **k; ++ ++ k = r = malloc(sizeof(char *) * (strv_length(l) + 1)); ++ if (!r) ++ return NULL; ++ ++ if (l) ++ for (; *l; k++, l++) { ++ *k = strdup(*l); ++ if (!*k) { ++ strv_free(r); ++ return NULL; ++ } ++ } ++ ++ *k = NULL; ++ return r; ++} ++ ++unsigned strv_length(char * const *l) { ++ unsigned n = 0; ++ ++ if (!l) ++ return 0; ++ ++ for (; *l; l++) ++ n++; ++ ++ return n; ++} ++ ++char **strv_new_ap(const char *x, va_list ap) { ++ const char *s; ++ char **a; ++ unsigned n = 0, i = 0; ++ va_list aq; ++ ++ /* As a special trick we ignore all listed strings that equal ++ * (const char*) -1. This is supposed to be used with the ++ * STRV_IFNOTNULL() macro to include possibly NULL strings in ++ * the string list. */ ++ ++ if (x) { ++ n = x == (const char*) -1 ? 0 : 1; ++ ++ va_copy(aq, ap); ++ while ((s = va_arg(aq, const char*))) { ++ if (s == (const char*) -1) ++ continue; ++ ++ n++; ++ } ++ ++ va_end(aq); ++ } ++ ++ a = malloc(sizeof(char *) * (n + 1)); ++ if (!a) ++ return NULL; ++ ++ if (x) { ++ if (x != (const char*) -1) { ++ a[i] = strdup(x); ++ if (!a[i]) ++ goto fail; ++ i++; ++ } ++ ++ while ((s = va_arg(ap, const char*))) { ++ ++ if (s == (const char*) -1) ++ continue; ++ ++ a[i] = strdup(s); ++ if (!a[i]) ++ goto fail; ++ ++ i++; ++ } ++ } ++ ++ a[i] = NULL; ++ ++ return a; ++ ++fail: ++ strv_free(a); ++ return NULL; ++} ++ ++char **strv_new(const char *x, ...) { ++ char **r; ++ va_list ap; ++ ++ va_start(ap, x); ++ r = strv_new_ap(x, ap); ++ va_end(ap); ++ ++ return r; ++} ++ ++int strv_extend_strv(char ***a, char **b) { ++ int r; ++ char **s; ++ ++ STRV_FOREACH(s, b) { ++ r = strv_extend(a, *s); ++ if (r < 0) ++ return r; ++ } ++ ++ return 0; ++} ++ ++int strv_extend_strv_concat(char ***a, char **b, const char *suffix) { ++ int r; ++ char **s; ++ ++ STRV_FOREACH(s, b) { ++ char *v; ++ ++ v = strappend(*s, suffix); ++ if (!v) ++ return -ENOMEM; ++ ++ r = strv_push(a, v); ++ if (r < 0) { ++ free(v); ++ return r; ++ } ++ } ++ ++ return 0; ++} ++ ++ ++#define _FOREACH_WORD(word, length, s, separator, quoted, state) \ ++ for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted))) ++ ++#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \ ++ _FOREACH_WORD(word, length, s, separator, false, state) ++ ++ ++char **strv_split(const char *s, const char *separator) { ++ const char *word, *state; ++ size_t l; ++ unsigned n, i; ++ char **r; ++ ++ assert(s); ++ ++ n = 0; ++ FOREACH_WORD_SEPARATOR(word, l, s, separator, state) ++ n++; ++ ++ r = malloc(sizeof(char *) * (n + 1)); ++ if (!r) ++ return NULL; ++ ++ i = 0; ++ FOREACH_WORD_SEPARATOR(word, l, s, separator, state) { ++ r[i] = strndup(word, l); ++ if (!r[i]) { ++ strv_free(r); ++ return NULL; ++ } ++ ++ i++; ++ } ++ ++ r[i] = NULL; ++ return r; ++} ++ ++char *strv_join(char **l, const char *separator) { ++ char *r, *e; ++ char **s; ++ size_t n, k; ++ ++ if (!separator) ++ separator = " "; ++ ++ k = strlen(separator); ++ ++ n = 0; ++ STRV_FOREACH(s, l) { ++ if (n != 0) ++ n += k; ++ n += strlen(*s); ++ } ++ ++ r = malloc(n + 1); ++ if (!r) ++ return NULL; ++ ++ e = r; ++ STRV_FOREACH(s, l) { ++ if (e != r) ++ e = stpcpy(e, separator); ++ ++ e = stpcpy(e, *s); ++ } ++ ++ *e = 0; ++ ++ return r; ++} ++ ++int strv_push(char ***l, char *value) { ++ char **c; ++ unsigned n, m; ++ ++ if (!value) ++ return 0; ++ ++ n = strv_length(*l); ++ ++ /* Increase and check for overflow */ ++ m = n + 2; ++ if (m < n) ++ return -ENOMEM; ++ ++ c = realloc(*l, sizeof(char *) * m); ++ if (!c) ++ return -ENOMEM; ++ ++ c[n] = value; ++ c[n+1] = NULL; ++ ++ *l = c; ++ return 0; ++} ++ ++int strv_push_prepend(char ***l, char *value) { ++ char **c; ++ unsigned n, m, i; ++ ++ if (!value) ++ return 0; ++ ++ n = strv_length(*l); ++ ++ /* increase and check for overflow */ ++ m = n + 2; ++ if (m < n) ++ return -ENOMEM; ++ ++ c = malloc(sizeof(char *) * m); ++ if (!c) ++ return -ENOMEM; ++ ++ for (i = 0; i < n; i++) ++ c[i+1] = (*l)[i]; ++ ++ c[0] = value; ++ c[n+1] = NULL; ++ ++ free(*l); ++ *l = c; ++ ++ return 0; ++} ++ ++int strv_consume(char ***l, char *value) { ++ int r; ++ ++ r = strv_push(l, value); ++ if (r < 0) ++ free(value); ++ ++ return r; ++} ++ ++int strv_consume_prepend(char ***l, char *value) { ++ int r; ++ ++ r = strv_push_prepend(l, value); ++ if (r < 0) ++ free(value); ++ ++ return r; ++} ++ ++int strv_extend(char ***l, const char *value) { ++ char *v; ++ ++ if (!value) ++ return 0; ++ ++ v = strdup(value); ++ if (!v) ++ return -ENOMEM; ++ ++ return strv_consume(l, v); ++} ++ ++char **strv_remove(char **l, const char *s) { ++ char **f, **t; ++ ++ if (!l) ++ return NULL; ++ ++ assert(s); ++ ++ /* Drops every occurrence of s in the string list, edits ++ * in-place. */ ++ ++ for (f = t = l; *f; f++) ++ if (strcmp(*f, s) == 0) ++ free(*f); ++ else ++ *(t++) = *f; ++ ++ *t = NULL; ++ return l; ++} ++ ++int strv_extendf(char ***l, const char *format, ...) { ++ va_list ap; ++ char *x; ++ int r; ++ ++ va_start(ap, format); ++ r = vasprintf(&x, format, ap); ++ va_end(ap); ++ ++ if (r < 0) ++ return -ENOMEM; ++ ++ return strv_consume(l, x); ++} ++ ++int strv_extendv(char ***l, const char *format, va_list ap) { ++ char *x; ++ int r; ++ ++ r = vasprintf(&x, format, ap); ++ if (r < 0) ++ return -ENOMEM; ++ ++ return strv_consume(l, x); ++} ++ ++char **strv_reverse(char **l) { ++ unsigned n, i; ++ ++ n = strv_length(l); ++ if (n <= 1) ++ return l; ++ ++ for (i = 0; i < n / 2; i++) { ++ char *t; ++ ++ t = l[i]; ++ l[i] = l[n-1-i]; ++ l[n-1-i] = t; ++ } ++ ++ return l; ++} +diff --git a/lib/sysfs.c b/lib/sysfs.c +index 0bfd622..65a8394 100644 +--- a/lib/sysfs.c ++++ b/lib/sysfs.c +@@ -10,6 +10,7 @@ + #include "at.h" + #include "pathnames.h" + #include "sysfs.h" ++#include "all-io.h" + + char *sysfs_devno_attribute_path(dev_t devno, char *buf, + size_t bufsiz, const char *attr) +@@ -203,9 +204,9 @@ int sysfs_has_attribute(struct sysfs_cxt *cxt, const char *attr) + return sysfs_stat(cxt, attr, &st) == 0; + } + +-static int sysfs_open(struct sysfs_cxt *cxt, const char *attr) ++static int sysfs_open(struct sysfs_cxt *cxt, const char *attr, int flags) + { +- int fd = open_at(cxt->dir_fd, cxt->dir_path, attr, O_RDONLY|O_CLOEXEC); ++ int fd = open_at(cxt->dir_fd, cxt->dir_path, attr, flags); + + if (fd == -1 && errno == ENOENT && + strncmp(attr, "queue/", 6) == 0 && cxt->parent) { +@@ -238,7 +239,7 @@ DIR *sysfs_opendir(struct sysfs_cxt *cxt, const char *attr) + int fd = -1; + + if (attr) +- fd = sysfs_open(cxt, attr); ++ fd = sysfs_open(cxt, attr, O_RDONLY|O_CLOEXEC); + + else if (cxt->dir_fd >= 0) + /* request to open root of device in sysfs (/sys/block/) +@@ -263,7 +264,7 @@ DIR *sysfs_opendir(struct sysfs_cxt *cxt, const char *attr) + + static FILE *sysfs_fopen(struct sysfs_cxt *cxt, const char *attr) + { +- int fd = sysfs_open(cxt, attr); ++ int fd = sysfs_open(cxt, attr, O_RDONLY|O_CLOEXEC); + + return fd < 0 ? NULL : fdopen(fd, "r" UL_CLOEXECSTR); + } +@@ -417,6 +418,42 @@ int sysfs_read_int(struct sysfs_cxt *cxt, const char *attr, int *res) + return -1; + } + ++int sysfs_write_string(struct sysfs_cxt *cxt, const char *attr, const char *str) ++{ ++ int fd = sysfs_open(cxt, attr, O_WRONLY|O_CLOEXEC); ++ int rc, errsv; ++ ++ if (fd < 0) ++ return -errno; ++ rc = write_all(fd, str, strlen(str)); ++ ++ errsv = errno; ++ close(fd); ++ errno = errsv; ++ return rc; ++} ++ ++int sysfs_write_u64(struct sysfs_cxt *cxt, const char *attr, uint64_t num) ++{ ++ char buf[sizeof(stringify_value(ULLONG_MAX))]; ++ int fd, rc = 0, len, errsv; ++ ++ fd = sysfs_open(cxt, attr, O_WRONLY|O_CLOEXEC); ++ if (fd < 0) ++ return -errno; ++ ++ len = snprintf(buf, sizeof(buf), "%" PRIu64, num); ++ if (len < 0 || (size_t) len >= sizeof(buf)) ++ rc = len < 0 ? -errno : -E2BIG; ++ else ++ rc = write_all(fd, buf, len); ++ ++ errsv = errno; ++ close(fd); ++ errno = errsv; ++ return rc; ++} ++ + char *sysfs_strdup(struct sysfs_cxt *cxt, const char *attr) + { + char buf[1024]; +diff --git a/sys-utils/Makemodule.am b/sys-utils/Makemodule.am +index 6badd17..408e884 100644 +--- a/sys-utils/Makemodule.am ++++ b/sys-utils/Makemodule.am +@@ -184,6 +184,13 @@ losetup_static_LDADD = $(losetup_LDADD) + endif + endif # BUILD_LOSETUP + ++if BUILD_ZRAMCTL ++sbin_PROGRAMS += zramctl ++dist_man_MANS += sys-utils/zramctl.8 ++zramctl_SOURCES = sys-utils/zramctl.c ++zramctl_LDADD = $(LDADD) libcommon.la libsmartcols.la ++zramctl_CFLAGS = $(AM_CFLAGS) -I$(ul_libsmartcols_incdir) ++endif + + if BUILD_PRLIMIT + usrbin_exec_PROGRAMS += prlimit +diff --git a/sys-utils/zramctl.8 b/sys-utils/zramctl.8 +new file mode 100644 +index 0000000..f6fc45c +--- /dev/null ++++ b/sys-utils/zramctl.8 +@@ -0,0 +1,123 @@ ++.TH ZRAMCTL 8 "July 2014" "util-linux" "System Administration" ++.SH NAME ++zramctl \- set up and control zram devices ++.SH SYNOPSIS ++.ad l ++Get info: ++.sp ++.in +5 ++.BR zramctl " [options]" ++.sp ++.in -5 ++Reset zram: ++.sp ++.in +5 ++.B "zramctl \-r" ++.IR zramdev ... ++.sp ++.in -5 ++Print name of first unused zram device: ++.sp ++.in +5 ++.B "zramctl \-f" ++.sp ++.in -5 ++Set up a zram device: ++.sp ++.in +5 ++.B zramctl ++.RB [ \-f " | "\fIzramdev\fP ] ++.RB [ \-s ++.IR size ] ++.RB [ \-t ++.IR number ] ++.RB [ \-a ++.IR algorithm ] ++.sp ++.in -5 ++.ad b ++.SH DESCRIPTION ++.B zramctl ++is used to quickly set up zram device parameters, to reset zram devices, and to ++query the status of used zram devices. If no option is given, all zram devices ++are shown. ++ ++.SH OPTIONS ++.TP ++.BR \-a , " \-\-algorithm lzo" | lz4 ++Set the compression algorithm to be used for compressing data in the zram device. ++.TP ++.BR \-f , " \-\-find" ++Find the first unused zram device. If a \fB--size\fR argument is present, then ++initialize the device. ++.TP ++.BR \-n , " \-\-noheadings" ++Do not print a header line in status output. ++.TP ++.BR \-o , " \-\-output " \fIlist ++Define the status output columns to be used. If no output arrangement is ++specified, then a default set is used. ++Use \fB\-\-help\fP to get a list of all supported columns. ++.TP ++.B \-\-raw ++Use the raw format for status output. ++.TP ++.BR \-r , " \-\-reset" ++Reset the options of the specified zram device(s). Zram device settings ++can be changed only after a reset. ++.TP ++.BR \-s , " \-\-size " \fIsize ++Create a zram device of the specified \fIsize\fR. ++Zram devices are aligned to memory pages; when the requested \fIsize\fR is ++not a multiple of the page size, it will be rounded up to the next multiple. ++When not otherwise specified, the unit of the \fIsize\fR parameter is bytes. ++.IP ++The \fIsize\fR argument may be followed by the multiplicative suffixes KiB (=1024), ++MiB (=1024*1024), and so on for GiB, TiB, PiB, EiB, ZiB and YiB (the "iB" ++is optional, e.g., "K" has the same meaning as "KiB") or the suffixes ++KB (=1000), MB (=1000*1000), and so on for GB, TB, PB, EB, ZB and YB. ++.TP ++.BR \-t , " \-\-streams " \fInumber ++Set the maximum number of compression streams that can be used for the device. ++The default is one stream. ++.TP ++.BR \-V , " \-\-version" ++Display version information and exit. ++.TP ++.BR \-h , " \-\-help" ++Display help text and exit. ++ ++.SH RETURN VALUE ++.B zramctl ++returns 0 on success, nonzero on failure. ++ ++.SH FILES ++.TP ++.I /dev/zram[0..N] ++zram block devices ++ ++.SH EXAMPLE ++The following commands set up a zram device with a size of one gigabyte ++and use it as swap device. ++.nf ++.IP ++# zramctl --find --size 1024M ++/dev/zram0 ++# mkswap /dev/zram0 ++# swapon /dev/zram0 ++ ... ++# swapoff /dev/zram0 ++# zramctl --reset /dev/zram0 ++.fi ++.SH SEE ALSO ++.UR http://git.\:kernel.\:org\:/cgit\:/linux\:/kernel\:/git\:/torvalds\:/linux.git\:/tree\:/Documentation\:/blockdev\:/zram.txt ++Linux kernel documentation ++.UE . ++.SH AUTHORS ++.nf ++Timofey Titovets ++Karel Zak ++.fi ++.SH AVAILABILITY ++The zramctl command is part of the util-linux package and is available from ++https://www.kernel.org/pub/linux/utils/util-linux/. +diff --git a/sys-utils/zramctl.c b/sys-utils/zramctl.c +new file mode 100644 +index 0000000..853401c +--- /dev/null ++++ b/sys-utils/zramctl.c +@@ -0,0 +1,736 @@ ++/* ++ * zramctl - control compressed block devices in RAM ++ * ++ * Copyright (c) 2014 Timofey Titovets ++ * Copyright (C) 2014 Karel Zak ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it would be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "c.h" ++#include "nls.h" ++#include "closestream.h" ++#include "strutils.h" ++#include "xalloc.h" ++#include "sysfs.h" ++#include "optutils.h" ++#include "ismounted.h" ++#include "strv.h" ++#include "path.h" ++#include "pathnames.h" ++ ++/*#define CONFIG_ZRAM_DEBUG*/ ++ ++#ifdef CONFIG_ZRAM_DEBUG ++# define DBG(x) do { fputs("zram: ", stderr); x; fputc('\n', stderr); } while(0) ++#else ++# define DBG(x) ++#endif ++ ++/* status output columns */ ++struct colinfo { ++ const char *name; ++ double whint; ++ int flags; ++ const char *help; ++}; ++ ++enum { ++ COL_NAME = 0, ++ COL_DISKSIZE, ++ COL_ORIG_SIZE, ++ COL_COMP_SIZE, ++ COL_ALGORITHM, ++ COL_STREAMS, ++ COL_ZEROPAGES, ++ COL_MEMTOTAL, ++ COL_MEMLIMIT, ++ COL_MEMUSED, ++ COL_MIGRATED, ++ COL_MOUNTPOINT ++}; ++ ++static const struct colinfo infos[] = { ++ [COL_NAME] = { "NAME", 0.25, 0, N_("zram device name") }, ++ [COL_DISKSIZE] = { "DISKSIZE", 5, SCOLS_FL_RIGHT, N_("limit on the uncompressed amount of data") }, ++ [COL_ORIG_SIZE] = { "DATA", 5, SCOLS_FL_RIGHT, N_("uncompressed size of stored data") }, ++ [COL_COMP_SIZE] = { "COMPR", 5, SCOLS_FL_RIGHT, N_("compressed size of stored data") }, ++ [COL_ALGORITHM] = { "ALGORITHM", 3, 0, N_("the selected compression algorithm") }, ++ [COL_STREAMS] = { "STREAMS", 3, SCOLS_FL_RIGHT, N_("number of concurrent compress operations") }, ++ [COL_ZEROPAGES] = { "ZERO-PAGES", 3, SCOLS_FL_RIGHT, N_("empty pages with no allocated memory") }, ++ [COL_MEMTOTAL] = { "TOTAL", 5, SCOLS_FL_RIGHT, N_("all memory including allocator fragmentation and metadata overhead") }, ++ [COL_MEMLIMIT] = { "MEM-LIMIT", 5, SCOLS_FL_RIGHT, N_("memory limit used to store compressed data") }, ++ [COL_MEMUSED] = { "MEM-USED", 5, SCOLS_FL_RIGHT, N_("memory zram have been consumed to store compressed data") }, ++ [COL_MIGRATED] = { "MIGRATED", 5, SCOLS_FL_RIGHT, N_("number of objects migrated by compaction") }, ++ [COL_MOUNTPOINT]= { "MOUNTPOINT",0.10, SCOLS_FL_TRUNC, N_("where the device is mounted") }, ++}; ++ ++static int columns[ARRAY_SIZE(infos) * 2] = {-1}; ++static int ncolumns; ++ ++enum { ++ MM_ORIG_DATA_SIZE = 0, ++ MM_COMPR_DATA_SIZE, ++ MM_MEM_USED_TOTAL, ++ MM_MEM_LIMIT, ++ MM_MEM_USED_MAX, ++ MM_ZERO_PAGES, ++ MM_NUM_MIGRATED ++}; ++ ++static const char *mm_stat_names[] = { ++ [MM_ORIG_DATA_SIZE] = "orig_data_size", ++ [MM_COMPR_DATA_SIZE] = "compr_data_size", ++ [MM_MEM_USED_TOTAL] = "mem_used_total", ++ [MM_MEM_LIMIT] = "mem_limit", ++ [MM_MEM_USED_MAX] = "mem_used_max", ++ [MM_ZERO_PAGES] = "zero_pages", ++ [MM_NUM_MIGRATED] = "num_migrated" ++}; ++ ++ ++struct zram { ++ char devname[32]; ++ struct sysfs_cxt sysfs; ++ char **mm_stat; ++ ++ unsigned int mm_stat_probed : 1, ++ control_probed : 1, ++ has_control : 1; /* has /sys/class/zram-control/ */ ++}; ++ ++#define ZRAM_EMPTY { .devname = { '\0' }, .sysfs = UL_SYSFSCXT_EMPTY } ++ ++static unsigned int raw, no_headings, inbytes; ++ ++ ++static int get_column_id(int num) ++{ ++ assert(num < ncolumns); ++ assert(columns[num] < (int) ARRAY_SIZE(infos)); ++ return columns[num]; ++} ++ ++static const struct colinfo *get_column_info(int num) ++{ ++ return &infos[ get_column_id(num) ]; ++} ++ ++static int column_name_to_id(const char *name, size_t namesz) ++{ ++ size_t i; ++ ++ for (i = 0; i < ARRAY_SIZE(infos); i++) { ++ const char *cn = infos[i].name; ++ ++ if (!strncasecmp(name, cn, namesz) && !*(cn + namesz)) ++ return i; ++ } ++ warnx(_("unknown column: %s"), name); ++ return -1; ++} ++ ++static void zram_reset_stat(struct zram *z) ++{ ++ if (z) { ++ strv_free(z->mm_stat); ++ z->mm_stat = NULL; ++ z->mm_stat_probed = 0; ++ } ++} ++ ++static void zram_set_devname(struct zram *z, const char *devname, size_t n) ++{ ++ assert(z); ++ ++ if (!devname) ++ snprintf(z->devname, sizeof(z->devname), "/dev/zram%zu", n); ++ else { ++ strncpy(z->devname, devname, sizeof(z->devname)); ++ z->devname[sizeof(z->devname) - 1] = '\0'; ++ } ++ ++ DBG(fprintf(stderr, "set devname: %s", z->devname)); ++ sysfs_deinit(&z->sysfs); ++ zram_reset_stat(z); ++} ++ ++static int zram_get_devnum(struct zram *z) ++{ ++ int n; ++ ++ assert(z); ++ ++ if (sscanf(z->devname, "/dev/zram%d", &n) == 1) ++ return n; ++ return -EINVAL; ++} ++ ++static struct zram *new_zram(const char *devname) ++{ ++ struct zram *z = xcalloc(1, sizeof(struct zram)); ++ ++ DBG(fprintf(stderr, "new: %p", z)); ++ if (devname) ++ zram_set_devname(z, devname, 0); ++ return z; ++} ++ ++static void free_zram(struct zram *z) ++{ ++ if (!z) ++ return; ++ DBG(fprintf(stderr, "free: %p", z)); ++ sysfs_deinit(&z->sysfs); ++ zram_reset_stat(z); ++ free(z); ++} ++ ++static struct sysfs_cxt *zram_get_sysfs(struct zram *z) ++{ ++ assert(z); ++ ++ if (!z->sysfs.devno) { ++ dev_t devno = sysfs_devname_to_devno(z->devname, NULL); ++ if (!devno) ++ return NULL; ++ if (sysfs_init(&z->sysfs, devno, NULL)) ++ return NULL; ++ if (*z->devname != '/') { ++ /* canonicalize the device name according to /sys */ ++ char name[PATH_MAX]; ++ if (sysfs_get_devname(&z->sysfs, name, sizeof(name))) ++ snprintf(z->devname, sizeof(z->devname), "/dev/%s", name); ++ } ++ } ++ ++ return &z->sysfs; ++} ++ ++static inline int zram_exist(struct zram *z) ++{ ++ assert(z); ++ ++ errno = 0; ++ if (zram_get_sysfs(z) == NULL) { ++ errno = ENODEV; ++ return 0; ++ } ++ ++ DBG(fprintf(stderr, "%s exists", z->devname)); ++ return 1; ++} ++ ++static int zram_set_u64parm(struct zram *z, const char *attr, uint64_t num) ++{ ++ struct sysfs_cxt *sysfs = zram_get_sysfs(z); ++ if (!sysfs) ++ return -EINVAL; ++ DBG(fprintf(stderr, "%s writing %ju to %s", z->devname, num, attr)); ++ return sysfs_write_u64(sysfs, attr, num); ++} ++ ++static int zram_set_strparm(struct zram *z, const char *attr, const char *str) ++{ ++ struct sysfs_cxt *sysfs = zram_get_sysfs(z); ++ if (!sysfs) ++ return -EINVAL; ++ DBG(fprintf(stderr, "%s writing %s to %s", z->devname, str, attr)); ++ return sysfs_write_string(sysfs, attr, str); ++} ++ ++ ++static int zram_used(struct zram *z) ++{ ++ uint64_t size; ++ struct sysfs_cxt *sysfs = zram_get_sysfs(z); ++ ++ if (sysfs && ++ sysfs_read_u64(sysfs, "disksize", &size) == 0 && ++ size > 0) { ++ ++ DBG(fprintf(stderr, "%s used", z->devname)); ++ return 1; ++ } ++ DBG(fprintf(stderr, "%s unused", z->devname)); ++ return 0; ++} ++ ++static int zram_has_control(struct zram *z) ++{ ++ if (!z->control_probed) { ++ z->has_control = access(_PATH_SYS_CLASS "/zram-control/", F_OK) == 0 ? 1 : 0; ++ z->control_probed = 1; ++ DBG(fprintf(stderr, "zram-control: %s", z->has_control ? "yes" : "no")); ++ } ++ ++ return z->has_control; ++} ++ ++static int zram_control_add(struct zram *z) ++{ ++ int n; ++ ++ if (!zram_has_control(z)) ++ return -ENOSYS; ++ ++ n = path_read_s32(_PATH_SYS_CLASS "/zram-control/hot_add"); ++ if (n < 0) ++ return n; ++ ++ DBG(fprintf(stderr, "hot-add: %d", n)); ++ zram_set_devname(z, NULL, n); ++ return 0; ++} ++ ++static int zram_control_remove(struct zram *z) ++{ ++ char str[sizeof stringify_value(INT_MAX)]; ++ int n; ++ ++ if (!zram_has_control(z)) ++ return -ENOSYS; ++ ++ n = zram_get_devnum(z); ++ if (n < 0) ++ return n; ++ ++ DBG(fprintf(stderr, "hot-remove: %d", n)); ++ snprintf(str, sizeof(str), "%d", n); ++ return path_write_str(str, _PATH_SYS_CLASS "/zram-control/hot_remove"); ++} ++ ++static struct zram *find_free_zram(void) ++{ ++ struct zram *z = new_zram(NULL); ++ size_t i; ++ int isfree = 0; ++ ++ for (i = 0; isfree == 0; i++) { ++ DBG(fprintf(stderr, "find free: checking zram%zu", i)); ++ zram_set_devname(z, NULL, i); ++ if (!zram_exist(z) && zram_control_add(z) != 0) ++ break; ++ isfree = !zram_used(z); ++ } ++ if (!isfree) { ++ free_zram(z); ++ z = NULL; ++ } ++ return z; ++} ++ ++static char *get_mm_stat(struct zram *z, size_t idx, int bytes) ++{ ++ struct sysfs_cxt *sysfs; ++ const char *name; ++ uint64_t num; ++ ++ assert(idx < ARRAY_SIZE(mm_stat_names)); ++ assert(z); ++ ++ sysfs = zram_get_sysfs(z); ++ if (!sysfs) ++ return NULL; ++ ++ /* Linux >= 4.1 uses /sys/block/zram/mm_stat */ ++ if (!z->mm_stat && !z->mm_stat_probed) { ++ char *str; ++ ++ str = sysfs_strdup(sysfs, "mm_stat"); ++ if (str) { ++ z->mm_stat = strv_split(str, " "); ++ if (strv_length(z->mm_stat) < ARRAY_SIZE(mm_stat_names)) ++ errx(EXIT_FAILURE, _("Failed to parse mm_stat")); ++ } ++ z->mm_stat_probed = 1; ++ free(str); ++ ++ } ++ ++ if (z->mm_stat) { ++ if (bytes) ++ return xstrdup(z->mm_stat[idx]); ++ ++ num = strtou64_or_err(z->mm_stat[idx], _("Failed to parse mm_stat")); ++ return size_to_human_string(SIZE_SUFFIX_1LETTER, num); ++ } ++ ++ /* Linux < 4.1 uses /sys/block/zram/ */ ++ name = mm_stat_names[idx]; ++ if (bytes) ++ return sysfs_strdup(sysfs, name); ++ else if (sysfs_read_u64(sysfs, name, &num) == 0) ++ return size_to_human_string(SIZE_SUFFIX_1LETTER, num); ++ return NULL; ++} ++ ++static void fill_table_row(struct libscols_table *tb, struct zram *z) ++{ ++ static struct libscols_line *ln; ++ struct sysfs_cxt *sysfs; ++ size_t i; ++ uint64_t num; ++ ++ assert(tb); ++ assert(z); ++ ++ DBG(fprintf(stderr, "%s: filling status table", z->devname)); ++ ++ sysfs = zram_get_sysfs(z); ++ if (!sysfs) ++ return; ++ ++ ln = scols_table_new_line(tb, NULL); ++ if (!ln) ++ err(EXIT_FAILURE, _("failed to initialize output line")); ++ ++ for (i = 0; i < (size_t) ncolumns; i++) { ++ char *str = NULL; ++ ++ switch (get_column_id(i)) { ++ case COL_NAME: ++ str = xstrdup(z->devname); ++ break; ++ case COL_DISKSIZE: ++ if (inbytes) ++ str = sysfs_strdup(sysfs, "disksize"); ++ else if (sysfs_read_u64(sysfs, "disksize", &num) == 0) ++ str = size_to_human_string(SIZE_SUFFIX_1LETTER, num); ++ break; ++ case COL_ALGORITHM: ++ { ++ char *alg = sysfs_strdup(sysfs, "comp_algorithm"); ++ if (!alg) ++ break; ++ if (strstr(alg, "[lzo]") == NULL) { ++ if (strstr(alg, "[lz4]") == NULL) ++ ; ++ else ++ str = xstrdup("lz4"); ++ } else ++ str = xstrdup("lzo"); ++ free(alg); ++ break; ++ } ++ case COL_MOUNTPOINT: ++ { ++ char path[PATH_MAX] = { '\0' }; ++ int fl; ++ ++ check_mount_point(z->devname, &fl, path, sizeof(path)); ++ if (*path) ++ str = xstrdup(path); ++ break; ++ } ++ case COL_STREAMS: ++ str = sysfs_strdup(sysfs, "max_comp_streams"); ++ break; ++ case COL_ZEROPAGES: ++ str = get_mm_stat(z, MM_ZERO_PAGES, 1); ++ break; ++ case COL_ORIG_SIZE: ++ str = get_mm_stat(z, MM_ORIG_DATA_SIZE, inbytes); ++ break; ++ case COL_COMP_SIZE: ++ str = get_mm_stat(z, MM_COMPR_DATA_SIZE, inbytes); ++ break; ++ case COL_MEMTOTAL: ++ str = get_mm_stat(z, MM_MEM_USED_TOTAL, inbytes); ++ break; ++ case COL_MEMLIMIT: ++ str = get_mm_stat(z, MM_MEM_LIMIT, inbytes); ++ break; ++ case COL_MEMUSED: ++ str = get_mm_stat(z, MM_MEM_USED_MAX, inbytes); ++ break; ++ case COL_MIGRATED: ++ str = get_mm_stat(z, MM_NUM_MIGRATED, inbytes); ++ break; ++ } ++ if (str) ++ scols_line_refer_data(ln, i, str); ++ } ++} ++ ++static void status(struct zram *z) ++{ ++ struct libscols_table *tb; ++ size_t i; ++ ++ scols_init_debug(0); ++ ++ tb = scols_new_table(); ++ if (!tb) ++ err(EXIT_FAILURE, _("failed to initialize output table")); ++ ++ scols_table_enable_raw(tb, raw); ++ scols_table_enable_noheadings(tb, no_headings); ++ ++ for (i = 0; i < (size_t) ncolumns; i++) { ++ const struct colinfo *col = get_column_info(i); ++ ++ if (!scols_table_new_column(tb, col->name, col->whint, col->flags)) ++ err(EXIT_FAILURE, _("failed to initialize output column")); ++ } ++ ++ if (z) ++ fill_table_row(tb, z); /* just one device specified */ ++ else { ++ /* list all used devices */ ++ z = new_zram(NULL); ++ ++ for (i = 0; ; i++) { ++ zram_set_devname(z, NULL, i); ++ if (!zram_exist(z)) ++ break; ++ if (zram_used(z)) ++ fill_table_row(tb, z); ++ } ++ free_zram(z); ++ } ++ ++ scols_print_table(tb); ++ scols_unref_table(tb); ++} ++ ++static void __attribute__ ((__noreturn__)) usage(FILE * out) ++{ ++ size_t i; ++ ++ fputs(USAGE_HEADER, out); ++ fprintf(out, _( " %1$s [options] \n" ++ " %1$s -r [...]\n" ++ " %1$s [options] -f | -s \n"), ++ program_invocation_short_name); ++ ++ fputs(USAGE_SEPARATOR, out); ++ fputs(_("Set up and control zram devices.\n"), out); ++ ++ fputs(USAGE_OPTIONS, out); ++ fputs(_(" -a, --algorithm lzo|lz4 compression algorithm to use\n"), out); ++ fputs(_(" -b, --bytes print sizes in bytes rather than in human readable format\n"), out); ++ fputs(_(" -f, --find find a free device\n"), out); ++ fputs(_(" -n, --noheadings don't print headings\n"), out); ++ fputs(_(" -o, --output columns to use for status output\n"), out); ++ fputs(_(" --raw use raw status output format\n"), out); ++ fputs(_(" -r, --reset reset all specified devices\n"), out); ++ fputs(_(" -s, --size device size\n"), out); ++ fputs(_(" -t, --streams number of compression streams\n"), out); ++ ++ fputs(USAGE_SEPARATOR, out); ++ fputs(USAGE_HELP, out); ++ fputs(USAGE_VERSION, out); ++ ++ fputs(_("\nAvailable columns (for --output):\n"), out); ++ for (i = 0; i < ARRAY_SIZE(infos); i++) ++ fprintf(out, " %11s %s\n", infos[i].name, _(infos[i].help)); ++ ++ fprintf(out, USAGE_MAN_TAIL("zramctl(8)")); ++ exit(out == stderr ? 1 : EXIT_SUCCESS); ++} ++ ++/* actions */ ++enum { ++ A_NONE = 0, ++ A_STATUS, ++ A_CREATE, ++ A_FINDONLY, ++ A_RESET ++}; ++ ++int main(int argc, char **argv) ++{ ++ uintmax_t size = 0, nstreams = 0; ++ char *algorithm = NULL; ++ int rc = 0, c, find = 0, act = A_NONE; ++ struct zram *zram = NULL; ++ ++ enum { OPT_RAW = CHAR_MAX + 1 }; ++ ++ static const struct option longopts[] = { ++ { "algorithm", required_argument, NULL, 'a' }, ++ { "bytes", no_argument, NULL, 'b' }, ++ { "find", no_argument, NULL, 'f' }, ++ { "help", no_argument, NULL, 'h' }, ++ { "output", required_argument, NULL, 'o' }, ++ { "noheadings",no_argument, NULL, 'n' }, ++ { "reset", no_argument, NULL, 'r' }, ++ { "raw", no_argument, NULL, OPT_RAW }, ++ { "size", required_argument, NULL, 's' }, ++ { "streams", required_argument, NULL, 't' }, ++ { "version", no_argument, NULL, 'V' }, ++ { NULL, 0, NULL, 0 } ++ }; ++ ++ static const ul_excl_t excl[] = { ++ { 'f', 'o', 'r' }, ++ { 'o', 'r', 's' }, ++ { 0 } ++ }; ++ int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT; ++ ++ setlocale(LC_ALL, ""); ++ bindtextdomain(PACKAGE, LOCALEDIR); ++ textdomain(PACKAGE); ++ atexit(close_stdout); ++ ++ while ((c = getopt_long(argc, argv, "a:bfho:nrs:t:V", longopts, NULL)) != -1) { ++ ++ err_exclusive_options(c, longopts, excl, excl_st); ++ ++ switch (c) { ++ case 'a': ++ if (strcmp(optarg,"lzo") && strcmp(optarg,"lz4")) ++ errx(EXIT_FAILURE, _("unsupported algorithm: %s"), ++ optarg); ++ algorithm = optarg; ++ break; ++ case 'b': ++ inbytes = 1; ++ break; ++ case 'f': ++ find = 1; ++ break; ++ case 'o': ++ ncolumns = string_to_idarray(optarg, ++ columns, ARRAY_SIZE(columns), ++ column_name_to_id); ++ if (ncolumns < 0) ++ return EXIT_FAILURE; ++ break; ++ case 's': ++ size = strtosize_or_err(optarg, _("failed to parse size")); ++ act = A_CREATE; ++ break; ++ case 't': ++ nstreams = strtou64_or_err(optarg, _("failed to parse streams")); ++ break; ++ case 'r': ++ act = A_RESET; ++ break; ++ case OPT_RAW: ++ raw = 1; ++ break; ++ case 'n': ++ no_headings = 1; ++ break; ++ case 'V': ++ printf(UTIL_LINUX_VERSION); ++ return EXIT_SUCCESS; ++ case 'h': ++ usage(stdout); ++ default: ++ usage(stderr); ++ } ++ } ++ ++ if (find && optind < argc) ++ errx(EXIT_FAILURE, _("option --find is mutually exclusive " ++ "with ")); ++ if (act == A_NONE) ++ act = find ? A_FINDONLY : A_STATUS; ++ ++ if (act != A_RESET && optind + 1 < argc) ++ errx(EXIT_FAILURE, _("only one at a time is allowed")); ++ ++ if ((act == A_STATUS || act == A_FINDONLY) && (algorithm || nstreams)) ++ errx(EXIT_FAILURE, _("options --algorithm and --streams " ++ "must be combined with --size")); ++ ++ switch (act) { ++ case A_STATUS: ++ if (!ncolumns) { /* default columns */ ++ columns[ncolumns++] = COL_NAME; ++ columns[ncolumns++] = COL_ALGORITHM; ++ columns[ncolumns++] = COL_DISKSIZE; ++ columns[ncolumns++] = COL_ORIG_SIZE; ++ columns[ncolumns++] = COL_COMP_SIZE; ++ columns[ncolumns++] = COL_MEMTOTAL; ++ columns[ncolumns++] = COL_STREAMS; ++ columns[ncolumns++] = COL_MOUNTPOINT; ++ } ++ if (optind < argc) { ++ zram = new_zram(argv[optind++]); ++ if (!zram_exist(zram)) ++ err(EXIT_FAILURE, "%s", zram->devname); ++ } ++ status(zram); ++ free_zram(zram); ++ break; ++ case A_RESET: ++ if (optind == argc) ++ errx(EXIT_FAILURE, _("no device specified")); ++ while (optind < argc) { ++ zram = new_zram(argv[optind]); ++ if (!zram_exist(zram) ++ || zram_set_u64parm(zram, "reset", 1)) { ++ warn(_("%s: failed to reset"), zram->devname); ++ rc = 1; ++ } ++ zram_control_remove(zram); ++ free_zram(zram); ++ optind++; ++ } ++ break; ++ case A_FINDONLY: ++ zram = find_free_zram(); ++ if (!zram) ++ errx(EXIT_FAILURE, _("no free zram device found")); ++ printf("%s\n", zram->devname); ++ free_zram(zram); ++ break; ++ case A_CREATE: ++ if (find) { ++ zram = find_free_zram(); ++ if (!zram) ++ errx(EXIT_FAILURE, _("no free zram device found")); ++ } else if (optind == argc) ++ errx(EXIT_FAILURE, _("no device specified")); ++ else { ++ zram = new_zram(argv[optind]); ++ if (!zram_exist(zram)) ++ err(EXIT_FAILURE, "%s", zram->devname); ++ } ++ ++ if (zram_set_u64parm(zram, "reset", 1)) ++ err(EXIT_FAILURE, _("%s: failed to reset"), zram->devname); ++ ++ if (nstreams && ++ zram_set_u64parm(zram, "max_comp_streams", nstreams)) ++ err(EXIT_FAILURE, _("%s: failed to set number of streams"), zram->devname); ++ ++ if (algorithm && ++ zram_set_strparm(zram, "comp_algorithm", algorithm)) ++ err(EXIT_FAILURE, _("%s: failed to set algorithm"), zram->devname); ++ ++ if (zram_set_u64parm(zram, "disksize", size)) ++ err(EXIT_FAILURE, _("%s: failed to set disksize (%ju bytes)"), ++ zram->devname, size); ++ if (find) ++ printf("%s\n", zram->devname); ++ free_zram(zram); ++ break; ++ } ++ ++ return rc ? EXIT_FAILURE : EXIT_SUCCESS; ++} +-- +2.9.3 + diff --git a/SOURCES/0107-libblkid-zfs-let-s-keep-compiler-happy.patch b/SOURCES/0107-libblkid-zfs-let-s-keep-compiler-happy.patch new file mode 100644 index 0000000..ca625de --- /dev/null +++ b/SOURCES/0107-libblkid-zfs-let-s-keep-compiler-happy.patch @@ -0,0 +1,28 @@ +From eda050c1fc9f65fc138c9fabf35ef7865c5b10a7 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Fri, 30 May 2014 11:27:41 +0200 +Subject: [PATCH 107/116] libblkid: (zfs) let's keep compiler happy + +Upstream: http://github.com/karelzak/util-linux/commit/59cbbd71cdfb6a6fc6901e287b300aa8d45d6606 +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1392661 +Signed-off-by: Karel Zak +--- + libblkid/src/superblocks/zfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libblkid/src/superblocks/zfs.c b/libblkid/src/superblocks/zfs.c +index 56ee472..86da59d 100644 +--- a/libblkid/src/superblocks/zfs.c ++++ b/libblkid/src/superblocks/zfs.c +@@ -171,7 +171,7 @@ static int probe_zfs(blkid_probe pr, + uint64_t swab_magic = swab64(UBERBLOCK_MAGIC); + struct zfs_uberblock *ub; + int swab_endian; +- loff_t offset, ub_offset; ++ loff_t offset, ub_offset = 0; + int tried; + int found; + +-- +2.9.3 + diff --git a/SOURCES/0108-blkid-make-zfs-detection-more-robust.patch b/SOURCES/0108-blkid-make-zfs-detection-more-robust.patch new file mode 100644 index 0000000..7d929bd --- /dev/null +++ b/SOURCES/0108-blkid-make-zfs-detection-more-robust.patch @@ -0,0 +1,112 @@ +From a0e00751052b06508f6cfe4a434ebf2e1a04bf07 Mon Sep 17 00:00:00 2001 +From: Michal Humpula +Date: Wed, 25 Feb 2015 20:25:05 +0100 +Subject: [PATCH 108/116] blkid: make zfs detection more robust + +Try to use all the possible uberblock locations. + +Upstream: https://github.com/karelzak/util-linux/commit/5dd705ba65dc80cf8630b3b1b4f3a1ba153e7eec +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1392661 +Signed-off-by: Karel Zak +--- + libblkid/src/superblocks/zfs.c | 42 +++++++++++++++++++++++++++--------------- + 1 file changed, 27 insertions(+), 15 deletions(-) + +diff --git a/libblkid/src/superblocks/zfs.c b/libblkid/src/superblocks/zfs.c +index 86da59d..4a64a03 100644 +--- a/libblkid/src/superblocks/zfs.c ++++ b/libblkid/src/superblocks/zfs.c +@@ -19,6 +19,7 @@ + #define VDEV_LABEL_UBERBLOCK (128 * 1024ULL) + #define VDEV_LABEL_NVPAIR ( 16 * 1024ULL) + #define VDEV_LABEL_SIZE (256 * 1024ULL) ++#define UBERBLOCK_SIZE 1024ULL + + /* #include */ + #define UBERBLOCK_MAGIC 0x00bab10c /* oo-ba-bloc! */ +@@ -31,7 +32,7 @@ struct zfs_uberblock { + char ub_rootbp; /* MOS objset_phys_t */ + } __attribute__((packed)); + +-#define ZFS_TRIES 64 ++#define ZFS_TRIES 512 + #define ZFS_WANT 4 + + #define DATA_TYPE_UINT64 8 +@@ -162,11 +163,10 @@ static void zfs_extract_guid_name(blkid_probe pr, loff_t offset) + #define zdebug(fmt, ...) do {} while(0) + /*#define zdebug(fmt, a...) fprintf(stderr, fmt, ##a)*/ + +-/* ZFS has 128x1kB host-endian root blocks, stored in 2 areas at the start +- * of the disk, and 2 areas at the end of the disk. Check only some of them... +- * #4 (@ 132kB) is the first one written on a new filesystem. */ +-static int probe_zfs(blkid_probe pr, +- const struct blkid_idmag *mag __attribute__((__unused__))) ++/* ZFS has 128x1kB host-endian root blocks, stored in 2 areas (labels) ++ * at the start of the disk, and 2 areas at the end of the disk. ++ */ ++static int probe_zfs(blkid_probe pr, const struct blkid_idmag *mag) + { + uint64_t swab_magic = swab64(UBERBLOCK_MAGIC); + struct zfs_uberblock *ub; +@@ -174,15 +174,29 @@ static int probe_zfs(blkid_probe pr, + loff_t offset, ub_offset = 0; + int tried; + int found; ++ loff_t blk_align = (pr->size % (256 * 1024ULL)); + + zdebug("probe_zfs\n"); +- /* Look for at least 4 uberblocks to ensure a positive match */ ++ /* Look for at least 4 uberblocks to ensure a positive match. ++ Begin with Label 0 (L0) at the start of the block device. */ + for (tried = found = 0, offset = VDEV_LABEL_UBERBLOCK; +- tried < ZFS_TRIES && found < ZFS_WANT; +- tried++, offset += 4096) { +- /* also try the second uberblock copy */ +- if (tried == (ZFS_TRIES / 2)) ++ found < ZFS_WANT && tried < ZFS_TRIES; ++ tried++, offset += UBERBLOCK_SIZE) ++ { ++ /* Leave L0 to try other labels */ ++ switch(tried) { ++ case 128: // jump to L1, just after L0 + offset = VDEV_LABEL_SIZE + VDEV_LABEL_UBERBLOCK; ++ break; ++ case 256: // jump to L2 near the far end of the block device ++ offset = pr->size - 2 * VDEV_LABEL_SIZE + VDEV_LABEL_UBERBLOCK - blk_align; ++ zdebug("probe_zfs: l2 offset %llu\n", offset >> 10); ++ break; ++ case 384: // jump to L3 at the furthest end of the block device ++ offset = pr->size - VDEV_LABEL_SIZE + VDEV_LABEL_UBERBLOCK - blk_align; ++ zdebug("probe_zfs: l3 offset %llu\n", offset >> 10); ++ break; ++ } + + ub = (struct zfs_uberblock *) + blkid_probe_get_buffer(pr, offset, +@@ -193,15 +207,14 @@ static int probe_zfs(blkid_probe pr, + if (ub->ub_magic == UBERBLOCK_MAGIC) { + ub_offset = offset; + found++; ++ zdebug("probe_zfs: found little-endian uberblock at %llu\n", offset >> 10); + } + + if ((swab_endian = (ub->ub_magic == swab_magic))) { + ub_offset = offset; + found++; ++ zdebug("probe_zfs: found big-endian uberblock at %llu\n", offset >> 10); + } +- +- zdebug("probe_zfs: found %s-endian uberblock at %llu\n", +- swab_endian ? "big" : "little", offset >> 10); + } + + if (found < 4) +@@ -230,4 +243,3 @@ const struct blkid_idinfo zfs_idinfo = + .minsz = 64 * 1024 * 1024, + .magics = BLKID_NONE_MAGIC + }; +- +-- +2.9.3 + diff --git a/SOURCES/0109-zfs-make-less-syscalls.patch b/SOURCES/0109-zfs-make-less-syscalls.patch new file mode 100644 index 0000000..b43620d --- /dev/null +++ b/SOURCES/0109-zfs-make-less-syscalls.patch @@ -0,0 +1,154 @@ +From 8646f60d1b421b48b43405fa286548a0bf3f5da4 Mon Sep 17 00:00:00 2001 +From: Michal Humpula +Date: Sat, 28 Feb 2015 21:19:42 +0100 +Subject: [PATCH 109/116] zfs: make less syscalls + +Upstream: https://github.com/karelzak/util-linux/commit/e44a4c7ac9522c03b76d8b62ce88b443771fdb0b +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1392661 +Signed-off-by: Karel Zak +--- + libblkid/src/superblocks/zfs.c | 95 ++++++++++++++++++++++++++---------------- + 1 file changed, 58 insertions(+), 37 deletions(-) + +diff --git a/libblkid/src/superblocks/zfs.c b/libblkid/src/superblocks/zfs.c +index 4a64a03..9b5601e 100644 +--- a/libblkid/src/superblocks/zfs.c ++++ b/libblkid/src/superblocks/zfs.c +@@ -20,6 +20,7 @@ + #define VDEV_LABEL_NVPAIR ( 16 * 1024ULL) + #define VDEV_LABEL_SIZE (256 * 1024ULL) + #define UBERBLOCK_SIZE 1024ULL ++#define UBERBLOCKS_COUNT 128 + + /* #include */ + #define UBERBLOCK_MAGIC 0x00bab10c /* oo-ba-bloc! */ +@@ -32,7 +33,6 @@ struct zfs_uberblock { + char ub_rootbp; /* MOS objset_phys_t */ + } __attribute__((packed)); + +-#define ZFS_TRIES 512 + #define ZFS_WANT 4 + + #define DATA_TYPE_UINT64 8 +@@ -163,61 +163,82 @@ static void zfs_extract_guid_name(blkid_probe pr, loff_t offset) + #define zdebug(fmt, ...) do {} while(0) + /*#define zdebug(fmt, a...) fprintf(stderr, fmt, ##a)*/ + +-/* ZFS has 128x1kB host-endian root blocks, stored in 2 areas (labels) +- * at the start of the disk, and 2 areas at the end of the disk. +- */ ++static int find_uberblocks(const void *label, loff_t *ub_offset, int *swap_endian) ++{ ++ uint64_t swab_magic = swab64(UBERBLOCK_MAGIC); ++ struct zfs_uberblock *ub; ++ int i, found = 0; ++ loff_t offset = VDEV_LABEL_UBERBLOCK; ++ ++ for (i = 0; i < UBERBLOCKS_COUNT; i++, offset += UBERBLOCK_SIZE) { ++ ub = (struct zfs_uberblock *)(label + offset); ++ ++ if (ub->ub_magic == UBERBLOCK_MAGIC) { ++ *ub_offset = offset; ++ *swap_endian = 0; ++ found++; ++ zdebug("probe_zfs: found little-endian uberblock at %llu\n", offset >> 10); ++ } ++ ++ if (ub->ub_magic == swab_magic) { ++ *ub_offset = offset; ++ *swap_endian = 1; ++ found++; ++ zdebug("probe_zfs: found big-endian uberblock at %llu\n", offset >> 10); ++ } ++ } ++ ++ return found; ++} ++ ++/* ZFS has 128x1kB host-endian root blocks, stored in 2 areas at the start ++ * of the disk, and 2 areas at the end of the disk. Check only some of them... ++ * #4 (@ 132kB) is the first one written on a new filesystem. */ + static int probe_zfs(blkid_probe pr, const struct blkid_idmag *mag) + { + uint64_t swab_magic = swab64(UBERBLOCK_MAGIC); ++ int swab_endian = 0; + struct zfs_uberblock *ub; +- int swab_endian; + loff_t offset, ub_offset = 0; +- int tried; +- int found; ++ int label_no, found = 0, found_in_label; ++ void *label; + loff_t blk_align = (pr->size % (256 * 1024ULL)); + + zdebug("probe_zfs\n"); +- /* Look for at least 4 uberblocks to ensure a positive match. +- Begin with Label 0 (L0) at the start of the block device. */ +- for (tried = found = 0, offset = VDEV_LABEL_UBERBLOCK; +- found < ZFS_WANT && tried < ZFS_TRIES; +- tried++, offset += UBERBLOCK_SIZE) +- { +- /* Leave L0 to try other labels */ +- switch(tried) { +- case 128: // jump to L1, just after L0 +- offset = VDEV_LABEL_SIZE + VDEV_LABEL_UBERBLOCK; ++ /* Look for at least 4 uberblocks to ensure a positive match */ ++ for (label_no = 0; label_no < 4; label_no++) { ++ switch(label_no) { ++ case 0: // jump to L0 ++ offset = 0; + break; +- case 256: // jump to L2 near the far end of the block device +- offset = pr->size - 2 * VDEV_LABEL_SIZE + VDEV_LABEL_UBERBLOCK - blk_align; +- zdebug("probe_zfs: l2 offset %llu\n", offset >> 10); ++ case 1: // jump to L1 ++ offset = VDEV_LABEL_SIZE; + break; +- case 384: // jump to L3 at the furthest end of the block device +- offset = pr->size - VDEV_LABEL_SIZE + VDEV_LABEL_UBERBLOCK - blk_align; +- zdebug("probe_zfs: l3 offset %llu\n", offset >> 10); ++ case 2: // jump to L2 ++ offset = pr->size - 2 * VDEV_LABEL_SIZE - blk_align; ++ break; ++ case 3: // jump to L3 ++ offset = pr->size - VDEV_LABEL_SIZE - blk_align; + break; + } + +- ub = (struct zfs_uberblock *) +- blkid_probe_get_buffer(pr, offset, +- sizeof(struct zfs_uberblock)); +- if (ub == NULL) ++ label = blkid_probe_get_buffer(pr, offset, VDEV_LABEL_SIZE); ++ if (label == NULL) + return errno ? -errno : 1; + +- if (ub->ub_magic == UBERBLOCK_MAGIC) { +- ub_offset = offset; +- found++; +- zdebug("probe_zfs: found little-endian uberblock at %llu\n", offset >> 10); +- } ++ found_in_label = find_uberblocks(label, &ub_offset, &swab_endian); + +- if ((swab_endian = (ub->ub_magic == swab_magic))) { +- ub_offset = offset; +- found++; +- zdebug("probe_zfs: found big-endian uberblock at %llu\n", offset >> 10); ++ if (found_in_label > 0) { ++ found+= found_in_label; ++ ub = (struct zfs_uberblock *)(label + ub_offset); ++ ub_offset += offset; ++ ++ if (found >= ZFS_WANT) ++ break; + } + } + +- if (found < 4) ++ if (found < ZFS_WANT) + return 1; + + /* If we found the 4th uberblock, then we will have exited from the +-- +2.9.3 + diff --git a/SOURCES/0110-libblkid-zfs-keep-bufferes-read-only.patch b/SOURCES/0110-libblkid-zfs-keep-bufferes-read-only.patch new file mode 100644 index 0000000..ad08711 --- /dev/null +++ b/SOURCES/0110-libblkid-zfs-keep-bufferes-read-only.patch @@ -0,0 +1,48 @@ +From eeb629102da9a9a916d201bbd5f13ee7ad23844d Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Tue, 22 Sep 2015 15:27:39 +0200 +Subject: [PATCH 110/116] libblkid: (zfs) keep bufferes read-only + +Upstream: https://github.com/karelzak/util-linux/commit/9325a8be9e55cc01d9f580e14dd2193829245183 +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1392661 +Signed-off-by: Karel Zak +--- + libblkid/src/superblocks/zfs.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/libblkid/src/superblocks/zfs.c b/libblkid/src/superblocks/zfs.c +index 9b5601e..8e88b39 100644 +--- a/libblkid/src/superblocks/zfs.c ++++ b/libblkid/src/superblocks/zfs.c +@@ -70,9 +70,10 @@ struct nvlist { + + static void zfs_extract_guid_name(blkid_probe pr, loff_t offset) + { ++ unsigned char *p, buff[4096]; + struct nvlist *nvl; + struct nvpair *nvp; +- size_t left = 4096; ++ size_t left = sizeof(buff); + int found = 0; + + offset = (offset & ~(VDEV_LABEL_SIZE - 1)) + VDEV_LABEL_NVPAIR; +@@ -81,10 +82,14 @@ static void zfs_extract_guid_name(blkid_probe pr, loff_t offset) + * the first 4k (left) of the nvlist. This is true for all pools + * I've seen, and simplifies this code somewhat, because we don't + * have to handle an nvpair crossing a buffer boundary. */ +- nvl = (struct nvlist *)blkid_probe_get_buffer(pr, offset, left); +- if (nvl == NULL) ++ p = blkid_probe_get_buffer(pr, offset, left); ++ if (!p) + return; + ++ /* libblkid buffers are strictly readonly, but the code below modifies nvpair etc. */ ++ memcpy(buff, p, sizeof(buff)); ++ nvl = (struct nvlist *) buff; ++ + nvdebug("zfs_extract: nvlist offset %llu\n", offset); + + nvp = &nvl->nvl_nvpair; +-- +2.9.3 + diff --git a/SOURCES/0111-libblkid-don-t-mark-zfs-as-RAID.patch b/SOURCES/0111-libblkid-don-t-mark-zfs-as-RAID.patch new file mode 100644 index 0000000..8436e87 --- /dev/null +++ b/SOURCES/0111-libblkid-don-t-mark-zfs-as-RAID.patch @@ -0,0 +1,28 @@ +From 400facb19f228e3507de2137e2f9165b3365b7df Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Wed, 18 Nov 2015 11:55:35 +0100 +Subject: [PATCH 111/116] libblkid: don't mark zfs as RAID + +Upstream: https://github.com/karelzak/util-linux/commit/710dd492394be6cd2f3dd65c057ae7827ee6e89d +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1392661 +Signed-off-by: Karel Zak +--- + libblkid/src/superblocks/zfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libblkid/src/superblocks/zfs.c b/libblkid/src/superblocks/zfs.c +index 8e88b39..5074495 100644 +--- a/libblkid/src/superblocks/zfs.c ++++ b/libblkid/src/superblocks/zfs.c +@@ -264,7 +264,7 @@ static int probe_zfs(blkid_probe pr, const struct blkid_idmag *mag) + const struct blkid_idinfo zfs_idinfo = + { + .name = "zfs_member", +- .usage = BLKID_USAGE_RAID, ++ .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_zfs, + .minsz = 64 * 1024 * 1024, + .magics = BLKID_NONE_MAGIC +-- +2.9.3 + diff --git a/SOURCES/0112-tests-update-ZFS-test.patch b/SOURCES/0112-tests-update-ZFS-test.patch new file mode 100644 index 0000000..9368222 --- /dev/null +++ b/SOURCES/0112-tests-update-ZFS-test.patch @@ -0,0 +1,28 @@ +From 0f0a36e64ed47721e8b8d41b81ae3b1817d19194 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Thu, 19 Nov 2015 19:08:00 +0100 +Subject: [PATCH 112/116] tests: update ZFS test + +Upstream: https://github.com/karelzak/util-linux/commit/0172ebba52718afe89b5d1941266825b065358cb +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1392661 +Signed-off-by: Karel Zak +--- + tests/expected/blkid/low-probe-zfs | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/expected/blkid/low-probe-zfs b/tests/expected/blkid/low-probe-zfs +index 46727de..952e0e5 100644 +--- a/tests/expected/blkid/low-probe-zfs ++++ b/tests/expected/blkid/low-probe-zfs +@@ -1,7 +1,7 @@ + ID_FS_LABEL=tank + ID_FS_LABEL_ENC=tank + ID_FS_TYPE=zfs_member +-ID_FS_USAGE=raid ++ID_FS_USAGE=filesystem + ID_FS_UUID=1782036546311300980 + ID_FS_UUID_ENC=1782036546311300980 + ID_FS_UUID_SUB=13179280127379850514 +-- +2.9.3 + diff --git a/SOURCES/0113-libblkid-zfs-add-cast-to-fix-UB-cppcheck.patch b/SOURCES/0113-libblkid-zfs-add-cast-to-fix-UB-cppcheck.patch new file mode 100644 index 0000000..6ac7f51 --- /dev/null +++ b/SOURCES/0113-libblkid-zfs-add-cast-to-fix-UB-cppcheck.patch @@ -0,0 +1,31 @@ +From a569050329d914ad5aa15978f2a4a3d969c7c8b1 Mon Sep 17 00:00:00 2001 +From: Boris Egorov +Date: Tue, 19 Jan 2016 11:37:57 +0600 +Subject: [PATCH 113/116] libblkid: (zfs) add cast to fix UB [cppcheck] + +[libblkid/src/superblocks/zfs.c:173]: (error) Shifting 32-bit value by 56 bits is undefined behaviour +[libblkid/src/superblocks/zfs.c:173]: (error) Shifting 32-bit value by 40 bits is undefined behaviour + +Upstream: https://github.com/karelzak/util-linux/commit/18b76be61c11fd5f11fcb84aa6a946d3b03d7225 +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1392661 +Signed-off-by: Karel Zak +--- + libblkid/src/superblocks/zfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libblkid/src/superblocks/zfs.c b/libblkid/src/superblocks/zfs.c +index 5074495..ff12fa6 100644 +--- a/libblkid/src/superblocks/zfs.c ++++ b/libblkid/src/superblocks/zfs.c +@@ -170,7 +170,7 @@ static void zfs_extract_guid_name(blkid_probe pr, loff_t offset) + + static int find_uberblocks(const void *label, loff_t *ub_offset, int *swap_endian) + { +- uint64_t swab_magic = swab64(UBERBLOCK_MAGIC); ++ uint64_t swab_magic = swab64((uint64_t)UBERBLOCK_MAGIC); + struct zfs_uberblock *ub; + int i, found = 0; + loff_t offset = VDEV_LABEL_UBERBLOCK; +-- +2.9.3 + diff --git a/SOURCES/0114-libblkid-Avoid-OOB-access-on-illegal-ZFS-superblocks.patch b/SOURCES/0114-libblkid-Avoid-OOB-access-on-illegal-ZFS-superblocks.patch new file mode 100644 index 0000000..9d58bd6 --- /dev/null +++ b/SOURCES/0114-libblkid-Avoid-OOB-access-on-illegal-ZFS-superblocks.patch @@ -0,0 +1,48 @@ +From 7e1c9da4773237e368bdc0539ef91d55ef19806c Mon Sep 17 00:00:00 2001 +From: Tobias Stoeckmann +Date: Sun, 28 Aug 2016 21:15:59 +0200 +Subject: [PATCH 114/116] libblkid: Avoid OOB access on illegal ZFS superblocks + +64 bit systems can trigger an out of boundary access while performing +a ZFS superblock probe. + +This happens due to a possible integer overflow while calculating +the remaining available bytes. The variable is of type "int" and the +string length is allowed to be larger than INT_MAX, which means that +avail calculation can overflow, circumventing the "avail < 0" check and +therefore accessing memory outside the "buff" array later on. + +[kzak@redhat.com (rhel7): - remove unused swab_magic] + +Upstream: https://github.com/karelzak/util-linux/commit/8fa57ab0b5696031da800e243def32bc5265ff6d +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1392661 +Signed-off-by: Tobias Stoeckmann +Signed-off-by: Karel Zak +--- + libblkid/src/superblocks/zfs.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/libblkid/src/superblocks/zfs.c b/libblkid/src/superblocks/zfs.c +index ff12fa6..2c7b4b7 100644 +--- a/libblkid/src/superblocks/zfs.c ++++ b/libblkid/src/superblocks/zfs.c +@@ -115,7 +115,7 @@ static void zfs_extract_guid_name(blkid_probe pr, loff_t offset) + + nvs->nvs_type = be32_to_cpu(nvs->nvs_type); + nvs->nvs_strlen = be32_to_cpu(nvs->nvs_strlen); +- if (nvs->nvs_strlen > UINT_MAX - sizeof(*nvs)) ++ if (nvs->nvs_strlen > INT_MAX - sizeof(*nvs)) + break; + avail -= nvs->nvs_strlen + sizeof(*nvs); + nvdebug("nvstring: type %u string %*s\n", nvs->nvs_type, +@@ -201,7 +201,6 @@ static int find_uberblocks(const void *label, loff_t *ub_offset, int *swap_endia + * #4 (@ 132kB) is the first one written on a new filesystem. */ + static int probe_zfs(blkid_probe pr, const struct blkid_idmag *mag) + { +- uint64_t swab_magic = swab64(UBERBLOCK_MAGIC); + int swab_endian = 0; + struct zfs_uberblock *ub; + loff_t offset, ub_offset = 0; +-- +2.9.3 + diff --git a/SOURCES/0115-lscpu-backport-from-v2.29.patch b/SOURCES/0115-lscpu-backport-from-v2.29.patch new file mode 100644 index 0000000..9d95342 --- /dev/null +++ b/SOURCES/0115-lscpu-backport-from-v2.29.patch @@ -0,0 +1,2190 @@ +From 7ffb3c628dea313496c829bcb40447545470847e Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Tue, 21 Mar 2017 14:57:37 +0100 +Subject: [PATCH 115/116] lscpu: backport from v2.29 + +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1360764 +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1397709 +Signed-off-by: Karel Zak +--- + configure.ac | 3 +- + include/c.h | 30 ++ + include/pathnames.h | 2 + + include/xalloc.h | 10 + + sys-utils/Makemodule.am | 8 +- + sys-utils/lscpu-dmi.c | 285 ++++++++++++++ + sys-utils/lscpu.1 | 53 ++- + sys-utils/lscpu.c | 964 ++++++++++++++++++++++++++++++++++++++++-------- + sys-utils/lscpu.h | 26 ++ + 9 files changed, 1220 insertions(+), 161 deletions(-) + create mode 100644 sys-utils/lscpu-dmi.c + create mode 100644 sys-utils/lscpu.h + +diff --git a/configure.ac b/configure.ac +index db7095a..78258d6 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1059,8 +1059,9 @@ AM_CONDITIONAL(BUILD_LSBLK, test "x$build_lsblk" = xyes) + + UL_BUILD_INIT([lscpu], [check]) + UL_REQUIRES_LINUX([lscpu]) ++UL_REQUIRES_BUILD([lscpu], [libsmartcols]) + UL_REQUIRES_HAVE([lscpu], [cpu_set_t], [cpu_set_t type]) +-AM_CONDITIONAL(BUILD_LSCPU, test "x$build_lscpu" = xyes) ++AM_CONDITIONAL([BUILD_LSCPU], [test "x$build_lscpu" = xyes]) + + + UL_BUILD_INIT([lslogins], [check]) +diff --git a/include/c.h b/include/c.h +index 3754e75..8ff61b4 100644 +--- a/include/c.h ++++ b/include/c.h +@@ -200,6 +200,19 @@ errmsg(char doexit, int excode, char adderr, const char *fmt, ...) + #endif + #endif /* !HAVE_ERR_H */ + ++/* Don't use inline function to avoid '#include "nls.h"' in c.h ++ */ ++#define errtryhelp(eval) __extension__ ({ \ ++ fprintf(stderr, _("Try '%s --help' for more information.\n"), \ ++ program_invocation_short_name); \ ++ exit(eval); \ ++}) ++ ++#define errtryh(eval) __extension__ ({ \ ++ fprintf(stderr, _("Try '%s -h' for more information.\n"), \ ++ program_invocation_short_name); \ ++ exit(eval); \ ++}) + + static inline __attribute__((const)) int is_power_of_2(unsigned long num) + { +@@ -317,6 +330,23 @@ static inline int usleep(useconds_t usec) + #define stringify(s) #s + + /* ++ * UL_ASAN_BLACKLIST is a macro to tell AddressSanitizer (a compile-time ++ * instrumentation shipped with Clang and GCC) to not instrument the ++ * annotated function. Furthermore, it will prevent the compiler from ++ * inlining the function because inlining currently breaks the blacklisting ++ * mechanism of AddressSanitizer. ++ */ ++#if defined(__has_feature) ++# if __has_feature(address_sanitizer) ++# define UL_ASAN_BLACKLIST __attribute__((noinline)) __attribute__((no_sanitize_memory)) __attribute__((no_sanitize_address)) ++# else ++# define UL_ASAN_BLACKLIST /* nothing */ ++# endif ++#else ++# define UL_ASAN_BLACKLIST /* nothing */ ++#endif ++ ++/* + * Note that sysconf(_SC_GETPW_R_SIZE_MAX) returns *initial* suggested size for + * pwd buffer and in some cases it is not large enough. See POSIX and + * getpwnam_r man page for more details. +diff --git a/include/pathnames.h b/include/pathnames.h +index b648afc..fa4bddb 100644 +--- a/include/pathnames.h ++++ b/include/pathnames.h +@@ -131,6 +131,8 @@ + # define _PATH_DEV "/dev/" + #endif + ++#define _PATH_DEV_MEM "/dev/mem" ++ + #define _PATH_DEV_LOOP "/dev/loop" + #define _PATH_DEV_LOOPCTL "/dev/loop-control" + #define _PATH_DEV_TTY "/dev/tty" +diff --git a/include/xalloc.h b/include/xalloc.h +index 1a1799a..883e472 100644 +--- a/include/xalloc.h ++++ b/include/xalloc.h +@@ -99,6 +99,16 @@ static inline int __attribute__ ((__format__(printf, 2, 3))) + } + + ++static inline int __attribute__ ((__format__(printf, 2, 0))) ++xvasprintf(char **strp, const char *fmt, va_list ap) ++{ ++ int ret = vasprintf(&(*strp), fmt, ap); ++ if (ret < 0) ++ err(XALLOC_EXIT_CODE, "cannot allocate string"); ++ return ret; ++} ++ ++ + static inline char *xgethostname(void) + { + char *name; +diff --git a/sys-utils/Makemodule.am b/sys-utils/Makemodule.am +index 408e884..0496b84 100644 +--- a/sys-utils/Makemodule.am ++++ b/sys-utils/Makemodule.am +@@ -274,8 +274,12 @@ endif + + if BUILD_LSCPU + usrbin_exec_PROGRAMS += lscpu +-lscpu_SOURCES = sys-utils/lscpu.c +-lscpu_LDADD = $(LDADD) libcommon.la ++lscpu_SOURCES = \ ++ sys-utils/lscpu.c \ ++ sys-utils/lscpu.h \ ++ sys-utils/lscpu-dmi.c ++lscpu_LDADD = $(LDADD) libcommon.la libsmartcols.la $(RTAS_LIBS) ++lscpu_CFLAGS = $(AM_CFLAGS) -I$(ul_libsmartcols_incdir) + dist_man_MANS += sys-utils/lscpu.1 + endif + +diff --git a/sys-utils/lscpu-dmi.c b/sys-utils/lscpu-dmi.c +new file mode 100644 +index 0000000..0e497d1 +--- /dev/null ++++ b/sys-utils/lscpu-dmi.c +@@ -0,0 +1,285 @@ ++/* ++ * lscpu-dmi - Module to parse SMBIOS information ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it would be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Code originally taken from the dmidecode utility and slightly rewritten ++ * to suite the needs of lscpu ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "c.h" ++#include "pathnames.h" ++#include "all-io.h" ++#include "lscpu.h" ++ ++#define WORD(x) (uint16_t)(*(const uint16_t *)(x)) ++#define DWORD(x) (uint32_t)(*(const uint32_t *)(x)) ++ ++struct dmi_header ++{ ++ uint8_t type; ++ uint8_t length; ++ uint16_t handle; ++ uint8_t *data; ++}; ++ ++static int checksum(const uint8_t *buf, size_t len) ++{ ++ uint8_t sum = 0; ++ size_t a; ++ ++ for (a = 0; a < len; a++) ++ sum += buf[a]; ++ return (sum == 0); ++} ++ ++static void *get_mem_chunk(size_t base, size_t len, const char *devmem) ++{ ++ void *p = NULL; ++ int fd; ++ ++ if ((fd = open(devmem, O_RDONLY)) < 0) ++ return NULL; ++ ++ if (!(p = malloc(len))) ++ goto nothing; ++ if (lseek(fd, base, SEEK_SET) == -1) ++ goto nothing; ++ if (read_all(fd, p, len) == -1) ++ goto nothing; ++ ++ close(fd); ++ return p; ++ ++nothing: ++ free(p); ++ close(fd); ++ return NULL; ++} ++ ++static void to_dmi_header(struct dmi_header *h, uint8_t *data) ++{ ++ h->type = data[0]; ++ h->length = data[1]; ++ h->handle = WORD(data + 2); ++ h->data = data; ++} ++ ++static char *dmi_string(const struct dmi_header *dm, uint8_t s) ++{ ++ char *bp = (char *)dm->data; ++ ++ if (s == 0) ++ return NULL; ++ ++ bp += dm->length; ++ while (s > 1 && *bp) ++ { ++ bp += strlen(bp); ++ bp++; ++ s--; ++ } ++ ++ if (!*bp) ++ return NULL; ++ ++ return bp; ++} ++ ++static int hypervisor_from_dmi_table(uint32_t base, uint16_t len, ++ uint16_t num, const char *devmem) ++{ ++ uint8_t *buf; ++ uint8_t *data; ++ int i = 0; ++ char *vendor = NULL; ++ char *product = NULL; ++ char *manufacturer = NULL; ++ int rc = HYPER_NONE; ++ ++ data = buf = get_mem_chunk(base, len, devmem); ++ if (!buf) ++ goto done; ++ ++ /* 4 is the length of an SMBIOS structure header */ ++ while (i < num && data + 4 <= buf + len) { ++ uint8_t *next; ++ struct dmi_header h; ++ ++ to_dmi_header(&h, data); ++ ++ /* ++ * If a short entry is found (less than 4 bytes), not only it ++ * is invalid, but we cannot reliably locate the next entry. ++ * Better stop at this point. ++ */ ++ if (h.length < 4) ++ goto done; ++ ++ /* look for the next handle */ ++ next = data + h.length; ++ while (next - buf + 1 < len && (next[0] != 0 || next[1] != 0)) ++ next++; ++ next += 2; ++ switch (h.type) { ++ case 0: ++ vendor = dmi_string(&h, data[0x04]); ++ break; ++ case 1: ++ manufacturer = dmi_string(&h, data[0x04]); ++ product = dmi_string(&h, data[0x05]); ++ break; ++ default: ++ break; ++ } ++ ++ data = next; ++ i++; ++ } ++ if (manufacturer && !strcmp(manufacturer, "innotek GmbH")) ++ rc = HYPER_INNOTEK; ++ else if (manufacturer && strstr(manufacturer, "HITACHI") && ++ product && strstr(product, "LPAR")) ++ rc = HYPER_HITACHI; ++ else if (vendor && !strcmp(vendor, "Parallels")) ++ rc = HYPER_PARALLELS; ++done: ++ free(buf); ++ return rc; ++} ++ ++#if defined(__x86_64__) || defined(__i386__) ++static int hypervisor_decode_legacy(uint8_t *buf, const char *devmem) ++{ ++ if (!checksum(buf, 0x0F)) ++ return HYPER_NONE; ++ ++ return hypervisor_from_dmi_table(DWORD(buf + 0x08), WORD(buf + 0x06), ++ WORD(buf + 0x0C), ++ devmem); ++} ++#endif ++ ++static int hypervisor_decode_smbios(uint8_t *buf, const char *devmem) ++{ ++ if (!checksum(buf, buf[0x05]) ++ || memcmp(buf + 0x10, "_DMI_", 5) != 0 ++ || !checksum(buf + 0x10, 0x0F)) ++ return -1; ++ ++ return hypervisor_from_dmi_table(DWORD(buf + 0x18), WORD(buf + 0x16), ++ WORD(buf + 0x1C), ++ devmem); ++} ++ ++/* ++ * Probe for EFI interface ++ */ ++#define EFI_NOT_FOUND (-1) ++#define EFI_NO_SMBIOS (-2) ++static int address_from_efi(size_t *address) ++{ ++ FILE *tab; ++ char linebuf[64]; ++ int ret; ++ ++ *address = 0; /* Prevent compiler warning */ ++ ++ /* ++ * Linux up to 2.6.6: /proc/efi/systab ++ * Linux 2.6.7 and up: /sys/firmware/efi/systab ++ */ ++ if (!(tab = fopen("/sys/firmware/efi/systab", "r")) && ++ !(tab = fopen("/proc/efi/systab", "r"))) ++ return EFI_NOT_FOUND; /* No EFI interface */ ++ ++ ret = EFI_NO_SMBIOS; ++ while ((fgets(linebuf, sizeof(linebuf) - 1, tab)) != NULL) { ++ char *addrp = strchr(linebuf, '='); ++ if (!addrp) ++ continue; ++ *(addrp++) = '\0'; ++ if (strcmp(linebuf, "SMBIOS") == 0) { ++ *address = strtoul(addrp, NULL, 0); ++ ret = 0; ++ break; ++ } ++ } ++ ++ fclose(tab); ++ return ret; ++} ++ ++int read_hypervisor_dmi(void) ++{ ++ int rc = HYPER_NONE; ++ uint8_t *buf = NULL; ++ size_t fp = 0; ++ ++ if (sizeof(uint8_t) != 1 ++ || sizeof(uint16_t) != 2 ++ || sizeof(uint32_t) != 4 ++ || '\0' != 0) ++ return rc; ++ ++ /* First try EFI (ia64, Intel-based Mac) */ ++ switch (address_from_efi(&fp)) { ++ case EFI_NOT_FOUND: ++ goto memory_scan; ++ case EFI_NO_SMBIOS: ++ goto done; ++ } ++ ++ buf = get_mem_chunk(fp, 0x20, _PATH_DEV_MEM); ++ if (!buf) ++ goto done; ++ ++ rc = hypervisor_decode_smbios(buf, _PATH_DEV_MEM); ++ if (rc) ++ goto done; ++ free(buf); ++ buf = NULL; ++memory_scan: ++#if defined(__x86_64__) || defined(__i386__) ++ /* Fallback to memory scan (x86, x86_64) */ ++ buf = get_mem_chunk(0xF0000, 0x10000, _PATH_DEV_MEM); ++ if (!buf) ++ goto done; ++ ++ for (fp = 0; fp <= 0xFFF0; fp += 16) { ++ if (memcmp(buf + fp, "_SM_", 4) == 0 && fp <= 0xFFE0) { ++ rc = hypervisor_decode_smbios(buf + fp, _PATH_DEV_MEM); ++ if (rc == -1) ++ fp += 16; ++ ++ } else if (memcmp(buf + fp, "_DMI_", 5) == 0) ++ rc = hypervisor_decode_legacy(buf + fp, _PATH_DEV_MEM); ++ ++ if (rc >= 0) ++ break; ++ } ++#endif ++done: ++ free(buf); ++ return rc; ++} +diff --git a/sys-utils/lscpu.1 b/sys-utils/lscpu.1 +index f747a35..8636e52 100644 +--- a/sys-utils/lscpu.1 ++++ b/sys-utils/lscpu.1 +@@ -1,34 +1,42 @@ +-.\" Process this file with +-.\" groff -man -Tascii lscpu.1 +-.\" +-.TH LSCPU 1 "January 2013" "util-linux" "User Commands" ++.TH LSCPU 1 "November 2015" "util-linux" "User Commands" + .SH NAME + lscpu \- display information about the CPU architecture + .SH SYNOPSIS + .B lscpu +-.RB [ \-a | \-b | \-c "] [" \-x "] [" \-s " \fIdirectory\fP] [" \-e [=\fIlist\fP]| \-p [=\fIlist\fP]] ++.RB [ \-a | \-b | \-c | \-J "] [" \-x "] [" \-y "] [" \-s " \fIdirectory\fP] [" \-e [=\fIlist\fP]| \-p [=\fIlist\fP]] + .br + .B lscpu + .BR \-h | \-V + .SH DESCRIPTION + .B lscpu +-gathers CPU architecture information from sysfs and /proc/cpuinfo. The ++gathers CPU architecture information from sysfs, /proc/cpuinfo and any ++applicable architecture-specific libraries (e.g.\& librtas on Powerpc). The + command output can be optimized for parsing or for easy readability by humans. + The information includes, for example, the number of CPUs, threads, cores, + sockets, and Non-Uniform Memory Access (NUMA) nodes. There is also information + about the CPU caches and cache sharing, family, model, bogoMIPS, byte order, + and stepping. +- ++.sp ++In virtualized environments, the CPU architecture information displayed ++reflects the configuration of the guest operating system which is ++typically different from the physical (host) system. On architectures that ++support retrieving physical topology information, ++.B lscpu ++also displays the number of physical sockets, chips, cores in the host system. ++.sp + Options that result in an output table have a \fIlist\fP argument. Use this + argument to customize the command output. Specify a comma-separated list of + column labels to limit the output table to only the specified columns, arranged + in the specified order. See \fBCOLUMNS\fP for a list of valid column labels. The + column labels are not case sensitive. +- ++.sp + Not all columns are supported on all architectures. If an unsupported column is + specified, \fBlscpu\fP prints the column but does not provide any data for it. + + .SS COLUMNS ++Note that topology elements (core, socket, etc.) use a sequential unique ID ++starting from zero, but CPU logical numbers follow the kernel where there is ++no guarantee of sequential numbering. + .TP + .B CPU + The logical CPU number of a CPU as used by the Linux kernel. +@@ -42,8 +50,11 @@ The logical socket number. A socket can contain several cores. + .B BOOK + The logical book number. A book can contain several sockets. + .TP ++.B DRAWER ++The logical drawer number. A drawer can contain several books. ++.TP + .B NODE +-The logical NUMA node number. A node may contain several books. ++The logical NUMA node number. A node can contain several drawers. + .TP + .B CACHE + Information about how caches are shared between CPUs. +@@ -77,6 +88,14 @@ For vertical polarization, the column also shows the degree of concentration, + high, medium, or low. This column contains data only if your hardware system + and hypervisor support CPU polarization. + .RE ++.TP ++.B MAXMHZ ++Maximum megahertz value for the CPU. Useful when \fBlscpu\fP is used as hardware ++inventory information gathering tool. Notice that the megahertz value is ++dynamic, and driven by CPU governor depending on current resource need. ++.TP ++.B MINMHZ ++Minimum megahertz value for the CPU. + .SH OPTIONS + .TP + .BR \-a , " \-\-all" +@@ -92,7 +111,7 @@ Limit the output to offline CPUs. + This option may only be specified together with option \fB-e\fR or \fB-p\fR. + .TP + .BR \-e , " \-\-extended" [=\fIlist\fP] +-Display the CPU information in human readable format. ++Display the CPU information in human-readable format. + + If the \fIlist\fP argument is omitted, all columns for which data is available + are included in the command output. +@@ -102,7 +121,7 @@ When specifying the \fIlist\fP argument, the string of option, equal sign (=), a + Examples: '\fB-e=cpu,node\fP' or '\fB--extended=cpu,node\fP'. + .TP + .BR \-h , " \-\-help" +-Display help information and exit. ++Display help text and exit. + .TP + .BR \-p , " \-\-parse" [=\fIlist\fP] + Optimize the command output for easy parsing. +@@ -126,6 +145,16 @@ of the Linux instance to be inspected. + Use hexadecimal masks for CPU sets (for example 0x3). The default is to print + the sets in list format (for example 0,1). + .TP ++.BR \-y , " \-\-physical" ++Display physical IDs for all columns with topology elements (core, socket, etc.). ++Other than logical IDs, which are assigned by \fBlscpu\fP, physical IDs are ++platform-specific values that are provided by the kernel. Physical IDs are not ++necessarily unique and they might not be arranged sequentially. ++If the kernel could not retrieve a physical ID for an element \fBlscpu\fP prints ++the dash (-) character. ++ ++The CPU logical numbers are not affected by this option. ++.TP + .BR \-V , " \-\-version" + Display version information and exit. + .SH BUGS +@@ -145,4 +174,4 @@ Heiko Carstens + .BR chcpu (8) + .SH AVAILABILITY + The lscpu command is part of the util-linux package and is available from +-ftp://ftp.kernel.org/pub/linux/utils/util-linux/. ++https://www.kernel.org/pub/linux/utils/util-linux/. +diff --git a/sys-utils/lscpu.c b/sys-utils/lscpu.c +index 7a00636..683fd66 100644 +--- a/sys-utils/lscpu.c ++++ b/sys-utils/lscpu.c +@@ -19,6 +19,7 @@ + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + ++#include + #include + #include + #include +@@ -33,21 +34,46 @@ + #include + #include + ++#if (defined(__x86_64__) || defined(__i386__)) ++# if !defined( __SANITIZE_ADDRESS__) ++# define INCLUDE_VMWARE_BDOOR ++# else ++# warning VMWARE detection disabled by __SANITIZE_ADDRESS__ ++# endif ++#endif ++ ++#ifdef INCLUDE_VMWARE_BDOOR ++# include ++# include ++# include ++# include ++# ifdef HAVE_SYS_IO_H ++# include ++# endif ++#endif ++ ++#if defined(HAVE_LIBRTAS) ++#include ++#endif ++ ++#include ++ + #include "cpuset.h" + #include "nls.h" + #include "xalloc.h" + #include "c.h" + #include "strutils.h" + #include "bitops.h" +-#include "tt.h" + #include "path.h" + #include "closestream.h" + #include "optutils.h" ++#include "lscpu.h" + + #define CACHE_MAX 100 + + /* /sys paths */ + #define _PATH_SYS_SYSTEM "/sys/devices/system" ++#define _PATH_SYS_HYP_FEATURES "/sys/hypervisor/properties/features" + #define _PATH_SYS_CPU _PATH_SYS_SYSTEM "/cpu" + #define _PATH_SYS_NODE _PATH_SYS_SYSTEM "/node" + #define _PATH_PROC_XEN "/proc/xen" +@@ -55,35 +81,71 @@ + #define _PATH_PROC_CPUINFO "/proc/cpuinfo" + #define _PATH_PROC_PCIDEVS "/proc/bus/pci/devices" + #define _PATH_PROC_SYSINFO "/proc/sysinfo" ++#define _PATH_PROC_STATUS "/proc/self/status" ++#define _PATH_PROC_VZ "/proc/vz" ++#define _PATH_PROC_BC "/proc/bc" ++#define _PATH_PROC_DEVICETREE "/proc/device-tree" ++#define _PATH_DEV_MEM "/dev/mem" ++#define _PATH_PROC_OSRELEASE "/proc/sys/kernel/osrelease" ++ ++/* Xen Domain feature flag used for /sys/hypervisor/properties/features */ ++#define XENFEAT_supervisor_mode_kernel 3 ++#define XENFEAT_mmu_pt_update_preserve_ad 5 ++#define XENFEAT_hvm_callback_vector 8 ++ ++#define XEN_FEATURES_PV_MASK (1U << XENFEAT_mmu_pt_update_preserve_ad) ++#define XEN_FEATURES_PVH_MASK ( (1U << XENFEAT_supervisor_mode_kernel) \ ++ | (1U << XENFEAT_hvm_callback_vector) ) + + /* virtualization types */ + enum { + VIRT_NONE = 0, + VIRT_PARA, +- VIRT_FULL ++ VIRT_FULL, ++ VIRT_CONT + }; +-const char *virt_types[] = { ++static const char *virt_types[] = { + [VIRT_NONE] = N_("none"), + [VIRT_PARA] = N_("para"), +- [VIRT_FULL] = N_("full") ++ [VIRT_FULL] = N_("full"), ++ [VIRT_CONT] = N_("container"), + }; + +-/* hypervisor vendors */ +-enum { +- HYPER_NONE = 0, +- HYPER_XEN, +- HYPER_KVM, +- HYPER_MSHV, +- HYPER_VMWARE, +- HYPER_IBM +-}; +-const char *hv_vendors[] = { ++static const char *hv_vendors[] = { + [HYPER_NONE] = NULL, + [HYPER_XEN] = "Xen", + [HYPER_KVM] = "KVM", + [HYPER_MSHV] = "Microsoft", + [HYPER_VMWARE] = "VMware", +- [HYPER_IBM] = "IBM" ++ [HYPER_IBM] = "IBM", ++ [HYPER_VSERVER] = "Linux-VServer", ++ [HYPER_UML] = "User-mode Linux", ++ [HYPER_INNOTEK] = "Innotek GmbH", ++ [HYPER_HITACHI] = "Hitachi", ++ [HYPER_PARALLELS] = "Parallels", ++ [HYPER_VBOX] = "Oracle", ++ [HYPER_OS400] = "OS/400", ++ [HYPER_PHYP] = "pHyp", ++ [HYPER_SPAR] = "Unisys s-Par", ++ [HYPER_WSL] = "Windows Subsystem for Linux" ++}; ++ ++static const int hv_vendor_pci[] = { ++ [HYPER_NONE] = 0x0000, ++ [HYPER_XEN] = 0x5853, ++ [HYPER_KVM] = 0x0000, ++ [HYPER_MSHV] = 0x1414, ++ [HYPER_VMWARE] = 0x15ad, ++ [HYPER_VBOX] = 0x80ee, ++}; ++ ++static const int hv_graphics_pci[] = { ++ [HYPER_NONE] = 0x0000, ++ [HYPER_XEN] = 0x0001, ++ [HYPER_KVM] = 0x0000, ++ [HYPER_MSHV] = 0x5353, ++ [HYPER_VMWARE] = 0x0710, ++ [HYPER_VBOX] = 0xbeef, + }; + + /* CPU modes */ +@@ -107,7 +169,7 @@ enum { + DISP_VERTICAL = 1 + }; + +-const char *disp_modes[] = { ++static const char *disp_modes[] = { + [DISP_HORIZONTAL] = N_("horizontal"), + [DISP_VERTICAL] = N_("vertical") + }; +@@ -126,7 +188,7 @@ struct polarization_modes { + char *readable; + }; + +-struct polarization_modes polar_modes[] = { ++static struct polarization_modes polar_modes[] = { + [POLAR_UNKNOWN] = {"U", "-"}, + [POLAR_VLOW] = {"VL", "vert-low"}, + [POLAR_VMEDIUM] = {"VM", "vert-medium"}, +@@ -138,6 +200,7 @@ struct polarization_modes polar_modes[] = { + struct lscpu_desc { + char *arch; + char *vendor; ++ char *machinetype; /* s390 */ + char *family; + char *model; + char *modelname; +@@ -148,9 +211,14 @@ struct lscpu_desc { + int hyper; /* hypervisor vendor ID */ + int virtype; /* VIRT_PARA|FULL|NONE ? */ + char *mhz; ++ char *dynamic_mhz; /* dynamic mega hertz (s390) */ ++ char *static_mhz; /* static mega hertz (s390) */ ++ char **maxmhz; /* maximum mega hertz */ ++ char **minmhz; /* minimum mega hertz */ + char *stepping; + char *bogomips; + char *flags; ++ char *mtid; /* maximum thread id (s390) */ + int dispatching; /* none, horizontal or vertical */ + int mode; /* rm, lm or/and tm */ + +@@ -159,33 +227,58 @@ struct lscpu_desc { + cpu_set_t *present; /* mask with present CPUs */ + cpu_set_t *online; /* mask with online CPUs */ + ++ int nthreads; /* number of online threads */ ++ ++ int ncaches; ++ struct cpu_cache *caches; ++ ++ int necaches; /* extra caches (s390) */ ++ struct cpu_cache *ecaches; ++ ++ /* ++ * All maps are sequentially indexed (0..ncpuspos), the array index ++ * does not have match with cpuX number as presented by kernel. You ++ * have to use real_cpu_num() to get the real cpuX number. ++ * ++ * For example, the possible system CPUs are: 1,3,5, it means that ++ * ncpuspos=3, so all arrays are in range 0..3. ++ */ ++ int *idx2cpunum; /* mapping index to CPU num */ ++ + int nnodes; /* number of NUMA modes */ + int *idx2nodenum; /* Support for discontinuous nodes */ + cpu_set_t **nodemaps; /* array with NUMA nodes */ + ++ /* drawers -- based on drawer_siblings (internal kernel map of cpuX's ++ * hardware threads within the same drawer */ ++ int ndrawers; /* number of all online drawers */ ++ cpu_set_t **drawermaps; /* unique drawer_siblings */ ++ int *drawerids; /* physical drawer ids */ ++ + /* books -- based on book_siblings (internal kernel map of cpuX's + * hardware threads within the same book */ + int nbooks; /* number of all online books */ + cpu_set_t **bookmaps; /* unique book_siblings */ ++ int *bookids; /* physical book ids */ + + /* sockets -- based on core_siblings (internal kernel map of cpuX's + * hardware threads within the same physical_package_id (socket)) */ + int nsockets; /* number of all online sockets */ + cpu_set_t **socketmaps; /* unique core_siblings */ ++ int *socketids; /* physical socket ids */ + +- /* cores -- based on thread_siblings (internel kernel map of cpuX's ++ /* cores -- based on thread_siblings (internal kernel map of cpuX's + * hardware threads within the same core as cpuX) */ + int ncores; /* number of all online cores */ + cpu_set_t **coremaps; /* unique thread_siblings */ +- +- int nthreads; /* number of online threads */ +- +- int ncaches; +- struct cpu_cache *caches; ++ int *coreids; /* physical core ids */ + + int *polarization; /* cpu polarization */ + int *addresses; /* physical cpu addresses */ + int *configured; /* cpu configured */ ++ int physsockets; /* Physical sockets (modules) */ ++ int physchips; /* Physical chips */ ++ int physcoresperchip; /* Physical cores per chip */ + }; + + enum { +@@ -205,7 +298,8 @@ struct lscpu_modifier { + unsigned int hex:1, /* print CPU masks rather than CPU lists */ + compat:1, /* use backwardly compatible format */ + online:1, /* print online CPUs */ +- offline:1; /* print offline CPUs */ ++ offline:1, /* print offline CPUs */ ++ physical:1; /* use physical numbers */ + }; + + static int maxcpus; /* size in bits of kernel cpu mask */ +@@ -217,6 +311,8 @@ static int maxcpus; /* size in bits of kernel cpu mask */ + ((_d) && (_d)->present ? \ + CPU_ISSET_S((_cpu), CPU_ALLOC_SIZE(maxcpus), (_d)->present) : 0) + ++#define real_cpu_num(_d, _i) ((_d)->idx2cpunum[(_i)]) ++ + /* + * IDs + */ +@@ -226,11 +322,14 @@ enum { + COL_SOCKET, + COL_NODE, + COL_BOOK, ++ COL_DRAWER, + COL_CACHE, + COL_POLARIZATION, + COL_ADDRESS, + COL_CONFIGURED, + COL_ONLINE, ++ COL_MAXMHZ, ++ COL_MINMHZ, + }; + + /* column description +@@ -249,11 +348,14 @@ static struct lscpu_coldesc coldescs[] = + [COL_SOCKET] = { "SOCKET", N_("logical socket number") }, + [COL_NODE] = { "NODE", N_("logical NUMA node number") }, + [COL_BOOK] = { "BOOK", N_("logical book number") }, ++ [COL_DRAWER] = { "DRAWER", N_("logical drawer number") }, + [COL_CACHE] = { "CACHE", N_("shows how caches are shared between CPUs") }, + [COL_POLARIZATION] = { "POLARIZATION", N_("CPU dispatching mode on virtual hardware") }, + [COL_ADDRESS] = { "ADDRESS", N_("physical address of a CPU") }, + [COL_CONFIGURED] = { "CONFIGURED", N_("shows if the hypervisor has allocated the CPU") }, +- [COL_ONLINE] = { "ONLINE", N_("shows if Linux currently makes use of the CPU") } ++ [COL_ONLINE] = { "ONLINE", N_("shows if Linux currently makes use of the CPU") }, ++ [COL_MAXMHZ] = { "MAXMHZ", N_("shows the maximum MHz of the CPU") }, ++ [COL_MINMHZ] = { "MINMHZ", N_("shows the minimum MHz of the CPU") } + }; + + static int +@@ -282,7 +384,8 @@ lookup(char *line, char *pattern, char **value) + char *p, *v; + int len = strlen(pattern); + +- if (!*line) ++ /* don't re-fill already found tags, first one wins */ ++ if (!*line || *value) + return 0; + + /* pattern */ +@@ -313,6 +416,63 @@ lookup(char *line, char *pattern, char **value) + return 1; + } + ++/* Parse extra cache lines contained within /proc/cpuinfo but which are not ++ * part of the cache topology information within the sysfs filesystem. ++ * This is true for all shared caches on e.g. s390. When there are layers of ++ * hypervisors in between it is not knows which CPUs share which caches. ++ * Therefore information about shared caches is only available in ++ * /proc/cpuinfo. ++ * Format is: ++ * "cache : level= type= scope= size= line_size= associativity=" ++ */ ++static int ++lookup_cache(char *line, struct lscpu_desc *desc) ++{ ++ struct cpu_cache *cache; ++ long long size; ++ char *p, type; ++ int level; ++ ++ /* Make sure line starts with "cache :" */ ++ if (strncmp(line, "cache", 5)) ++ return 0; ++ for (p = line + 5; isdigit(*p); p++); ++ for (; isspace(*p); p++); ++ if (*p != ':') ++ return 0; ++ ++ p = strstr(line, "scope=") + 6; ++ /* Skip private caches, also present in sysfs */ ++ if (!p || strncmp(p, "Private", 7) == 0) ++ return 0; ++ p = strstr(line, "level="); ++ if (!p || sscanf(p, "level=%d", &level) != 1) ++ return 0; ++ p = strstr(line, "type=") + 5; ++ if (!p || !*p) ++ return 0; ++ type = 0; ++ if (strncmp(p, "Data", 4) == 0) ++ type = 'd'; ++ if (strncmp(p, "Instruction", 11) == 0) ++ type = 'i'; ++ p = strstr(line, "size="); ++ if (!p || sscanf(p, "size=%lld", &size) != 1) ++ return 0; ++ ++ desc->necaches++; ++ desc->ecaches = xrealloc(desc->ecaches, ++ desc->necaches * sizeof(struct cpu_cache)); ++ cache = &desc->ecaches[desc->necaches - 1]; ++ memset(cache, 0 , sizeof(*cache)); ++ if (type) ++ xasprintf(&cache->name, "L%d%c", level, type); ++ else ++ xasprintf(&cache->name, "L%d", level); ++ xasprintf(&cache->size, "%lldK", size); ++ return 1; ++} ++ + /* Don't init the mode for platforms where we are not able to + * detect that CPU supports 64-bit mode. + */ +@@ -338,6 +498,45 @@ init_mode(struct lscpu_modifier *mod) + return m; + } + ++#if defined(HAVE_LIBRTAS) ++#define PROCESSOR_MODULE_INFO 43 ++static int strbe16toh(const char *buf, int offset) ++{ ++ return (buf[offset] << 8) + buf[offset+1]; ++} ++ ++static void read_physical_info_powerpc(struct lscpu_desc *desc) ++{ ++ char buf[BUFSIZ]; ++ int rc, len, ntypes; ++ ++ desc->physsockets = desc->physchips = desc->physcoresperchip = 0; ++ ++ rc = rtas_get_sysparm(PROCESSOR_MODULE_INFO, sizeof(buf), buf); ++ if (rc < 0) ++ return; ++ ++ len = strbe16toh(buf, 0); ++ if (len < 8) ++ return; ++ ++ ntypes = strbe16toh(buf, 2); ++ ++ assert(ntypes <= 1); ++ if (!ntypes) ++ return; ++ ++ desc->physsockets = strbe16toh(buf, 4); ++ desc->physchips = strbe16toh(buf, 6); ++ desc->physcoresperchip = strbe16toh(buf, 8); ++} ++#else ++static void read_physical_info_powerpc( ++ struct lscpu_desc *desc __attribute__((__unused__))) ++{ ++} ++#endif ++ + static void + read_basicinfo(struct lscpu_desc *desc, struct lscpu_modifier *mod) + { +@@ -361,13 +560,20 @@ read_basicinfo(struct lscpu_desc *desc, struct lscpu_modifier *mod) + else if (lookup(buf, "model name", &desc->modelname)) ; + else if (lookup(buf, "stepping", &desc->stepping)) ; + else if (lookup(buf, "cpu MHz", &desc->mhz)) ; ++ else if (lookup(buf, "cpu MHz dynamic", &desc->dynamic_mhz)) ; /* s390 */ ++ else if (lookup(buf, "cpu MHz static", &desc->static_mhz)) ; /* s390 */ + else if (lookup(buf, "flags", &desc->flags)) ; /* x86 */ + else if (lookup(buf, "features", &desc->flags)) ; /* s390 */ ++ else if (lookup(buf, "Features", &desc->flags)) ; /* aarch64 */ + else if (lookup(buf, "type", &desc->flags)) ; /* sparc64 */ + else if (lookup(buf, "bogomips", &desc->bogomips)) ; ++ else if (lookup(buf, "BogoMIPS", &desc->bogomips)) ; /* aarch64 */ + else if (lookup(buf, "bogomips per cpu", &desc->bogomips)) ; /* s390 */ + else if (lookup(buf, "cpu", &desc->cpu)) ; + else if (lookup(buf, "revision", &desc->revision)) ; ++ else if (lookup(buf, "CPU revision", &desc->revision)) ; /* aarch64 */ ++ else if (lookup(buf, "max thread id", &desc->mtid)) ; /* s390 */ ++ else if (lookup_cache(buf, desc)) ; + else + continue; + } +@@ -397,9 +603,9 @@ read_basicinfo(struct lscpu_desc *desc, struct lscpu_modifier *mod) + + fclose(fp); + +- if (path_exist(_PATH_SYS_SYSTEM "/cpu/kernel_max")) ++ if (path_exist(_PATH_SYS_CPU "/kernel_max")) + /* note that kernel_max is maximum index [NR_CPUS-1] */ +- maxcpus = path_read_s32(_PATH_SYS_SYSTEM "/cpu/kernel_max") + 1; ++ maxcpus = path_read_s32(_PATH_SYS_CPU "/kernel_max") + 1; + + else if (mod->system == SYSTEM_LIVE) + /* the root is '/' so we are working with data from the current kernel */ +@@ -412,32 +618,49 @@ read_basicinfo(struct lscpu_desc *desc, struct lscpu_modifier *mod) + + setsize = CPU_ALLOC_SIZE(maxcpus); + +- if (path_exist(_PATH_SYS_SYSTEM "/cpu/possible")) { +- cpu_set_t *tmp = path_read_cpulist(maxcpus, _PATH_SYS_SYSTEM "/cpu/possible"); ++ if (path_exist(_PATH_SYS_CPU "/possible")) { ++ cpu_set_t *tmp = path_read_cpulist(maxcpus, _PATH_SYS_CPU "/possible"); ++ int num, idx; ++ + desc->ncpuspos = CPU_COUNT_S(setsize, tmp); ++ desc->idx2cpunum = xcalloc(desc->ncpuspos, sizeof(int)); ++ ++ for (num = 0, idx = 0; num < maxcpus; num++) { ++ if (CPU_ISSET(num, tmp)) ++ desc->idx2cpunum[idx++] = num; ++ } + cpuset_free(tmp); + } else + err(EXIT_FAILURE, _("failed to determine number of CPUs: %s"), +- _PATH_SYS_SYSTEM "/cpu/possible"); ++ _PATH_SYS_CPU "/possible"); + + + /* get mask for present CPUs */ +- if (path_exist(_PATH_SYS_SYSTEM "/cpu/present")) { +- desc->present = path_read_cpulist(maxcpus, _PATH_SYS_SYSTEM "/cpu/present"); ++ if (path_exist(_PATH_SYS_CPU "/present")) { ++ desc->present = path_read_cpulist(maxcpus, _PATH_SYS_CPU "/present"); + desc->ncpus = CPU_COUNT_S(setsize, desc->present); + } + + /* get mask for online CPUs */ +- if (path_exist(_PATH_SYS_SYSTEM "/cpu/online")) { +- desc->online = path_read_cpulist(maxcpus, _PATH_SYS_SYSTEM "/cpu/online"); ++ if (path_exist(_PATH_SYS_CPU "/online")) { ++ desc->online = path_read_cpulist(maxcpus, _PATH_SYS_CPU "/online"); + desc->nthreads = CPU_COUNT_S(setsize, desc->online); + } + + /* get dispatching mode */ +- if (path_exist(_PATH_SYS_SYSTEM "/cpu/dispatching")) +- desc->dispatching = path_read_s32(_PATH_SYS_SYSTEM "/cpu/dispatching"); ++ if (path_exist(_PATH_SYS_CPU "/dispatching")) ++ desc->dispatching = path_read_s32(_PATH_SYS_CPU "/dispatching"); + else + desc->dispatching = -1; ++ ++ if (mod->system == SYSTEM_LIVE) ++ read_physical_info_powerpc(desc); ++ ++ if ((fp = path_fopen("r", 0, _PATH_PROC_SYSINFO))) { ++ while (fgets(buf, sizeof(buf), fp) != NULL && !desc->machinetype) ++ lookup(buf, "Type", &desc->machinetype); ++ fclose(fp); ++ } + } + + static int +@@ -483,10 +706,9 @@ cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx, + __asm__( + #if defined(__PIC__) && defined(__i386__) + /* x86 PIC cannot clobber ebx -- gcc bitches */ +- "pushl %%ebx;" ++ "xchg %%ebx, %%esi;" + "cpuid;" +- "movl %%ebx, %%esi;" +- "popl %%ebx;" ++ "xchg %%esi, %%ebx;" + : "=S" (*ebx), + #else + "cpuid;" +@@ -523,34 +745,230 @@ read_hypervisor_cpuid(struct lscpu_desc *desc) + desc->hyper = HYPER_MSHV; + else if (!strncmp("VMwareVMware", hyper_vendor_id, 12)) + desc->hyper = HYPER_VMWARE; ++ else if (!strncmp("UnisysSpar64", hyper_vendor_id, 12)) ++ desc->hyper = HYPER_SPAR; + } + +-#else /* ! __x86_64__ */ ++#else /* ! (__x86_64__ || __i386__) */ + static void + read_hypervisor_cpuid(struct lscpu_desc *desc __attribute__((__unused__))) + { + } + #endif + ++static int is_compatible(const char *path, const char *str) ++{ ++ FILE *fd = path_fopen("r", 0, "%s", path); ++ ++ if (fd) { ++ char buf[256]; ++ size_t i, len; ++ ++ memset(buf, 0, sizeof(buf)); ++ len = fread(buf, 1, sizeof(buf) - 1, fd); ++ fclose(fd); ++ ++ for (i = 0; i < len;) { ++ if (!strcmp(&buf[i], str)) ++ return 1; ++ i += strlen(&buf[i]); ++ i++; ++ } ++ } ++ ++ return 0; ++} ++ ++static int ++read_hypervisor_powerpc(struct lscpu_desc *desc) ++{ ++ assert(!desc->hyper); ++ ++ /* IBM iSeries: legacy, para-virtualized on top of OS/400 */ ++ if (path_exist("/proc/iSeries")) { ++ desc->hyper = HYPER_OS400; ++ desc->virtype = VIRT_PARA; ++ ++ /* PowerNV (POWER Non-Virtualized, bare-metal) */ ++ } else if (is_compatible(_PATH_PROC_DEVICETREE "/compatible", "ibm,powernv")) { ++ desc->hyper = HYPER_NONE; ++ desc->virtype = VIRT_NONE; ++ ++ /* PowerVM (IBM's proprietary hypervisor, aka pHyp) */ ++ } else if (path_exist(_PATH_PROC_DEVICETREE "/ibm,partition-name") ++ && path_exist(_PATH_PROC_DEVICETREE "/hmc-managed?") ++ && !path_exist(_PATH_PROC_DEVICETREE "/chosen/qemu,graphic-width")) { ++ FILE *fd; ++ desc->hyper = HYPER_PHYP; ++ desc->virtype = VIRT_PARA; ++ fd = path_fopen("r", 0, _PATH_PROC_DEVICETREE "/ibm,partition-name"); ++ if (fd) { ++ char buf[256]; ++ if (fscanf(fd, "%255s", buf) == 1 && !strcmp(buf, "full")) ++ desc->virtype = VIRT_NONE; ++ fclose(fd); ++ } ++ ++ /* Qemu */ ++ } else if (is_compatible(_PATH_PROC_DEVICETREE "/compatible", "qemu,pseries")) { ++ desc->hyper = HYPER_KVM; ++ desc->virtype = VIRT_PARA; ++ } ++ return desc->hyper; ++} ++ ++#ifdef INCLUDE_VMWARE_BDOOR ++ ++#define VMWARE_BDOOR_MAGIC 0x564D5868 ++#define VMWARE_BDOOR_PORT 0x5658 ++#define VMWARE_BDOOR_CMD_GETVERSION 10 ++ ++static UL_ASAN_BLACKLIST ++void vmware_bdoor(uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) ++{ ++ __asm__( ++#if defined(__PIC__) && defined(__i386__) ++ /* x86 PIC cannot clobber ebx -- gcc bitches */ ++ "xchg %%ebx, %%esi;" ++ "inl (%%dx), %%eax;" ++ "xchg %%esi, %%ebx;" ++ : "=S" (*ebx), ++#else ++ "inl (%%dx), %%eax;" ++ : "=b" (*ebx), ++#endif ++ "=a" (*eax), ++ "=c" (*ecx), ++ "=d" (*edx) ++ : "0" (VMWARE_BDOOR_MAGIC), ++ "1" (VMWARE_BDOOR_CMD_GETVERSION), ++ "2" (VMWARE_BDOOR_PORT), ++ "3" (0) ++ : "memory"); ++} ++ ++static jmp_buf segv_handler_env; ++ ++static void ++segv_handler(__attribute__((__unused__)) int sig, ++ __attribute__((__unused__)) siginfo_t *info, ++ __attribute__((__unused__)) void *ignored) ++{ ++ siglongjmp(segv_handler_env, 1); ++} ++ ++static int ++is_vmware_platform(void) ++{ ++ uint32_t eax, ebx, ecx, edx; ++ struct sigaction act, oact; ++ ++ /* ++ * FIXME: Not reliable for non-root users. Note it works as expected if ++ * vmware_bdoor() is not optimized for PIE, but then it fails to build ++ * on 32bit x86 systems. See lscpu git log for more details (commit ++ * 7845b91dbc7690064a2be6df690e4aaba728fb04). kzak [3-Nov-2016] ++ */ ++ if (getuid() != 0) ++ return 0; ++ ++ /* ++ * The assembly routine for vmware detection works ++ * fine under vmware, even if ran as regular user. But ++ * on real HW or under other hypervisors, it segfaults (which is ++ * expected). So we temporarily install SIGSEGV handler to catch ++ * the signal. All this magic is needed because lscpu ++ * isn't supposed to require root privileges. ++ */ ++ if (sigsetjmp(segv_handler_env, 1)) ++ return 0; ++ ++ memset(&act, 0, sizeof(act)); ++ act.sa_sigaction = segv_handler; ++ act.sa_flags = SA_SIGINFO; ++ ++ if (sigaction(SIGSEGV, &act, &oact)) ++ err(EXIT_FAILURE, _("cannot set signal handler")); ++ ++ vmware_bdoor(&eax, &ebx, &ecx, &edx); ++ ++ if (sigaction(SIGSEGV, &oact, NULL)) ++ err(EXIT_FAILURE, _("cannot restore signal handler")); ++ ++ return eax != (uint32_t)-1 && ebx == VMWARE_BDOOR_MAGIC; ++} ++ ++#else /* ! INCLUDE_VMWARE_BDOOR */ ++ ++static int ++is_vmware_platform(void) ++{ ++ return 0; ++} ++ ++#endif /* INCLUDE_VMWARE_BDOOR */ ++ + static void + read_hypervisor(struct lscpu_desc *desc, struct lscpu_modifier *mod) + { +- if (mod->system != SYSTEM_SNAPSHOT) ++ FILE *fd; ++ ++ /* We have to detect WSL first. is_vmware_platform() crashes on Windows 10. */ ++ ++ if ((fd = path_fopen("r", 0, _PATH_PROC_OSRELEASE))) { ++ char buf[256]; ++ ++ if (fgets(buf, sizeof(buf), fd) != NULL) { ++ if (strstr(buf, "Microsoft")) { ++ desc->hyper = HYPER_WSL; ++ desc->virtype = VIRT_CONT; ++ } ++ } ++ fclose(fd); ++ if (desc->virtype) ++ return; ++ } ++ ++ if (mod->system != SYSTEM_SNAPSHOT) { + read_hypervisor_cpuid(desc); ++ if (!desc->hyper) ++ desc->hyper = read_hypervisor_dmi(); ++ if (!desc->hyper && is_vmware_platform()) ++ desc->hyper = HYPER_VMWARE; ++ } + +- if (desc->hyper) +- /* hvm */ ++ if (desc->hyper) { + desc->virtype = VIRT_FULL; + ++ if (desc->hyper == HYPER_XEN) { ++ uint32_t features; ++ ++ fd = path_fopen("r", 0, _PATH_SYS_HYP_FEATURES); ++ if (fd && fscanf(fd, "%x", &features) == 1) { ++ /* Xen PV domain */ ++ if (features & XEN_FEATURES_PV_MASK) ++ desc->virtype = VIRT_PARA; ++ /* Xen PVH domain */ ++ else if ((features & XEN_FEATURES_PVH_MASK) ++ == XEN_FEATURES_PVH_MASK) ++ desc->virtype = VIRT_PARA; ++ fclose(fd); ++ } else { ++ err(EXIT_FAILURE, _("failed to read from: %s"), ++ _PATH_SYS_HYP_FEATURES); ++ } ++ } ++ } else if (read_hypervisor_powerpc(desc) > 0) {} ++ ++ /* Xen para-virt or dom0 */ + else if (path_exist(_PATH_PROC_XEN)) { +- /* Xen para-virt or dom0 */ +- FILE *fd = path_fopen("r", 0, _PATH_PROC_XENCAP); + int dom0 = 0; ++ fd = path_fopen("r", 0, _PATH_PROC_XENCAP); + + if (fd) { + char buf[256]; + +- if (fscanf(fd, "%s", buf) == 1 && ++ if (fscanf(fd, "%255s", buf) == 1 && + !strcmp(buf, "control_d")) + dom0 = 1; + fclose(fd); +@@ -558,16 +976,21 @@ read_hypervisor(struct lscpu_desc *desc, struct lscpu_modifier *mod) + desc->virtype = dom0 ? VIRT_NONE : VIRT_PARA; + desc->hyper = HYPER_XEN; + +- } else if (has_pci_device(0x5853, 0x0001)) { +- /* Xen full-virt on non-x86_64 */ ++ /* Xen full-virt on non-x86_64 */ ++ } else if (has_pci_device( hv_vendor_pci[HYPER_XEN], hv_graphics_pci[HYPER_XEN])) { + desc->hyper = HYPER_XEN; + desc->virtype = VIRT_FULL; +- } else if (path_exist(_PATH_PROC_SYSINFO)) { +- FILE *fd = path_fopen("r", 0, _PATH_PROC_SYSINFO); ++ } else if (has_pci_device( hv_vendor_pci[HYPER_VMWARE], hv_graphics_pci[HYPER_VMWARE])) { ++ desc->hyper = HYPER_VMWARE; ++ desc->virtype = VIRT_FULL; ++ } else if (has_pci_device( hv_vendor_pci[HYPER_VBOX], hv_graphics_pci[HYPER_VBOX])) { ++ desc->hyper = HYPER_VBOX; ++ desc->virtype = VIRT_FULL; ++ ++ /* IBM PR/SM */ ++ } else if ((fd = path_fopen("r", 0, _PATH_PROC_SYSINFO))) { + char buf[BUFSIZ]; + +- if (!fd) +- return; + desc->hyper = HYPER_IBM; + desc->hypervisor = "PR/SM"; + desc->virtype = VIRT_FULL; +@@ -597,6 +1020,45 @@ read_hypervisor(struct lscpu_desc *desc, struct lscpu_modifier *mod) + } + fclose(fd); + } ++ ++ /* OpenVZ/Virtuozzo - /proc/vz dir should exist ++ * /proc/bc should not */ ++ else if (path_exist(_PATH_PROC_VZ) && !path_exist(_PATH_PROC_BC)) { ++ desc->hyper = HYPER_PARALLELS; ++ desc->virtype = VIRT_CONT; ++ ++ /* IBM */ ++ } else if (desc->vendor && ++ (strcmp(desc->vendor, "PowerVM Lx86") == 0 || ++ strcmp(desc->vendor, "IBM/S390") == 0)) { ++ desc->hyper = HYPER_IBM; ++ desc->virtype = VIRT_FULL; ++ ++ /* User-mode-linux */ ++ } else if (desc->modelname && strstr(desc->modelname, "UML")) { ++ desc->hyper = HYPER_UML; ++ desc->virtype = VIRT_PARA; ++ ++ /* Linux-VServer */ ++ } else if ((fd = path_fopen("r", 0, _PATH_PROC_STATUS))) { ++ char buf[BUFSIZ]; ++ char *val = NULL; ++ ++ while (fgets(buf, sizeof(buf), fd) != NULL) { ++ if (lookup(buf, "VxID", &val)) ++ break; ++ } ++ fclose(fd); ++ ++ if (val) { ++ while (isdigit(*val)) ++ ++val; ++ if (!*val) { ++ desc->hyper = HYPER_VSERVER; ++ desc->virtype = VIRT_CONT; ++ } ++ } ++ } + } + + /* add @set to the @ary, unnecessary set is deallocated. */ +@@ -622,9 +1084,12 @@ static int add_cpuset_to_array(cpu_set_t **ary, int *items, cpu_set_t *set) + } + + static void +-read_topology(struct lscpu_desc *desc, int num) ++read_topology(struct lscpu_desc *desc, int idx) + { +- cpu_set_t *thread_siblings, *core_siblings, *book_siblings; ++ cpu_set_t *thread_siblings, *core_siblings; ++ cpu_set_t *book_siblings, *drawer_siblings; ++ int coreid, socketid, bookid, drawerid; ++ int i, num = real_cpu_num(desc, idx); + + if (!path_exist(_PATH_SYS_CPU "/cpu%d/topology/thread_siblings", num)) + return; +@@ -634,13 +1099,32 @@ read_topology(struct lscpu_desc *desc, int num) + core_siblings = path_read_cpuset(maxcpus, _PATH_SYS_CPU + "/cpu%d/topology/core_siblings", num); + book_siblings = NULL; +- if (path_exist(_PATH_SYS_CPU "/cpu%d/topology/book_siblings", num)) { ++ if (path_exist(_PATH_SYS_CPU "/cpu%d/topology/book_siblings", num)) + book_siblings = path_read_cpuset(maxcpus, _PATH_SYS_CPU + "/cpu%d/topology/book_siblings", num); +- } ++ drawer_siblings = NULL; ++ if (path_exist(_PATH_SYS_CPU "/cpu%d/topology/drawer_siblings", num)) ++ drawer_siblings = path_read_cpuset(maxcpus, _PATH_SYS_CPU ++ "/cpu%d/topology/drawer_siblings", num); ++ coreid = -1; ++ if (path_exist(_PATH_SYS_CPU "/cpu%d/topology/core_id", num)) ++ coreid = path_read_s32(_PATH_SYS_CPU ++ "/cpu%d/topology/core_id", num); ++ socketid = -1; ++ if (path_exist(_PATH_SYS_CPU "/cpu%d/topology/physical_package_id", num)) ++ socketid = path_read_s32(_PATH_SYS_CPU ++ "/cpu%d/topology/physical_package_id", num); ++ bookid = -1; ++ if (path_exist(_PATH_SYS_CPU "/cpu%d/topology/book_id", num)) ++ bookid = path_read_s32(_PATH_SYS_CPU ++ "/cpu%d/topology/book_id", num); ++ drawerid = -1; ++ if (path_exist(_PATH_SYS_CPU "/cpu%d/topology/drawer_id", num)) ++ drawerid = path_read_s32(_PATH_SYS_CPU ++ "/cpu%d/topology/drawer_id", num); + + if (!desc->coremaps) { +- int nbooks, nsockets, ncores, nthreads; ++ int ndrawers, nbooks, nsockets, ncores, nthreads; + size_t setsize = CPU_ALLOC_SIZE(maxcpus); + + /* threads within one core */ +@@ -666,12 +1150,17 @@ read_topology(struct lscpu_desc *desc, int num) + if (!nbooks) + nbooks = 1; + ++ /* number of drawers */ ++ ndrawers = desc->ncpus / nbooks / nthreads / ncores / nsockets; ++ if (!ndrawers) ++ ndrawers = 1; ++ + /* all threads, see also read_basicinfo() + * -- fallback for kernels without + * /sys/devices/system/cpu/online. + */ + if (!desc->nthreads) +- desc->nthreads = nbooks * nsockets * ncores * nthreads; ++ desc->nthreads = ndrawers * nbooks * nsockets * ncores * nthreads; + + /* For each map we make sure that it can have up to ncpuspos + * entries. This is because we cannot reliably calculate the +@@ -681,19 +1170,43 @@ read_topology(struct lscpu_desc *desc, int num) + */ + desc->coremaps = xcalloc(desc->ncpuspos, sizeof(cpu_set_t *)); + desc->socketmaps = xcalloc(desc->ncpuspos, sizeof(cpu_set_t *)); +- if (book_siblings) ++ desc->coreids = xcalloc(desc->ncpuspos, sizeof(*desc->drawerids)); ++ desc->socketids = xcalloc(desc->ncpuspos, sizeof(*desc->drawerids)); ++ for (i = 0; i < desc->ncpuspos; i++) ++ desc->coreids[i] = desc->socketids[i] = -1; ++ if (book_siblings) { + desc->bookmaps = xcalloc(desc->ncpuspos, sizeof(cpu_set_t *)); ++ desc->bookids = xcalloc(desc->ncpuspos, sizeof(*desc->drawerids)); ++ for (i = 0; i < desc->ncpuspos; i++) ++ desc->bookids[i] = -1; ++ } ++ if (drawer_siblings) { ++ desc->drawermaps = xcalloc(desc->ncpuspos, sizeof(cpu_set_t *)); ++ desc->drawerids = xcalloc(desc->ncpuspos, sizeof(*desc->drawerids)); ++ for (i = 0; i < desc->ncpuspos; i++) ++ desc->drawerids[i] = -1; ++ } + } + + add_cpuset_to_array(desc->socketmaps, &desc->nsockets, core_siblings); ++ desc->coreids[idx] = coreid; + add_cpuset_to_array(desc->coremaps, &desc->ncores, thread_siblings); +- if (book_siblings) ++ desc->socketids[idx] = socketid; ++ if (book_siblings) { + add_cpuset_to_array(desc->bookmaps, &desc->nbooks, book_siblings); ++ desc->bookids[idx] = bookid; ++ } ++ if (drawer_siblings) { ++ add_cpuset_to_array(desc->drawermaps, &desc->ndrawers, drawer_siblings); ++ desc->drawerids[idx] = drawerid; ++ } + } ++ + static void +-read_polarization(struct lscpu_desc *desc, int num) ++read_polarization(struct lscpu_desc *desc, int idx) + { + char mode[64]; ++ int num = real_cpu_num(desc, idx); + + if (desc->dispatching < 0) + return; +@@ -703,35 +1216,67 @@ read_polarization(struct lscpu_desc *desc, int num) + desc->polarization = xcalloc(desc->ncpuspos, sizeof(int)); + path_read_str(mode, sizeof(mode), _PATH_SYS_CPU "/cpu%d/polarization", num); + if (strncmp(mode, "vertical:low", sizeof(mode)) == 0) +- desc->polarization[num] = POLAR_VLOW; ++ desc->polarization[idx] = POLAR_VLOW; + else if (strncmp(mode, "vertical:medium", sizeof(mode)) == 0) +- desc->polarization[num] = POLAR_VMEDIUM; ++ desc->polarization[idx] = POLAR_VMEDIUM; + else if (strncmp(mode, "vertical:high", sizeof(mode)) == 0) +- desc->polarization[num] = POLAR_VHIGH; ++ desc->polarization[idx] = POLAR_VHIGH; + else if (strncmp(mode, "horizontal", sizeof(mode)) == 0) +- desc->polarization[num] = POLAR_HORIZONTAL; ++ desc->polarization[idx] = POLAR_HORIZONTAL; + else +- desc->polarization[num] = POLAR_UNKNOWN; ++ desc->polarization[idx] = POLAR_UNKNOWN; + } + + static void +-read_address(struct lscpu_desc *desc, int num) ++read_address(struct lscpu_desc *desc, int idx) + { ++ int num = real_cpu_num(desc, idx); ++ + if (!path_exist(_PATH_SYS_CPU "/cpu%d/address", num)) + return; + if (!desc->addresses) + desc->addresses = xcalloc(desc->ncpuspos, sizeof(int)); +- desc->addresses[num] = path_read_s32(_PATH_SYS_CPU "/cpu%d/address", num); ++ desc->addresses[idx] = path_read_s32(_PATH_SYS_CPU "/cpu%d/address", num); + } + + static void +-read_configured(struct lscpu_desc *desc, int num) ++read_configured(struct lscpu_desc *desc, int idx) + { ++ int num = real_cpu_num(desc, idx); ++ + if (!path_exist(_PATH_SYS_CPU "/cpu%d/configure", num)) + return; + if (!desc->configured) + desc->configured = xcalloc(desc->ncpuspos, sizeof(int)); +- desc->configured[num] = path_read_s32(_PATH_SYS_CPU "/cpu%d/configure", num); ++ desc->configured[idx] = path_read_s32(_PATH_SYS_CPU "/cpu%d/configure", num); ++} ++ ++static void ++read_max_mhz(struct lscpu_desc *desc, int idx) ++{ ++ int num = real_cpu_num(desc, idx); ++ ++ if (!path_exist(_PATH_SYS_CPU "/cpu%d/cpufreq/cpuinfo_max_freq", num)) ++ return; ++ if (!desc->maxmhz) ++ desc->maxmhz = xcalloc(desc->ncpuspos, sizeof(char *)); ++ xasprintf(&(desc->maxmhz[idx]), "%.4f", ++ (float)path_read_s32(_PATH_SYS_CPU ++ "/cpu%d/cpufreq/cpuinfo_max_freq", num) / 1000); ++} ++ ++static void ++read_min_mhz(struct lscpu_desc *desc, int idx) ++{ ++ int num = real_cpu_num(desc, idx); ++ ++ if (!path_exist(_PATH_SYS_CPU "/cpu%d/cpufreq/cpuinfo_min_freq", num)) ++ return; ++ if (!desc->minmhz) ++ desc->minmhz = xcalloc(desc->ncpuspos, sizeof(char *)); ++ xasprintf(&(desc->minmhz[idx]), "%.4f", ++ (float)path_read_s32(_PATH_SYS_CPU ++ "/cpu%d/cpufreq/cpuinfo_min_freq", num) / 1000); + } + + static int +@@ -744,13 +1289,14 @@ cachecmp(const void *a, const void *b) + } + + static void +-read_cache(struct lscpu_desc *desc, int num) ++read_cache(struct lscpu_desc *desc, int idx) + { + char buf[256]; + int i; ++ int num = real_cpu_num(desc, idx); + + if (!desc->ncaches) { +- while(path_exist(_PATH_SYS_SYSTEM "/cpu/cpu%d/cache/index%d", ++ while(path_exist(_PATH_SYS_CPU "/cpu%d/cache/index%d", + num, desc->ncaches)) + desc->ncaches++; + +@@ -763,7 +1309,7 @@ read_cache(struct lscpu_desc *desc, int num) + struct cpu_cache *ca = &desc->caches[i]; + cpu_set_t *map; + +- if (!path_exist(_PATH_SYS_SYSTEM "/cpu/cpu%d/cache/index%d", ++ if (!path_exist(_PATH_SYS_CPU "/cpu%d/cache/index%d", + num, i)) + continue; + if (!ca->name) { +@@ -791,10 +1337,13 @@ read_cache(struct lscpu_desc *desc, int num) + ca->name = xstrdup(buf); + + /* cache size */ +- path_read_str(buf, sizeof(buf), +- _PATH_SYS_CPU "/cpu%d/cache/index%d/size", +- num, i); +- ca->size = xstrdup(buf); ++ if (path_exist(_PATH_SYS_CPU "/cpu%d/cache/index%d/size",num, i)) { ++ path_read_str(buf, sizeof(buf), ++ _PATH_SYS_CPU "/cpu%d/cache/index%d/size", num, i); ++ ca->size = xstrdup(buf); ++ } else { ++ ca->size = xstrdup("unknown size"); ++ } + } + + /* information about how CPUs share different caches */ +@@ -867,17 +1416,18 @@ read_nodes(struct lscpu_desc *desc) + /* information about how nodes share different CPUs */ + for (i = 0; i < desc->nnodes; i++) + desc->nodemaps[i] = path_read_cpuset(maxcpus, +- _PATH_SYS_SYSTEM "/node/node%d/cpumap", ++ _PATH_SYS_NODE "/node%d/cpumap", + desc->idx2nodenum[i]); + } + + static char * +-get_cell_data(struct lscpu_desc *desc, int cpu, int col, ++get_cell_data(struct lscpu_desc *desc, int idx, int col, + struct lscpu_modifier *mod, + char *buf, size_t bufsz) + { + size_t setsize = CPU_ALLOC_SIZE(maxcpus); +- size_t idx; ++ size_t i; ++ int cpu = real_cpu_num(desc, idx); + + *buf = '\0'; + +@@ -886,24 +1436,57 @@ get_cell_data(struct lscpu_desc *desc, int cpu, int col, + snprintf(buf, bufsz, "%d", cpu); + break; + case COL_CORE: +- if (cpuset_ary_isset(cpu, desc->coremaps, +- desc->ncores, setsize, &idx) == 0) +- snprintf(buf, bufsz, "%zd", idx); ++ if (mod->physical) { ++ if (desc->coreids[idx] == -1) ++ snprintf(buf, bufsz, "-"); ++ else ++ snprintf(buf, bufsz, "%d", desc->coreids[idx]); ++ } else { ++ if (cpuset_ary_isset(cpu, desc->coremaps, ++ desc->ncores, setsize, &i) == 0) ++ snprintf(buf, bufsz, "%zu", i); ++ } + break; + case COL_SOCKET: +- if (cpuset_ary_isset(cpu, desc->socketmaps, +- desc->nsockets, setsize, &idx) == 0) +- snprintf(buf, bufsz, "%zd", idx); ++ if (mod->physical) { ++ if (desc->socketids[idx] == -1) ++ snprintf(buf, bufsz, "-"); ++ else ++ snprintf(buf, bufsz, "%d", desc->socketids[idx]); ++ } else { ++ if (cpuset_ary_isset(cpu, desc->socketmaps, ++ desc->nsockets, setsize, &i) == 0) ++ snprintf(buf, bufsz, "%zu", i); ++ } + break; + case COL_NODE: + if (cpuset_ary_isset(cpu, desc->nodemaps, +- desc->nnodes, setsize, &idx) == 0) +- snprintf(buf, bufsz, "%d", desc->idx2nodenum[idx]); ++ desc->nnodes, setsize, &i) == 0) ++ snprintf(buf, bufsz, "%d", desc->idx2nodenum[i]); ++ break; ++ case COL_DRAWER: ++ if (mod->physical) { ++ if (desc->drawerids[idx] == -1) ++ snprintf(buf, bufsz, "-"); ++ else ++ snprintf(buf, bufsz, "%d", desc->drawerids[idx]); ++ } else { ++ if (cpuset_ary_isset(cpu, desc->drawermaps, ++ desc->ndrawers, setsize, &i) == 0) ++ snprintf(buf, bufsz, "%zu", i); ++ } + break; + case COL_BOOK: +- if (cpuset_ary_isset(cpu, desc->bookmaps, +- desc->nbooks, setsize, &idx) == 0) +- snprintf(buf, bufsz, "%zd", idx); ++ if (mod->physical) { ++ if (desc->bookids[idx] == -1) ++ snprintf(buf, bufsz, "-"); ++ else ++ snprintf(buf, bufsz, "%d", desc->bookids[idx]); ++ } else { ++ if (cpuset_ary_isset(cpu, desc->bookmaps, ++ desc->nbooks, setsize, &i) == 0) ++ snprintf(buf, bufsz, "%zu", i); ++ } + break; + case COL_CACHE: + { +@@ -915,24 +1498,26 @@ get_cell_data(struct lscpu_desc *desc, int cpu, int col, + struct cpu_cache *ca = &desc->caches[j]; + + if (cpuset_ary_isset(cpu, ca->sharedmaps, +- ca->nsharedmaps, setsize, &idx) == 0) { +- int x = snprintf(p, sz, "%zd", idx); +- if (x <= 0 || (size_t) x + 2 >= sz) ++ ca->nsharedmaps, setsize, &i) == 0) { ++ int x = snprintf(p, sz, "%zu", i); ++ if (x < 0 || (size_t) x >= sz) + return NULL; + p += x; + sz -= x; + } + if (j != 0) { ++ if (sz < 2) ++ return NULL; + *p++ = mod->compat ? ',' : ':'; + *p = '\0'; +- sz++; ++ sz--; + } + } + break; + } + case COL_POLARIZATION: + if (desc->polarization) { +- int x = desc->polarization[cpu]; ++ int x = desc->polarization[idx]; + + snprintf(buf, bufsz, "%s", + mod->mode == OUTPUT_PARSABLE ? +@@ -942,28 +1527,36 @@ get_cell_data(struct lscpu_desc *desc, int cpu, int col, + break; + case COL_ADDRESS: + if (desc->addresses) +- snprintf(buf, bufsz, "%d", desc->addresses[cpu]); ++ snprintf(buf, bufsz, "%d", desc->addresses[idx]); + break; + case COL_CONFIGURED: + if (!desc->configured) + break; + if (mod->mode == OUTPUT_PARSABLE) +- snprintf(buf, bufsz, +- desc->configured[cpu] ? _("Y") : _("N")); ++ snprintf(buf, bufsz, "%s", ++ desc->configured[idx] ? _("Y") : _("N")); + else +- snprintf(buf, bufsz, +- desc->configured[cpu] ? _("yes") : _("no")); ++ snprintf(buf, bufsz, "%s", ++ desc->configured[idx] ? _("yes") : _("no")); + break; + case COL_ONLINE: + if (!desc->online) + break; + if (mod->mode == OUTPUT_PARSABLE) +- snprintf(buf, bufsz, ++ snprintf(buf, bufsz, "%s", + is_cpu_online(desc, cpu) ? _("Y") : _("N")); + else +- snprintf(buf, bufsz, ++ snprintf(buf, bufsz, "%s", + is_cpu_online(desc, cpu) ? _("yes") : _("no")); + break; ++ case COL_MAXMHZ: ++ if (desc->maxmhz) ++ xstrncpy(buf, desc->maxmhz[idx], bufsz); ++ break; ++ case COL_MINMHZ: ++ if (desc->minmhz) ++ xstrncpy(buf, desc->minmhz[idx], bufsz); ++ break; + } + return buf; + } +@@ -982,14 +1575,16 @@ get_cell_header(struct lscpu_desc *desc, int col, + + for (i = desc->ncaches - 1; i >= 0; i--) { + int x = snprintf(p, sz, "%s", desc->caches[i].name); +- if (x <= 0 || (size_t) x + 2 > sz) ++ if (x < 0 || (size_t) x >= sz) + return NULL; + sz -= x; + p += x; + if (i > 0) { ++ if (sz < 2) ++ return NULL; + *p++ = mod->compat ? ',' : ':'; + *p = '\0'; +- sz++; ++ sz--; + } + } + if (desc->ncaches) +@@ -1073,12 +1668,13 @@ print_parsable(struct lscpu_desc *desc, int cols[], int ncols, + */ + for (i = 0; i < desc->ncpuspos; i++) { + int c; ++ int cpu = real_cpu_num(desc, i); + +- if (!mod->offline && desc->online && !is_cpu_online(desc, i)) ++ if (!mod->offline && desc->online && !is_cpu_online(desc, cpu)) + continue; +- if (!mod->online && desc->online && is_cpu_online(desc, i)) ++ if (!mod->online && desc->online && is_cpu_online(desc, cpu)) + continue; +- if (desc->present && !is_cpu_present(desc, i)) ++ if (desc->present && !is_cpu_present(desc, cpu)) + continue; + for (c = 0; c < ncols; c++) { + if (mod->compat && cols[c] == COL_CACHE) { +@@ -1106,38 +1702,49 @@ print_readable(struct lscpu_desc *desc, int cols[], int ncols, + struct lscpu_modifier *mod) + { + int i; +- char buf[BUFSIZ], *data; +- struct tt *tt = tt_new_table(0); ++ char buf[BUFSIZ]; ++ const char *data; ++ struct libscols_table *table; + +- if (!tt) ++ scols_init_debug(0); ++ ++ table = scols_new_table(); ++ if (!table) + err(EXIT_FAILURE, _("failed to initialize output table")); + + for (i = 0; i < ncols; i++) { + data = get_cell_header(desc, cols[i], mod, buf, sizeof(buf)); +- tt_define_column(tt, xstrdup(data), 0, 0); ++ if (!scols_table_new_column(table, xstrdup(data), 0, 0)) ++ err(EXIT_FAILURE, _("failed to initialize output column")); + } + + for (i = 0; i < desc->ncpuspos; i++) { + int c; +- struct tt_line *line; ++ struct libscols_line *line; ++ int cpu = real_cpu_num(desc, i); + +- if (!mod->offline && desc->online && !is_cpu_online(desc, i)) ++ if (!mod->offline && desc->online && !is_cpu_online(desc, cpu)) + continue; +- if (!mod->online && desc->online && is_cpu_online(desc, i)) ++ if (!mod->online && desc->online && is_cpu_online(desc, cpu)) + continue; +- if (desc->present && !is_cpu_present(desc, i)) ++ if (desc->present && !is_cpu_present(desc, cpu)) + continue; + +- line = tt_add_line(tt, NULL); ++ line = scols_table_new_line(table, NULL); ++ if (!line) ++ err(EXIT_FAILURE, _("failed to initialize output line")); + + for (c = 0; c < ncols; c++) { + data = get_cell_data(desc, i, cols[c], mod, + buf, sizeof(buf)); +- tt_line_set_data(line, c, data && *data ? xstrdup(data) : "-"); ++ if (!data || !*data) ++ data = "-"; ++ scols_line_set_data(line, c, data); + } + } + +- tt_print_table(tt); ++ scols_print_table(table); ++ scols_unref_table(table); + } + + /* output formats " "*/ +@@ -1211,8 +1818,9 @@ print_summary(struct lscpu_desc *desc, struct lscpu_modifier *mod) + err(EXIT_FAILURE, _("failed to callocate cpu set")); + CPU_ZERO_S(setsize, set); + for (i = 0; i < desc->ncpuspos; i++) { +- if (!is_cpu_online(desc, i) && is_cpu_present(desc, i)) +- CPU_SET_S(i, setsize, set); ++ int cpu = real_cpu_num(desc, i); ++ if (!is_cpu_online(desc, cpu) && is_cpu_present(desc, cpu)) ++ CPU_SET_S(cpu, setsize, set); + } + print_cpuset(mod->hex ? _("Off-line CPU(s) mask:") : + _("Off-line CPU(s) list:"), +@@ -1221,9 +1829,12 @@ print_summary(struct lscpu_desc *desc, struct lscpu_modifier *mod) + } + + if (desc->nsockets) { +- int cores_per_socket, sockets_per_book, books; ++ int threads_per_core, cores_per_socket, sockets_per_book; ++ int books_per_drawer, drawers; ++ FILE *fd; + +- cores_per_socket = sockets_per_book = books = 0; ++ threads_per_core = cores_per_socket = sockets_per_book = 0; ++ books_per_drawer = drawers = 0; + /* s390 detects its cpu topology via /proc/sysinfo, if present. + * Using simply the cpu topology masks in sysfs will not give + * usable results since everything is virtualized. E.g. +@@ -1232,27 +1843,36 @@ print_summary(struct lscpu_desc *desc, struct lscpu_modifier *mod) + * If the cpu topology is not exported (e.g. 2nd level guest) + * fall back to old calculation scheme. + */ +- if (path_exist(_PATH_PROC_SYSINFO)) { +- FILE *fd = path_fopen("r", 0, _PATH_PROC_SYSINFO); ++ if ((fd = path_fopen("r", 0, _PATH_PROC_SYSINFO))) { + char pbuf[BUFSIZ]; +- int t0, t1, t2; ++ int t0, t1; + + while (fd && fgets(pbuf, sizeof(pbuf), fd) != NULL) { + if (sscanf(pbuf, "CPU Topology SW:%d%d%d%d%d%d", +- &t0, &t1, &t2, &books, &sockets_per_book, ++ &t0, &t1, &drawers, &books_per_drawer, ++ &sockets_per_book, + &cores_per_socket) == 6) + break; + } + if (fd) + fclose(fd); + } +- print_n(_("Thread(s) per core:"), desc->nthreads / desc->ncores); ++ if (desc->mtid) ++ threads_per_core = atoi(desc->mtid) + 1; ++ print_n(_("Thread(s) per core:"), ++ threads_per_core ?: desc->nthreads / desc->ncores); + print_n(_("Core(s) per socket:"), + cores_per_socket ?: desc->ncores / desc->nsockets); + if (desc->nbooks) { + print_n(_("Socket(s) per book:"), + sockets_per_book ?: desc->nsockets / desc->nbooks); +- print_n(_("Book(s):"), books ?: desc->nbooks); ++ if (desc->ndrawers) { ++ print_n(_("Book(s) per drawer:"), ++ books_per_drawer ?: desc->nbooks / desc->ndrawers); ++ print_n(_("Drawer(s):"), drawers ?: desc->ndrawers); ++ } else { ++ print_n(_("Book(s):"), books_per_drawer ?: desc->nbooks); ++ } + } else { + print_n(_("Socket(s):"), sockets_per_book ?: desc->nsockets); + } +@@ -1261,6 +1881,8 @@ print_summary(struct lscpu_desc *desc, struct lscpu_modifier *mod) + print_n(_("NUMA node(s):"), desc->nnodes); + if (desc->vendor) + print_s(_("Vendor ID:"), desc->vendor); ++ if (desc->machinetype) ++ print_s(_("Machine type:"), desc->machinetype); + if (desc->family) + print_s(_("CPU family:"), desc->family); + if (desc->model || desc->revision) +@@ -1271,6 +1893,14 @@ print_summary(struct lscpu_desc *desc, struct lscpu_modifier *mod) + print_s(_("Stepping:"), desc->stepping); + if (desc->mhz) + print_s(_("CPU MHz:"), desc->mhz); ++ if (desc->dynamic_mhz) ++ print_s(_("CPU dynamic MHz:"), desc->dynamic_mhz); ++ if (desc->static_mhz) ++ print_s(_("CPU static MHz:"), desc->static_mhz); ++ if (desc->maxmhz) ++ print_s(_("CPU max MHz:"), desc->maxmhz[0]); ++ if (desc->minmhz) ++ print_s(_("CPU min MHz:"), desc->minmhz[0]); + if (desc->bogomips) + print_s(_("BogoMIPS:"), desc->bogomips); + if (desc->virtflag) { +@@ -1297,10 +1927,29 @@ print_summary(struct lscpu_desc *desc, struct lscpu_modifier *mod) + } + } + ++ if (desc->necaches) { ++ char cbuf[512]; ++ ++ for (i = desc->necaches - 1; i >= 0; i--) { ++ snprintf(cbuf, sizeof(cbuf), ++ _("%s cache:"), desc->ecaches[i].name); ++ print_s(cbuf, desc->ecaches[i].size); ++ } ++ } ++ + for (i = 0; i < desc->nnodes; i++) { + snprintf(buf, sizeof(buf), _("NUMA node%d CPU(s):"), desc->idx2nodenum[i]); + print_cpuset(buf, desc->nodemaps[i], mod->hex); + } ++ ++ if (desc->flags) ++ print_s(_("Flags:"), desc->flags); ++ ++ if (desc->physsockets) { ++ print_n(_("Physical sockets:"), desc->physsockets); ++ print_n(_("Physical chips:"), desc->physchips); ++ print_n(_("Physical cores/chip:"), desc->physcoresperchip); ++ } + } + + static void __attribute__((__noreturn__)) usage(FILE *out) +@@ -1310,6 +1959,9 @@ static void __attribute__((__noreturn__)) usage(FILE *out) + fputs(USAGE_HEADER, out); + fprintf(out, _(" %s [options]\n"), program_invocation_short_name); + ++ fputs(USAGE_SEPARATOR, out); ++ fputs(_("Display information about the CPU architecture.\n"), out); ++ + fputs(USAGE_OPTIONS, out); + fputs(_(" -a, --all print both online and offline CPUs (default for -e)\n"), out); + fputs(_(" -b, --online print online CPUs only (default for -p)\n"), out); +@@ -1318,6 +1970,7 @@ static void __attribute__((__noreturn__)) usage(FILE *out) + fputs(_(" -p, --parse[=] print out a parsable format\n"), out); + fputs(_(" -s, --sysroot use specified directory as system root\n"), out); + fputs(_(" -x, --hex print hexadecimal masks rather than lists of CPUs\n"), out); ++ fputs(_(" -y, --physical print physical instead of logical IDs\n"), out); + fputs(USAGE_SEPARATOR, out); + fputs(USAGE_HELP, out); + fputs(USAGE_VERSION, out); +@@ -1327,7 +1980,7 @@ static void __attribute__((__noreturn__)) usage(FILE *out) + for (i = 0; i < ARRAY_SIZE(coldescs); i++) + fprintf(out, " %13s %s\n", coldescs[i].name, _(coldescs[i].help)); + +- fprintf(out, _("\nFor more details see lscpu(1).\n")); ++ fprintf(out, USAGE_MAN_TAIL("lscpu(1)")); + + exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); + } +@@ -1335,22 +1988,23 @@ static void __attribute__((__noreturn__)) usage(FILE *out) + int main(int argc, char *argv[]) + { + struct lscpu_modifier _mod = { .mode = OUTPUT_SUMMARY }, *mod = &_mod; +- struct lscpu_desc _desc = { .flags = 0 }, *desc = &_desc; ++ struct lscpu_desc _desc = { .flags = NULL }, *desc = &_desc; + int c, i; + int columns[ARRAY_SIZE(coldescs)], ncolumns = 0; + int cpu_modifier_specified = 0; + + static const struct option longopts[] = { +- { "all", no_argument, 0, 'a' }, +- { "online", no_argument, 0, 'b' }, +- { "offline", no_argument, 0, 'c' }, +- { "help", no_argument, 0, 'h' }, +- { "extended", optional_argument, 0, 'e' }, +- { "parse", optional_argument, 0, 'p' }, +- { "sysroot", required_argument, 0, 's' }, +- { "hex", no_argument, 0, 'x' }, +- { "version", no_argument, 0, 'V' }, +- { NULL, 0, 0, 0 } ++ { "all", no_argument, NULL, 'a' }, ++ { "online", no_argument, NULL, 'b' }, ++ { "offline", no_argument, NULL, 'c' }, ++ { "help", no_argument, NULL, 'h' }, ++ { "extended", optional_argument, NULL, 'e' }, ++ { "parse", optional_argument, NULL, 'p' }, ++ { "sysroot", required_argument, NULL, 's' }, ++ { "physical", no_argument, NULL, 'y' }, ++ { "hex", no_argument, NULL, 'x' }, ++ { "version", no_argument, NULL, 'V' }, ++ { NULL, 0, NULL, 0 } + }; + + static const ul_excl_t excl[] = { /* rows and cols in ASCII order */ +@@ -1365,7 +2019,7 @@ int main(int argc, char *argv[]) + textdomain(PACKAGE); + atexit(close_stdout); + +- while ((c = getopt_long(argc, argv, "abce::hp::s:xV", longopts, NULL)) != -1) { ++ while ((c = getopt_long(argc, argv, "abce::hp::s:xyV", longopts, NULL)) != -1) { + + err_exclusive_options(c, longopts, excl, excl_st); + +@@ -1404,12 +2058,14 @@ int main(int argc, char *argv[]) + case 'x': + mod->hex = 1; + break; ++ case 'y': ++ mod->physical = 1; ++ break; + case 'V': +- printf(_("%s from %s\n"), program_invocation_short_name, +- PACKAGE_STRING); ++ printf(UTIL_LINUX_VERSION); + return EXIT_SUCCESS; + default: +- usage(stderr); ++ errtryhelp(EXIT_FAILURE); + } + } + +@@ -1433,17 +2089,27 @@ int main(int argc, char *argv[]) + read_basicinfo(desc, mod); + + for (i = 0; i < desc->ncpuspos; i++) { ++ /* only consider present CPUs */ ++ if (desc->present && ++ !CPU_ISSET(real_cpu_num(desc, i), desc->present)) ++ continue; + read_topology(desc, i); + read_cache(desc, i); + read_polarization(desc, i); + read_address(desc, i); + read_configured(desc, i); ++ read_max_mhz(desc, i); ++ read_min_mhz(desc, i); + } + + if (desc->caches) + qsort(desc->caches, desc->ncaches, + sizeof(struct cpu_cache), cachecmp); + ++ if (desc->ecaches) ++ qsort(desc->ecaches, desc->necaches, ++ sizeof(struct cpu_cache), cachecmp); ++ + read_nodes(desc); + read_hypervisor(desc, mod); + +@@ -1468,6 +2134,8 @@ int main(int argc, char *argv[]) + columns[ncolumns++] = COL_CPU; + if (desc->nodemaps) + columns[ncolumns++] = COL_NODE; ++ if (desc->drawermaps) ++ columns[ncolumns++] = COL_DRAWER; + if (desc->bookmaps) + columns[ncolumns++] = COL_BOOK; + if (desc->socketmaps) +@@ -1484,6 +2152,10 @@ int main(int argc, char *argv[]) + columns[ncolumns++] = COL_POLARIZATION; + if (desc->addresses) + columns[ncolumns++] = COL_ADDRESS; ++ if (desc->maxmhz) ++ columns[ncolumns++] = COL_MAXMHZ; ++ if (desc->minmhz) ++ columns[ncolumns++] = COL_MINMHZ; + } + print_readable(desc, columns, ncolumns, mod); + break; +diff --git a/sys-utils/lscpu.h b/sys-utils/lscpu.h +new file mode 100644 +index 0000000..4906c26 +--- /dev/null ++++ b/sys-utils/lscpu.h +@@ -0,0 +1,26 @@ ++#ifndef LSCPU_H ++#define LSCPU_H ++ ++/* hypervisor vendors */ ++enum { ++ HYPER_NONE = 0, ++ HYPER_XEN, ++ HYPER_KVM, ++ HYPER_MSHV, ++ HYPER_VMWARE, ++ HYPER_IBM, /* sys-z powervm */ ++ HYPER_VSERVER, ++ HYPER_UML, ++ HYPER_INNOTEK, /* VBOX */ ++ HYPER_HITACHI, ++ HYPER_PARALLELS, /* OpenVZ/VIrtuozzo */ ++ HYPER_VBOX, ++ HYPER_OS400, ++ HYPER_PHYP, ++ HYPER_SPAR, ++ HYPER_WSL, ++}; ++ ++extern int read_hypervisor_dmi(void); ++ ++#endif /* LSCPU_H */ +-- +2.9.3 + diff --git a/SOURCES/0116-fdisk-use-sysfs_devno_is_wholedisk.patch b/SOURCES/0116-fdisk-use-sysfs_devno_is_wholedisk.patch new file mode 100644 index 0000000..e758236 --- /dev/null +++ b/SOURCES/0116-fdisk-use-sysfs_devno_is_wholedisk.patch @@ -0,0 +1,58 @@ +From e86fe103accdf5dd688b3710c873094cfa41ae5f Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Tue, 21 Mar 2017 15:11:29 +0100 +Subject: [PATCH 116/116] fdisk: use sysfs_devno_is_wholedisk() + +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1402183 +Signed-off-by: Karel Zak +--- + lib/wholedisk.c | 23 ++++++++--------------- + 1 file changed, 8 insertions(+), 15 deletions(-) + +diff --git a/lib/wholedisk.c b/lib/wholedisk.c +index 5161a1e..7c63204 100644 +--- a/lib/wholedisk.c ++++ b/lib/wholedisk.c +@@ -1,14 +1,10 @@ +-/* +- * No copyright is claimed. This code is in the public domain; do with +- * it what you wish. +- * +- * Written by Karel Zak +- */ ++ + #include + #include + #include + + #include "blkdev.h" ++#include "sysfs.h" + #include "wholedisk.h" + + int is_whole_disk_fd(int fd, const char *name) +@@ -35,16 +31,13 @@ int is_whole_disk_fd(int fd, const char *name) + + int is_whole_disk(const char *name) + { +- int fd = -1, res = 0; +-#ifdef HDIO_GETGEO +- fd = open(name, O_RDONLY|O_CLOEXEC); +- if (fd != -1) +-#endif +- res = is_whole_disk_fd(fd, name); ++ dev_t devno = sysfs_devname_to_devno(name, NULL); ++ ++ if (sysfs_devno_is_lvm_private(devno) || ++ sysfs_devno_is_wholedisk(devno) <= 0) ++ return 0; + +- if (fd != -1) +- close(fd); +- return res; ++ return 1; + } + + #ifdef TEST_PROGRAM +-- +2.9.3 + diff --git a/SOURCES/0117-zramctl-add-bash-completion.patch b/SOURCES/0117-zramctl-add-bash-completion.patch new file mode 100644 index 0000000..22f54f3 --- /dev/null +++ b/SOURCES/0117-zramctl-add-bash-completion.patch @@ -0,0 +1,93 @@ +From 0b8ef4d8289fa1af0296ae01faf0e60293c725fd Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Wed, 22 Mar 2017 12:13:43 +0100 +Subject: [PATCH] zramctl: add bash completion + +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1358755 +Signed-off-by: Karel Zak +--- + bash-completion/Makemodule.am | 3 ++- + bash-completion/zramctl | 57 +++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 59 insertions(+), 1 deletion(-) + create mode 100644 bash-completion/zramctl + +diff --git a/bash-completion/Makemodule.am b/bash-completion/Makemodule.am +index c3791e7..84ab258 100644 +--- a/bash-completion/Makemodule.am ++++ b/bash-completion/Makemodule.am +@@ -30,7 +30,8 @@ dist_bashcompletion_DATA = \ + bash-completion/setsid \ + bash-completion/tailf \ + bash-completion/whereis \ +- bash-completion/wipefs ++ bash-completion/wipefs \ ++ bash-completion/zramctl + + # disk-utils... + if BUILD_BFS +diff --git a/bash-completion/zramctl b/bash-completion/zramctl +new file mode 100644 +index 0000000..a4ef536 +--- /dev/null ++++ b/bash-completion/zramctl +@@ -0,0 +1,57 @@ ++_zramctl_module() ++{ ++ local cur prev OPTS ++ COMPREPLY=() ++ cur="${COMP_WORDS[COMP_CWORD]}" ++ prev="${COMP_WORDS[COMP_CWORD-1]}" ++ case $prev in ++ '-a'|'--algorithm') ++ COMPREPLY=( $(compgen -W "lzo lz4" -- $cur) ) ++ return 0 ++ ;; ++ '-o'|'--output') ++ local prefix realcur OUTPUT_ALL OUTPUT ++ realcur="${cur##*,}" ++ prefix="${cur%$realcur}" ++ OUTPUT_ALL="NAME DISKSIZE DATA COMPR ALGORITHM STREAMS ZERO-PAGES TOTAL MOUNTPOINT" ++ for WORD in $OUTPUT_ALL; do ++ if ! [[ $prefix == *"$WORD"* ]]; then ++ OUTPUT="$WORD $OUTPUT" ++ fi ++ done ++ compopt -o nospace ++ COMPREPLY=( $(compgen -P "$prefix" -W "$OUTPUT" -S ',' -- $realcur) ) ++ return 0 ++ ;; ++ '-s'|'--size') ++ COMPREPLY=( $(compgen -W "size" -- $cur) ) ++ return 0 ++ ;; ++ '-t'|'--streams') ++ COMPREPLY=( $(compgen -W "number" -- $cur) ) ++ return 0 ++ ;; ++ esac ++ case $cur in ++ -*) ++ OPTS=" --algorithm ++ --bytes ++ --find ++ --noheadings ++ --output ++ --raw ++ --reset ++ --size ++ --streams ++ --help ++ --version" ++ COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) ) ++ return 0 ++ ;; ++ esac ++ local IFS=$'\n' ++ compopt -o filenames ++ COMPREPLY=( $(compgen -f -- ${cur:-"/dev/zram"}) ) ++ return 0 ++} ++complete -F _zramctl_module zramctl +-- +2.9.3 + diff --git a/SOURCES/0118-zramctl-make-mm_stat-parser-more-robust.patch b/SOURCES/0118-zramctl-make-mm_stat-parser-more-robust.patch new file mode 100644 index 0000000..9e5c205 --- /dev/null +++ b/SOURCES/0118-zramctl-make-mm_stat-parser-more-robust.patch @@ -0,0 +1,38 @@ +From a7f11e525e9dd5abf844ada0ddd0ae74950e2e40 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Thu, 30 Mar 2017 12:10:01 +0200 +Subject: [PATCH] zramctl: make mm_stat parser more robust + +Let's fallback to attribute files if mm_stat file is incomplete. It +should not happen, but I have seen RHEL7 kernel where is no +num_migrated/pages_compacted attribute... + +Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1358755 +Upstream: http://github.com/karelzak/util-linux/commit/2546d54bd8b0ceac75d6d7e6c483479022d97509 +Signed-off-by: Karel Zak +--- + sys-utils/zramctl.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/sys-utils/zramctl.c b/sys-utils/zramctl.c +index 853401c..c3112d6 100644 +--- a/sys-utils/zramctl.c ++++ b/sys-utils/zramctl.c +@@ -359,8 +359,12 @@ static char *get_mm_stat(struct zram *z, size_t idx, int bytes) + str = sysfs_strdup(sysfs, "mm_stat"); + if (str) { + z->mm_stat = strv_split(str, " "); +- if (strv_length(z->mm_stat) < ARRAY_SIZE(mm_stat_names)) +- errx(EXIT_FAILURE, _("Failed to parse mm_stat")); ++ ++ /* make sure kernel provides mm_stat as expected */ ++ if (strv_length(z->mm_stat) < ARRAY_SIZE(mm_stat_names)) { ++ strv_free(z->mm_stat); ++ z->mm_stat = NULL; ++ } + } + z->mm_stat_probed = 1; + free(str); +-- +2.9.3 + diff --git a/SOURCES/0119-fdisk-improve-menu-and-u-for-GPT.patch b/SOURCES/0119-fdisk-improve-menu-and-u-for-GPT.patch new file mode 100644 index 0000000..2d8099a --- /dev/null +++ b/SOURCES/0119-fdisk-improve-menu-and-u-for-GPT.patch @@ -0,0 +1,74 @@ +From 846f494a89cfe00bcea5e12d9526df76be9196a6 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Tue, 4 Apr 2017 11:12:29 +0200 +Subject: [PATCH] fdisk: improve menu and 'u' for GPT + +* print 't' in the menu for GPT +* don't toggle to cylinders for GPT +* force sectors if GPT detected +* improve expert 'd' command description + +Addresses: Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1344720 +Signed-off-by: Karel Zak +--- + fdisks/fdisk.c | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +diff --git a/fdisks/fdisk.c b/fdisks/fdisk.c +index 177921a..b47b975 100644 +--- a/fdisks/fdisk.c ++++ b/fdisks/fdisk.c +@@ -70,7 +70,7 @@ static const struct menulist_descr menulist[] = { + {'c', N_("toggle the dos compatibility flag"), {FDISK_DISKLABEL_DOS, 0}}, + {'c', N_("toggle the mountable flag"), {FDISK_DISKLABEL_SUN, 0}}, + {'d', N_("delete a partition"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF | FDISK_DISKLABEL_GPT, 0}}, +- {'d', N_("print the raw data in the partition table"), {0, FDISK_DISKLABEL_ANY}}, ++ {'d', N_("print the raw data in the first sector"), {0, FDISK_DISKLABEL_ANY}}, + {'e', N_("change number of extra sectors per cylinder"), {0, FDISK_DISKLABEL_SUN}}, + {'e', N_("edit drive data"), {FDISK_DISKLABEL_OSF, 0}}, + {'e', N_("list extended partitions"), {0, FDISK_DISKLABEL_DOS}}, +@@ -94,7 +94,7 @@ static const struct menulist_descr menulist[] = { + {'s', N_("change number of sectors/track"), {0, FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN}}, + {'s', N_("create a new empty Sun disklabel"), {~FDISK_DISKLABEL_OSF, 0}}, + {'s', N_("show complete disklabel"), {FDISK_DISKLABEL_OSF, 0}}, +- {'t', N_("change a partition's system id"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF, 0}}, ++ {'t', N_("change a partition's system id"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF | FDISK_DISKLABEL_GPT, 0}}, + {'u', N_("change display/entry units"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_OSF, 0}}, + {'v', N_("verify the partition table"), {FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_GPT, + FDISK_DISKLABEL_DOS | FDISK_DISKLABEL_SUN | FDISK_DISKLABEL_SGI | FDISK_DISKLABEL_GPT}}, +@@ -1018,6 +1018,11 @@ static void command_prompt(struct fdisk_context *cxt) + fdisk_context_switch_label(cxt, "dos"); + } + ++ if (fdisk_is_disklabel(cxt, GPT) && fdisk_context_use_cylinders(cxt)) { ++ printf(_("Use cylinders for GPT is unsupported. ")); ++ toggle_units(cxt); ++ } ++ + while (1) { + + assert(cxt->label); +@@ -1073,6 +1078,8 @@ static void command_prompt(struct fdisk_context *cxt) + break; + case 'g': + fdisk_create_disklabel(cxt, "gpt"); ++ if (fdisk_is_disklabel(cxt, GPT) && fdisk_context_use_cylinders(cxt)) ++ toggle_units(cxt); + break; + case 'G': + fdisk_create_disklabel(cxt, "sgi"); +@@ -1107,7 +1114,10 @@ static void command_prompt(struct fdisk_context *cxt) + change_partition_type(cxt); + break; + case 'u': +- toggle_units(cxt); ++ if (fdisk_is_disklabel(cxt, GPT) && !fdisk_context_use_cylinders(cxt)) ++ printf(_("Use cylinders for GPT is unsupported.")); ++ else ++ toggle_units(cxt); + break; + case 'v': + verify(cxt); +-- +2.9.3 + diff --git a/SOURCES/0120-tests-update-for-RHEL7.4-changes.patch b/SOURCES/0120-tests-update-for-RHEL7.4-changes.patch new file mode 100644 index 0000000..6e21777 --- /dev/null +++ b/SOURCES/0120-tests-update-for-RHEL7.4-changes.patch @@ -0,0 +1,209 @@ +From e5d31b4ffb3f978a8935d35301a59eeafe6a50d4 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Tue, 4 Apr 2017 11:58:09 +0200 +Subject: [PATCH 120/121] tests: update for RHEL7.4 changes + +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1360764 +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1344726 +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1402183 +Signed-off-by: Karel Zak +--- + lib/Makemodule.am | 1 + + tests/expected/fdisk/gpt | 5 +++++ + tests/expected/lscpu/lscpu-armv7 | 5 +++++ + tests/expected/lscpu/lscpu-s390-kvm | 2 ++ + tests/expected/lscpu/lscpu-s390-lpar | 2 ++ + tests/expected/lscpu/lscpu-s390-zvm | 2 ++ + tests/expected/lscpu/lscpu-x86_64-64cpu | 5 ++++- + tests/expected/lscpu/lscpu-x86_64-dell_e4310 | 5 ++++- + tests/ts/fdisk/gpt | 3 ++- + 9 files changed, 27 insertions(+), 3 deletions(-) + +diff --git a/lib/Makemodule.am b/lib/Makemodule.am +index faf9d74..acae27a 100644 +--- a/lib/Makemodule.am ++++ b/lib/Makemodule.am +@@ -82,6 +82,7 @@ test_ismounted_LDADD = libcommon.la + + test_wholedisk_SOURCES = lib/wholedisk.c + test_wholedisk_CFLAGS = -DTEST_PROGRAM ++test_wholedisk_LDADD = libcommon.la + + test_mangle_SOURCES = lib/mangle.c + test_mangle_CFLAGS = -DTEST_PROGRAM +diff --git a/tests/expected/fdisk/gpt b/tests/expected/fdisk/gpt +index b73d5c3..017d819 100644 +--- a/tests/expected/fdisk/gpt ++++ b/tests/expected/fdisk/gpt +@@ -7,6 +7,7 @@ Units = sectors of 1 * 512 = 512 bytes + Sector size (logical/physical): 512 bytes / 512 bytes + I/O size (minimum/optimal): 512 bytes / 512 bytes + Disk label type: gpt ++Disk identifier: + + + # Start End Size Type Name +@@ -21,6 +22,7 @@ Units = sectors of 1 * 512 = 512 bytes + Sector size (logical/physical): 512 bytes / 512 bytes + I/O size (minimum/optimal): 512 bytes / 512 bytes + Disk label type: gpt ++Disk identifier: + + + # Start End Size Type Name +@@ -42,6 +44,7 @@ Units = sectors of 1 * 512 = 512 bytes + Sector size (logical/physical): 512 bytes / 512 bytes + I/O size (minimum/optimal): 512 bytes / 512 bytes + Disk label type: gpt ++Disk identifier: + + + # Start End Size Type Name +@@ -63,6 +66,7 @@ Units = sectors of 1 * 512 = 512 bytes + Sector size (logical/physical): 512 bytes / 512 bytes + I/O size (minimum/optimal): 512 bytes / 512 bytes + Disk label type: gpt ++Disk identifier: + + + # Start End Size Type Name +@@ -83,6 +87,7 @@ Units = sectors of 1 * 512 = 512 bytes + Sector size (logical/physical): 512 bytes / 512 bytes + I/O size (minimum/optimal): 512 bytes / 512 bytes + Disk label type: gpt ++Disk identifier: + + + # Start End Size Type Name +diff --git a/tests/expected/lscpu/lscpu-armv7 b/tests/expected/lscpu/lscpu-armv7 +index a1b691c..bcb16cc 100644 +--- a/tests/expected/lscpu/lscpu-armv7 ++++ b/tests/expected/lscpu/lscpu-armv7 +@@ -3,6 +3,11 @@ On-line CPU(s) list: 0,1 + Thread(s) per core: 1 + Core(s) per socket: 2 + Socket(s): 1 ++Model: 4 ++CPU max MHz: 1700.0000 ++CPU min MHz: 200.0000 ++BogoMIPS: 1694.10 ++Flags: swp half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpv4 idiva idivt + + # The following is the parsable format, which can be fed to other + # programs. Each different item in every column has an unique ID +diff --git a/tests/expected/lscpu/lscpu-s390-kvm b/tests/expected/lscpu/lscpu-s390-kvm +index 1aa42f9..66d1c04 100644 +--- a/tests/expected/lscpu/lscpu-s390-kvm ++++ b/tests/expected/lscpu/lscpu-s390-kvm +@@ -6,11 +6,13 @@ Core(s) per socket: 1 + Socket(s) per book: 1 + Book(s): 3 + Vendor ID: IBM/S390 ++Machine type: 2817 + BogoMIPS: 14367.00 + Hypervisor: KVM/Linux + Hypervisor vendor: KVM + Virtualization type: full + Dispatching mode: horizontal ++Flags: esan3 zarch stfle msa ldisp eimm dfp edat etf3eh highgprs + + # The following is the parsable format, which can be fed to other + # programs. Each different item in every column has an unique ID +diff --git a/tests/expected/lscpu/lscpu-s390-lpar b/tests/expected/lscpu/lscpu-s390-lpar +index 0799ab9..9c8ac2c 100644 +--- a/tests/expected/lscpu/lscpu-s390-lpar ++++ b/tests/expected/lscpu/lscpu-s390-lpar +@@ -7,11 +7,13 @@ Core(s) per socket: 4 + Socket(s) per book: 6 + Book(s): 4 + Vendor ID: IBM/S390 ++Machine type: 2817 + BogoMIPS: 14367.00 + Hypervisor: PR/SM + Hypervisor vendor: IBM + Virtualization type: full + Dispatching mode: vertical ++Flags: esan3 zarch stfle msa ldisp eimm dfp etf3eh highgprs + + # The following is the parsable format, which can be fed to other + # programs. Each different item in every column has an unique ID +diff --git a/tests/expected/lscpu/lscpu-s390-zvm b/tests/expected/lscpu/lscpu-s390-zvm +index 04dcf76..4cd6b8f 100644 +--- a/tests/expected/lscpu/lscpu-s390-zvm ++++ b/tests/expected/lscpu/lscpu-s390-zvm +@@ -6,11 +6,13 @@ Core(s) per socket: 1 + Socket(s) per book: 1 + Book(s): 4 + Vendor ID: IBM/S390 ++Machine type: 2817 + BogoMIPS: 14367.00 + Hypervisor: z/VM 6.1.0 + Hypervisor vendor: IBM + Virtualization type: full + Dispatching mode: horizontal ++Flags: esan3 zarch stfle msa ldisp eimm dfp etf3eh highgprs + + # The following is the parsable format, which can be fed to other + # programs. Each different item in every column has an unique ID +diff --git a/tests/expected/lscpu/lscpu-x86_64-64cpu b/tests/expected/lscpu/lscpu-x86_64-64cpu +index 32aa57c..07990ea 100644 +--- a/tests/expected/lscpu/lscpu-x86_64-64cpu ++++ b/tests/expected/lscpu/lscpu-x86_64-64cpu +@@ -11,7 +11,9 @@ Model: 46 + Model name: Intel(R) Xeon(R) CPU X7550 @ 2.00GHz + Stepping: 6 + CPU MHz: 1064.000 +-BogoMIPS: 3989.44 ++CPU max MHz: 1996.0000 ++CPU min MHz: 1064.0000 ++BogoMIPS: 3990.31 + Virtualization: VT-x + L1d cache: 32K + L1i cache: 32K +@@ -20,6 +22,7 @@ L3 cache: 18432K + NUMA node0 CPU(s): 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62 + NUMA node2 CPU(s): 1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61 + NUMA node3 CPU(s): 3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63 ++Flags: fpu vme de pse tsc msr pae mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good xtopology nonstop_tsc aperfmperf pni dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm dca sse4_1 sse4_2 x2apic popcnt lahf_lm ida epb dts tpr_shadow vnmi flexpriority ept vpid + + # The following is the parsable format, which can be fed to other + # programs. Each different item in every column has an unique ID +diff --git a/tests/expected/lscpu/lscpu-x86_64-dell_e4310 b/tests/expected/lscpu/lscpu-x86_64-dell_e4310 +index a81878d..39ec32c 100644 +--- a/tests/expected/lscpu/lscpu-x86_64-dell_e4310 ++++ b/tests/expected/lscpu/lscpu-x86_64-dell_e4310 +@@ -11,13 +11,16 @@ Model: 37 + Model name: Intel(R) Core(TM) i5 CPU M 560 @ 2.67GHz + Stepping: 5 + CPU MHz: 1199.000 +-BogoMIPS: 5319.97 ++CPU max MHz: 2667.0000 ++CPU min MHz: 1199.0000 ++BogoMIPS: 5319.92 + Virtualization: VT-x + L1d cache: 32K + L1i cache: 32K + L2 cache: 256K + L3 cache: 3072K + NUMA node0 CPU(s): 0-3 ++Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm sse4_1 sse4_2 popcnt aes lahf_lm ida arat dts tpr_shadow vnmi flexpriority ept vpid + + # The following is the parsable format, which can be fed to other + # programs. Each different item in every column has an unique ID +diff --git a/tests/ts/fdisk/gpt b/tests/ts/fdisk/gpt +index a0902ca..ec3438f 100755 +--- a/tests/ts/fdisk/gpt ++++ b/tests/ts/fdisk/gpt +@@ -38,7 +38,8 @@ function print_layout { + echo -ne "\n---layout----------" >> $TS_OUTPUT + $TS_CMD_FDISK -l ${TEST_IMAGE_NAME} 2> /dev/null | \ + sed 's/^.*\.img/__ts_dev__/g; +- s/^[[:blank:]]*Device Boot/ Device Boot/g' >> $TS_OUTPUT 2>&1 ++ s/^[[:blank:]]*Device Boot/ Device Boot/g; ++ s/^Disk identifier:.*/Disk identifier: /g' >> $TS_OUTPUT 2>&1 + echo -ne "-------------------\n\n" >> $TS_OUTPUT + } + +-- +2.9.3 + diff --git a/SOURCES/0121-zramctl-be-more-specific-about-default-output.patch b/SOURCES/0121-zramctl-be-more-specific-about-default-output.patch new file mode 100644 index 0000000..105761a --- /dev/null +++ b/SOURCES/0121-zramctl-be-more-specific-about-default-output.patch @@ -0,0 +1,31 @@ +From 46d4d1c8d1b62c8f2dda1639e75b5d0e6bafaf27 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Tue, 4 Apr 2017 12:06:45 +0200 +Subject: [PATCH 121/121] zramctl: be more specific about default output + +Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1358755 +Signed-off-by: Karel Zak +--- + sys-utils/zramctl.8 | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/sys-utils/zramctl.8 b/sys-utils/zramctl.8 +index f6fc45c..9ca2983 100644 +--- a/sys-utils/zramctl.8 ++++ b/sys-utils/zramctl.8 +@@ -39,9 +39,9 @@ Set up a zram device: + .SH DESCRIPTION + .B zramctl + is used to quickly set up zram device parameters, to reset zram devices, and to +-query the status of used zram devices. If no option is given, all zram devices +-are shown. +- ++query the status of used zram devices. ++.PP ++If no option is given, all non-zero size zram devices are shown. + .SH OPTIONS + .TP + .BR \-a , " \-\-algorithm lzo" | lz4 +-- +2.9.3 + diff --git a/SOURCES/0122-libfdisk-gpt-fix-UUID-printing.patch b/SOURCES/0122-libfdisk-gpt-fix-UUID-printing.patch new file mode 100644 index 0000000..eefa83f --- /dev/null +++ b/SOURCES/0122-libfdisk-gpt-fix-UUID-printing.patch @@ -0,0 +1,46 @@ +From a95f7a89ed81fb3d7c3135baae20b056b7f8e661 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Wed, 10 May 2017 15:26:55 +0200 +Subject: [PATCH] libfdisk: (gpt) fix UUID printing + +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1344726 +Signed-off-by: Karel Zak +--- + libfdisk/src/gpt.c | 14 +++----------- + 1 file changed, 3 insertions(+), 11 deletions(-) + +diff --git a/libfdisk/src/gpt.c b/libfdisk/src/gpt.c +index 899e1b2..612ce09 100644 +--- a/libfdisk/src/gpt.c ++++ b/libfdisk/src/gpt.c +@@ -1690,7 +1690,7 @@ static int gpt_create_disklabel(struct fdisk_context *cxt) + { + int rc = 0; + ssize_t esz = 0; +- struct gpt_guid *uid; ++ char str[37]; + struct fdisk_gpt_label *gpt; + + assert(cxt); +@@ -1746,16 +1746,8 @@ static int gpt_create_disklabel(struct fdisk_context *cxt) + cxt->label->nparts_max = le32_to_cpu(gpt->pheader->npartition_entries); + cxt->label->nparts_cur = 0; + +- uid = &gpt->pheader->disk_guid; +- fdisk_info(cxt, _("Building a new GPT disklabel " +- "(GUID: %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X)\n"), +- uid->time_low, uid->time_mid, +- uid->time_hi_and_version, +- uid->clock_seq_hi, +- uid->clock_seq_low, +- uid->node[0], uid->node[1], +- uid->node[2], uid->node[3], +- uid->node[4], uid->node[5]); ++ guid_to_string(&gpt->pheader->disk_guid, str); ++ fdisk_info(cxt, _("Building a new GPT disklabel (GUID: %s)\n"), str); + fdisk_label_set_changed(cxt->label, 1); + done: + return rc; +-- +2.9.3 + diff --git a/SOURCES/0123-libblkid-Add-metadata-signature-check-for-IMSM-on-4K.patch b/SOURCES/0123-libblkid-Add-metadata-signature-check-for-IMSM-on-4K.patch new file mode 100644 index 0000000..b17f426 --- /dev/null +++ b/SOURCES/0123-libblkid-Add-metadata-signature-check-for-IMSM-on-4K.patch @@ -0,0 +1,60 @@ +From 2181ce4a5726c4c72e68e6964b7ef7442e507707 Mon Sep 17 00:00:00 2001 +From: Alexey Obitotskiy +Date: Fri, 24 Jun 2016 11:59:35 +0200 +Subject: [PATCH] libblkid: Add metadata signature check for IMSM on 4Kn drives + +Drives with 512 and 4K sectors have different offset for +metadata signature. Without signature detected on 4Kn drives +those drives will not be recognized as raid member. This +patch adds checking for IMSM signature for 4Kn drives. + +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1451704 +Signed-off-by: Alexey Obitotskiy +Signed-off-by: Karel Zak +--- + libblkid/src/superblocks/isw_raid.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/libblkid/src/superblocks/isw_raid.c b/libblkid/src/superblocks/isw_raid.c +index 065c2b2..81d53a1 100644 +--- a/libblkid/src/superblocks/isw_raid.c ++++ b/libblkid/src/superblocks/isw_raid.c +@@ -25,11 +25,11 @@ struct isw_metadata { + + #define ISW_SIGNATURE "Intel Raid ISM Cfg Sig. " + +- + static int probe_iswraid(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) + { + uint64_t off; ++ unsigned int sector_size; + struct isw_metadata *isw; + + if (pr->size < 0x10000) +@@ -37,16 +37,17 @@ static int probe_iswraid(blkid_probe pr, + if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) + return 1; + +- off = ((pr->size / 0x200) - 2) * 0x200; +- isw = (struct isw_metadata *) +- blkid_probe_get_buffer(pr, +- off, +- sizeof(struct isw_metadata)); ++ sector_size = blkid_probe_get_sectorsize(pr); ++ off = ((pr->size / sector_size) - 2) * sector_size; ++ ++ isw = (struct isw_metadata *)blkid_probe_get_buffer(pr, ++ off, sizeof(struct isw_metadata)); + if (!isw) + return errno ? -errno : 1; + + if (memcmp(isw->sig, ISW_SIGNATURE, sizeof(ISW_SIGNATURE)-1) != 0) + return 1; ++ + if (blkid_probe_sprintf_version(pr, "%6s", + &isw->sig[sizeof(ISW_SIGNATURE)-1]) != 0) + return 1; +-- +2.9.4 + diff --git a/SOURCES/0124-lscpu-use-sysfs-for-table-access-if-available.patch b/SOURCES/0124-lscpu-use-sysfs-for-table-access-if-available.patch new file mode 100644 index 0000000..d31a3ca --- /dev/null +++ b/SOURCES/0124-lscpu-use-sysfs-for-table-access-if-available.patch @@ -0,0 +1,66 @@ +From 6999f3f3ca525bb6b132f4ed804e7f8fe62e5f79 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Wed, 12 Apr 2017 10:11:29 +0100 +Subject: [PATCH] lscpu: use sysfs for table access if available + +On ARM systems, accessing SMBIOS tables via /dev/mem using read() +calls is not supported. The reason is that such tables are usually +located in EFI_RUNTIME_SERVICE_DATA memory, which is not covered +by the linear mapping on those systems, and so read() calls will +fail. + +So instead, use the /sys/firmware/dmi/tables/DMI sysfs file, which +contains the entire structure table array, and will be available +on any recent Linux system, even on ones that only export the rev3 +SMBIOS entry point, which is currently ignored by lscpu. + +Note that the max 'num' value is inferred from the size. This is not +a limitation of the sysfs interface, but a limitation of the rev3 +entry point, which no longer carries a number of array elements. + +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1455664 +Upstream: http://github.com/karelzak/util-linux/commit/92a6392c41c11bcb49af9f129dfbd1fed651f044 +Signed-off-by: Ard Biesheuvel +Tested-by: Alexander Graf +Reviewed-by: Alexander Graf +--- + sys-utils/lscpu-dmi.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/sys-utils/lscpu-dmi.c b/sys-utils/lscpu-dmi.c +index 0e497d1..a8298ff 100644 +--- a/sys-utils/lscpu-dmi.c ++++ b/sys-utils/lscpu-dmi.c +@@ -192,6 +192,18 @@ static int hypervisor_decode_smbios(uint8_t *buf, const char *devmem) + devmem); + } + ++static int hypervisor_decode_sysfw(void) ++{ ++ static char const sys_fw_dmi_tables[] = "/sys/firmware/dmi/tables/DMI"; ++ struct stat st; ++ ++ if (stat(sys_fw_dmi_tables, &st)) ++ return -1; ++ ++ return hypervisor_from_dmi_table(0, st.st_size, st.st_size / 4, ++ sys_fw_dmi_tables); ++} ++ + /* + * Probe for EFI interface + */ +@@ -242,6 +254,10 @@ int read_hypervisor_dmi(void) + || '\0' != 0) + return rc; + ++ rc = hypervisor_decode_sysfw(); ++ if (rc >= 0) ++ return rc; ++ + /* First try EFI (ia64, Intel-based Mac) */ + switch (address_from_efi(&fp)) { + case EFI_NOT_FOUND: +-- +2.9.4 + diff --git a/SOURCES/0125-lscpu-improve-for-offline-CPUs-on-AMD.patch b/SOURCES/0125-lscpu-improve-for-offline-CPUs-on-AMD.patch new file mode 100644 index 0000000..a6a214c --- /dev/null +++ b/SOURCES/0125-lscpu-improve-for-offline-CPUs-on-AMD.patch @@ -0,0 +1,44 @@ +From 4150eb1025c059f9459f98ef6c6c3fac730eaf93 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Thu, 1 Jun 2017 12:07:41 +0200 +Subject: [PATCH] lscpu: improve for offline CPUs on AMD + +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1457744 +Signed-off-by: Karel Zak +--- + sys-utils/lscpu.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/sys-utils/lscpu.c b/sys-utils/lscpu.c +index 683fd66..1ee73f3 100644 +--- a/sys-utils/lscpu.c ++++ b/sys-utils/lscpu.c +@@ -1550,11 +1550,11 @@ get_cell_data(struct lscpu_desc *desc, int idx, int col, + is_cpu_online(desc, cpu) ? _("yes") : _("no")); + break; + case COL_MAXMHZ: +- if (desc->maxmhz) ++ if (desc->maxmhz && desc->maxmhz[idx]) + xstrncpy(buf, desc->maxmhz[idx], bufsz); + break; + case COL_MINMHZ: +- if (desc->minmhz) ++ if (desc->minmhz && desc->minmhz[idx]) + xstrncpy(buf, desc->minmhz[idx], bufsz); + break; + } +@@ -1897,9 +1897,9 @@ print_summary(struct lscpu_desc *desc, struct lscpu_modifier *mod) + print_s(_("CPU dynamic MHz:"), desc->dynamic_mhz); + if (desc->static_mhz) + print_s(_("CPU static MHz:"), desc->static_mhz); +- if (desc->maxmhz) ++ if (desc->maxmhz && desc->maxmhz[0]) + print_s(_("CPU max MHz:"), desc->maxmhz[0]); +- if (desc->minmhz) ++ if (desc->minmhz && desc->minmhz[0]) + print_s(_("CPU min MHz:"), desc->minmhz[0]); + if (desc->bogomips) + print_s(_("BogoMIPS:"), desc->bogomips); +-- +2.9.4 + diff --git a/SPECS/util-linux.spec b/SPECS/util-linux.spec index b6716ab..27d18a9 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: 33%{?dist}.2 +Release: 43%{?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 @@ -261,12 +261,79 @@ Patch85: 0085-libblkid-store-only-canonical-devnames-to-the-cache.patch Patch86: 0086-libblkid-avoid-recursion-in-EBR.patch # -# RHEL7.3.Z +# RHEL7.4 # # 1405238 - findmnt --target behaviour changed in 7.3, shows all mount-points in chroot Patch87: 0087-findmnt-fix-target-behaviour.patch -# 1420262 - CVE-2017-2616 util-linux +# 1419474 Patch88: 0088-su-properly-clear-child-PID.patch +# 1344102 - fdisk does not handle 4kN devices correctly in 'Blocks' calculation +Patch89: 0089-fdisk-fix-Blocks-column-calculation.patch +# 1344720 - when fdisk detects gpt table, expected menu items seem to be missing in the 'm' output +Patch90: 0090-fdisk-fix-menu-for-GPT.patch +# 1323916 - logger unnecessarily splits messages sent via stdin into 1024 byte chunks +Patch91: 0091-logger-backport-size.patch +# 1344726 - [RFE] fdisk: output UID from gpt in fdisk when detecting that a gpt partition table is present +Patch92: 0092-fdisk-print-header-UUID-for-GPT.patch +# 1362662 - fdisk -l fails/stops on first passive/not ready device, works on RHEL6 +Patch93: 0093-fdisk-improve-l-error-handling.patch +# 1369436 - losetup man page incorrect syntax for Setup loop device +Patch94: 0094-losetup-improve-man-page-SYNOPSIS.patch +# 1392656 - [LLNL 7.4 Bug] fix buffer overflows in util-linux with upstream patch +Patch95: 0095-libblkid-fix-potential-bufer-overflows.patch +# 1370959 - [FJ7.3 Bug]: man 8 umount is wrong. +Patch96: 0096-umount-fix-obsolete-info-about-loop-in-umount.8.patch +# 1357746 - mount -av" report NFS "successfully mounted" but it is not. +Patch97: 0097-mount-fix-all-and-nofail-return-code.patch +# 1417722 - umount -a results in selinux being reported as Disabled +Patch98: 0098-umount-exclude-selinuxfs-from-all.patch +# 1402825 - RHEL7: "sfdisk -s" can't list the disk size +Patch99: 0099-sfdisk-remove-useless-CDROM-detection-for-s.patch +# 1403973 - /usr/bin/more crash on repeat search on failed regex match +Patch100: 0100-more-fix-repeat-search-crash.patch +# 1403971 - /usr/bin/more crash in end_it due to double free +Patch101: 0101-more-avoid-double-free-on-exit.patch +# 1358095 - ipcs shows wrong gid information +Patch102: 0102-ipcs-show-gid-instead-of-uid.patch +# 1358097 - ipcs shows strange status message in ja locale +Patch103: 0103-ipcs-fix-JP-status-message.patch +# 1378100 - fix swapon discard option parsing +Patch104: 0104-swapon-fix-discard-option-parsing.patch +# 1416467 - [RFE] Add support for posix_fallocate(3) call in fallocate(1) utility +Patch105: 0105-fallocate-Added-posix_fallocate-support.patch +# 1358755 - Backport request for zramctl on util-linux v2.23.2 +Patch106: 0106-zramctl-backport-from-v2.29.patch +# 1392661 - [LLNL 7.4 Bug] add zfs patches to util-linux +Patch107: 0107-libblkid-zfs-let-s-keep-compiler-happy.patch +Patch108: 0108-blkid-make-zfs-detection-more-robust.patch +Patch109: 0109-zfs-make-less-syscalls.patch +Patch110: 0110-libblkid-zfs-keep-bufferes-read-only.patch +Patch111: 0111-libblkid-don-t-mark-zfs-as-RAID.patch +Patch112: 0112-tests-update-ZFS-test.patch +Patch113: 0113-libblkid-zfs-add-cast-to-fix-UB-cppcheck.patch +Patch114: 0114-libblkid-Avoid-OOB-access-on-illegal-ZFS-superblocks.patch +# 1360764 - SMT: "Threads Per Core" will automatically change when odd or even number of vcpu are enabled online. +# 1397709 - [7.4 FEAT] Refresh code for lscpu to support s390x cpu topology +Patch115: 0115-lscpu-backport-from-v2.29.patch +# 1402183 - [HPE 7.3 Bug] fdisk -l does not list non-BTT NVDIMM devices +Patch116: 0116-fdisk-use-sysfs_devno_is_wholedisk.patch +# 1358755 - Backport request for zramctl on util-linux v2.23.2 +Patch117: 0117-zramctl-add-bash-completion.patch +Patch118: 0118-zramctl-make-mm_stat-parser-more-robust.patch +# 1344720 - when fdisk detects gpt table, expected menu items seem to be missing in the 'm' output +Patch119: 0119-fdisk-improve-menu-and-u-for-GPT.patch +# 1360764 1397709 - lscpu rebase +Patch120: 0120-tests-update-for-RHEL7.4-changes.patch +# 1358755 - Backport request for zramctl on util-linux v2.23.2 +Patch121: 0121-zramctl-be-more-specific-about-default-output.patch +# 1344726 - [RFE] fdisk: output UID from gpt in fdisk when detecting that a gpt partition table is present +Patch122: 0122-libfdisk-gpt-fix-UUID-printing.patch +# 1451704 - [Intel 7.4 BUG] IMSM RAID on 4k disks not assembled on boot +Patch123: 0123-libblkid-Add-metadata-signature-check-for-IMSM-on-4K.patch +# 1455664 - lscpu causes kernel panic on HPE Comanche / Cavium ThunderX2 (cn99xx) +Patch124: 0124-lscpu-use-sysfs-for-table-access-if-available.patch +# 1457744 - lscpu -e get crashed after offline one host cpu on amd machine +Patch125: 0125-lscpu-improve-for-offline-CPUs-on-AMD.patch %description The util-linux package contains a large variety of low-level system @@ -388,6 +455,9 @@ unset LINGUAS || : # unfortunately, we did changes to build-system ./autogen.sh +# we modify .po files by RHEL patches +rm -f po/stamp* + export CFLAGS="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 $RPM_OPT_FLAGS" export SUID_CFLAGS="-fpie" export SUID_LDFLAGS="-pie -Wl,-z,relro -Wl,-z,now" @@ -775,14 +845,15 @@ fi %{_mandir}/man8/resizepart.8* %{_mandir}/man8/rtcwake.8* %{_mandir}/man8/setarch.8* -%{_mandir}/man8/sulogin.8.gz +%{_mandir}/man8/sulogin.8* %{_mandir}/man8/swaplabel.8* %{_mandir}/man8/swapoff.8* %{_mandir}/man8/swapon.8* %{_mandir}/man8/switch_root.8* %{_mandir}/man8/umount.8* -%{_mandir}/man8/wdctl.8.gz +%{_mandir}/man8/wdctl.8* %{_mandir}/man8/wipefs.8* +%{_mandir}/man8/zramctl.8* %{_sbindir}/addpart %{_sbindir}/agetty %{_sbindir}/blkdiscard @@ -817,7 +888,7 @@ fi %{_sbindir}/swapon %{_sbindir}/switch_root %{_sbindir}/wipefs - +%{_sbindir}/zramctl %{compldir}/addpart %{compldir}/blkdiscard %{compldir}/blkid @@ -896,6 +967,7 @@ fi %{compldir}/whereis %{compldir}/wipefs %{compldir}/write +%{compldir}/zramctl %ifnarch s390 s390x %{_sbindir}/clock @@ -992,10 +1064,57 @@ fi %{_libdir}/pkgconfig/uuid.pc %changelog -* Wed Feb 8 2017 Karel Zak 2.23.2-33.el7_3.2 -* fix CVE-2017-2616 - Sending SIGKILL to other processes with root privileges via su - -* Mon Jan 23 2017 Karel Zak 2.23.2-33.el7_3.1 +* Thu Jun 01 2017 Karel Zak 2.23.2-43 +- fix #1457744 - lscpu -e get crashed after offline one host cpu on amd machine + +* Wed May 31 2017 Karel Zak 2.23.2-42 +- fix #1455664 - lscpu causes kernel panic on HPE Comanche / Cavium ThunderX2 (cn99xx) + +* Tue May 23 2017 Karel Zak 2.23.2-41 +- fix #1451704 - IMSM RAID on 4k disks not assembled on boot +- force gettext messages refresh (for #1358097 bugfix) + +* Wed May 10 2017 Karel Zak 2.23.2-40 +- improve libfdisk GPT UUID printing (#1344726) + +* Tue Apr 04 2017 Karel Zak 2.23.2-39 +- update package regression tests (due to #1360764 #1397709) +- improve zramctl man page (#1358755) + +* Tue Apr 04 2017 Karel Zak 2.23.2-38 +- improve fdisk menu for GPT (#1344720) + +* Thu Mar 30 2017 Karel Zak 2.23.2-37 +- improve zram mm_stat parser (#1358755) + +* Wed Mar 22 2017 Karel Zak 2.23.2-36 +- fix #1344102 - fdisk does not handle 4kN devices correctly in 'Blocks' calculation +- fix #1344720 - when fdisk detects gpt table, expected menu items seem to be missing in the 'm' output +- fix #1323916 - logger unnecessarily splits messages sent via stdin into 1024 byte chunks +- fix #1344726 - [RFE] fdisk: output UID from gpt in fdisk when detecting that a gpt partition table is present +- fix #1362662 - fdisk -l fails/stops on first passive/not ready device, works on RHEL6 +- fix #1369436 - losetup man page incorrect syntax for Setup loop device +- fix #1392656 - [LLNL 7.4 Bug] fix buffer overflows in util-linux with upstream patch +- fix #1370959 - [FJ7.3 Bug]: man 8 umount is wrong. +- fix #1357746 - mount -av" report NFS "successfully mounted" but it is not. +- fix #1417722 - umount -a results in selinux being reported as Disabled +- fix #1402825 - RHEL7: "sfdisk -s" can't list the disk size +- fix #1403973 - /usr/bin/more crash on repeat search on failed regex match +- fix #1403971 - /usr/bin/more crash in end_it due to double free +- fix #1358095 - ipcs shows wrong gid information +- fix #1358097 - ipcs shows strange status message in ja locale +- fix #1378100 - fix swapon discard option parsing +- fix #1416467 - [RFE] Add support for posix_fallocate(3) call in fallocate(1) utility +- fix #1358755 - Backport request for zramctl on util-linux v2.23.2 +- fix #1392661 - [LLNL 7.4 Bug] add zfs patches to util-linux +- fix #1360764 - SMT: "Threads Per Core" will automatically change when odd or even number of vcpu are enabled online. +- fix #1397709 - [7.4 FEAT] Refresh code for lscpu to support s390x cpu topology +- fix #1402183 - [HPE 7.3 Bug] fdisk -l does not list non-BTT NVDIMM devices + +* Wed Feb 8 2017 Karel Zak 2.23.2-35 +* fix #1419474 - su: properly clear child PID + +* Mon Jan 23 2017 Karel Zak 2.23.2-34 - fix #1405238 - findmnt --target behaviour changed in 7.3, shows all mount-points in chroot * Tue Jul 12 2016 Karel Zak 2.23.2-33