diff --git a/SOURCES/0060-build-sys-add-CFLAGS-and-LDFLAGS-for-daemons-and-sha.patch b/SOURCES/0060-build-sys-add-CFLAGS-and-LDFLAGS-for-daemons-and-sha.patch new file mode 100644 index 0000000..cc9d680 --- /dev/null +++ b/SOURCES/0060-build-sys-add-CFLAGS-and-LDFLAGS-for-daemons-and-sha.patch @@ -0,0 +1,166 @@ +From 097c66ef2dd4779e01d13ad4a5f9733334fa9d1a Mon Sep 17 00:00:00 2001 +From: Karel Zak <kzak@redhat.com> +Date: Tue, 27 Aug 2013 10:02:04 +0200 +Subject: [PATCH 60/84] build-sys: add CFLAGS and LDFLAGS for daemons and + shared libs + +This is necessary for paranoid security guys who believe that things +like "-Wl,-z,relro" or "-Wl,-z,bind_now" is a way how to make the +world a safer place... + +[rhel7: add also SOLIB_* to libfdisk] + +Upstream: http://github.com/karelzak/util-linux/commit/03d00d495f3b505d9cae967c629fb38aca301e01 +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1092520 +Signed-off-by: Karel Zak <kzak@redhat.com> +--- + Documentation/howto-compilation.txt | 10 +++++----- + configure.ac | 10 ++++++++++ + libblkid/src/Makemodule.am | 2 ++ + libfdisk/src/Makemodule.am | 3 +++ + libmount/src/Makemodule.am | 2 ++ + libuuid/src/Makemodule.am | 7 ++++++- + misc-utils/Makemodule.am | 3 ++- + 7 files changed, 30 insertions(+), 7 deletions(-) + +diff --git a/Documentation/howto-compilation.txt b/Documentation/howto-compilation.txt +index bebe0d2..4b39246 100644 +--- a/Documentation/howto-compilation.txt ++++ b/Documentation/howto-compilation.txt +@@ -27,12 +27,12 @@ Compiling + The SUID_* feature is currently supported for chfn, chsh, + newgrp, su, write, mount, and umount. + +- Preferred compilation options for developers, when +- using gcc, are: ++ Use DAEMON_CFLAGS and DAEMON_LDFLAGS when you want to define ++ special compiler options for daemons; supported for uuidd. + +- export CFLAGS="-Wmissing-parameter-type -Wsign-compare +- -Wtype-limits -Wuninitialized -Wunused-parameter +- -Wunused-but-set-parameter -fno-common" ++ Use SOLIB_CFLAGS and SOLIB_LDFLAGS when you want to define ++ special compiler options for shared libraries; supported for ++ libmount, libblkid and libuuid. + + FIXME: add notes about klib and uClib. + +diff --git a/configure.ac b/configure.ac +index f7c27cd..f3c7214 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1538,6 +1538,16 @@ AC_ARG_VAR([SUID_CFLAGS], + AC_ARG_VAR([SUID_LDFLAGS], + [LDFLAGS used for binaries which are usually with the suid bit]) + ++AC_ARG_VAR([DAEMON_CFLAGS], ++ [CFLAGS used for binaries which are usually executed as daemons]) ++AC_ARG_VAR([DAEMON_LDFLAGS], ++ [LDFLAGS used for binaries which are usually executed as daemons]) ++ ++AC_ARG_VAR([SOLIB_CFLAGS], ++ [CFLAGS used for shared libraries]) ++AC_ARG_VAR([SOLIB_LDFLAGS], ++ [LDFLAGS used for shared libraries]) ++ + LIBS="" + + +diff --git a/libblkid/src/Makemodule.am b/libblkid/src/Makemodule.am +index 04d8621..1563976 100644 +--- a/libblkid/src/Makemodule.am ++++ b/libblkid/src/Makemodule.am +@@ -113,6 +113,7 @@ libblkid_la_LIBADD = libcommon.la + + + libblkid_la_CFLAGS = \ ++ $(SOLIB_CFLAGS) \ + -I$(ul_libblkid_incdir) \ + -I$(top_srcdir)/libblkid/src + +@@ -128,6 +129,7 @@ libblkid_la_DEPENDENCIES = \ + libblkid/src/blkid.h.in + + libblkid_la_LDFLAGS = \ ++ $(SOLIB_LDFLAGS) \ + -Wl,--version-script=$(top_srcdir)/libblkid/src/blkid.sym \ + -version-info $(LIBBLKID_VERSION_INFO) + +diff --git a/libfdisk/src/Makemodule.am b/libfdisk/src/Makemodule.am +index fbfb1b4..5c50001 100644 +--- a/libfdisk/src/Makemodule.am ++++ b/libfdisk/src/Makemodule.am +@@ -25,6 +25,8 @@ nodist_libfdisk_la_SOURCES = libfdisk/src/fdiskP.h + libfdisk_la_LIBADD = libcommon.la + + libfdisk_la_CFLAGS = \ ++ $(AM_CFLAGS) \ ++ $(SOLIB_CFLAGS) \ + -I$(ul_libfdisk_incdir) \ + -I$(top_srcdir)/libfdisk/src + +@@ -39,6 +41,7 @@ libfdisk_la_CFLAGS += -I$(ul_libuuid_incdir) + endif + + libfdisk_la_DEPENDENCIES = $(libfdisk_la_LIBADD) ++libfdisk_la_LDFLAGS = $(SOLIB_LDFLAGS) + + + check_PROGRAMS += \ +diff --git a/libmount/src/Makemodule.am b/libmount/src/Makemodule.am +index 494e02a..8ef07e5 100644 +--- a/libmount/src/Makemodule.am ++++ b/libmount/src/Makemodule.am +@@ -33,6 +33,7 @@ nodist_libmount_la_SOURCES = libmount/src/mountP.h + libmount_la_LIBADD = libcommon.la libblkid.la $(SELINUX_LIBS) + + libmount_la_CFLAGS = \ ++ $(SOLIB_CFLAGS) \ + -I$(ul_libblkid_incdir) \ + -I$(ul_libmount_incdir) \ + -I$(top_srcdir)/libmount/src +@@ -43,6 +44,7 @@ libmount_la_DEPENDENCIES = \ + libmount/src/libmount.h.in + + libmount_la_LDFLAGS = \ ++ $(SOLIB_LDFLAGS) \ + -Wl,--version-script=$(top_srcdir)/libmount/src/libmount.sym \ + -version-info $(LIBMOUNT_VERSION_INFO) + +diff --git a/libuuid/src/Makemodule.am b/libuuid/src/Makemodule.am +index 73f1ba9..a20cb4c 100644 +--- a/libuuid/src/Makemodule.am ++++ b/libuuid/src/Makemodule.am +@@ -29,9 +29,14 @@ libuuid_la_SOURCES = \ + + libuuid_la_DEPENDENCIES = libuuid/src/uuid.sym + libuuid_la_LIBADD = $(SOCKET_LIBS) +-libuuid_la_CFLAGS = -I$(ul_libuuid_incdir) -Ilibuuid/src ++ ++libuuid_la_CFLAGS = \ ++ $(SOLIB_CFLAGS) \ ++ -I$(ul_libuuid_incdir) \ ++ -Ilibuuid/src + + libuuid_la_LDFLAGS = \ ++ $(SOLIB_LDFLAGS) \ + -Wl,--version-script=$(top_srcdir)/libuuid/src/uuid.sym \ + -version-info $(LIBUUID_VERSION_INFO) + +diff --git a/misc-utils/Makemodule.am b/misc-utils/Makemodule.am +index a615047..70a78f2 100644 +--- a/misc-utils/Makemodule.am ++++ b/misc-utils/Makemodule.am +@@ -77,7 +77,8 @@ if BUILD_UUIDD + usrsbin_exec_PROGRAMS += uuidd + dist_man_MANS += misc-utils/uuidd.8 + uuidd_LDADD = $(LDADD) libuuid.la +-uuidd_CFLAGS = $(AM_CFLAGS) -I$(ul_libuuid_incdir) ++uuidd_CFLAGS = $(DAEMON_CFLAGS) $(AM_CFLAGS) -I$(ul_libuuid_incdir) ++uuidd_LDFLAGS = $(DAEMON_LDFLAGS) $(AM_LDFLAGS) + uuidd_SOURCES = misc-utils/uuidd.c + if USE_SOCKET_ACTIVATION + uuidd_SOURCES += misc-utils/sd-daemon.c misc-utils/sd-daemon.h +-- +2.7.4 + diff --git a/SOURCES/0060-fdisk-backport-DOS-logical-partitions-chain-reorder.patch b/SOURCES/0060-fdisk-backport-DOS-logical-partitions-chain-reorder.patch deleted file mode 100644 index 86e577c..0000000 --- a/SOURCES/0060-fdisk-backport-DOS-logical-partitions-chain-reorder.patch +++ /dev/null @@ -1,231 +0,0 @@ -From 81745b42a2722f11006c05de87ff90de08cf8cee Mon Sep 17 00:00:00 2001 -From: Karel Zak <kzak@redhat.com> -Date: Tue, 28 Jun 2016 11:30:21 +0200 -Subject: [PATCH] fdisk: backport DOS logical partitions chain reorder - -... from the current upstream. - -Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1304246 -Signed-off-by: Karel Zak <kzak@redhat.com> ---- - fdisks/fdiskdoslabel.c | 170 +++++++++++++++++++++++++++++++++---------------- - include/c.h | 8 +++ - 2 files changed, 124 insertions(+), 54 deletions(-) - -diff --git a/fdisks/fdiskdoslabel.c b/fdisks/fdiskdoslabel.c -index fe04ac7..b7eb35a 100644 ---- a/fdisks/fdiskdoslabel.c -+++ b/fdisks/fdiskdoslabel.c -@@ -55,6 +55,22 @@ static int MBRbuffer_changed; - #define cround(c, n) (fdisk_context_use_cylinders(c) ? \ - ((n) / fdisk_context_get_units_per_sector(c)) + 1 : (n)) - -+ -+static unsigned long long -+get_abs_partition_start(struct pte *pe) -+{ -+ return pe->offset + get_start_sect(pe->part_table); -+} -+ -+static unsigned long long -+get_abs_partition_end(struct pte *pe) -+{ -+ unsigned long long size; -+ -+ size = get_nr_sects(pe->part_table); -+ return get_abs_partition_start(pe) + size - (size ? 1 : 0); -+} -+ - static void warn_alignment(struct fdisk_context *cxt) - { - if (nowarn) -@@ -1254,67 +1270,113 @@ void dos_list_table_expert(struct fdisk_context *cxt, int extend) - } - } - --/* -- * Fix the chain of logicals. -- * extended_offset is unchanged, the set of sectors used is unchanged -- * The chain is sorted so that sectors increase, and so that -- * starting sectors increase. -- * -- * After this it may still be that cfdisk doesn't like the table. -- * (This is because cfdisk considers expanded parts, from link to -- * end of partition, and these may still overlap.) -- * Now -- * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda -- * may help. -- */ -+ -+static void print_chain_of_logicals(struct fdisk_context *cxt) -+{ -+ size_t i; -+ -+ fputc('\n', stdout); -+ -+ for (i = 4; i < cxt->label->nparts_max; i++) { -+ struct pte *pe = &ptes[i]; -+ -+ fprintf(stderr, "#%02zu EBR [%10ju], " -+ "data[start=%10ju (%10ju), size=%10ju], " -+ "link[start=%10ju (%10ju), size=%10ju]\n", -+ i, (uintmax_t) pe->offset, -+ /* data */ -+ (uintmax_t) get_start_sect(pe->part_table), -+ (uintmax_t) get_abs_partition_start(pe), -+ (uintmax_t) get_nr_sects(pe->part_table), -+ /* link */ -+ (uintmax_t) get_start_sect(pe->ext_pointer), -+ (uintmax_t) (extended_offset + get_start_sect(pe->ext_pointer)), -+ (uintmax_t) get_nr_sects(pe->ext_pointer)); -+ } -+} -+ -+static int cmp_ebr_offsets(const void *a, const void *b) -+{ -+ struct pte *ae = (struct pte *) a, -+ *be = (struct pte *) b; -+ -+ if (ae->offset == 0 && be->offset == 0) -+ return 0; -+ if (ae->offset == 0) -+ return 1; -+ if (be->offset == 0) -+ return -1; -+ -+ return cmp_numbers(ae->offset, be->offset); -+} -+ - static void fix_chain_of_logicals(struct fdisk_context *cxt) - { -- size_t j, oj, ojj, sj, sjj; -- struct partition *pj,*pjj,tmp; -- -- /* Stage 1: sort sectors but leave sector of part 4 */ -- /* (Its sector is the global extended_offset.) */ -- stage1: -- for (j = 5; j < cxt->label->nparts_max - 1; j++) { -- oj = ptes[j].offset; -- ojj = ptes[j+1].offset; -- if (oj > ojj) { -- ptes[j].offset = ojj; -- ptes[j+1].offset = oj; -- pj = ptes[j].part_table; -- set_start_sect(pj, get_start_sect(pj)+oj-ojj); -- pjj = ptes[j+1].part_table; -- set_start_sect(pjj, get_start_sect(pjj)+ojj-oj); -- set_start_sect(ptes[j-1].ext_pointer, -- ojj-extended_offset); -- set_start_sect(ptes[j].ext_pointer, -- oj-extended_offset); -- goto stage1; -+ struct pte *last; -+ size_t i; -+ -+ DBG(CONTEXT, print_chain_of_logicals(cxt)); -+ -+ /* Sort chain by EBR offsets */ -+ qsort(&ptes[4], cxt->label->nparts_max - 4, sizeof(struct pte), -+ cmp_ebr_offsets); -+ -+again: -+ /* Sort data partitions by start */ -+ for (i = 4; i < cxt->label->nparts_max - 1; i++) { -+ struct pte *cur = &ptes[i], -+ *nxt = &ptes[i + 1]; -+ -+ if (get_abs_partition_start(cur) > -+ get_abs_partition_start(nxt)) { -+ -+ struct partition tmp = *cur->part_table; -+ sector_t cur_start = get_abs_partition_start(cur), -+ nxt_start = get_abs_partition_start(nxt); -+ -+ /* swap data partitions */ -+ *cur->part_table = *nxt->part_table; -+ *nxt->part_table = tmp; -+ -+ /* Recount starts according to EBR offsets, the absolute -+ * address still has to be the same! */ -+ set_start_sect(cur->part_table, nxt_start - cur->offset); -+ set_start_sect(nxt->part_table, cur_start - nxt->offset); -+ -+ cur->changed = 1; -+ nxt->changed = 1; -+ goto again; - } - } - -- /* Stage 2: sort starting sectors */ -- stage2: -- for (j = 4; j < cxt->label->nparts_max - 1; j++) { -- pj = ptes[j].part_table; -- pjj = ptes[j+1].part_table; -- sj = get_start_sect(pj); -- sjj = get_start_sect(pjj); -- oj = ptes[j].offset; -- ojj = ptes[j+1].offset; -- if (oj+sj > ojj+sjj) { -- tmp = *pj; -- *pj = *pjj; -- *pjj = tmp; -- set_start_sect(pj, ojj+sjj-oj); -- set_start_sect(pjj, oj+sj-ojj); -- goto stage2; -- } -+ /* Update EBR links */ -+ for (i = 4; i < cxt->label->nparts_max - 1; i++) { -+ struct pte *cur = &ptes[i], -+ *nxt = &ptes[i + 1]; -+ -+ sector_t noff = nxt->offset - extended_offset, -+ ooff = get_start_sect(cur->ext_pointer); -+ -+ if (noff == ooff) -+ continue; -+ -+ DBG(CONTEXT, dbgprint("DOS: fix EBR [%10ju] link %ju -> %ju", -+ (uintmax_t) cur->offset, -+ (uintmax_t) ooff, (uintmax_t) noff)); -+ -+ set_partition(cxt, i, 1, nxt->offset, -+ get_abs_partition_end(nxt), -+ EXTENDED); -+ } -+ -+ /* always terminate the chain ! */ -+ last = &ptes[cxt->label->nparts_max - 1]; -+ if (last) { -+ clear_partition(last->ext_pointer); -+ last->changed = 1; - } - -- /* Probably something was changed */ -- for (j = 4; j < cxt->label->nparts_max; j++) -- ptes[j].changed = 1; -+ DBG(CONTEXT, print_chain_of_logicals(cxt)); - } - - void dos_fix_partition_table_order(struct fdisk_context *cxt) -diff --git a/include/c.h b/include/c.h -index a50e8a5..ef2ea69 100644 ---- a/include/c.h -+++ b/include/c.h -@@ -110,6 +110,14 @@ - _max1 > _max2 ? _max1 : _max2; }) - #endif - -+#ifndef cmp_numbers -+# define cmp_numbers(x, y) __extension__ ({ \ -+ __typeof__(x) _a = (x); \ -+ __typeof__(y) _b = (y); \ -+ (void) (&_a == &_b); \ -+ _a == _b ? 0 : _a > _b ? 1 : -1; }) -+#endif -+ - #ifndef offsetof - #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) - #endif --- -2.7.4 - diff --git a/SOURCES/0061-libmount-be-more-restrictive-about-valid-tag-names.patch b/SOURCES/0061-libmount-be-more-restrictive-about-valid-tag-names.patch new file mode 100644 index 0000000..7e5d394 --- /dev/null +++ b/SOURCES/0061-libmount-be-more-restrictive-about-valid-tag-names.patch @@ -0,0 +1,183 @@ +From f5ef29a5b5c51fe2039352dabcc4946fa2f55861 Mon Sep 17 00:00:00 2001 +From: Karel Zak <kzak@redhat.com> +Date: Tue, 2 Jul 2013 10:46:10 +0200 +Subject: [PATCH 61/84] libmount: be more restrictive about valid tag names + + # mount DUMMY=filename.img /mnt + +The 'DUMMY=filename.img' is a filename and should not be +interpreted as tag name. The valid tag names are LABEL, UUID, +PARTLABEL and PARTUUID only. + +Upstream: http://github.com/karelzak/util-linux/commit/2c6b25f01802808b142d450af3352605720899da +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1248003 +Signed-off-by: Karel Zak <kzak@redhat.com> +--- + libmount/src/cache.c | 29 ++++++++++++----------------- + libmount/src/fs.c | 9 ++++++--- + libmount/src/mountP.h | 2 ++ + libmount/src/tab.c | 20 ++++++++------------ + libmount/src/utils.c | 12 ++++++++++++ + 5 files changed, 40 insertions(+), 32 deletions(-) + +diff --git a/libmount/src/cache.c b/libmount/src/cache.c +index 7b65122..43a4daf 100644 +--- a/libmount/src/cache.c ++++ b/libmount/src/cache.c +@@ -583,22 +583,18 @@ error: + char *mnt_resolve_spec(const char *spec, struct libmnt_cache *cache) + { + char *cn = NULL; ++ char *t = NULL, *v = NULL; + + if (!spec) + return NULL; + +- if (strchr(spec, '=')) { +- char *tag, *val; +- +- if (!blkid_parse_tag_string(spec, &tag, &val)) { +- cn = mnt_resolve_tag(tag, val, cache); +- +- free(tag); +- free(val); +- } +- } else ++ if (blkid_parse_tag_string(spec, &t, &v) == 0 && mnt_valid_tagname(t)) ++ cn = mnt_resolve_tag(t, v, cache); ++ else + cn = mnt_resolve_path(spec, cache); + ++ free(t); ++ free(v); + return cn; + } + +@@ -663,6 +659,7 @@ int test_read_tags(struct libmnt_test *ts, int argc, char *argv[]) + + while(fgets(line, sizeof(line), stdin)) { + size_t sz = strlen(line); ++ char *t = NULL, *v = NULL; + + if (sz > 0 && line[sz - 1] == '\n') + line[sz - 1] = '\0'; +@@ -674,16 +671,14 @@ int test_read_tags(struct libmnt_test *ts, int argc, char *argv[]) + if (mnt_cache_read_tags(cache, line) < 0) + fprintf(stderr, "%s: read tags failed\n", line); + +- } else if (strchr(line, '=')) { +- char *tag, *val; ++ } else if (blkid_parse_tag_string(line, &t, &v) == 0) { + const char *cn = NULL; + +- if (!blkid_parse_tag_string(line, &tag, &val)) { +- cn = cache_find_tag(cache, tag, val); ++ if (mnt_valid_tagname(t)) ++ cn = cache_find_tag(cache, t, v); ++ free(t); ++ free(v); + +- free(tag); +- free(val); +- } + if (cn) + printf("%s: %s\n", line, cn); + else +diff --git a/libmount/src/fs.c b/libmount/src/fs.c +index c95cdc7..75e3bbb 100644 +--- a/libmount/src/fs.c ++++ b/libmount/src/fs.c +@@ -318,9 +318,12 @@ int __mnt_fs_set_source_ptr(struct libmnt_fs *fs, char *source) + + assert(fs); + +- if (source && *source != '/' && strchr(source, '=')) { +- if (blkid_parse_tag_string(source, &t, &v) != 0) +- return -1; ++ if (source && blkid_parse_tag_string(source, &t, &v) == 0 && ++ !mnt_valid_tagname(t)) { ++ /* parsable but unknown tag -- ignore */ ++ free(t); ++ free(v); ++ t = v = NULL; + } + + if (fs->source != source) +diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h +index e064a68..7b0848f 100644 +--- a/libmount/src/mountP.h ++++ b/libmount/src/mountP.h +@@ -136,6 +136,8 @@ extern int startswith(const char *s, const char *sx) + + extern char *stripoff_last_component(char *path); + ++extern int mnt_valid_tagname(const char *tagname); ++ + extern int is_file_empty(const char *name); + + extern int mkdir_p(const char *path, mode_t mode); +diff --git a/libmount/src/tab.c b/libmount/src/tab.c +index e3524a8..1ba1eec 100644 +--- a/libmount/src/tab.c ++++ b/libmount/src/tab.c +@@ -801,7 +801,8 @@ struct libmnt_fs *mnt_table_find_tag(struct libmnt_table *tb, const char *tag, + struct libmnt_fs *mnt_table_find_source(struct libmnt_table *tb, + const char *source, int direction) + { +- struct libmnt_fs *fs = NULL; ++ struct libmnt_fs *fs; ++ char *t = NULL, *v = NULL; + + assert(tb); + +@@ -812,18 +813,13 @@ struct libmnt_fs *mnt_table_find_source(struct libmnt_table *tb, + + DBG(TAB, mnt_debug_h(tb, "lookup SOURCE: '%s'", source)); + +- if (source && *source && strchr(source, '=')) { +- char *tag, *val; +- +- if (blkid_parse_tag_string(source, &tag, &val) == 0) { +- +- fs = mnt_table_find_tag(tb, tag, val, direction); +- +- free(tag); +- free(val); +- } +- } else ++ if (blkid_parse_tag_string(source, &t, &v) || !mnt_valid_tagname(t)) + fs = mnt_table_find_srcpath(tb, source, direction); ++ else ++ fs = mnt_table_find_tag(tb, t, v, direction); ++ ++ free(t); ++ free(v); + + return fs; + } +diff --git a/libmount/src/utils.c b/libmount/src/utils.c +index 6a444ad..9305bb8 100644 +--- a/libmount/src/utils.c ++++ b/libmount/src/utils.c +@@ -65,6 +65,18 @@ int is_file_empty(const char *name) + return (stat(name, &st) != 0 || st.st_size == 0); + } + ++int mnt_valid_tagname(const char *tagname) ++{ ++ if (tagname && *tagname && ( ++ strcmp("UUID", tagname) == 0 || ++ strcmp("LABEL", tagname) == 0 || ++ strcmp("PARTUUID", tagname) == 0 || ++ strcmp("PARTLABEL", tagname) == 0)) ++ return 1; ++ ++ return 0; ++} ++ + int mnt_parse_offset(const char *str, size_t len, uintmax_t *res) + { + char *p; +-- +2.7.4 + diff --git a/SOURCES/0062-mount-umount-swapon-fsck-lsblk-findmnt-ignore-malfor.patch b/SOURCES/0062-mount-umount-swapon-fsck-lsblk-findmnt-ignore-malfor.patch new file mode 100644 index 0000000..5bfb445 --- /dev/null +++ b/SOURCES/0062-mount-umount-swapon-fsck-lsblk-findmnt-ignore-malfor.patch @@ -0,0 +1,172 @@ +From 28663e752e125da99f8636ea0227d168f1e0e6aa Mon Sep 17 00:00:00 2001 +From: Karel Zak <kzak@redhat.com> +Date: Thu, 15 Oct 2015 11:53:44 +0200 +Subject: [PATCH 62/84] mount, umount, swapon, fsck, lsblk, findmnt: ignore + malformed lines + +The libmount provides way how to deal with parsing errors in fstab -- +on error callback function is executed and according to the return +libmount manipulate with the malformed line, possible are three +states: + + 1/ fatal error; all file ignored (callback rc < 0) + 2/ recoverable error; malformed line ignored (callback rc > 0) + 3/ ignore the error (callback rc == 0) + +The 2/ is the default if no callback specified. + +Unfortunately our utils uses 3/. The correct way is to use 2/. + +Upstream: http://github.com/karelzak/util-linux/commit/1cd9d0d7463850ef6b16a78b8a55e56dbf9a8db1 +Upstream: http://github.com/karelzak/util-linux/commit/1bb02a2da9f1bf7d80b352d540b29371099ab570 +Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1271850 +Signed-off-by: Karel Zak <kzak@redhat.com> +--- + disk-utils/fsck.c | 2 +- + libmount/src/tab_parse.c | 2 +- + misc-utils/findmnt.c | 2 +- + misc-utils/lsblk.c | 11 +++++++++++ + sys-utils/mount.c | 2 +- + sys-utils/swapon-common.c | 11 +++++++++++ + sys-utils/umount.c | 2 +- + 7 files changed, 27 insertions(+), 5 deletions(-) + +diff --git a/disk-utils/fsck.c b/disk-utils/fsck.c +index 6e3a2c0..3ef8e5b 100644 +--- a/disk-utils/fsck.c ++++ b/disk-utils/fsck.c +@@ -421,7 +421,7 @@ static int parser_errcb(struct libmnt_table *tb __attribute__ ((__unused__)), + const char *filename, int line) + { + warnx(_("%s: parse error at line %d -- ignore"), filename, line); +- return 0; ++ return 1; + } + + /* +diff --git a/libmount/src/tab_parse.c b/libmount/src/tab_parse.c +index e930fd8..987e671 100644 +--- a/libmount/src/tab_parse.c ++++ b/libmount/src/tab_parse.c +@@ -540,7 +540,7 @@ int mnt_table_parse_stream(struct libmnt_table *tb, FILE *f, const char *filenam + } + if (rc) { + mnt_free_fs(fs); +- if (rc == 1) ++ if (rc > 0) + continue; /* recoverable error */ + if (feof(f)) + break; +diff --git a/misc-utils/findmnt.c b/misc-utils/findmnt.c +index 615ba08..f16da91 100644 +--- a/misc-utils/findmnt.c ++++ b/misc-utils/findmnt.c +@@ -752,7 +752,7 @@ static int parser_errcb(struct libmnt_table *tb __attribute__ ((__unused__)), + const char *filename, int line) + { + warnx(_("%s: parse error at line %d"), filename, line); +- return 0; ++ return 1; + } + + static char **append_tabfile(char **files, int *nfiles, char *filename) +diff --git a/misc-utils/lsblk.c b/misc-utils/lsblk.c +index 9e12a90..cd28c1d 100644 +--- a/misc-utils/lsblk.c ++++ b/misc-utils/lsblk.c +@@ -337,6 +337,15 @@ static char *get_device_path(struct blkdev_cxt *cxt) + return xstrdup(path); + } + ++static int table_parser_errcb(struct libmnt_table *tb __attribute__((__unused__)), ++ const char *filename, int line) ++{ ++ if (filename) ++ warnx(_("%s: parse error: ignore entry at line %d."), ++ filename, line); ++ return 1; ++} ++ + static int is_active_swap(const char *filename) + { + if (!swaps) { +@@ -346,6 +355,7 @@ static int is_active_swap(const char *filename) + if (!mntcache) + mntcache = mnt_new_cache(); + ++ mnt_table_set_parser_errcb(swaps, table_parser_errcb); + mnt_table_set_cache(swaps, mntcache); + mnt_table_parse_swaps(swaps, NULL); + } +@@ -368,6 +378,7 @@ static char *get_device_mountpoint(struct blkdev_cxt *cxt) + if (!mntcache) + mntcache = mnt_new_cache(); + ++ mnt_table_set_parser_errcb(mtab, table_parser_errcb); + mnt_table_set_cache(mtab, mntcache); + mnt_table_parse_mtab(mtab, NULL); + } +diff --git a/sys-utils/mount.c b/sys-utils/mount.c +index 0998b01..f332070 100644 +--- a/sys-utils/mount.c ++++ b/sys-utils/mount.c +@@ -101,7 +101,7 @@ static int table_parser_errcb(struct libmnt_table *tb __attribute__((__unused__) + if (filename) + warnx(_("%s: parse error: ignore entry at line %d."), + filename, line); +- return 0; ++ return 1; + } + + /* +diff --git a/sys-utils/swapon-common.c b/sys-utils/swapon-common.c +index 5c95ef3..5f14ddb 100644 +--- a/sys-utils/swapon-common.c ++++ b/sys-utils/swapon-common.c +@@ -11,12 +11,22 @@ static struct libmnt_table *swaps, *fstab; + + struct libmnt_cache *mntcache; + ++static int table_parser_errcb(struct libmnt_table *tb __attribute__((__unused__)), ++ const char *filename, int line) ++{ ++ if (filename) ++ warnx(_("%s: parse error: ignore entry at line %d."), ++ filename, line); ++ return 1; ++} ++ + struct libmnt_table *get_fstab(void) + { + if (!fstab) { + fstab = mnt_new_table(); + if (!fstab) + return NULL; ++ mnt_table_set_parser_errcb(fstab, table_parser_errcb); + mnt_table_set_cache(fstab, mntcache); + if (mnt_table_parse_fstab(fstab, NULL) != 0) + return NULL; +@@ -32,6 +42,7 @@ struct libmnt_table *get_swaps(void) + if (!swaps) + return NULL; + mnt_table_set_cache(swaps, mntcache); ++ mnt_table_set_parser_errcb(swaps, table_parser_errcb); + if (mnt_table_parse_swaps(swaps, NULL) != 0) + return NULL; + } +diff --git a/sys-utils/umount.c b/sys-utils/umount.c +index 1bd275f..9c47744 100644 +--- a/sys-utils/umount.c ++++ b/sys-utils/umount.c +@@ -45,7 +45,7 @@ static int table_parser_errcb(struct libmnt_table *tb __attribute__((__unused__) + if (filename) + warnx(_("%s: parse error: ignore entry at line %d."), + filename, line); +- return 0; ++ return 1; + } + + +-- +2.7.4 + diff --git a/SOURCES/0063-login-mount-fix-__SC_GETPW_R_SIZE_MAX-usage.patch b/SOURCES/0063-login-mount-fix-__SC_GETPW_R_SIZE_MAX-usage.patch new file mode 100644 index 0000000..73f80e0 --- /dev/null +++ b/SOURCES/0063-login-mount-fix-__SC_GETPW_R_SIZE_MAX-usage.patch @@ -0,0 +1,146 @@ +From 3d1333293ef48117060cd4e285e9c49a6d061e83 Mon Sep 17 00:00:00 2001 +From: Karel Zak <kzak@redhat.com> +Date: Tue, 15 Dec 2015 12:25:56 +0100 +Subject: [PATCH 63/84] login, mount: fix __SC_GETPW_R_SIZE_MAX usage + +sysconf(_SC_GETPW_R_SIZE_MAX) returns initial suggested size for pwd +buffer (see getpwnam_r man page or POSIX). This is not large enough in +some cases. + +Yes, this sysconf option is misnamed (should be _SC_GETPW_R_SIZE_MIN). + +Upstream: http://github.com/karelzak/util-linux/commit/f7ac9e71b18fa7314151f2ab65ee0bdd2ea89c07 +Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1290689 +Signed-off-by: Karel Zak <kzak@redhat.com> +--- + include/c.h | 7 +++++++ + libmount/src/utils.c | 25 ++++++------------------- + login-utils/login.c | 12 ++---------- + 3 files changed, 15 insertions(+), 29 deletions(-) + +diff --git a/include/c.h b/include/c.h +index a50e8a5..7b59ce8 100644 +--- a/include/c.h ++++ b/include/c.h +@@ -300,4 +300,11 @@ static inline int usleep(useconds_t usec) + # define SEEK_HOLE 4 + #endif + ++/* ++ * Note that sysconf(_SC_GETPW_R_SIZE_MAX) returns *initial* suggested size for ++ * pwd buffer and in some cases it is not large enough. See POSIX and ++ * getpwnam_r man page for more details. ++ */ ++#define UL_GETPW_BUFSIZ (16 * 1024) ++ + #endif /* UTIL_LINUX_C_H */ +diff --git a/libmount/src/utils.c b/libmount/src/utils.c +index 9305bb8..7c6f5b1 100644 +--- a/libmount/src/utils.c ++++ b/libmount/src/utils.c +@@ -538,16 +538,6 @@ int mnt_get_filesystems(char ***filesystems, const char *pattern) + return rc; + } + +-static size_t get_pw_record_size(void) +-{ +-#ifdef _SC_GETPW_R_SIZE_MAX +- long sz = sysconf(_SC_GETPW_R_SIZE_MAX); +- if (sz > 0) +- return sz; +-#endif +- return 16384; +-} +- + /* + * Returns allocated string with username or NULL. + */ +@@ -555,14 +545,13 @@ char *mnt_get_username(const uid_t uid) + { + struct passwd pwd; + struct passwd *res; +- size_t sz = get_pw_record_size(); + char *buf, *username = NULL; + +- buf = malloc(sz); ++ buf = malloc(UL_GETPW_BUFSIZ); + if (!buf) + return NULL; + +- if (!getpwuid_r(uid, &pwd, buf, sz, &res) && res) ++ if (!getpwuid_r(uid, &pwd, buf, UL_GETPW_BUFSIZ, &res) && res) + username = strdup(pwd.pw_name); + + free(buf); +@@ -574,17 +563,16 @@ int mnt_get_uid(const char *username, uid_t *uid) + int rc = -1; + struct passwd pwd; + struct passwd *pw; +- size_t sz = get_pw_record_size(); + char *buf; + + if (!username || !uid) + return -EINVAL; + +- buf = malloc(sz); ++ buf = malloc(UL_GETPW_BUFSIZ); + if (!buf) + return -ENOMEM; + +- if (!getpwnam_r(username, &pwd, buf, sz, &pw) && pw) { ++ if (!getpwnam_r(username, &pwd, buf, UL_GETPW_BUFSIZ, &pw) && pw) { + *uid= pw->pw_uid; + rc = 0; + } else { +@@ -602,17 +590,16 @@ int mnt_get_gid(const char *groupname, gid_t *gid) + int rc = -1; + struct group grp; + struct group *gr; +- size_t sz = get_pw_record_size(); + char *buf; + + if (!groupname || !gid) + return -EINVAL; + +- buf = malloc(sz); ++ buf = malloc(UL_GETPW_BUFSIZ); + if (!buf) + return -ENOMEM; + +- if (!getgrnam_r(groupname, &grp, buf, sz, &gr) && gr) { ++ if (!getgrnam_r(groupname, &grp, buf, UL_GETPW_BUFSIZ, &gr) && gr) { + *gid= gr->gr_gid; + rc = 0; + } else { +diff --git a/login-utils/login.c b/login-utils/login.c +index a59dd3a..e0e960f 100644 +--- a/login-utils/login.c ++++ b/login-utils/login.c +@@ -671,22 +671,14 @@ static struct passwd *get_passwd_entry(const char *username, + struct passwd *pwd) + { + struct passwd *res = NULL; +- size_t sz = 16384; + int x; + + if (!pwdbuf || !username) + return NULL; + +-#ifdef _SC_GETPW_R_SIZE_MAX +- { +- long xsz = sysconf(_SC_GETPW_R_SIZE_MAX); +- if (xsz > 0) +- sz = (size_t) xsz; +- } +-#endif +- *pwdbuf = xrealloc(*pwdbuf, sz); ++ *pwdbuf = xrealloc(*pwdbuf, UL_GETPW_BUFSIZ); + +- x = getpwnam_r(username, pwd, *pwdbuf, sz, &res); ++ x = getpwnam_r(username, pwd, *pwdbuf, UL_GETPW_BUFSIZ, &res); + if (!res) { + errno = x; + return NULL; +-- +2.7.4 + diff --git a/SOURCES/0064-bash-completion-use-n-as-IFS-when-ask-for-filenames.patch b/SOURCES/0064-bash-completion-use-n-as-IFS-when-ask-for-filenames.patch new file mode 100644 index 0000000..6e63208 --- /dev/null +++ b/SOURCES/0064-bash-completion-use-n-as-IFS-when-ask-for-filenames.patch @@ -0,0 +1,623 @@ +From 28907c1a50132c9a308b8d2c22bf4905041c446f Mon Sep 17 00:00:00 2001 +From: Karel Zak <kzak@redhat.com> +Date: Mon, 30 Sep 2013 15:49:00 +0200 +Subject: [PATCH 64/84] bash-completion: use '\n' as IFS when ask for filenames +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The bash completion for more(1) treats the space-separated pieces of +filenames as different files. + + $ touch foo\ bar + $ more foo<TAB> + bar foo + +Upstream: http://github.com/karelzak/util-linux/commit/ce3e6b15e2c4478b2df9a7016c168b16325abfb0 +Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1296366 +Reported-by: Ángel González <ingenit@zoho.com> +Signed-off-by: Karel Zak <kzak@redhat.com> +--- + bash-completion/blkid | 1 + + bash-completion/colcrt | 1 + + bash-completion/column | 1 + + bash-completion/cytune | 1 + + bash-completion/dmesg | 1 + + bash-completion/fallocate | 1 + + bash-completion/findmnt | 1 + + bash-completion/flock | 1 + + bash-completion/fsck.cramfs | 1 + + bash-completion/hexdump | 1 + + bash-completion/hwclock | 1 + + bash-completion/ionice | 1 + + bash-completion/last | 1 + + bash-completion/ldattach | 1 + + bash-completion/logger | 1 + + bash-completion/look | 1 + + bash-completion/losetup | 1 + + bash-completion/lscpu | 1 + + bash-completion/lslocks | 1 + + bash-completion/mcookie | 1 + + bash-completion/mkfs.cramfs | 1 + + bash-completion/mkswap | 1 + + bash-completion/more | 2 ++ + bash-completion/mountpoint | 1 + + bash-completion/namei | 1 + + bash-completion/nsenter | 1 + + bash-completion/pg | 1 + + bash-completion/pivot_root | 1 + + bash-completion/readprofile | 1 + + bash-completion/rename | 1 + + bash-completion/rev | 1 + + bash-completion/script | 1 + + bash-completion/scriptreplay | 1 + + bash-completion/setterm | 1 + + bash-completion/sfdisk | 1 + + bash-completion/su | 1 + + bash-completion/swaplabel | 1 + + bash-completion/tailf | 1 + + bash-completion/tunelp | 1 + + bash-completion/ul | 1 + + bash-completion/utmpdump | 1 + + bash-completion/uuidd | 3 +++ + bash-completion/wall | 1 + + bash-completion/wdctl | 1 + + bash-completion/whereis | 1 + + 45 files changed, 48 insertions(+) + +diff --git a/bash-completion/blkid b/bash-completion/blkid +index b439328..9f97dd9 100644 +--- a/bash-completion/blkid ++++ b/bash-completion/blkid +@@ -6,6 +6,7 @@ _blkid_module() + prev="${COMP_WORDS[COMP_CWORD-1]}" + case $prev in + '-c') ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/colcrt b/bash-completion/colcrt +index f9e4c33..c66d7e6 100644 +--- a/bash-completion/colcrt ++++ b/bash-completion/colcrt +@@ -19,6 +19,7 @@ _colcrt_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/column b/bash-completion/column +index f5cb86b..3af8e73 100644 +--- a/bash-completion/column ++++ b/bash-completion/column +@@ -30,6 +30,7 @@ _column_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/cytune b/bash-completion/cytune +index 4f42838..f685c88 100644 +--- a/bash-completion/cytune ++++ b/bash-completion/cytune +@@ -33,6 +33,7 @@ _cytune_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- ${cur:-"/dev/tty"}) ) + return 0 +diff --git a/bash-completion/dmesg b/bash-completion/dmesg +index 60ecc1a..eab41ba 100644 +--- a/bash-completion/dmesg ++++ b/bash-completion/dmesg +@@ -6,6 +6,7 @@ _dmesg_module() + prev="${COMP_WORDS[COMP_CWORD-1]}" + case $prev in + '-F'|'--file') ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/fallocate b/bash-completion/fallocate +index 5007b60..2c6e4cb 100644 +--- a/bash-completion/fallocate ++++ b/bash-completion/fallocate +@@ -20,6 +20,7 @@ _fallocate_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/findmnt b/bash-completion/findmnt +index 9386d8f..3ed331a 100644 +--- a/bash-completion/findmnt ++++ b/bash-completion/findmnt +@@ -18,6 +18,7 @@ _findmnt_module() + return 0 + ;; + '-F'|'--tab-file') ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/flock b/bash-completion/flock +index 8cd60d3..8e7f8b8 100644 +--- a/bash-completion/flock ++++ b/bash-completion/flock +@@ -38,6 +38,7 @@ _flock_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- ${cur:-"/"}) ) + return 0 +diff --git a/bash-completion/fsck.cramfs b/bash-completion/fsck.cramfs +index 84f6f31..acf6564 100644 +--- a/bash-completion/fsck.cramfs ++++ b/bash-completion/fsck.cramfs +@@ -6,6 +6,7 @@ _fsck.cramfs_module() + prev="${COMP_WORDS[COMP_CWORD-1]}" + case $prev in + '-x'|'--destination') ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -o dirnames -- ${cur:-"/"}) ) + return 0 +diff --git a/bash-completion/hexdump b/bash-completion/hexdump +index 0c91187..c17bcae 100644 +--- a/bash-completion/hexdump ++++ b/bash-completion/hexdump +@@ -28,6 +28,7 @@ _hexdump_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/hwclock b/bash-completion/hwclock +index 0c4ebaf..de1ac20 100644 +--- a/bash-completion/hwclock ++++ b/bash-completion/hwclock +@@ -6,6 +6,7 @@ _hwclock_module() + prev="${COMP_WORDS[COMP_CWORD-1]}" + case $prev in + '-f'|'--rtc'|'--adjfile') ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/ionice b/bash-completion/ionice +index 3a01c51..1b1c5fe 100644 +--- a/bash-completion/ionice ++++ b/bash-completion/ionice +@@ -30,6 +30,7 @@ _ionice_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/last b/bash-completion/last +index 493051e..c93be3d 100644 +--- a/bash-completion/last ++++ b/bash-completion/last +@@ -6,6 +6,7 @@ _last_module() + prev="${COMP_WORDS[COMP_CWORD-1]}" + case $prev in + '-f') ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/ldattach b/bash-completion/ldattach +index 830142d..0b9d260 100644 +--- a/bash-completion/ldattach ++++ b/bash-completion/ldattach +@@ -42,6 +42,7 @@ _ldattach_module() + return 0 + ;; + /*) ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/logger b/bash-completion/logger +index f46be8a..963abc7 100644 +--- a/bash-completion/logger ++++ b/bash-completion/logger +@@ -6,6 +6,7 @@ _logger_module() + prev="${COMP_WORDS[COMP_CWORD-1]}" + case $prev in + '-f'|'--file') ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/look b/bash-completion/look +index e8676ba..303a756 100644 +--- a/bash-completion/look ++++ b/bash-completion/look +@@ -20,6 +20,7 @@ _look_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/losetup b/bash-completion/losetup +index 75240b8..874c549 100644 +--- a/bash-completion/losetup ++++ b/bash-completion/losetup +@@ -60,6 +60,7 @@ _losetup_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/lscpu b/bash-completion/lscpu +index bce07c4..244b418 100644 +--- a/bash-completion/lscpu ++++ b/bash-completion/lscpu +@@ -41,6 +41,7 @@ _lscpu_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/lslocks b/bash-completion/lslocks +index 337d07e..c9cff2c 100644 +--- a/bash-completion/lslocks ++++ b/bash-completion/lslocks +@@ -38,6 +38,7 @@ _lslocks_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/mcookie b/bash-completion/mcookie +index eb3f54b..4345b6e 100644 +--- a/bash-completion/mcookie ++++ b/bash-completion/mcookie +@@ -6,6 +6,7 @@ _mcookie_module() + prev="${COMP_WORDS[COMP_CWORD-1]}" + case $prev in + '-f'|'--file') ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/mkfs.cramfs b/bash-completion/mkfs.cramfs +index 38ab3b6..af74e12 100644 +--- a/bash-completion/mkfs.cramfs ++++ b/bash-completion/mkfs.cramfs +@@ -36,6 +36,7 @@ _mkfs.cramfs_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/mkswap b/bash-completion/mkswap +index c411b30..b72efaf 100644 +--- a/bash-completion/mkswap ++++ b/bash-completion/mkswap +@@ -28,6 +28,7 @@ _mkswap_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/more b/bash-completion/more +index 945c7b3..809cea2 100644 +--- a/bash-completion/more ++++ b/bash-completion/more +@@ -21,6 +21,8 @@ _more_module() + return 0 + ;; + esac ++ ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/mountpoint b/bash-completion/mountpoint +index 8fe27b8..f74efc9 100644 +--- a/bash-completion/mountpoint ++++ b/bash-completion/mountpoint +@@ -20,6 +20,7 @@ _mountpoint_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- ${cur:-"/"}) ) + return 0 +diff --git a/bash-completion/namei b/bash-completion/namei +index 63fb37a..6402735 100644 +--- a/bash-completion/namei ++++ b/bash-completion/namei +@@ -16,6 +16,7 @@ _namei_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/nsenter b/bash-completion/nsenter +index 2970b8d..268f378 100644 +--- a/bash-completion/nsenter ++++ b/bash-completion/nsenter +@@ -40,6 +40,7 @@ _nsenter_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/pg b/bash-completion/pg +index 9b1bad9..8fce130 100644 +--- a/bash-completion/pg ++++ b/bash-completion/pg +@@ -25,6 +25,7 @@ _pg_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/pivot_root b/bash-completion/pivot_root +index 961c883..95df4b4 100644 +--- a/bash-completion/pivot_root ++++ b/bash-completion/pivot_root +@@ -11,6 +11,7 @@ _pivot_root_module() + esac + case $COMP_CWORD in + 1|2) ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -o dirnames -- ${cur:-"/"}) ) + ;; +diff --git a/bash-completion/readprofile b/bash-completion/readprofile +index a5f45f5..bd265a6 100644 +--- a/bash-completion/readprofile ++++ b/bash-completion/readprofile +@@ -6,6 +6,7 @@ _readprofile_module() + prev="${COMP_WORDS[COMP_CWORD-1]}" + case $prev in + '-m'|'--mapfile'|'-p'|'--profile') ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/rename b/bash-completion/rename +index 3842c4d..81365a5 100644 +--- a/bash-completion/rename ++++ b/bash-completion/rename +@@ -24,6 +24,7 @@ _rename_module() + COMPREPLY=( $(compgen -W "replacement" -- $cur) ) + ;; + *) ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + ;; +diff --git a/bash-completion/rev b/bash-completion/rev +index 619c5c4..e5397d5 100644 +--- a/bash-completion/rev ++++ b/bash-completion/rev +@@ -16,6 +16,7 @@ _rev_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/script b/bash-completion/script +index 329fc48..d7efd7e 100644 +--- a/bash-completion/script ++++ b/bash-completion/script +@@ -32,6 +32,7 @@ _script_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/scriptreplay b/bash-completion/scriptreplay +index 2ad7b11..a4aa8a0 100644 +--- a/bash-completion/scriptreplay ++++ b/bash-completion/scriptreplay +@@ -24,6 +24,7 @@ _scriptreplay_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/setterm b/bash-completion/setterm +index 7fa0a4e..a7ef6eb 100644 +--- a/bash-completion/setterm ++++ b/bash-completion/setterm +@@ -45,6 +45,7 @@ _setterm_module() + return 0 + ;; + '-file') ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/sfdisk b/bash-completion/sfdisk +index 0226b04..609104c 100644 +--- a/bash-completion/sfdisk ++++ b/bash-completion/sfdisk +@@ -14,6 +14,7 @@ _sfdisk_module() + return 0 + ;; + '-O'|'-I') ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/su b/bash-completion/su +index e739b56..dad1b5f 100644 +--- a/bash-completion/su ++++ b/bash-completion/su +@@ -38,6 +38,7 @@ _su_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/swaplabel b/bash-completion/swaplabel +index 093169e..08aa9cd 100644 +--- a/bash-completion/swaplabel ++++ b/bash-completion/swaplabel +@@ -24,6 +24,7 @@ _swaplabel_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/tailf b/bash-completion/tailf +index e3dd295..0d4c869 100644 +--- a/bash-completion/tailf ++++ b/bash-completion/tailf +@@ -20,6 +20,7 @@ _tailf_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/tunelp b/bash-completion/tunelp +index 614b235..bd2cce2 100644 +--- a/bash-completion/tunelp ++++ b/bash-completion/tunelp +@@ -44,6 +44,7 @@ _tunelp_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- ${cur:-"/dev/lp"}) ) + return 0 +diff --git a/bash-completion/ul b/bash-completion/ul +index c00e510..449cbe0 100644 +--- a/bash-completion/ul ++++ b/bash-completion/ul +@@ -25,6 +25,7 @@ _ul_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/utmpdump b/bash-completion/utmpdump +index 3b868ce..7e4fd5a 100644 +--- a/bash-completion/utmpdump ++++ b/bash-completion/utmpdump +@@ -16,6 +16,7 @@ _utmpdump_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/uuidd b/bash-completion/uuidd +index c45b067..c8f6697 100644 +--- a/bash-completion/uuidd ++++ b/bash-completion/uuidd +@@ -6,16 +6,19 @@ _uuidd_module() + prev="${COMP_WORDS[COMP_CWORD-1]}" + case $prev in + '-p'|'--pid'|'-s'|'--socket') ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 + ;; + '-T'|'--timeout') ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -W "timeout" -- $cur) ) + return 0 + ;; + '-n'|'--uuids') ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -W "number" -- $cur) ) + return 0 +diff --git a/bash-completion/wall b/bash-completion/wall +index 55d9658..e3145ff 100644 +--- a/bash-completion/wall ++++ b/bash-completion/wall +@@ -20,6 +20,7 @@ _wall_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- $cur) ) + return 0 +diff --git a/bash-completion/wdctl b/bash-completion/wdctl +index 33b4e1f..4f16e76 100644 +--- a/bash-completion/wdctl ++++ b/bash-completion/wdctl +@@ -56,6 +56,7 @@ _wdctl_module() + return 0 + ;; + esac ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -f -- ${cur:-"/dev/"}) ) + return 0 +diff --git a/bash-completion/whereis b/bash-completion/whereis +index 2273a07..0dcbac3 100644 +--- a/bash-completion/whereis ++++ b/bash-completion/whereis +@@ -6,6 +6,7 @@ _whereis_module() + prev="${COMP_WORDS[COMP_CWORD-1]}" + case $prev in + '-B'|'-M'|'-S') ++ local IFS=$'\n' + compopt -o filenames + COMPREPLY=( $(compgen -o dirnames -- ${cur:-"/"}) ) + return 0 +-- +2.7.4 + diff --git a/SOURCES/0065-hwclock-change-audit-message.patch b/SOURCES/0065-hwclock-change-audit-message.patch new file mode 100644 index 0000000..a50d8e2 --- /dev/null +++ b/SOURCES/0065-hwclock-change-audit-message.patch @@ -0,0 +1,31 @@ +From 19b9d9197374c5811e32777ca70a32eef37a1fb0 Mon Sep 17 00:00:00 2001 +From: Karel Zak <kzak@redhat.com> +Date: Thu, 7 Jan 2016 13:23:24 +0100 +Subject: [PATCH 65/84] hwclock: change audit message + +The preferred layout is name=value for audit messages. + +Upstream: http://github.com/karelzak/util-linux/commit/fbed7e09f826e7804e99522cc1dd3cf54c9cdb67 +Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1296521 +References: https://bugzilla.redhat.com/show_bug.cgi?id=1296278 +Signed-off-by: Karel Zak <kzak@redhat.com> +--- + sys-utils/hwclock.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sys-utils/hwclock.c b/sys-utils/hwclock.c +index c7789c8..ac9294b 100644 +--- a/sys-utils/hwclock.c ++++ b/sys-utils/hwclock.c +@@ -1939,7 +1939,7 @@ void __attribute__((__noreturn__)) hwaudit_exit(int status) + { + if (hwaudit_on) { + audit_log_user_message(hwaudit_fd, AUDIT_USYS_CONFIG, +- "changing system time", NULL, NULL, NULL, ++ "op=change-system-time", NULL, NULL, NULL, + status ? 0 : 1); + close(hwaudit_fd); + } +-- +2.7.4 + diff --git a/SOURCES/0066-su-clean-up-groups-initialization.patch b/SOURCES/0066-su-clean-up-groups-initialization.patch new file mode 100644 index 0000000..ebd0225 --- /dev/null +++ b/SOURCES/0066-su-clean-up-groups-initialization.patch @@ -0,0 +1,186 @@ +From b2a41801904c4b281a717dde7f5e146cbd4500b3 Mon Sep 17 00:00:00 2001 +From: Karel Zak <kzak@redhat.com> +Date: Mon, 15 Feb 2016 13:55:37 +0100 +Subject: [PATCH 66/84] su: clean up groups initialization + +This patch does not change any su/runuser behaviour, code changes: + +* don't use huge groups[NGROUPS_MAX]; the array has 256k, but we need + it only occasionally when -G/-g specified. + +* the current code uses groups[0] for -g and the rest for -G, this patch adds + 'gid' to remember -g argument to avoid memmove() + +* add function add_supp_group() to simplify su_main() + +* add note about -G and -g relation to the man pages (undocumented now) + +Upstream: http://github.com/karelzak/util-linux/commit/c619d3d167115990e9228b27851e0cc2faa8f936 +Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1304426 +Signed-off-by: Karel Zak <kzak@redhat.com> +--- + login-utils/runuser.1 | 5 ++-- + login-utils/su-common.c | 68 +++++++++++++++++++++++++++---------------------- + login-utils/su.1 | 5 ++-- + 3 files changed, 44 insertions(+), 34 deletions(-) + +diff --git a/login-utils/runuser.1 b/login-utils/runuser.1 +index 7201ff0..d82dbb0 100644 +--- a/login-utils/runuser.1 ++++ b/login-utils/runuser.1 +@@ -75,8 +75,9 @@ shell. + \fB\-g\fR, \fB\-\-group\fR=\fIgroup\fR\fR + specify the primary group, this option is allowed for root user only + .TP +-\fB\-G\fR, \fB\-\-supp-group\fR=\fIgroup\fR\fR +-specify a supplemental group, this option is allowed for root user only ++.BR \-G , " \-\-supp\-group" = \fIgroup ++Specify a supplemental group. This option is available to the root user only. The first specified ++supplementary group is also used as a primary group if the option \fB\-\-group\fR is unspecified. + .TP + \fB\-\fR, \fB\-l\fR, \fB\-\-login\fR + Starts the shell as login shell with an environment similar to a real +diff --git a/login-utils/su-common.c b/login-utils/su-common.c +index dd87804..d53d690 100644 +--- a/login-utils/su-common.c ++++ b/login-utils/su-common.c +@@ -535,7 +535,7 @@ modify_environment (const struct passwd *pw, const char *shell) + /* Become the user and group(s) specified by PW. */ + + static void +-init_groups (const struct passwd *pw, gid_t *groups, int num_groups) ++init_groups (const struct passwd *pw, gid_t *groups, size_t num_groups) + { + int retval; + +@@ -707,6 +707,28 @@ evaluate_uid(void) + return (uid_t) 0 == ruid && ruid == euid ? 0 : 1; + } + ++static gid_t ++add_supp_group(const char *name, gid_t **groups, size_t *ngroups) ++{ ++ struct group *gr; ++ ++ if (*ngroups >= NGROUPS_MAX) ++ errx(EXIT_FAILURE, ++ P_("specifying more than %d supplemental group is not possible", ++ "specifying more than %d supplemental groups is not possible", ++ NGROUPS_MAX - 1), NGROUPS_MAX - 1); ++ ++ gr = getgrnam(name); ++ if (!gr) ++ errx(EXIT_FAILURE, _("group %s does not exist"), name); ++ ++ *groups = xrealloc(*groups, sizeof(gid_t) * (*ngroups + 1)); ++ (*groups)[*ngroups] = gr->gr_gid; ++ (*ngroups)++; ++ ++ return gr->gr_gid; ++} ++ + int + su_main (int argc, char **argv, int mode) + { +@@ -717,10 +739,12 @@ su_main (int argc, char **argv, int mode) + char *shell = NULL; + struct passwd *pw; + struct passwd pw_copy; +- struct group *gr; +- gid_t groups[NGROUPS_MAX]; +- int num_supp_groups = 0; +- int use_gid = 0; ++ ++ gid_t *groups = NULL; ++ size_t ngroups = 0; ++ bool use_supp = false; ++ bool use_gid = false; ++ gid_t gid = 0; + + static const struct option longopts[] = { + {"command", required_argument, NULL, 'c'}, +@@ -765,23 +789,13 @@ su_main (int argc, char **argv, int mode) + break; + + case 'g': +- gr = getgrnam(optarg); +- if (!gr) +- errx(EXIT_FAILURE, _("group %s does not exist"), optarg); +- use_gid = 1; +- groups[0] = gr->gr_gid; ++ use_gid = true; ++ gid = add_supp_group(optarg, &groups, &ngroups); + break; + + case 'G': +- num_supp_groups++; +- if (num_supp_groups >= NGROUPS_MAX) +- errx(EXIT_FAILURE, +- _("can't specify more than %d supplemental groups"), +- NGROUPS_MAX - 1); +- gr = getgrnam(optarg); +- if (!gr) +- errx(EXIT_FAILURE, _("group %s does not exist"), optarg); +- groups[num_supp_groups] = gr->gr_gid; ++ use_supp = true; ++ add_supp_group(optarg, &groups, &ngroups); + break; + + case 'l': +@@ -852,7 +866,7 @@ su_main (int argc, char **argv, int mode) + break; + } + +- if ((num_supp_groups || use_gid) && restricted) ++ if ((use_supp || use_gid) && restricted) + errx(EXIT_FAILURE, _("only root can specify alternative groups")); + + logindefs_load_defaults = load_config; +@@ -878,16 +892,10 @@ su_main (int argc, char **argv, int mode) + : DEFAULT_SHELL); + endpwent (); + +- if (num_supp_groups && !use_gid) +- { +- pw->pw_gid = groups[1]; +- memmove (groups, groups + 1, sizeof(gid_t) * num_supp_groups); +- } +- else if (use_gid) +- { ++ if (use_supp && !use_gid) + pw->pw_gid = groups[0]; +- num_supp_groups++; +- } ++ else if (use_gid) ++ pw->pw_gid = gid; + + authenticate (pw); + +@@ -912,7 +920,7 @@ su_main (int argc, char **argv, int mode) + shell = xstrdup (shell ? shell : pw->pw_shell); + } + +- init_groups (pw, groups, num_supp_groups); ++ init_groups (pw, groups, ngroups); + + if (!simulate_login || command) + suppress_pam_info = 1; /* don't print PAM info messages */ +diff --git a/login-utils/su.1 b/login-utils/su.1 +index eab1a6f..1f69868 100644 +--- a/login-utils/su.1 ++++ b/login-utils/su.1 +@@ -62,8 +62,9 @@ shell. + \fB\-g\fR, \fB\-\-group\fR=\fIgroup\fR\fR + specify the primary group, this option is allowed for root user only + .TP +-\fB\-G\fR, \fB\-\-supp-group\fR=\fIgroup\fR\fR +-specify a supplemental group, this option is allowed for root user only ++.BR \-G , " \-\-supp\-group" = \fIgroup ++Specify a supplemental group. This option is available to the root user only. The first specified ++supplementary group is also used as a primary group if the option \fB\-\-group\fR is unspecified. + .TP + \fB\-\fR, \fB\-l\fR, \fB\-\-login\fR + Starts the shell as login shell with an environment similar to a real +-- +2.7.4 + diff --git a/SOURCES/0067-lscpu-Fix-model-and-model-name-on-Power-Systems.patch b/SOURCES/0067-lscpu-Fix-model-and-model-name-on-Power-Systems.patch new file mode 100644 index 0000000..9bf633c --- /dev/null +++ b/SOURCES/0067-lscpu-Fix-model-and-model-name-on-Power-Systems.patch @@ -0,0 +1,83 @@ +From 246ab88515fca389c02602521fc765d3e597fd7a Mon Sep 17 00:00:00 2001 +From: Vasant Hegde <hegdevasant@linux.vnet.ibm.com> +Date: Mon, 14 Mar 2016 20:18:07 +0530 +Subject: [PATCH 67/84] lscpu: Fix model and model name on Power Systems + +On Power System, lspcu presently displays system model number instead of +processor model name. 'model' tag in cpuinfo contains system model name, +not processor model. Instead it uses 'cpu' tag for processor model name. +Also it uses 'revision' tag for processor model. + +Fix lspcu so that it displays processor model number. Also display processor +model name. + +cpuinfo output on Power System: + ... + ... + + processor : 127 + cpu : POWER8E (raw), altivec supported + clock : 4322.000000MHz + revision : 2.1 (pvr 004b 0201) + + timebase : 512000000 + platform : PowerNV + model : 8286-42A + machine : PowerNV 8286-42A + firmware : OPAL + +Output without this patch: + Architecture: ppc64le + Byte Order: Little Endian + CPU(s): 128 + On-line CPU(s) list: 0-127 + Thread(s) per core: 8 + Core(s) per socket: 4 + Socket(s): 4 + NUMA node(s): 4 + Model: 8286-42A + ... + ... + +Output with this patch: + Architecture: ppc64le + Byte Order: Little Endian + CPU(s): 128 + On-line CPU(s) list: 0-127 + Thread(s) per core: 8 + Core(s) per socket: 4 + Socket(s): 4 + NUMA node(s): 4 + Model: 2.1 (pvr 004b 0201) + Model name: POWER8E (raw), altivec supported + ... + ... + +Upstream: http://github.com/karelzak/util-linux/commit/3ac03fe4d20558b55635a048d7f2fb0f5e85ee2a +Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1326615 +Signed-off-by: Vasant Hegde <hegdevasant@linux.vnet.ibm.com> +--- + sys-utils/lscpu.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/sys-utils/lscpu.c b/sys-utils/lscpu.c +index 4af8176..68b15af 100644 +--- a/sys-utils/lscpu.c ++++ b/sys-utils/lscpu.c +@@ -355,8 +355,13 @@ read_basicinfo(struct lscpu_desc *desc, struct lscpu_modifier *mod) + else if (lookup(buf, "vendor_id", &desc->vendor)) ; + else if (lookup(buf, "family", &desc->family)) ; + else if (lookup(buf, "cpu family", &desc->family)) ; ++#if defined(__powerpc__) || defined(__powerpc64__) ++ else if (lookup(buf, "revision", &desc->model)) ; ++ else if (lookup(buf, "cpu", &desc->modelname)) ; ++#else + else if (lookup(buf, "model", &desc->model)) ; + else if (lookup(buf, "model name", &desc->modelname)) ; ++#endif + else if (lookup(buf, "stepping", &desc->stepping)) ; + else if (lookup(buf, "cpu MHz", &desc->mhz)) ; + else if (lookup(buf, "flags", &desc->flags)) ; /* x86 */ +-- +2.7.4 + diff --git a/SOURCES/0068-lscpu-use-cpu-and-revision-tag-if-available.patch b/SOURCES/0068-lscpu-use-cpu-and-revision-tag-if-available.patch new file mode 100644 index 0000000..c1962e2 --- /dev/null +++ b/SOURCES/0068-lscpu-use-cpu-and-revision-tag-if-available.patch @@ -0,0 +1,105 @@ +From cd0d8ef86151d72a246d565844d4c0470feb6b20 Mon Sep 17 00:00:00 2001 +From: Ruediger Meier <ruediger.meier@ga-group.nl> +Date: Wed, 16 Mar 2016 13:18:18 +0100 +Subject: [PATCH 68/84] lscpu: use cpu and revision tag if available + +Avoid ifdef which does not work with --sysroot. Our existing test +dumps produce even better output now for ppc and sparc. + +The logic moved to the printing section. + +Upstream: http://github.com/karelzak/util-linux/commit/641350fe822e7f1ac10873dad9a364bdeaba8083 +Upstream: http://github.com/karelzak/util-linux/commit/86c4817e0ea02656ddb62fe27757a9fd4f13b2d3 +Upstream: http://github.com/karelzak/util-linux/commit/c95e3889725389e9d7e24d29c2a71b015959575f +Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1326615 +CC: Vasant Hegde <hegdevasant@linux.vnet.ibm.com> +Signed-off-by: Ruediger Meier <ruediger.meier@ga-group.nl> +Signed-off-by: Karel Zak <kzak@redhat.com> +--- + sys-utils/lscpu.c | 17 ++++++++--------- + tests/expected/lscpu/lscpu-ppc64-POWER7 | 3 ++- + tests/expected/lscpu/lscpu-ppc64-POWER7-64cpu | 3 ++- + 3 files changed, 12 insertions(+), 11 deletions(-) + +diff --git a/sys-utils/lscpu.c b/sys-utils/lscpu.c +index 68b15af..7a00636 100644 +--- a/sys-utils/lscpu.c ++++ b/sys-utils/lscpu.c +@@ -141,6 +141,8 @@ struct lscpu_desc { + char *family; + char *model; + char *modelname; ++ char *revision; /* alternative for model (ppc) */ ++ char *cpu; /* alternative for modelname (ppc, sparc) */ + char *virtflag; /* virtualization flag (vmx, svm) */ + char *hypervisor; /* hypervisor software */ + int hyper; /* hypervisor vendor ID */ +@@ -355,13 +357,8 @@ read_basicinfo(struct lscpu_desc *desc, struct lscpu_modifier *mod) + else if (lookup(buf, "vendor_id", &desc->vendor)) ; + else if (lookup(buf, "family", &desc->family)) ; + else if (lookup(buf, "cpu family", &desc->family)) ; +-#if defined(__powerpc__) || defined(__powerpc64__) +- else if (lookup(buf, "revision", &desc->model)) ; +- else if (lookup(buf, "cpu", &desc->modelname)) ; +-#else + else if (lookup(buf, "model", &desc->model)) ; + else if (lookup(buf, "model name", &desc->modelname)) ; +-#endif + else if (lookup(buf, "stepping", &desc->stepping)) ; + else if (lookup(buf, "cpu MHz", &desc->mhz)) ; + else if (lookup(buf, "flags", &desc->flags)) ; /* x86 */ +@@ -369,6 +366,8 @@ read_basicinfo(struct lscpu_desc *desc, struct lscpu_modifier *mod) + else if (lookup(buf, "type", &desc->flags)) ; /* sparc64 */ + else if (lookup(buf, "bogomips", &desc->bogomips)) ; + else if (lookup(buf, "bogomips per cpu", &desc->bogomips)) ; /* s390 */ ++ else if (lookup(buf, "cpu", &desc->cpu)) ; ++ else if (lookup(buf, "revision", &desc->revision)) ; + else + continue; + } +@@ -1264,10 +1263,10 @@ print_summary(struct lscpu_desc *desc, struct lscpu_modifier *mod) + print_s(_("Vendor ID:"), desc->vendor); + if (desc->family) + print_s(_("CPU family:"), desc->family); +- if (desc->model) +- print_s(_("Model:"), desc->model); +- if (desc->modelname) +- print_s(_("Model name:"), desc->modelname); ++ if (desc->model || desc->revision) ++ print_s(_("Model:"), desc->revision ? desc->revision : desc->model); ++ if (desc->modelname || desc->cpu) ++ print_s(_("Model name:"), desc->cpu ? desc->cpu : desc->modelname); + if (desc->stepping) + print_s(_("Stepping:"), desc->stepping); + if (desc->mhz) +diff --git a/tests/expected/lscpu/lscpu-ppc64-POWER7 b/tests/expected/lscpu/lscpu-ppc64-POWER7 +index 0d6c5ba..9a3c0c9 100644 +--- a/tests/expected/lscpu/lscpu-ppc64-POWER7 ++++ b/tests/expected/lscpu/lscpu-ppc64-POWER7 +@@ -4,7 +4,8 @@ Thread(s) per core: 4 + Core(s) per socket: 1 + Socket(s): 4 + NUMA node(s): 1 +-Model: IBM,8233-E8B ++Model: 2.1 (pvr 003f 0201) ++Model name: POWER7 (architected), altivec supported + L1d cache: 32K + L1i cache: 32K + NUMA node0 CPU(s): 0-15 +diff --git a/tests/expected/lscpu/lscpu-ppc64-POWER7-64cpu b/tests/expected/lscpu/lscpu-ppc64-POWER7-64cpu +index 40e2736..d4ae6c1 100644 +--- a/tests/expected/lscpu/lscpu-ppc64-POWER7-64cpu ++++ b/tests/expected/lscpu/lscpu-ppc64-POWER7-64cpu +@@ -4,7 +4,8 @@ Thread(s) per core: 4 + Core(s) per socket: 1 + Socket(s): 16 + NUMA node(s): 2 +-Model: IBM,8231-E2B ++Model: 2.1 (pvr 003f 0201) ++Model name: POWER7 (architected), altivec supported + L1d cache: 32K + L1i cache: 32K + NUMA node0 CPU(s): 0-63 +-- +2.7.4 + diff --git a/SOURCES/0069-findfs-add-ability-to-work-with-PART-UUID-LABEL-too.patch b/SOURCES/0069-findfs-add-ability-to-work-with-PART-UUID-LABEL-too.patch new file mode 100644 index 0000000..48c3db4 --- /dev/null +++ b/SOURCES/0069-findfs-add-ability-to-work-with-PART-UUID-LABEL-too.patch @@ -0,0 +1,137 @@ +From 2555bd3bad9ea8e7ae40a727f59bb546d2aa2717 Mon Sep 17 00:00:00 2001 +From: Karel Zak <kzak@redhat.com> +Date: Fri, 28 Mar 2014 10:36:05 +0100 +Subject: [PATCH 69/84] findfs: add ability to work with PART{UUID,LABEL}= too + +Upstream: http://github.com/karelzak/util-linux/commit/c48508c2faa356c48c26d7d0070a6f20ae4ba9a0 +Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1335671 +Signed-off-by: Karel Zak <kzak@redhat.com> +--- + misc-utils/findfs.8 | 51 +++++++++++++++++++++++++++++++++++++++------------ + misc-utils/findfs.c | 17 +++++------------ + 2 files changed, 44 insertions(+), 24 deletions(-) + +diff --git a/misc-utils/findfs.8 b/misc-utils/findfs.8 +index 8a6bca1..b92cd45 100644 +--- a/misc-utils/findfs.8 ++++ b/misc-utils/findfs.8 +@@ -7,19 +7,45 @@ + findfs \- find a filesystem by label or UUID + .SH SYNOPSIS + .B findfs +-.BI LABEL= label +-.sp +-.B findfs +-.BI UUID= uuid ++.BI NAME= value + .SH DESCRIPTION + .B findfs +-will search the disks in the system looking for a filesystem which has +-a label matching +-.I label +-or a UUID equal to +-.IR uuid . +-If the filesystem is found, the device name for the filesystem will +-be printed on stdout. ++will search the block devices in the system looking for a filesystem or ++partition with specified tag. The currently supported tags are: ++.TP ++.B LABEL=<label> ++Specifies filesystem label. ++.TP ++.B UUID=<uuid> ++Specifies filesystem UUID. ++.TP ++.B PARTUUID=<uuid> ++Specifies partition UUID. This partition identifier is supported for example for ++GUID Partition Table (GPT) partition tables. ++.TP ++.B PARTLABEL=<label> ++Specifies partition label (name). The partition labels are supported for example for ++GUID Partition Table (GPT) or MAC partition tables. ++.PP ++If the filesystem or partition is found, the device name will be printed on ++stdout. ++ ++The complete overview about filesystems and partitions you can get for example ++by ++.RS ++ ++.br ++.BI "lsblk \-\-fs" ++.br ++ ++.BI "partx --show <disk>" ++.br ++ ++.BI blkid ++.br ++ ++.RE ++ + .PP + .SH AUTHOR + .B findfs +@@ -30,7 +56,8 @@ the util-linux package by Karel Zak (kzak@redhat.com). + enables debug output. + .SH SEE ALSO + .BR blkid (8), +-.BR fsck (8) ++.BR lsblk (8), ++.BR partx (8) + .SH AVAILABILITY + The findfs command is part of the util-linux package and is available from + ftp://ftp.kernel.org/pub/linux/utils/util-linux/. +diff --git a/misc-utils/findfs.c b/misc-utils/findfs.c +index bc4a843..29ca1cb 100644 +--- a/misc-utils/findfs.c ++++ b/misc-utils/findfs.c +@@ -19,8 +19,7 @@ static void __attribute__((__noreturn__)) usage(int rc) + { + FILE *out = rc ? stderr : stdout; + fputs(USAGE_HEADER, out); +- fprintf(out, _(" %1$s [options] LABEL=<label>\n" +- " %1$s [options] UUID=<uuid>\n"), ++ fprintf(out, _(" %s [options] {LABEL,UUID,PARTUUID,PARTLABEL}=<value>\n"), + program_invocation_short_name); + fputs(USAGE_OPTIONS, out); + fputs(USAGE_HELP, out); +@@ -31,7 +30,7 @@ static void __attribute__((__noreturn__)) usage(int rc) + + int main(int argc, char **argv) + { +- char *dev, *tk, *vl; ++ char *dev; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); +@@ -43,23 +42,17 @@ int main(int argc, char **argv) + * with version from e2fsprogs */ + usage(2); + +- if (!strncmp(argv[1], "LABEL=", 6)) { +- tk = "LABEL"; +- vl = argv[1] + 6; +- } else if (!strncmp(argv[1], "UUID=", 5)) { +- tk = "UUID"; +- vl = argv[1] + 5; +- } else if (strcmp(argv[1], "-V") == 0 || ++ if (strcmp(argv[1], "-V") == 0 || + strcmp(argv[1], "--version") == 0) { + printf(UTIL_LINUX_VERSION); + return EXIT_SUCCESS; + } else if (strcmp(argv[1], "-h") == 0 || + strcmp(argv[1], "--help") == 0) { + usage(EXIT_SUCCESS); +- } else ++ } else if (argv[1][0] == '-') + usage(2); + +- dev = blkid_evaluate_tag(tk, vl, NULL); ++ dev = blkid_evaluate_tag(argv[1], NULL, NULL); + if (!dev) + errx(EXIT_FAILURE, _("unable to resolve '%s'"), argv[1]); + +-- +2.7.4 + diff --git a/SOURCES/0070-libblkid-fix-memory-leak-in-blkid_parse_tag_string.patch b/SOURCES/0070-libblkid-fix-memory-leak-in-blkid_parse_tag_string.patch new file mode 100644 index 0000000..4453744 --- /dev/null +++ b/SOURCES/0070-libblkid-fix-memory-leak-in-blkid_parse_tag_string.patch @@ -0,0 +1,44 @@ +From 8af4232ff50154588c75f25a951b5619f05d0421 Mon Sep 17 00:00:00 2001 +From: Karel Zak <kzak@redhat.com> +Date: Tue, 19 Nov 2013 17:52:56 +0100 +Subject: [PATCH 70/84] libblkid: fix memory leak in blkid_parse_tag_string() + +Upstream: http://github.com/karelzak/util-linux/commit/c1178175e7adb35388a3e34495974d7f24f45d5d +Upstream: http://github.com/karelzak/util-linux/commit/aab691cf8deb4a53782a0317b6f96c5d8b61f8e9 +Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1335671 +Signed-off-by: Karel Zak <kzak@redhat.com> +--- + libblkid/src/tag.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/libblkid/src/tag.c b/libblkid/src/tag.c +index 3a70950..3aede04 100644 +--- a/libblkid/src/tag.c ++++ b/libblkid/src/tag.c +@@ -237,14 +237,18 @@ int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val) + goto errout; /* missing closing quote */ + *cp = '\0'; + } +- value = value && *value ? strdup(value) : NULL; +- if (!value) +- goto errout; ++ ++ if (ret_val) { ++ value = *value ? strdup(value) : NULL; ++ if (!value) ++ goto errout; ++ *ret_val = value; ++ } + + if (ret_type) + *ret_type = name; +- if (ret_val) +- *ret_val = value; ++ else ++ free(name); + + return 0; + +-- +2.7.4 + diff --git a/SOURCES/0071-findmnt-don-t-rely-on-st_dev-for-target.patch b/SOURCES/0071-findmnt-don-t-rely-on-st_dev-for-target.patch new file mode 100644 index 0000000..7d1bc7f --- /dev/null +++ b/SOURCES/0071-findmnt-don-t-rely-on-st_dev-for-target.patch @@ -0,0 +1,104 @@ +From 0f66811659aa8fd8b14ade8a80bfecd580962b2d Mon Sep 17 00:00:00 2001 +From: Karel Zak <kzak@redhat.com> +Date: Tue, 10 Mar 2015 12:51:44 +0100 +Subject: [PATCH 71/84] findmnt: don't rely on st_dev for --target + +The overlay filesystem does not provide usable st_dev (in traditional +UNIX way). It's necessary to search in /proc/self/mountinfo to detect +which path element is mountpoint. + +$ findmnt --target /mnt/merged/dir-a/foo +TARGET SOURCE FSTYPE OPTIONS +/mnt/merged overlay overlay rw,relatime,lowerdir=/mnt/low,upperdir=/mnt/high/data,workdir=/mnt/high/work + +Upstream: http://github.com/karelzak/util-linux/commit/cd41b385a06dde70bb45c3143d3459157bda58f8 +Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=587393 +Signed-off-by: Karel Zak <kzak@redhat.com> +--- + libmount/src/utils.c | 6 +++++- + misc-utils/findmnt.8 | 8 ++++++-- + misc-utils/findmnt.c | 17 +++++++++++------ + 3 files changed, 22 insertions(+), 9 deletions(-) + +diff --git a/libmount/src/utils.c b/libmount/src/utils.c +index 7c6f5b1..5783d88 100644 +--- a/libmount/src/utils.c ++++ b/libmount/src/utils.c +@@ -859,7 +859,11 @@ int mnt_open_uniq_filename(const char *filename, char **name) + * This function finds the mountpoint that a given path resides in. @path + * should be canonicalized. The returned pointer should be freed by the caller. + * +- * Returns: allocated string with target of the mounted device or NULL on error ++ * WARNING: the function compares st_dev of the @path elements. This traditional ++ * way maybe be insufficient on filesystems like Linux "overlay". See also ++ * mnt_table_find_target(). ++ * ++ * Returns: allocated string with the target of the mounted device or NULL on error + */ + char *mnt_get_mountpoint(const char *path) + { +diff --git a/misc-utils/findmnt.8 b/misc-utils/findmnt.8 +index 407636e..54739b7 100644 +--- a/misc-utils/findmnt.8 ++++ b/misc-utils/findmnt.8 +@@ -179,8 +179,12 @@ Search in + .IR /etc/fstab . + The output is in the list format (see \fB--list\fR). + .TP +-.BR \-T , " \-\-target \fIdir\fP" +-Explicitly define the mount target (mountpoint directory). ++.BR \-T , " \-\-target \fIpath\fP" ++Explicitly define the mount target (mountpoint directory). If the \fIpath\fR ++is not a mountpoint file or directory than ++.B findmnt ++checks \fIpath\fR elements in reverse order for get the mountpoint (this feature is ++supported only if search in kernel files and unsupported for \fB\-\-fstab\fP). + .TP + .BR \-t , " \-\-types \fIlist\fP" + Limit the set of printed filesystems. More than one type may be +diff --git a/misc-utils/findmnt.c b/misc-utils/findmnt.c +index f16da91..fe899db 100644 +--- a/misc-utils/findmnt.c ++++ b/misc-utils/findmnt.c +@@ -236,9 +236,12 @@ static void set_source_match(const char *data) + set_match(COL_SOURCE, data); + } + +-static void enable_extra_target_match(void) ++/* @tb has to be from kernel (so no fstab or so)! */ ++static void enable_extra_target_match(struct libmnt_table *tb) + { +- char *cn = NULL, *mnt = NULL; ++ char *cn = NULL; ++ const char *tgt = NULL, *mnt = NULL; ++ struct libmnt_fs *fs; + + /* + * Check if match pattern is mountpoint, if not use the +@@ -248,9 +251,11 @@ static void enable_extra_target_match(void) + if (!cn) + return; + +- mnt = mnt_get_mountpoint(cn); +- if (!mnt || strcmp(mnt, cn) == 0) +- return; ++ fs = mnt_table_find_mountpoint(tb, tgt, MNT_ITER_BACKWARD); ++ if (fs) ++ mnt = mnt_fs_get_target(fs); ++ if (mnt && strcmp(mnt, tgt) != 0) ++ set_match(COL_TARGET, xstrdup(mnt)); /* replace the current setting */ + + /* replace the current setting with the real mountpoint */ + set_match(COL_TARGET, mnt); +@@ -1484,7 +1489,7 @@ int main(int argc, char *argv[]) + * try it again with extra functionality for target + * match + */ +- enable_extra_target_match(); ++ enable_extra_target_match(tb); + rc = add_matching_lines(tb, tt, direction); + } + } +-- +2.7.4 + diff --git a/SOURCES/0072-libmount-cleanup-fs-root-detection-code.patch b/SOURCES/0072-libmount-cleanup-fs-root-detection-code.patch new file mode 100644 index 0000000..b0b881d --- /dev/null +++ b/SOURCES/0072-libmount-cleanup-fs-root-detection-code.patch @@ -0,0 +1,201 @@ +From bb3483bf21b9cbe462caaa74fbc03d2eb7845d74 Mon Sep 17 00:00:00 2001 +From: Karel Zak <kzak@redhat.com> +Date: Tue, 10 Mar 2015 13:35:56 +0100 +Subject: [PATCH 72/84] libmount: cleanup fs root detection code + +Upstream: http://github.com/karelzak/util-linux/commit/cc06a01ec551ed2bcd397a5097165b4434179b34 +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=587393 +Signed-off-by: Karel Zak <kzak@redhat.com> +--- + libmount/src/tab.c | 32 ++++++++++++++++++++----- + libmount/src/utils.c | 34 --------------------------- + tests/expected/libmount/utils-fs-root | 1 - + tests/expected/libmount/utils-fs-root-subdir | 1 - + tests/expected/libmount/utils-fs-root-subdir2 | 1 - + tests/ts/libmount/utils | 12 ---------- + 6 files changed, 26 insertions(+), 55 deletions(-) + delete mode 100644 tests/expected/libmount/utils-fs-root + delete mode 100644 tests/expected/libmount/utils-fs-root-subdir + delete mode 100644 tests/expected/libmount/utils-fs-root-subdir2 + +diff --git a/libmount/src/tab.c b/libmount/src/tab.c +index 1ba1eec..10ee7ce 100644 +--- a/libmount/src/tab.c ++++ b/libmount/src/tab.c +@@ -46,6 +46,8 @@ + #include "mountP.h" + #include "strutils.h" + #include "loopdev.h" ++#include "fileutils.h" ++#include "canonicalize.h" + + static int is_mountinfo(struct libmnt_table *tb); + +@@ -900,6 +902,20 @@ struct libmnt_fs *mnt_table_find_devno(struct libmnt_table *tb, + return NULL; + } + ++static char *remove_mountpoint_from_path(const char *path, const char *mnt) ++{ ++ char *res; ++ const char *p; ++ size_t sz; ++ ++ sz = strlen(mnt); ++ p = sz > 1 ? path + sz : path; ++ ++ res = *p ? strdup(p) : strdup("/"); ++ DBG(UTILS, mnt_debug("%s fs-root is %s", path, res)); ++ return res; ++} ++ + /* + * tb: /proc/self/mountinfo + * fs: filesystem +@@ -919,7 +935,8 @@ struct libmnt_fs *mnt_table_get_fs_root(struct libmnt_table *tb, + unsigned long mountflags, + char **fsroot) + { +- char *root = NULL, *mnt = NULL; ++ char *root = NULL; ++ const char *mnt = NULL; + const char *fstype; + struct libmnt_fs *src_fs = NULL; + +@@ -937,10 +954,15 @@ struct libmnt_fs *mnt_table_get_fs_root(struct libmnt_table *tb, + DBG(TAB, mnt_debug("fs-root for bind")); + + src = xsrc = mnt_resolve_spec(mnt_fs_get_source(fs), tb->cache); +- if (src) +- mnt = mnt_get_mountpoint(src); ++ if (src) { ++ struct libmnt_fs *fs = mnt_table_find_mountpoint(tb, ++ src, MNT_ITER_BACKWARD); ++ if (fs) ++ mnt = mnt_fs_get_target(fs); ++ } ++ + if (mnt) +- root = mnt_get_fs_root(src, mnt); ++ root = remove_mountpoint_from_path(src, mnt); + + if (xsrc && !tb->cache) { + free(xsrc); +@@ -1007,11 +1029,9 @@ dflt: + + DBG(TAB, mnt_debug("FS root result: %s", root)); + +- free(mnt); + return src_fs; + err: + free(root); +- free(mnt); + return NULL; + } + +diff --git a/libmount/src/utils.c b/libmount/src/utils.c +index 5783d88..2151ff9 100644 +--- a/libmount/src/utils.c ++++ b/libmount/src/utils.c +@@ -908,28 +908,6 @@ err: + return NULL; + } + +-char *mnt_get_fs_root(const char *path, const char *mnt) +-{ +- char *m = (char *) mnt, *res; +- const char *p; +- size_t sz; +- +- if (!m) +- m = mnt_get_mountpoint(path); +- if (!m) +- return NULL; +- +- sz = strlen(m); +- p = sz > 1 ? path + sz : path; +- +- if (m != mnt) +- free(m); +- +- res = *p ? strdup(p) : strdup("/"); +- DBG(UTILS, mnt_debug("%s fs-root is %s", path, res)); +- return res; +-} +- + /* + * Search for @name kernel command parametr. + * +@@ -1085,17 +1063,6 @@ int test_mountpoint(struct libmnt_test *ts, int argc, char *argv[]) + return 0; + } + +-int test_fsroot(struct libmnt_test *ts, int argc, char *argv[]) +-{ +- char *path = canonicalize_path(argv[1]), +- *mnt = path ? mnt_get_fs_root(path, NULL) : NULL; +- +- printf("%s: %s\n", argv[1], mnt ? : "unknown"); +- free(mnt); +- free(path); +- return 0; +-} +- + int test_filesystems(struct libmnt_test *ts, int argc, char *argv[]) + { + char **filesystems = NULL; +@@ -1170,7 +1137,6 @@ int main(int argc, char *argv[]) + { "--starts-with", test_startswith, "<string> <prefix>" }, + { "--ends-with", test_endswith, "<string> <prefix>" }, + { "--mountpoint", test_mountpoint, "<path>" }, +- { "--fs-root", test_fsroot, "<path>" }, + { "--cd-parent", test_chdir, "<path>" }, + { "--kernel-cmdline",test_kernel_cmdline, "<option> | <option>=" }, + { "--mkdir", test_mkdir, "<path>" }, +diff --git a/tests/expected/libmount/utils-fs-root b/tests/expected/libmount/utils-fs-root +deleted file mode 100644 +index 7746b28..0000000 +--- a/tests/expected/libmount/utils-fs-root ++++ /dev/null +@@ -1 +0,0 @@ +-/proc: / +diff --git a/tests/expected/libmount/utils-fs-root-subdir b/tests/expected/libmount/utils-fs-root-subdir +deleted file mode 100644 +index 09cdb8d..0000000 +--- a/tests/expected/libmount/utils-fs-root-subdir ++++ /dev/null +@@ -1 +0,0 @@ +-/proc/sys/kernel: /sys/kernel +diff --git a/tests/expected/libmount/utils-fs-root-subdir2 b/tests/expected/libmount/utils-fs-root-subdir2 +deleted file mode 100644 +index 2e8b89a..0000000 +--- a/tests/expected/libmount/utils-fs-root-subdir2 ++++ /dev/null +@@ -1 +0,0 @@ +-/etc: /etc +diff --git a/tests/ts/libmount/utils b/tests/ts/libmount/utils +index 6facaad..89ecf10 100755 +--- a/tests/ts/libmount/utils ++++ b/tests/ts/libmount/utils +@@ -64,18 +64,6 @@ ts_init_subtest "mountpoint-root" + ts_valgrind $TESTPROG --mountpoint / &> $TS_OUTPUT + ts_finalize_subtest + +-ts_init_subtest "fs-root" +-ts_valgrind $TESTPROG --fs-root /proc &> $TS_OUTPUT +-ts_finalize_subtest +- +-ts_init_subtest "fs-root-subdir" +-ts_valgrind $TESTPROG --fs-root /proc/sys/kernel &> $TS_OUTPUT +-ts_finalize_subtest +- +-ts_init_subtest "fs-root-subdir2" +-ts_valgrind $TESTPROG --fs-root /etc &> $TS_OUTPUT +-ts_finalize_subtest +- + ts_init_subtest "kernel-cmdline" + export LIBMOUNT_KERNEL_CMDLINE="$TS_SELF/files/kernel_cmdline" + ts_valgrind $TESTPROG --kernel-cmdline selinux= &>> $TS_OUTPUT +-- +2.7.4 + diff --git a/SOURCES/0073-libmount-mark-overlay-as-pseudo-FS.patch b/SOURCES/0073-libmount-mark-overlay-as-pseudo-FS.patch new file mode 100644 index 0000000..db6ce86 --- /dev/null +++ b/SOURCES/0073-libmount-mark-overlay-as-pseudo-FS.patch @@ -0,0 +1,27 @@ +From 346b97a27e817a001c71d45400f17429bd82b364 Mon Sep 17 00:00:00 2001 +From: Karel Zak <kzak@redhat.com> +Date: Wed, 11 Mar 2015 11:38:07 +0100 +Subject: [PATCH 73/84] libmount: mark overlay as pseudo-FS + +Upstream: http://github.com/karelzak/util-linux/commit/209fd7a74879d37cef3d5d1679bc9cad76b96c7a +Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=587393 +Signed-off-by: Karel Zak <kzak@redhat.com> +--- + libmount/src/utils.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/libmount/src/utils.c b/libmount/src/utils.c +index 2151ff9..c13fb96 100644 +--- a/libmount/src/utils.c ++++ b/libmount/src/utils.c +@@ -269,6 +269,7 @@ int mnt_fstype_is_pseudofs(const char *type) + "mqueue", + "nfsd", + "none", ++ "overlay", + "pipefs", + "proc", + "pstore", +-- +2.7.4 + diff --git a/SOURCES/0074-logger-be-more-precise-about-port-description.patch b/SOURCES/0074-logger-be-more-precise-about-port-description.patch new file mode 100644 index 0000000..8ff9c46 --- /dev/null +++ b/SOURCES/0074-logger-be-more-precise-about-port-description.patch @@ -0,0 +1,41 @@ +From f4ffe3de3ba721892af52c7ed5787f4470393242 Mon Sep 17 00:00:00 2001 +From: Karel Zak <kzak@redhat.com> +Date: Tue, 21 Jun 2016 13:35:33 +0200 +Subject: [PATCH 74/84] logger: be more precise about --port description + +Upstream: http://github.com/karelzak/util-linux/commit/1c7227598824b1d9140298e9fe5742cae4131130 +Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1344222 +Signed-off-by: Karel Zak <kzak@redhat.com> +--- + misc-utils/logger.1 | 1 + + misc-utils/logger.c | 2 +- + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/misc-utils/logger.1 b/misc-utils/logger.1 +index 5eb8d09..8c4faca 100644 +--- a/misc-utils/logger.1 ++++ b/misc-utils/logger.1 +@@ -72,6 +72,7 @@ port defined in /etc/services, which is often + \fB\-P\fR, \fB\-\-port\fR \fIport\fR + Use the specified + .IR port . ++When this option is not specified, the port defaults to syslog for udp and to syslog-conn for tcp connections. + .TP + \fB\-i\fR, \fB\-\-id\fR + Log the process ID of the logger process with each line. +diff --git a/misc-utils/logger.c b/misc-utils/logger.c +index c83c0b8..a331869 100644 +--- a/misc-utils/logger.c ++++ b/misc-utils/logger.c +@@ -222,7 +222,7 @@ static void __attribute__ ((__noreturn__)) usage(FILE *out) + " -f, --file <file> log the contents of this file\n" + " -h, --help display this help text and exit\n"), out); + fputs(_(" -n, --server <name> write to this remote syslog server\n" +- " -P, --port <number> use this UDP port\n" ++ " -P, --port <port> use this port for UDP or TCP connection\n" + " -p, --priority <prio> mark given message with this priority\n" + " -s, --stderr output message to standard error as well\n"), out); + fputs(_(" -t, --tag <tag> mark every line with this tag\n" +-- +2.7.4 + diff --git a/SOURCES/0075-libfdisk-gpt-be-more-careful-with-64bit-constants.patch b/SOURCES/0075-libfdisk-gpt-be-more-careful-with-64bit-constants.patch new file mode 100644 index 0000000..82190fa --- /dev/null +++ b/SOURCES/0075-libfdisk-gpt-be-more-careful-with-64bit-constants.patch @@ -0,0 +1,182 @@ +From 428be59e33d0875cdf5bf602a75328fb3d7c58ad Mon Sep 17 00:00:00 2001 +From: Karel Zak <kzak@redhat.com> +Date: Tue, 21 Jun 2016 14:06:14 +0200 +Subject: [PATCH 75/84] libfdisk: (gpt) be more careful with 64bit constants + +It's probably more robust (and readable) to be explicit when we count +with constant and 64bit numbers. + +Upstream: http://github.com/karelzak/util-linux/commit/0a7cdf80606cc0670ef7f740d37640b05932e0ce +Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1344482 +Signed-off-by: Karel Zak <kzak@redhat.com> +--- + libfdisk/src/gpt.c | 40 ++++++++++++++++++++-------------------- + 1 file changed, 20 insertions(+), 20 deletions(-) + +diff --git a/libfdisk/src/gpt.c b/libfdisk/src/gpt.c +index 482d453..d3bdc2d 100644 +--- a/libfdisk/src/gpt.c ++++ b/libfdisk/src/gpt.c +@@ -53,7 +53,7 @@ + #define GPT_MBR_PROTECTIVE 1 + #define GPT_MBR_HYBRID 2 + +-#define GPT_PRIMARY_PARTITION_TABLE_LBA 0x00000001 ++#define GPT_PRIMARY_PARTITION_TABLE_LBA 0x00000001ULL + + #define EFI_PMBR_OSTYPE 0xEE + #define MSDOS_MBR_SIGNATURE 0xAA55 +@@ -364,7 +364,7 @@ static int gpt_mknew_pmbr(struct fdisk_context *cxt) + pmbr->partition_record[0].end_track = 0xFF; + pmbr->partition_record[0].starting_lba = cpu_to_le32(1); + pmbr->partition_record[0].size_in_lba = +- cpu_to_le32(min((uint32_t) cxt->total_sectors - 1, 0xFFFFFFFF)); ++ cpu_to_le32((uint32_t) min(cxt->total_sectors - 1ULL, 0xFFFFFFFFULL)); + + return 0; + } +@@ -379,14 +379,14 @@ static void gpt_mknew_header_common(struct fdisk_context *cxt, + header->my_lba = cpu_to_le64(lba); + + if (lba == GPT_PRIMARY_PARTITION_TABLE_LBA) { /* primary */ +- header->alternative_lba = cpu_to_le64(cxt->total_sectors - 1); +- header->partition_entry_lba = cpu_to_le64(2); ++ header->alternative_lba = cpu_to_le64(cxt->total_sectors - 1ULL); ++ header->partition_entry_lba = cpu_to_le64(2ULL); + } else { /* backup */ + uint64_t esz = le32_to_cpu(header->npartition_entries) * sizeof(struct gpt_entry); + uint64_t esects = (esz + cxt->sector_size - 1) / cxt->sector_size; + + header->alternative_lba = cpu_to_le64(GPT_PRIMARY_PARTITION_TABLE_LBA); +- header->partition_entry_lba = cpu_to_le64(cxt->total_sectors - 1 - esects); ++ header->partition_entry_lba = cpu_to_le64(cxt->total_sectors - 1ULL - esects); + } + } + +@@ -451,8 +451,8 @@ static int gpt_mknew_header(struct fdisk_context *cxt, + header->npartition_entries = cpu_to_le32(GPT_NPARTITIONS); + header->sizeof_partition_entry = cpu_to_le32(sizeof(struct gpt_entry)); + +- last = cxt->total_sectors - 2 - esz; +- first = esz + 2; ++ last = cxt->total_sectors - 2ULL - esz; ++ first = esz + 2ULL; + + if (first < cxt->first_lba && cxt->first_lba < last) + /* Align according to topology */ +@@ -520,7 +520,7 @@ check_hybrid: + */ + if (ret == GPT_MBR_PROTECTIVE) { + if (le32_to_cpu(pmbr->partition_record[0].size_in_lba) != +- min((uint32_t) cxt->total_sectors - 1, 0xFFFFFFFF)) ++ (uint32_t) min(cxt->total_sectors - 1ULL, 0xFFFFFFFFULL)) + ret = 0; + } + done: +@@ -538,7 +538,7 @@ static uint64_t last_lba(struct fdisk_context *cxt) + } + + if (S_ISBLK(s.st_mode)) +- return cxt->total_sectors - 1; ++ return cxt->total_sectors - 1ULL; + else if (S_ISREG(s.st_mode)) { + uint64_t sectors = s.st_size >> cxt->sector_size; + return (sectors / cxt->sector_size) - 1ULL; +@@ -554,7 +554,7 @@ static ssize_t read_lba(struct fdisk_context *cxt, uint64_t lba, + + if (lseek(cxt->dev_fd, offset, SEEK_SET) == (off_t) -1) + return -1; +- return read(cxt->dev_fd, buffer, bytes) != bytes; ++ return read(cxt->dev_fd, buffer, bytes) != (ssize_t) bytes; + } + + +@@ -908,7 +908,7 @@ static uint64_t find_first_available(struct gpt_header *header, + if (first < gpt_partition_start(&e[i])) + continue; + if (first <= gpt_partition_end(&e[i])) { +- first = gpt_partition_end(&e[i]) + 1; ++ first = gpt_partition_end(&e[i]) + 1ULL; + first_moved = 1; + } + } +@@ -937,7 +937,7 @@ static uint64_t find_last_free(struct gpt_header *header, + uint64_t ps = gpt_partition_start(&e[i]); + + if (nearest_start > ps && ps > start) +- nearest_start = ps - 1; ++ nearest_start = ps - 1ULL; + } + + return nearest_start; +@@ -960,7 +960,7 @@ static uint64_t find_last_free_sector(struct gpt_header *header, + for (i = 0; i < le32_to_cpu(header->npartition_entries); i++) { + if ((last >= gpt_partition_start(&e[i])) && + (last <= gpt_partition_end(&e[i]))) { +- last = gpt_partition_start(&e[i]) - 1; ++ last = gpt_partition_start(&e[i]) - 1ULL; + last_moved = 1; + } + } +@@ -986,7 +986,7 @@ static uint64_t find_first_in_largest(struct gpt_header *header, struct gpt_entr + first_sect = find_first_available(header, e, start); + if (first_sect != 0) { + last_sect = find_last_free(header, e, first_sect); +- segment_size = last_sect - first_sect + 1; ++ segment_size = last_sect - first_sect + 1ULL; + + if (segment_size > selected_size) { + selected_size = segment_size; +@@ -1026,7 +1026,7 @@ static uint64_t get_free_sectors(struct fdisk_context *cxt, struct gpt_header *h + largest_seg = segment_sz; + totfound += segment_sz; + num++; +- start = last_sect + 1; ++ start = last_sect + 1ULL; + } + } while (first_sect); + +@@ -1165,7 +1165,7 @@ void gpt_list_table(struct fdisk_context *cxt, + continue; + + /* the partition has to inside usable range */ +- if (start < fu || start + size - 1 > lu) ++ if (start < fu || start + size - 1ULL > lu) + continue; + + name = encode_to_utf8((unsigned char *)gpt->ents[i].partition_name, +@@ -1266,11 +1266,11 @@ static int gpt_write_pmbr(struct fdisk_context *cxt) + * Set size_in_lba to the size of the disk minus one. If the size of the disk + * is too large to be represented by a 32bit LBA (2Tb), set it to 0xFFFFFFFF. + */ +- if (cxt->total_sectors - 1 > 0xFFFFFFFFULL) ++ if (cxt->total_sectors - 1ULL > 0xFFFFFFFFULL) + pmbr->partition_record[0].size_in_lba = cpu_to_le32(0xFFFFFFFF); + else + pmbr->partition_record[0].size_in_lba = +- cpu_to_le32(cxt->total_sectors - 1UL); ++ cpu_to_le32((uint32_t) (cxt->total_sectors - 1ULL)); + + offset = GPT_PMBR_LBA * cxt->sector_size; + if (offset != lseek(cxt->dev_fd, offset, SEEK_SET)) +@@ -1308,7 +1308,7 @@ static int gpt_write_disklabel(struct fdisk_context *cxt) + goto err0; + + /* check that the backup header is properly placed */ +- if (le64_to_cpu(gpt->pheader->alternative_lba) < cxt->total_sectors - 1) ++ if (le64_to_cpu(gpt->pheader->alternative_lba) < cxt->total_sectors - 1ULL) + /* TODO: correct this (with user authorization) and write */ + goto err0; + +@@ -1645,7 +1645,7 @@ static int gpt_add_partition( + + user_l = fdisk_ask_number_get_result(ask); + if (fdisk_ask_number_is_relative(ask)) +- user_l = fdisk_align_lba_in_range(cxt, user_l, user_f, dflt_l) - 1; ++ user_l = fdisk_align_lba_in_range(cxt, user_l, user_f, dflt_l) - 1ULL; + if (user_l > user_f && user_l <= disk_l) + break; + } +-- +2.7.4 + diff --git a/SOURCES/0076-lsns-backport-new-command.patch b/SOURCES/0076-lsns-backport-new-command.patch new file mode 100644 index 0000000..090bd16 --- /dev/null +++ b/SOURCES/0076-lsns-backport-new-command.patch @@ -0,0 +1,1251 @@ +From 03f539c766780a083010636cc67f96fcb2bab30f Mon Sep 17 00:00:00 2001 +From: Karel Zak <kzak@redhat.com> +Date: Fri, 24 Jun 2016 12:16:24 +0200 +Subject: [PATCH 76/84] lsns: backport new command + +Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1332084 +Signed-off-by: Karel Zak <kzak@redhat.com> +--- + bash-completion/lsns | 55 ++++ + configure.ac | 6 + + include/Makemodule.am | 1 + + include/c.h | 8 + + include/debug.h | 2 +- + include/idcache.h | 28 ++ + include/procutils.h | 2 + + lib/Makemodule.am | 1 + + lib/idcache.c | 117 ++++++++ + lib/procutils.c | 43 +++ + sys-utils/Makemodule.am | 7 + + sys-utils/lsns.8 | 78 +++++ + sys-utils/lsns.c | 748 ++++++++++++++++++++++++++++++++++++++++++++++++ + 13 files changed, 1095 insertions(+), 1 deletion(-) + create mode 100644 bash-completion/lsns + create mode 100644 include/idcache.h + create mode 100644 lib/idcache.c + create mode 100644 sys-utils/lsns.8 + create mode 100644 sys-utils/lsns.c + +diff --git a/bash-completion/lsns b/bash-completion/lsns +new file mode 100644 +index 0000000..d02df3b +--- /dev/null ++++ b/bash-completion/lsns +@@ -0,0 +1,55 @@ ++_lsns_module() ++{ ++ local cur prev OPTS LSNS_COLS_ALL ++ COMPREPLY=() ++ cur="${COMP_WORDS[COMP_CWORD]}" ++ prev="${COMP_WORDS[COMP_CWORD-1]}" ++ LSNS_COLS_ALL=" ++ NS TYPE PATH NPROCS PID PPID COMMAND UID USER ++ " ++ case $prev in ++ '-o'|'--output') ++ local prefix realcur LSNS_COLS ++ realcur="${cur##*,}" ++ prefix="${cur%$realcur}" ++ for WORD in $LSNS_COLS_ALL; do ++ if ! [[ $prefix == *"$WORD"* ]]; then ++ LSNS_COLS="$WORD $LSNS_COLS" ++ fi ++ done ++ compopt -o nospace ++ COMPREPLY=( $(compgen -P "$prefix" -W "$LSNS_COLS" -S ',' -- $realcur) ) ++ return 0 ++ ;; ++ '-p'|'--task') ++ COMPREPLY=( $(compgen -W "$(cd /proc && echo [0-9]*)" -- $cur) ) ++ return 0 ++ ;; ++ '-t'|'--type') ++ COMPREPLY=( $(compgen -W "mnt net ipc user pid uts" -- $cur) ) ++ return 0 ++ ;; ++ '-h'|'--help'|'-V'|'--version') ++ return 0 ++ ;; ++ esac ++ case $cur in ++ -*) ++ COMPREPLY=( $(compgen -W " ++ --list ++ --noheadings ++ --output ++ --task ++ --raw ++ --notruncate ++ --type ++ --help ++ --version ++ " -- $cur) ) ++ return 0 ++ ;; ++ esac ++ COMPREPLY=( $(compgen -W "mnt net pid uts ipc user" -- $cur ) ) ++ return 0 ++} ++complete -F _lsns_module lsns +diff --git a/configure.ac b/configure.ac +index f3c7214..5d9ea39 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1032,6 +1032,12 @@ UL_REQUIRES_BUILD([lslogins], [libsmartcols]) + AM_CONDITIONAL([BUILD_LSLOGINS], [test "x$build_lslogins" = xyes]) + + ++UL_BUILD_INIT([lsns], [check]) ++UL_REQUIRES_LINUX([lsns]) ++UL_REQUIRES_BUILD([lsns], [libsmartcols]) ++AM_CONDITIONAL([BUILD_LSNS], [test "x$build_lsns" = xyes]) ++ ++ + UL_BUILD_INIT([chcpu], [check]) + UL_REQUIRES_LINUX([chcpu]) + UL_REQUIRES_HAVE([chcpu], [cpu_set_t], [cpu_set_t type]) +diff --git a/include/Makemodule.am b/include/Makemodule.am +index 7b53244..757f317 100644 +--- a/include/Makemodule.am ++++ b/include/Makemodule.am +@@ -15,6 +15,7 @@ dist_noinst_HEADERS += \ + include/exec_shell.h \ + include/exitcodes.h \ + include/fileutils.h \ ++ include/idcache.h \ + include/ismounted.h \ + include/linux_reboot.h \ + include/linux_version.h \ +diff --git a/include/c.h b/include/c.h +index 7b59ce8..a2779a5 100644 +--- a/include/c.h ++++ b/include/c.h +@@ -110,6 +110,14 @@ + _max1 > _max2 ? _max1 : _max2; }) + #endif + ++#ifndef cmp_numbers ++# define cmp_numbers(x, y) __extension__ ({ \ ++ __typeof__(x) _a = (x); \ ++ __typeof__(y) _b = (y); \ ++ (void) (&_a == &_b); \ ++ _a == _b ? 0 : _a > _b ? 1 : -1; }) ++#endif ++ + #ifndef offsetof + #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + #endif +diff --git a/include/debug.h b/include/debug.h +index 25045aa..848e474 100644 +--- a/include/debug.h ++++ b/include/debug.h +@@ -15,7 +15,7 @@ struct dbg_mask { char *mname; int val; }; + + #define UL_DEBUG_DEFINE_MASK(m) int m ## _debug_mask + #define UL_DEBUG_DECLARE_MASK(m) extern UL_DEBUG_DEFINE_MASK(m) +-#define UL_DEBUG_DEFINE_MASKANEMS(m) static const struct dbg_mask m ## _masknames[] ++#define UL_DEBUG_DEFINE_MASKNAMES(m) static const struct dbg_mask m ## _masknames[] + + /* p - flag prefix, m - flag postfix */ + #define UL_DEBUG_DEFINE_FLAG(p, m) p ## m +diff --git a/include/idcache.h b/include/idcache.h +new file mode 100644 +index 0000000..912edd5 +--- /dev/null ++++ b/include/idcache.h +@@ -0,0 +1,28 @@ ++#ifndef UTIL_LINUX_IDCACHE_H ++#define UTIL_LINUX_IDCACHE_H ++ ++#include <sys/types.h> ++#include <pwd.h> ++ ++#define IDCACHE_FLAGS_NAMELEN (1 << 1) ++ ++struct identry { ++ unsigned long int id; ++ char *name; ++ struct identry *next; ++}; ++ ++struct idcache { ++ struct identry *ent; /* first entry */ ++ int width; /* name width */ ++}; ++ ++ ++extern struct idcache *new_idcache(void); ++extern void add_gid(struct idcache *cache, unsigned long int id); ++extern void add_uid(struct idcache *cache, unsigned long int id); ++ ++extern void free_idcache(struct idcache *ic); ++extern struct identry *get_id(struct idcache *ic, unsigned long int id); ++ ++#endif /* UTIL_LINUX_IDCACHE_H */ +diff --git a/include/procutils.h b/include/procutils.h +index 14b766c..9f8dd76 100644 +--- a/include/procutils.h ++++ b/include/procutils.h +@@ -28,5 +28,7 @@ extern void proc_processes_filter_by_name(struct proc_processes *ps, const char + extern void proc_processes_filter_by_uid(struct proc_processes *ps, uid_t uid); + extern int proc_next_pid(struct proc_processes *ps, pid_t *pid); + ++extern char *proc_get_command(pid_t pid); ++extern char *proc_get_command_name(pid_t pid); + + #endif /* UTIL_LINUX_PROCUTILS */ +diff --git a/lib/Makemodule.am b/lib/Makemodule.am +index eed31f1..73280f9 100644 +--- a/lib/Makemodule.am ++++ b/lib/Makemodule.am +@@ -8,6 +8,7 @@ libcommon_la_SOURCES = \ + lib/colors.c \ + lib/crc32.c \ + lib/env.c \ ++ lib/idcache.c \ + lib/fileutils.c \ + lib/ismounted.c \ + lib/mangle.c \ +diff --git a/lib/idcache.c b/lib/idcache.c +new file mode 100644 +index 0000000..3c358b8 +--- /dev/null ++++ b/lib/idcache.c +@@ -0,0 +1,117 @@ ++ ++#include <wchar.h> ++#include <pwd.h> ++#include <grp.h> ++#include <sys/types.h> ++ ++#include "c.h" ++#include "idcache.h" ++ ++#ifndef LOGIN_NAME_MAX ++#define LOGIN_NAME_MAX 256 ++#endif ++ ++struct identry *get_id(struct idcache *ic, unsigned long int id) ++{ ++ struct identry *ent; ++ ++ if (!ic) ++ return NULL; ++ ++ for (ent = ic->ent; ent; ent = ent->next) { ++ if (ent->id == id) ++ return ent; ++ } ++ ++ return NULL; ++} ++ ++struct idcache *new_idcache() ++{ ++ return calloc(1, sizeof(struct idcache)); ++} ++ ++void free_idcache(struct idcache *ic) ++{ ++ struct identry *ent = ic->ent; ++ ++ while (ent) { ++ struct identry *next = ent->next; ++ free(ent->name); ++ free(ent); ++ ent = next; ++ } ++ ++ free(ic); ++} ++ ++static void add_id(struct idcache *ic, char *name, unsigned long int id) ++{ ++ struct identry *ent, *x; ++ int w = 0; ++ ++ ent = calloc(1, sizeof(struct identry)); ++ if (!ent) ++ return; ++ ent->id = id; ++ ++ if (name) { ++#ifdef HAVE_WIDECHAR ++ wchar_t wc[LOGIN_NAME_MAX + 1]; ++ ++ if (mbstowcs(wc, name, LOGIN_NAME_MAX) > 0) { ++ wc[LOGIN_NAME_MAX] = '\0'; ++ w = wcswidth(wc, LOGIN_NAME_MAX); ++ } ++ else ++#endif ++ w = strlen(name); ++ } ++ ++ /* note, we ignore names with non-printable widechars */ ++ if (w > 0) { ++ ent->name = strdup(name); ++ if (!ent->name) { ++ free(ent); ++ return; ++ } ++ } else { ++ if (asprintf(&ent->name, "%lu", id) < 0) { ++ free(ent); ++ return; ++ } ++ } ++ ++ for (x = ic->ent; x && x->next; x = x->next); ++ ++ if (x) ++ x->next = ent; ++ else ++ ic->ent = ent; ++ ++ if (w <= 0) ++ w = ent->name ? strlen(ent->name) : 0; ++ ic->width = ic->width < w ? w : ic->width; ++ return; ++} ++ ++void add_uid(struct idcache *cache, unsigned long int id) ++{ ++ struct identry *ent= get_id(cache, id); ++ ++ if (!ent) { ++ struct passwd *pw = getpwuid((uid_t) id); ++ add_id(cache, pw ? pw->pw_name : NULL, id); ++ } ++} ++ ++void add_gid(struct idcache *cache, unsigned long int id) ++{ ++ struct identry *ent = get_id(cache, id); ++ ++ if (!ent) { ++ struct group *gr = getgrgid((gid_t) id); ++ add_id(cache, gr ? gr->gr_name : NULL, id); ++ } ++} ++ +diff --git a/lib/procutils.c b/lib/procutils.c +index d633261..8dfdec9 100644 +--- a/lib/procutils.c ++++ b/lib/procutils.c +@@ -25,6 +25,7 @@ + #include "procutils.h" + #include "at.h" + #include "c.h" ++#include "all-io.h" + + /* + * @pid: process ID for which we want to obtain the threads group +@@ -193,6 +194,48 @@ int proc_next_pid(struct proc_processes *ps, pid_t *pid) + return 0; + } + ++/* returns process command path, use free() for result */ ++static char *proc_file_strdup(pid_t pid, const char *name) ++{ ++ char buf[BUFSIZ], *res = NULL; ++ ssize_t sz = 0; ++ size_t i; ++ int fd; ++ ++ snprintf(buf, sizeof(buf), "/proc/%d/%s", (int) pid, name); ++ fd = open(buf, O_RDONLY); ++ if (fd < 0) ++ goto done; ++ ++ sz = read_all(fd, buf, sizeof(buf)); ++ if (sz <= 0) ++ goto done; ++ ++ for (i = 0; i < (size_t) sz; i++) { ++ ++ if (buf[i] == '\0') ++ buf[i] = ' '; ++ } ++ buf[sz - 1] = '\0'; ++ res = strdup(buf); ++done: ++ if (fd >= 0) ++ close(fd); ++ return res; ++} ++ ++/* returns process command path, use free() for result */ ++char *proc_get_command(pid_t pid) ++{ ++ return proc_file_strdup(pid, "cmdline"); ++} ++ ++/* returns process command name, use free() for result */ ++char *proc_get_command_name(pid_t pid) ++{ ++ return proc_file_strdup(pid, "comm"); ++} ++ + #ifdef TEST_PROGRAM + + static int test_tasks(int argc, char *argv[]) +diff --git a/sys-utils/Makemodule.am b/sys-utils/Makemodule.am +index c6c561c..9baf5a3 100644 +--- a/sys-utils/Makemodule.am ++++ b/sys-utils/Makemodule.am +@@ -182,6 +182,13 @@ prlimit_SOURCES = sys-utils/prlimit.c + prlimit_LDADD = $(LDADD) libcommon.la + endif + ++if BUILD_LSNS ++usrbin_exec_PROGRAMS += lsns ++dist_man_MANS += sys-utils/lsns.8 ++lsns_SOURCES = sys-utils/lsns.c ++lsns_LDADD = $(LDADD) libcommon.la libsmartcols.la ++lsns_CFLAGS = $(AM_CFLAGS) -I$(ul_libsmartcols_incdir) ++endif + + if BUILD_MOUNT + # +diff --git a/sys-utils/lsns.8 b/sys-utils/lsns.8 +new file mode 100644 +index 0000000..328df47 +--- /dev/null ++++ b/sys-utils/lsns.8 +@@ -0,0 +1,78 @@ ++.\" Man page for the lsns command. ++.\" Copyright 2015 Karel Zak <kzak@redhat.com> ++.\" May be distributed under the GNU General Public License ++ ++.TH LSNS 8 "December 2015" "util-linux" "System Administration" ++.SH NAME ++lsns \- list namespaces ++.SH SYNOPSIS ++.B lsns ++[options] ++.RI [ namespace ] ++ ++.SH DESCRIPTION ++.B lsns ++lists information about all the currently accessible namespaces or about the ++given \fInamespace\fP. The \fInamespace\fP identifier is an inode number. ++ ++The default output is subject to change. So whenever possible, you should ++avoid using default outputs in your scripts. Always explicitly define expected ++columns by using the \fB\-\-output\fR option together with a columns list in ++environments where a stable output is required. ++ ++Note that \fBlsns\fR reads information directly from the /proc filesystem and ++for non-root users it may return incomplete information. The current /proc ++filesystem may be unshared and affected by a PID namespace ++(see \fBunshare \-\-mount\-proc\fP for more details). ++.B lsns ++is not able to see persistent namespaces without processes where the namespace ++instance is held by a bind mount to /proc/\fIpid\fR/ns/\fItype\fR. ++ ++.SH OPTIONS ++.TP ++.BR \-l , " \-\-list" ++Use list output format. ++.TP ++.BR \-n , " \-\-noheadings" ++Do not print a header line. ++.TP ++.BR \-o , " \-\-output " \fIlist\fP ++Specify which output columns to print. Use \fB\-\-help\fR ++to get a list of all supported columns. ++ ++The default list of columns may be extended if \fIlist\fP is ++specified in the format \fB+\fIlist\fP (e.g. \fBlsns \-o +PATH\fP). ++.TP ++.BR \-p , " \-\-task " \fIpid\fP ++Display only the namespaces held by the process with this \fIpid\fR. ++.TP ++.BR \-r , " \-\-raw" ++Use the raw output format. ++.TP ++.BR \-t , " \-\-type " \fItype\fP ++Display the specified \fItype\fP of namespaces only. The supported types are ++\fBmnt\fP, \fBnet\fP, \fBipc\fP, \fBuser\fP, \fBpid\fP and \fButs\fP. This ++option may be given more than once. ++.TP ++.BR \-u , " \-\-notruncate" ++Do not truncate text in columns. ++.TP ++.BR \-V , " \-\-version" ++Display version information and exit. ++.TP ++.BR \-h , " \-\-help" ++Display help text and exit. ++ ++.SH AUTHORS ++.nf ++Karel Zak <kzak@redhat.com> ++.fi ++ ++.SH "SEE ALSO" ++.BR unshare (1), ++.BR nsenter (1), ++.BR clone (2) ++ ++.SH AVAILABILITY ++The lsns command is part of the util-linux package and is available from ++ftp://ftp.kernel.org/pub/linux/utils/util-linux/. +diff --git a/sys-utils/lsns.c b/sys-utils/lsns.c +new file mode 100644 +index 0000000..5ee2981 +--- /dev/null ++++ b/sys-utils/lsns.c +@@ -0,0 +1,748 @@ ++/* ++ * lsns(8) - list system namespaces ++ * ++ * Copyright (C) 2015 Karel Zak <kzak@redhat.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it would be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++#include <stdio.h> ++#include <string.h> ++#include <getopt.h> ++#include <stdlib.h> ++#include <assert.h> ++#include <dirent.h> ++#include <unistd.h> ++#include <sys/stat.h> ++#include <sys/types.h> ++#include <wchar.h> ++#include <libsmartcols.h> ++ ++#include "pathnames.h" ++#include "nls.h" ++#include "xalloc.h" ++#include "c.h" ++#include "list.h" ++#include "closestream.h" ++#include "optutils.h" ++#include "procutils.h" ++#include "strutils.h" ++#include "namespace.h" ++#include "path.h" ++#include "idcache.h" ++ ++#include "debug.h" ++ ++UL_DEBUG_DEFINE_MASK(lsns); ++UL_DEBUG_DEFINE_MASKNAMES(lsns) = UL_DEBUG_EMPTY_MASKNAMES; ++ ++#define LSNS_DEBUG_INIT (1 << 1) ++#define LSNS_DEBUG_PROC (1 << 2) ++#define LSNS_DEBUG_NS (1 << 3) ++#define LSNS_DEBUG_ALL 0xFFFF ++ ++#define DBG(m, x) __UL_DBG(lsns, LSNS_DEBUG_, m, x) ++#define ON_DBG(m, x) __UL_DBG_CALL(lsns, LSNS_DEBUG_, m, x) ++ ++struct idcache *uid_cache = NULL; ++ ++/* column IDs */ ++enum { ++ COL_NS = 0, ++ COL_TYPE, ++ COL_PATH, ++ COL_NPROCS, ++ COL_PID, ++ COL_PPID, ++ COL_COMMAND, ++ COL_UID, ++ COL_USER ++}; ++ ++/* column names */ ++struct colinfo { ++ const char *name; /* header */ ++ double whint; /* width hint (N < 1 is in percent of termwidth) */ ++ int flags; /* SCOLS_FL_* */ ++ const char *help; ++}; ++ ++/* columns descriptions */ ++static const struct colinfo infos[] = { ++ [COL_NS] = { "NS", 10, SCOLS_FL_RIGHT, N_("namespace identifier (inode number)") }, ++ [COL_TYPE] = { "TYPE", 5, 0, N_("kind of namespace") }, ++ [COL_PATH] = { "PATH", 0, 0, N_("path to the namespace")}, ++ [COL_NPROCS] = { "NPROCS", 5, SCOLS_FL_RIGHT, N_("number of processes in the namespace") }, ++ [COL_PID] = { "PID", 5, SCOLS_FL_RIGHT, N_("lowest PID in the namespace") }, ++ [COL_PPID] = { "PPID", 5, SCOLS_FL_RIGHT, N_("PPID of the PID") }, ++ [COL_COMMAND] = { "COMMAND", 0, SCOLS_FL_TRUNC, N_("command line of the PID")}, ++ [COL_UID] = { "UID", 0, SCOLS_FL_RIGHT, N_("UID of the PID")}, ++ [COL_USER] = { "USER", 0, 0, N_("username of the PID")} ++}; ++ ++static int columns[ARRAY_SIZE(infos) * 2]; ++static size_t ncolumns; ++ ++enum { ++ LSNS_ID_MNT = 0, ++ LSNS_ID_NET, ++ LSNS_ID_PID, ++ LSNS_ID_UTS, ++ LSNS_ID_IPC, ++ LSNS_ID_USER ++}; ++ ++static char *ns_names[] = { ++ [LSNS_ID_MNT] = "mnt", ++ [LSNS_ID_NET] = "net", ++ [LSNS_ID_PID] = "pid", ++ [LSNS_ID_UTS] = "uts", ++ [LSNS_ID_IPC] = "ipc", ++ [LSNS_ID_USER] = "user" ++}; ++ ++struct lsns_namespace { ++ ino_t id; ++ int type; /* LSNS_* */ ++ int nprocs; ++ ++ struct lsns_process *proc; ++ ++ struct list_head namespaces; /* lsns->processes member */ ++ struct list_head processes; /* head of lsns_process *siblings */ ++}; ++ ++struct lsns_process { ++ pid_t pid; /* process PID */ ++ pid_t ppid; /* parent's PID */ ++ pid_t tpid; /* thread group */ ++ char state; ++ uid_t uid; ++ ++ ino_t ns_ids[ARRAY_SIZE(ns_names)]; ++ struct list_head ns_siblings[ARRAY_SIZE(ns_names)]; ++ ++ struct list_head processes; /* list of processes */ ++ ++ struct libscols_line *outline; ++ struct lsns_process *parent; ++}; ++ ++struct lsns { ++ struct list_head processes; ++ struct list_head namespaces; ++ ++ pid_t fltr_pid; /* filter out by PID */ ++ ino_t fltr_ns; /* filter out by namespace */ ++ int fltr_types[ARRAY_SIZE(ns_names)]; ++ int fltr_ntypes; ++ ++ unsigned int raw : 1, ++ tree : 1, ++ list : 1, ++ notrunc : 1, ++ no_headings: 1; ++}; ++ ++static void lsns_init_debug(void) ++{ ++ __UL_INIT_DEBUG(lsns, LSNS_DEBUG_, 0, LSNS_DEBUG); ++} ++ ++static int ns_name2type(const char *name) ++{ ++ size_t i; ++ ++ for (i = 0; i < ARRAY_SIZE(ns_names); i++) { ++ if (strcmp(ns_names[i], name) == 0) ++ return i; ++ } ++ return -1; ++} ++ ++static int column_name_to_id(const char *name, size_t namesz) ++{ ++ size_t i; ++ ++ assert(name); ++ ++ for (i = 0; i < ARRAY_SIZE(infos); i++) { ++ const char *cn = infos[i].name; ++ ++ if (!strncasecmp(name, cn, namesz) && !*(cn + namesz)) ++ return i; ++ } ++ warnx(_("unknown column: %s"), name); ++ return -1; ++} ++ ++static inline int get_column_id(int num) ++{ ++ assert(num >= 0); ++ assert((size_t) num < ncolumns); ++ assert(columns[num] < (int) ARRAY_SIZE(infos)); ++ ++ return columns[num]; ++} ++ ++static inline const struct colinfo *get_column_info(unsigned num) ++{ ++ return &infos[ get_column_id(num) ]; ++} ++ ++static ino_t get_ns_ino(int dir, const char *nsname, ino_t *ino) ++{ ++ struct stat st; ++ char path[16]; ++ ++ snprintf(path, sizeof(path), "ns/%s", nsname); ++ ++ if (fstatat(dir, path, &st, 0) != 0) ++ return -errno; ++ *ino = st.st_ino; ++ return 0; ++} ++ ++ ++static int read_process(struct lsns *ls, pid_t pid) ++{ ++ struct lsns_process *p = NULL; ++ char buf[BUFSIZ]; ++ DIR *dir; ++ int rc = 0, fd; ++ FILE *f = NULL; ++ size_t i; ++ struct stat st; ++ ++ DBG(PROC, ul_debug("reading %d", (int) pid)); ++ ++ snprintf(buf, sizeof(buf), "/proc/%d", pid); ++ dir = opendir(buf); ++ if (!dir) ++ return -errno; ++ ++ p = xcalloc(1, sizeof(*p)); ++ if (!p) { ++ rc = -ENOMEM; ++ goto done; ++ } ++ ++ if (fstat(dirfd(dir), &st) == 0) { ++ p->uid = st.st_uid; ++ add_uid(uid_cache, st.st_uid); ++ } ++ ++ fd = openat(dirfd(dir), "stat", O_RDONLY); ++ if (fd < 0) { ++ rc = -errno; ++ goto done; ++ } ++ if (!(f = fdopen(fd, "r"))) { ++ rc = -errno; ++ goto done; ++ } ++ rc = fscanf(f, "%d %*s %c %d*[^\n]", &p->pid, &p->state, &p->ppid); ++ if (rc != 3) { ++ rc = rc < 0 ? -errno : -EINVAL; ++ goto done; ++ } ++ rc = 0; ++ ++ for (i = 0; i < ARRAY_SIZE(p->ns_ids); i++) { ++ INIT_LIST_HEAD(&p->ns_siblings[i]); ++ ++ if (!ls->fltr_types[i]) ++ continue; ++ ++ rc = get_ns_ino(dirfd(dir), ns_names[i], &p->ns_ids[i]); ++ if (rc && rc != -EACCES) ++ goto done; ++ rc = 0; ++ } ++ ++ INIT_LIST_HEAD(&p->processes); ++ ++ DBG(PROC, ul_debugobj(p, "new pid=%d", p->pid)); ++ list_add_tail(&p->processes, &ls->processes); ++done: ++ if (f) ++ fclose(f); ++ closedir(dir); ++ if (rc) ++ free(p); ++ return rc; ++} ++ ++static int read_processes(struct lsns *ls) ++{ ++ struct proc_processes *proc = NULL; ++ pid_t pid; ++ int rc = 0; ++ ++ DBG(PROC, ul_debug("opening /proc")); ++ ++ if (!(proc = proc_open_processes())) { ++ rc = -errno; ++ goto done; ++ } ++ ++ while (proc_next_pid(proc, &pid) == 0) { ++ rc = read_process(ls, pid); ++ if (rc && rc != -EACCES && rc != -ENOENT) ++ break; ++ rc = 0; ++ } ++done: ++ DBG(PROC, ul_debug("closing /proc")); ++ proc_close_processes(proc); ++ return rc; ++} ++ ++static struct lsns_namespace *get_namespace(struct lsns *ls, ino_t ino) ++{ ++ struct list_head *p; ++ ++ list_for_each(p, &ls->namespaces) { ++ struct lsns_namespace *ns = list_entry(p, struct lsns_namespace, namespaces); ++ ++ if (ns->id == ino) ++ return ns; ++ } ++ return NULL; ++} ++ ++static int namespace_has_process(struct lsns_namespace *ns, pid_t pid) ++{ ++ struct list_head *p; ++ ++ list_for_each(p, &ns->processes) { ++ struct lsns_process *proc = list_entry(p, struct lsns_process, ns_siblings[ns->type]); ++ ++ if (proc->pid == pid) ++ return 1; ++ } ++ return 0; ++} ++ ++static struct lsns_namespace *add_namespace(struct lsns *ls, int type, ino_t ino) ++{ ++ struct lsns_namespace *ns = xcalloc(1, sizeof(*ns)); ++ ++ if (!ns) ++ return NULL; ++ ++ DBG(NS, ul_debugobj(ns, "new %s[%ju]", ns_names[type], (uintmax_t)ino)); ++ ++ INIT_LIST_HEAD(&ns->processes); ++ INIT_LIST_HEAD(&ns->namespaces); ++ ++ ns->type = type; ++ ns->id = ino; ++ ++ list_add_tail(&ns->namespaces, &ls->namespaces); ++ return ns; ++} ++ ++static int add_process_to_namespace(struct lsns *ls, struct lsns_namespace *ns, struct lsns_process *proc) ++{ ++ struct list_head *p; ++ ++ DBG(NS, ul_debugobj(ns, "add process [%p] pid=%d to %s[%ju]", ++ proc, proc->pid, ns_names[ns->type], (uintmax_t)ns->id)); ++ ++ list_for_each(p, &ls->processes) { ++ struct lsns_process *xproc = list_entry(p, struct lsns_process, processes); ++ ++ if (xproc->pid == proc->ppid) /* my parent */ ++ proc->parent = xproc; ++ else if (xproc->ppid == proc->pid) /* my child */ ++ xproc->parent = proc; ++ } ++ ++ list_add_tail(&proc->ns_siblings[ns->type], &ns->processes); ++ ns->nprocs++; ++ ++ if (!ns->proc || ns->proc->pid > proc->pid) ++ ns->proc = proc; ++ ++ return 0; ++} ++ ++static int cmp_namespaces(struct list_head *a, struct list_head *b, ++ __attribute__((__unused__)) void *data) ++{ ++ struct lsns_namespace *xa = list_entry(a, struct lsns_namespace, namespaces), ++ *xb = list_entry(b, struct lsns_namespace, namespaces); ++ ++ return cmp_numbers(xa->id, xb->id); ++} ++ ++static int read_namespaces(struct lsns *ls) ++{ ++ struct list_head *p; ++ ++ DBG(NS, ul_debug("reading namespace")); ++ ++ list_for_each(p, &ls->processes) { ++ size_t i; ++ struct lsns_namespace *ns; ++ struct lsns_process *proc = list_entry(p, struct lsns_process, processes); ++ ++ for (i = 0; i < ARRAY_SIZE(proc->ns_ids); i++) { ++ if (proc->ns_ids[i] == 0) ++ continue; ++ if (!(ns = get_namespace(ls, proc->ns_ids[i]))) { ++ ns = add_namespace(ls, i, proc->ns_ids[i]); ++ if (!ns) ++ return -ENOMEM; ++ } ++ add_process_to_namespace(ls, ns, proc); ++ } ++ } ++ ++ list_sort(&ls->namespaces, cmp_namespaces, NULL); ++ ++ return 0; ++} ++ ++static void add_scols_line(struct lsns *ls, struct libscols_table *table, ++ struct lsns_namespace *ns, struct lsns_process *proc) ++{ ++ size_t i; ++ struct libscols_line *line; ++ ++ assert(ns); ++ assert(table); ++ ++ line = scols_table_new_line(table, ++ ls->tree && proc->parent ? proc->parent->outline : NULL); ++ if (!line) { ++ warn(_("failed to add line to output")); ++ return; ++ } ++ ++ for (i = 0; i < ncolumns; i++) { ++ char *str = NULL; ++ ++ switch (get_column_id(i)) { ++ case COL_NS: ++ xasprintf(&str, "%ju", (uintmax_t)ns->id); ++ break; ++ case COL_PID: ++ xasprintf(&str, "%d", (int) proc->pid); ++ break; ++ case COL_PPID: ++ xasprintf(&str, "%d", (int) proc->ppid); ++ break; ++ case COL_TYPE: ++ xasprintf(&str, "%s", ns_names[ns->type]); ++ break; ++ case COL_NPROCS: ++ xasprintf(&str, "%d", ns->nprocs); ++ break; ++ case COL_COMMAND: ++ str = proc_get_command(proc->pid); ++ if (!str) ++ str = proc_get_command_name(proc->pid); ++ break; ++ case COL_PATH: ++ xasprintf(&str, "/proc/%d/ns/%s", (int) proc->pid, ns_names[ns->type]); ++ break; ++ case COL_UID: ++ xasprintf(&str, "%d", (int) proc->uid); ++ break; ++ case COL_USER: ++ xasprintf(&str, "%s", get_id(uid_cache, proc->uid)->name); ++ break; ++ default: ++ break; ++ } ++ ++ if (str) ++ scols_line_set_data(line, i, str); ++ } ++ ++ proc->outline = line; ++} ++ ++static struct libscols_table *init_scols_table(struct lsns *ls) ++{ ++ struct libscols_table *tab; ++ size_t i; ++ ++ tab = scols_new_table(); ++ if (!tab) { ++ warn(_("failed to initialize output table")); ++ return NULL; ++ } ++ ++ scols_table_enable_raw(tab, ls->raw); ++ scols_table_enable_noheadings(tab, ls->no_headings); ++ ++ for (i = 0; i < ncolumns; i++) { ++ const struct colinfo *col = get_column_info(i); ++ int flags = col->flags; ++ ++ if (ls->notrunc) ++ flags &= ~SCOLS_FL_TRUNC; ++ if (ls->tree && get_column_id(i) == COL_COMMAND) ++ flags |= SCOLS_FL_TREE; ++ ++ if (!scols_table_new_column(tab, col->name, col->whint, flags)) { ++ warnx(_("failed to initialize output column")); ++ goto err; ++ } ++ } ++ ++ return tab; ++err: ++ scols_unref_table(tab); ++ return NULL; ++} ++ ++static int show_namespaces(struct lsns *ls) ++{ ++ struct libscols_table *tab; ++ struct list_head *p; ++ int rc = 0; ++ ++ tab = init_scols_table(ls); ++ if (!tab) ++ return -ENOMEM; ++ ++ list_for_each(p, &ls->namespaces) { ++ struct lsns_namespace *ns = list_entry(p, struct lsns_namespace, namespaces); ++ ++ if (ls->fltr_pid != 0 && !namespace_has_process(ns, ls->fltr_pid)) ++ continue; ++ ++ add_scols_line(ls, tab, ns, ns->proc); ++ } ++ ++ scols_print_table(tab); ++ scols_unref_table(tab); ++ return rc; ++} ++ ++static void show_process(struct lsns *ls, struct libscols_table *tab, ++ struct lsns_process *proc, struct lsns_namespace *ns) ++{ ++ /* ++ * create a tree from parent->child relation, but only if the parent is ++ * within the same namespace ++ */ ++ if (ls->tree ++ && proc->parent ++ && !proc->parent->outline ++ && proc->parent->ns_ids[ns->type] == proc->ns_ids[ns->type]) ++ show_process(ls, tab, proc->parent, ns); ++ ++ add_scols_line(ls, tab, ns, proc); ++} ++ ++ ++static int show_namespace_processes(struct lsns *ls, struct lsns_namespace *ns) ++{ ++ struct libscols_table *tab; ++ struct list_head *p; ++ ++ tab = init_scols_table(ls); ++ if (!tab) ++ return -ENOMEM; ++ ++ list_for_each(p, &ns->processes) { ++ struct lsns_process *proc = list_entry(p, struct lsns_process, ns_siblings[ns->type]); ++ ++ if (!proc->outline) ++ show_process(ls, tab, proc, ns); ++ } ++ ++ ++ scols_print_table(tab); ++ scols_unref_table(tab); ++ return 0; ++} ++ ++static void __attribute__ ((__noreturn__)) usage(FILE * out) ++{ ++ size_t i; ++ ++ fputs(USAGE_HEADER, out); ++ ++ fprintf(out, ++ _(" %s [options] [<namespace>]\n"), program_invocation_short_name); ++ ++ fputs(USAGE_SEPARATOR, out); ++ fputs(_("List system namespaces.\n"), out); ++ ++ fputs(USAGE_OPTIONS, out); ++ fputs(_(" -l, --list use list format output\n"), out); ++ fputs(_(" -n, --noheadings don't print headings\n"), out); ++ fputs(_(" -o, --output <list> define which output columns to use\n"), out); ++ fputs(_(" -p, --task <pid> print process namespaces\n"), out); ++ fputs(_(" -r, --raw use the raw output format\n"), out); ++ fputs(_(" -u, --notruncate don't truncate text in columns\n"), out); ++ fputs(_(" -t, --type <name> namespace type (mnt, net, ipc, user, pid, uts)\n"), out); ++ ++ fputs(USAGE_SEPARATOR, out); ++ fputs(USAGE_HELP, out); ++ fputs(USAGE_VERSION, out); ++ ++ fputs(_("\nAvailable columns (for --output):\n"), out); ++ ++ for (i = 0; i < ARRAY_SIZE(infos); i++) ++ fprintf(out, " %11s %s\n", infos[i].name, _(infos[i].help)); ++ ++ fprintf(out, USAGE_MAN_TAIL("lsns(8)")); ++ ++ exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); ++} ++ ++ ++int main(int argc, char *argv[]) ++{ ++ struct lsns ls; ++ int c; ++ int r = 0; ++ char *outarg = NULL; ++ static const struct option long_opts[] = { ++ { "task", required_argument, NULL, 'p' }, ++ { "help", no_argument, NULL, 'h' }, ++ { "output", required_argument, NULL, 'o' }, ++ { "notruncate", no_argument, NULL, 'u' }, ++ { "version", no_argument, NULL, 'V' }, ++ { "noheadings", no_argument, NULL, 'n' }, ++ { "list", no_argument, NULL, 'l' }, ++ { "raw", no_argument, NULL, 'r' }, ++ { "type", required_argument, NULL, 't' }, ++ { NULL, 0, NULL, 0 } ++ }; ++ ++ static const ul_excl_t excl[] = { /* rows and cols in ASCII order */ ++ { 'J','r' }, ++ { 0 } ++ }; ++ int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT; ++ ++ setlocale(LC_ALL, ""); ++ bindtextdomain(PACKAGE, LOCALEDIR); ++ textdomain(PACKAGE); ++ atexit(close_stdout); ++ ++ lsns_init_debug(); ++ memset(&ls, 0, sizeof(ls)); ++ ++ INIT_LIST_HEAD(&ls.processes); ++ INIT_LIST_HEAD(&ls.namespaces); ++ ++ while ((c = getopt_long(argc, argv, ++ "lp:o:nruhVt:", long_opts, NULL)) != -1) { ++ ++ err_exclusive_options(c, long_opts, excl, excl_st); ++ ++ switch(c) { ++ case 'l': ++ ls.list = 1; ++ break; ++ case 'o': ++ outarg = optarg; ++ break; ++ case 'V': ++ printf(UTIL_LINUX_VERSION); ++ return EXIT_SUCCESS; ++ case 'p': ++ ls.fltr_pid = strtos32_or_err(optarg, _("invalid PID argument")); ++ break; ++ case 'h': ++ usage(stdout); ++ case 'n': ++ ls.no_headings = 1; ++ break; ++ case 'r': ++ ls.raw = 1; ++ break; ++ case 'u': ++ ls.notrunc = 1; ++ break; ++ case 't': ++ { ++ int type = ns_name2type(optarg); ++ if (type < 0) ++ errx(EXIT_FAILURE, _("unknown namespace type: %s"), optarg); ++ ls.fltr_types[type] = 1; ++ ls.fltr_ntypes++; ++ break; ++ } ++ case '?': ++ default: ++ usage(stderr); ++ } ++ } ++ ++ if (!ls.fltr_ntypes) { ++ size_t i; ++ for (i = 0; i < ARRAY_SIZE(ns_names); i++) ++ ls.fltr_types[i] = 1; ++ } ++ ++ if (optind < argc) { ++ if (ls.fltr_pid) ++ errx(EXIT_FAILURE, _("--task is mutually exclusive with <namespace>")); ++ ls.fltr_ns = strtou64_or_err(argv[optind], _("invalid namespace argument")); ++ ls.tree = ls.list ? 0 : 1; ++ ++ if (!ncolumns) { ++ columns[ncolumns++] = COL_PID; ++ columns[ncolumns++] = COL_PPID; ++ columns[ncolumns++] = COL_USER; ++ columns[ncolumns++] = COL_COMMAND; ++ } ++ } ++ ++ if (!ncolumns) { ++ columns[ncolumns++] = COL_NS; ++ columns[ncolumns++] = COL_TYPE; ++ columns[ncolumns++] = COL_NPROCS; ++ columns[ncolumns++] = COL_PID; ++ columns[ncolumns++] = COL_USER; ++ columns[ncolumns++] = COL_COMMAND; ++ } ++ ++ if (outarg && string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns), ++ (int *) &ncolumns, column_name_to_id) < 0) ++ return EXIT_FAILURE; ++ ++ scols_init_debug(0); ++ ++ uid_cache = new_idcache(); ++ if (!uid_cache) ++ err(EXIT_FAILURE, _("failed to allocate UID cache")); ++ ++ r = read_processes(&ls); ++ if (!r) ++ r = read_namespaces(&ls); ++ if (!r) { ++ if (ls.fltr_ns) { ++ struct lsns_namespace *ns = get_namespace(&ls, ls.fltr_ns); ++ ++ if (!ns) ++ errx(EXIT_FAILURE, _("not found namespace: %ju"), (uintmax_t) ls.fltr_ns); ++ r = show_namespace_processes(&ls, ns); ++ } else ++ r = show_namespaces(&ls); ++ } ++ ++ free_idcache(uid_cache); ++ return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE; ++} +-- +2.7.4 + diff --git a/SOURCES/0077-lib-strutils-make-strmode-more-generic.patch b/SOURCES/0077-lib-strutils-make-strmode-more-generic.patch new file mode 100644 index 0000000..5534e62 --- /dev/null +++ b/SOURCES/0077-lib-strutils-make-strmode-more-generic.patch @@ -0,0 +1,76 @@ +From 7bf448fe38478b6e76824fa5bbd2d2d25a48f618 Mon Sep 17 00:00:00 2001 +From: Karel Zak <kzak@redhat.com> +Date: Tue, 30 Jun 2015 12:41:13 +0200 +Subject: [PATCH 77/84] lib/strutils: make strmode() more generic + +Upstream: http://github.com/karelzak/util-linux/commit/7015df4936ca320a86d2916533a17499ac5e4fcf +Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1153770 +Signed-off-by: Karel Zak <kzak@redhat.com> +--- + lib/strutils.c | 36 +++++++++++++++++++----------------- + 1 file changed, 19 insertions(+), 17 deletions(-) + +diff --git a/lib/strutils.c b/lib/strutils.c +index c263b86..f9cdcbb 100644 +--- a/lib/strutils.c ++++ b/lib/strutils.c +@@ -349,37 +349,39 @@ void strtotimeval_or_err(const char *str, struct timeval *tv, const char *errmes + */ + void strmode(mode_t mode, char *str) + { ++ unsigned short i = 0; ++ + if (S_ISDIR(mode)) +- str[0] = 'd'; ++ str[i++] = 'd'; + else if (S_ISLNK(mode)) +- str[0] = 'l'; ++ str[i++] = 'l'; + else if (S_ISCHR(mode)) +- str[0] = 'c'; ++ str[i++] = 'c'; + else if (S_ISBLK(mode)) +- str[0] = 'b'; ++ str[i++] = 'b'; + else if (S_ISSOCK(mode)) +- str[0] = 's'; ++ str[i++] = 's'; + else if (S_ISFIFO(mode)) +- str[0] = 'p'; ++ str[i++] = 'p'; + else if (S_ISREG(mode)) +- str[0] = '-'; ++ str[i++] = '-'; + +- str[1] = mode & S_IRUSR ? 'r' : '-'; +- str[2] = mode & S_IWUSR ? 'w' : '-'; +- str[3] = (mode & S_ISUID ++ str[i++] = mode & S_IRUSR ? 'r' : '-'; ++ str[i++] = mode & S_IWUSR ? 'w' : '-'; ++ str[i++] = (mode & S_ISUID + ? (mode & S_IXUSR ? 's' : 'S') + : (mode & S_IXUSR ? 'x' : '-')); +- str[4] = mode & S_IRGRP ? 'r' : '-'; +- str[5] = mode & S_IWGRP ? 'w' : '-'; +- str[6] = (mode & S_ISGID ++ str[i++] = mode & S_IRGRP ? 'r' : '-'; ++ str[i++] = mode & S_IWGRP ? 'w' : '-'; ++ str[i++] = (mode & S_ISGID + ? (mode & S_IXGRP ? 's' : 'S') + : (mode & S_IXGRP ? 'x' : '-')); +- str[7] = mode & S_IROTH ? 'r' : '-'; +- str[8] = mode & S_IWOTH ? 'w' : '-'; +- str[9] = (mode & S_ISVTX ++ str[i++] = mode & S_IROTH ? 'r' : '-'; ++ str[i++] = mode & S_IWOTH ? 'w' : '-'; ++ str[i++] = (mode & S_ISVTX + ? (mode & S_IXOTH ? 't' : 'T') + : (mode & S_IXOTH ? 'x' : '-')); +- str[10] = '\0'; ++ str[i] = '\0'; + } + + /* +-- +2.7.4 + diff --git a/SOURCES/0078-lsipc-backport-new-command.patch b/SOURCES/0078-lsipc-backport-new-command.patch new file mode 100644 index 0000000..e87be77 --- /dev/null +++ b/SOURCES/0078-lsipc-backport-new-command.patch @@ -0,0 +1,2000 @@ +From 9f643efe377d2a39929f19cc09e8890afc74d9a4 Mon Sep 17 00:00:00 2001 +From: Karel Zak <kzak@redhat.com> +Date: Fri, 24 Jun 2016 12:57:13 +0200 +Subject: [PATCH 78/84] lsipc: backport new command + +Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1153770 +Signed-off-by: Karel Zak <kzak@redhat.com> +--- + bash-completion/lsipc | 64 +++ + configure.ac | 6 + + include/xalloc.h | 7 + + sys-utils/Makemodule.am | 10 + + sys-utils/ipcs.c | 2 +- + sys-utils/ipcutils.c | 116 ++--- + sys-utils/ipcutils.h | 13 +- + sys-utils/lsipc.1 | 133 +++++ + sys-utils/lsipc.c | 1316 +++++++++++++++++++++++++++++++++++++++++++++++ + tests/functions.sh | 16 +- + tests/ts/ipcs/limits2 | 9 +- + 11 files changed, 1613 insertions(+), 79 deletions(-) + create mode 100644 bash-completion/lsipc + create mode 100644 sys-utils/lsipc.1 + create mode 100644 sys-utils/lsipc.c + +diff --git a/bash-completion/lsipc b/bash-completion/lsipc +new file mode 100644 +index 0000000..6a87393 +--- /dev/null ++++ b/bash-completion/lsipc +@@ -0,0 +1,64 @@ ++_lsipc_module() ++{ ++ local cur prev OPTS ARG ++ COMPREPLY=() ++ cur="${COMP_WORDS[COMP_CWORD]}" ++ prev="${COMP_WORDS[COMP_CWORD-1]}" ++ case $prev in ++ '-i'|'--id') ++ COMPREPLY=( $(compgen -W "id" -- $cur) ) ++ return 0 ++ ;; ++ '-h'|'--help'|'-V'|'--version') ++ return 0 ++ ;; ++ '-o'|'--output') ++ local prefix realcur OUTPUT_ALL OUTPUT ++ realcur="${cur##*,}" ++ prefix="${cur%$realcur}" ++ OUTPUT_ALL="GENERAL KEY ID OWNER PERMS CUID ++ CGID UID GID CHANGE MESSAGE USEDBYTES ++ MSGS SEND RECV LSPID LRPID SHARED BYTES ++ NATTCH STATUS ATTACH DETACH CPID LPID NSEMS ++ LASTOP" ++ for WORD in $OUTPUT_ALL; do ++ if ! [[ $prefix == *"$WORD"* ]]; then ++ OUTPUT="$WORD $OUTPUT" ++ fi ++ done ++ compopt -o nospace ++ COMPREPLY=( $(compgen -P "$prefix" -W "$OUTPUT" -S ',' -- $realcur) ) ++ return 0 ++ ;; ++ esac ++ case $cur in ++ -*) ++ OPTS="--id ++ --help ++ --version ++ --shmems ++ --queues ++ --semaphores ++ --colon-separate ++ --creator ++ --export ++ --global ++ --newline ++ --noheadings ++ --notruncate ++ --output ++ --pid ++ --print0 ++ --raw ++ --time ++ --time-format" ++ COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) ) ++ return 0 ++ ;; ++ esac ++ local IFS=$'\n' ++ compopt -o filenames ++ COMPREPLY=( $(compgen -f -- $cur) ) ++ return 0 ++} ++complete -F _lsipc_module lsipc +diff --git a/configure.ac b/configure.ac +index 5d9ea39..fe0a011 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1038,6 +1038,12 @@ UL_REQUIRES_BUILD([lsns], [libsmartcols]) + AM_CONDITIONAL([BUILD_LSNS], [test "x$build_lsns" = xyes]) + + ++UL_BUILD_INIT([lsipc], [check]) ++UL_REQUIRES_LINUX([lsipc]) ++UL_REQUIRES_BUILD([lsipc], [libsmartcols]) ++AM_CONDITIONAL([BUILD_LSIPC], [test "x$build_lsipc" = xyes]) ++ ++ + UL_BUILD_INIT([chcpu], [check]) + UL_REQUIRES_LINUX([chcpu]) + UL_REQUIRES_HAVE([chcpu], [cpu_set_t], [cpu_set_t type]) +diff --git a/include/xalloc.h b/include/xalloc.h +index 6342793..1a1799a 100644 +--- a/include/xalloc.h ++++ b/include/xalloc.h +@@ -19,6 +19,13 @@ + # define XALLOC_EXIT_CODE EXIT_FAILURE + #endif + ++static inline void __err_oom(const char *file, unsigned int line) ++{ ++ err(XALLOC_EXIT_CODE, "%s: %u: cannot allocate memory", file, line); ++} ++ ++#define err_oom() __err_oom(__FILE__, __LINE__) ++ + static inline __ul_alloc_size(1) + void *xmalloc(const size_t size) + { +diff --git a/sys-utils/Makemodule.am b/sys-utils/Makemodule.am +index 9baf5a3..6badd17 100644 +--- a/sys-utils/Makemodule.am ++++ b/sys-utils/Makemodule.am +@@ -22,6 +22,16 @@ ipcs_SOURCES = sys-utils/ipcs.c \ + ipcs_LDADD = $(LDADD) libcommon.la + + ++if BUILD_LSIPC ++usrbin_exec_PROGRAMS += lsipc ++dist_man_MANS += sys-utils/lsipc.1 ++lsipc_SOURCES = sys-utils/lsipc.c \ ++ sys-utils/ipcutils.c \ ++ sys-utils/ipcutils.h ++lsipc_LDADD = $(LDADD) libcommon.la libsmartcols.la ++lsipc_CFLAGS = $(AM_CFLAGS) -I$(ul_libsmartcols_incdir) ++endif ++ + usrbin_exec_PROGRAMS += renice + dist_man_MANS += sys-utils/renice.1 + renice_SOURCES = sys-utils/renice.c +diff --git a/sys-utils/ipcs.c b/sys-utils/ipcs.c +index 14f5f0b..1843cd5 100644 +--- a/sys-utils/ipcs.c ++++ b/sys-utils/ipcs.c +@@ -201,7 +201,7 @@ static void do_shm (char format, int unit) + _("max seg size"), lim.shmmax, "\n", 0); + ipc_print_size(unit == IPC_UNIT_DEFAULT ? IPC_UNIT_KB : unit, + _("max total shared memory"), +- lim.shmall * getpagesize(), "\n", 0); ++ (uint64_t) lim.shmall * getpagesize(), "\n", 0); + ipc_print_size(unit == IPC_UNIT_DEFAULT ? IPC_UNIT_BYTES : unit, + _("min seg size"), lim.shmmin, "\n", 0); + return; +diff --git a/sys-utils/ipcutils.c b/sys-utils/ipcutils.c +index 62d7428..51fce7b 100644 +--- a/sys-utils/ipcutils.c ++++ b/sys-utils/ipcutils.c +@@ -1,4 +1,3 @@ +- + #include <inttypes.h> + + #include "c.h" +@@ -54,8 +53,8 @@ int ipc_sem_get_limits(struct ipc_limits *lim) + + } + +- if (rc == 4) { +- struct seminfo seminfo; ++ if (rc != 4) { ++ struct seminfo seminfo = { .semmni = 0 }; + union semun arg = { .array = (ushort *) &seminfo }; + + if (semctl(0, 0, IPC_INFO, arg) < 0) +@@ -82,12 +81,15 @@ int ipc_shm_get_limits(struct ipc_limits *lim) + lim->shmmni = path_read_u64(_PATH_PROC_IPC_SHMMNI); + + } else { +- struct shminfo shminfo; ++ struct shminfo *shminfo; ++ struct shmid_ds shmbuf; + +- if (shmctl(0, IPC_INFO, (struct shmid_ds *) &shminfo) < 0) ++ if (shmctl(0, IPC_INFO, &shmbuf) < 0) + return 1; +- lim->shmmni = shminfo.shmmni; +- lim->shmall = shminfo.shmall; ++ shminfo = (struct shminfo *) &shmbuf; ++ lim->shmmni = shminfo->shmmni; ++ lim->shmall = shminfo->shmall; ++ lim->shmmax = shminfo->shmmax; + } + + return 0; +@@ -97,20 +99,24 @@ int ipc_shm_get_info(int id, struct shm_data **shmds) + { + FILE *f; + int i = 0, maxid; ++ char buf[BUFSIZ]; + struct shm_data *p; +- struct shm_info dummy; ++ struct shmid_ds dummy; + + p = *shmds = xcalloc(1, sizeof(struct shm_data)); + p->next = NULL; + + f = path_fopen("r", 0, _PATH_PROC_SYSV_SHM); + if (!f) +- goto fallback; ++ goto shm_fallback; + + while (fgetc(f) != '\n'); /* skip header */ + +- while (feof(f) == 0) { +- if (fscanf(f, ++ while (fgets(buf, sizeof(buf), f) != NULL) { ++ /* scan for the first 14-16 columns (e.g. Linux 2.6.32 has 14) */ ++ p->shm_rss = 0xdead; ++ p->shm_swp = 0xdead; ++ if (sscanf(buf, + "%d %d %o %"SCNu64 " %u %u " + "%"SCNu64 " %u %u %u %u %"SCNi64 " %"SCNi64 " %"SCNi64 + " %"SCNu64 " %"SCNu64 "\n", +@@ -129,8 +135,8 @@ int ipc_shm_get_info(int id, struct shm_data **shmds) + &p->shm_dtim, + &p->shm_ctim, + &p->shm_rss, +- &p->shm_swp) != 16) +- continue; ++ &p->shm_swp) < 14) ++ continue; /* invalid line, skipped */ + + if (id > -1) { + /* ID specified */ +@@ -153,28 +159,20 @@ int ipc_shm_get_info(int id, struct shm_data **shmds) + return i; + + /* Fallback; /proc or /sys file(s) missing. */ +-fallback: +- i = id < 0 ? 0 : id; +- +- maxid = shmctl(0, SHM_INFO, (struct shmid_ds *) &dummy); +- if (maxid < 0) +- return 0; ++shm_fallback: ++ maxid = shmctl(0, SHM_INFO, &dummy); + +- while (i <= maxid) { ++ for (int j = 0; j <= maxid; j++) { + int shmid; + struct shmid_ds shmseg; + struct ipc_perm *ipcp = &shmseg.shm_perm; + +- shmid = shmctl(i, SHM_STAT, &shmseg); +- if (shmid < 0) { +- if (-1 < id) { +- free(*shmds); +- return 0; +- } +- i++; ++ shmid = shmctl(j, SHM_STAT, &shmseg); ++ if (shmid < 0 || (id > -1 && shmid != id)) { + continue; + } + ++ i++; + p->shm_perm.key = ipcp->KEY; + p->shm_perm.id = shmid; + p->shm_perm.mode = ipcp->mode; +@@ -196,11 +194,12 @@ fallback: + p->next = xcalloc(1, sizeof(struct shm_data)); + p = p->next; + p->next = NULL; +- i++; + } else +- return 1; ++ break; + } + ++ if (i == 0) ++ free(*shmds); + return i; + } + +@@ -299,30 +298,22 @@ int ipc_sem_get_info(int id, struct sem_data **semds) + return i; + + /* Fallback; /proc or /sys file(s) missing. */ +- sem_fallback: +- i = id < 0 ? 0 : id; +- ++sem_fallback: + arg.array = (ushort *) (void *)&dummy; + maxid = semctl(0, 0, SEM_INFO, arg); +- if (maxid < 0) +- return 0; + +- while (i <= maxid) { ++ for (int j = 0; j <= maxid; j++) { + int semid; + struct semid_ds semseg; + struct ipc_perm *ipcp = &semseg.sem_perm; + arg.buf = (struct semid_ds *)&semseg; + +- semid = semctl(i, 0, SEM_STAT, arg); +- if (semid < 0) { +- if (-1 < id) { +- free(*semds); +- return 0; +- } +- i++; ++ semid = semctl(j, 0, SEM_STAT, arg); ++ if (semid < 0 || (id > -1 && semid != id)) { + continue; + } + ++ i++; + p->sem_perm.key = ipcp->KEY; + p->sem_perm.id = semid; + p->sem_perm.mode = ipcp->mode; +@@ -341,10 +332,12 @@ int ipc_sem_get_info(int id, struct sem_data **semds) + i++; + } else { + get_sem_elements(p); +- return 1; ++ break; + } + } + ++ if (i == 0) ++ free(*semds); + return i; + } + +@@ -398,10 +391,6 @@ int ipc_msg_get_info(int id, struct msg_data **msgds) + if (id > -1) { + /* ID specified */ + if (id == p->msg_perm.id) { +- /* +- * FIXME: q_qbytes are not in /proc +- * +- */ + if (msgctl(id, IPC_STAT, &msgseg) != -1) + p->q_qbytes = msgseg.msg_qbytes; + i = 1; +@@ -422,27 +411,19 @@ int ipc_msg_get_info(int id, struct msg_data **msgds) + return i; + + /* Fallback; /proc or /sys file(s) missing. */ +- msg_fallback: +- i = id < 0 ? 0 : id; +- +- maxid = msgctl(id, MSG_STAT, &dummy); +- if (maxid < 0) +- return 0; ++msg_fallback: ++ maxid = msgctl(0, MSG_INFO, &dummy); + +- while (i <= maxid) { ++ for (int j = 0; j <= maxid; j++) { + int msgid; + struct ipc_perm *ipcp = &msgseg.msg_perm; + +- msgid = msgctl(i, MSG_STAT, &msgseg); +- if (msgid < 0) { +- if (-1 < id) { +- free(*msgds); +- return 0; +- } +- i++; ++ msgid = msgctl(j, MSG_STAT, &msgseg); ++ if (msgid < 0 || (id > -1 && msgid != id)) { + continue; + } + ++ i++; + p->msg_perm.key = ipcp->KEY; + p->msg_perm.id = msgid; + p->msg_perm.mode = ipcp->mode; +@@ -463,11 +444,12 @@ int ipc_msg_get_info(int id, struct msg_data **msgds) + p->next = xcalloc(1, sizeof(struct msg_data)); + p = p->next; + p->next = NULL; +- i++; + } else +- return 1; ++ break; + } + ++ if (i == 0) ++ free(*msgds); + return i; + } + +@@ -508,10 +490,10 @@ void ipc_print_perms(FILE *f, struct ipc_stat *is) + fprintf(f, " %-10u\n", is->gid); + } + +-void ipc_print_size(int unit, char *msg, size_t size, const char *end, ++void ipc_print_size(int unit, char *msg, uint64_t size, const char *end, + int width) + { +- char format[16]; ++ char format[32]; + + if (!msg) + /* NULL */ ; +@@ -527,11 +509,11 @@ void ipc_print_size(int unit, char *msg, size_t size, const char *end, + switch (unit) { + case IPC_UNIT_DEFAULT: + case IPC_UNIT_BYTES: +- sprintf(format, "%%%dzu", width); ++ sprintf(format, "%%%dju", width); + printf(format, size); + break; + case IPC_UNIT_KB: +- sprintf(format, "%%%dzu", width); ++ sprintf(format, "%%%dju", width); + printf(format, size / 1024); + break; + case IPC_UNIT_HUMAN: +diff --git a/sys-utils/ipcutils.h b/sys-utils/ipcutils.h +index d2e5972..444065a 100644 +--- a/sys-utils/ipcutils.h ++++ b/sys-utils/ipcutils.h +@@ -12,6 +12,7 @@ + #include <unistd.h> + #include <grp.h> + #include <pwd.h> ++#include <stdint.h> + + /* + * SHM_DEST and SHM_LOCKED are defined in kernel headers, but inside +@@ -34,11 +35,11 @@ + # define SHM_INFO 14 + struct shm_info { + int used_ids; +- ulong shm_tot; /* total allocated shm */ +- ulong shm_rss; /* total resident shm */ +- ulong shm_swp; /* total swapped shm */ +- ulong swap_attempts; +- ulong swap_successes; ++ unsigned long shm_tot; /* total allocated shm */ ++ unsigned long shm_rss; /* total resident shm */ ++ unsigned long shm_swp; /* total swapped shm */ ++ unsigned long swap_attempts; ++ unsigned long swap_successes; + }; + #endif + +@@ -118,7 +119,7 @@ struct ipc_stat { + }; + + extern void ipc_print_perms(FILE *f, struct ipc_stat *is); +-extern void ipc_print_size(int unit, char *msg, size_t size, const char *end, int width); ++extern void ipc_print_size(int unit, char *msg, uint64_t size, const char *end, int width); + + /* See 'struct shmid_kernel' in kernel sources + */ +diff --git a/sys-utils/lsipc.1 b/sys-utils/lsipc.1 +new file mode 100644 +index 0000000..98449cb +--- /dev/null ++++ b/sys-utils/lsipc.1 +@@ -0,0 +1,133 @@ ++.\" Copyright 2015 Ondrej Oprala(ooprala@redhat.com) ++.\" May be distributed under the GNU General Public License ++.TH LSIPC "1" "November 2015" "util-linux" "User Commands" ++.SH NAME ++lsipc \- show information on IPC facilities currently employed in the system ++.SH SYNOPSIS ++.B lsipc ++[options] ++.SH DESCRIPTION ++.B lsipc ++shows information on the inter-process communication facilities ++for which the calling process has read access. ++.SH OPTIONS ++.TP ++\fB\-i\fR, \fB\-\-id\fR \fIid\fR ++Show full details on just the one resource element identified by ++.IR id . ++This option needs to be combined with one of the three resource options: ++.BR \-m , ++.BR \-q " or" ++.BR \-s . ++It is possible to override the default output format for this option with the ++\fB\-\-list\fR, \fB\-\-raw\fR, \fB\-\-json\fR or \fB\-\-export\fR option. ++.TP ++\fB\-g\fR, \fB\-\-global\fR ++Show system-wide usage and limits of IPC resources. ++This option may be combined with one of the three resource options: ++.BR \-m , ++.BR \-q " or" ++.BR \-s . ++The default is to show information about all resources. ++.TP ++\fB\-h\fR, \fB\-\-help\fR ++Display help text and exit. ++.TP ++\fB\-V\fR, \fB\-\-version\fR ++Display version information and exit. ++.SS "Resource options" ++.TP ++\fB\-m\fR, \fB\-\-shmems\fR ++Write information about active shared memory segments. ++.TP ++\fB\-q\fR, \fB\-\-queues\fR ++Write information about active message queues. ++.TP ++\fB\-s\fR, \fB\-\-semaphores\fR ++Write information about active semaphore sets. ++.SS "Output formatting" ++.TP ++\fB\-c\fR, \fB\-\-creator\fR ++Show creator and owner. ++.TP ++\fB\-e\fR, \fB\-\-export\fR ++Output data in the format of NAME=VALUE. ++.TP ++\fB\-l\fR, \fB\-\-list\fR ++Use the list output format. This is the default, except when \fB\-\-id\fR ++is used. ++.TP ++\fB\-n\fR, \fB\-\-newline\fR ++Display each piece of information on a separate line. ++.TP ++\fB\-\-noheadings\fR ++Do not print a header line. ++.TP ++\fB\-\-notruncate\fR ++Don't truncate output. ++.TP ++\fB\-o\fR, \fB\-\-output \fIlist\fP ++Specify which output columns to print. Use ++.B \-\-help ++to get a list of all supported columns. ++.TP ++\fB\-p\fR, \fB\-\-pid\fR ++Show PIDs of creator and last operator. ++.TP ++\fB\-r\fR, \fB\-\-raw\fR ++Raw output (no columnation). ++.TP ++\fB\-t\fR, \fB\-\-time\fR ++Write time information. The time of the last control operation that changed ++the access permissions for all facilities, the time of the last ++.I msgsnd() ++and ++.I msgrcv() ++operations on message queues, the time of the last ++.I shmat() ++and ++.I shmdt() ++operations on shared memory, and the time of the last ++.I semop() ++operation on semaphores. ++.TP ++\fB\-\-time\-format\fR \fItype\fP ++Display dates in short, full or iso format. The default is short, this time ++format is designed to be space efficient and human readable. ++ ++.SH EXIT STATUS ++.TP ++0 ++if OK, ++.TP ++1 ++if incorrect arguments specified, ++.TP ++2 ++if a serious error occurs. ++.SH SEE ALSO ++.BR ipcrm (1), ++.BR ipcmk (1), ++.BR msgrcv (2), ++.BR msgsnd (2), ++.BR semget (2), ++.BR semop (2), ++.BR shmat (2), ++.BR shmdt (2), ++.BR shmget (2) ++.SH HISTORY ++The \fBlsipc\fP utility is inspired by the \fBipcs\fP utility. ++.SH AUTHORS ++.MT ooprala@redhat.com ++Ondrej Oprala ++.ME ++.br ++.MT kzak@redhat.com ++Karel Zak ++.ME ++ ++.SH AVAILABILITY ++The lsipc command is part of the util-linux package and is available from ++.UR ftp://\:ftp.kernel.org\:/pub\:/linux\:/utils\:/util-linux/ ++Linux Kernel Archive ++.UE . +diff --git a/sys-utils/lsipc.c b/sys-utils/lsipc.c +new file mode 100644 +index 0000000..0be9d91 +--- /dev/null ++++ b/sys-utils/lsipc.c +@@ -0,0 +1,1316 @@ ++/* ++ * lsipc - List information about IPC instances employed in the system ++ * ++ * Copyright (C) 2015 Ondrej Oprala <ooprala@redhat.com> ++ * Copyright (C) 2015 Karel Zak <ooprala@redhat.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it would be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * ++ * lsipc is inspired by the ipcs utility. The aim is to create ++ * a utility unencumbered by a standard to provide more flexible ++ * means of controlling the output. ++ */ ++ ++#include <errno.h> ++#include <getopt.h> ++#include <sys/time.h> ++#include <unistd.h> ++ ++#include <libsmartcols.h> ++ ++#include "c.h" ++#include "nls.h" ++#include "closestream.h" ++#include "strutils.h" ++#include "optutils.h" ++#include "xalloc.h" ++#include "procutils.h" ++#include "ipcutils.h" ++ ++/* ++ * time modes ++ * */ ++enum { ++ TIME_INVALID = 0, ++ TIME_SHORT, ++ TIME_FULL, ++ TIME_ISO ++}; ++ ++/* ++ * IDs ++ */ ++enum { ++ /* generic */ ++ COLDESC_IDX_GEN_FIRST = 0, ++ COL_KEY = COLDESC_IDX_GEN_FIRST, ++ COL_ID, ++ COL_OWNER, ++ COL_PERMS, ++ COL_CUID, ++ COL_CUSER, ++ COL_CGID, ++ COL_CGROUP, ++ COL_UID, ++ COL_USER, ++ COL_GID, ++ COL_GROUP, ++ COL_CTIME, ++ COLDESC_IDX_GEN_LAST = COL_CTIME, ++ ++ /* msgq-specific */ ++ COLDESC_IDX_MSG_FIRST, ++ COL_USEDBYTES = COLDESC_IDX_MSG_FIRST, ++ COL_MSGS, ++ COL_SEND, ++ COL_RECV, ++ COL_LSPID, ++ COL_LRPID, ++ COLDESC_IDX_MSG_LAST = COL_LRPID, ++ ++ /* shm-specific */ ++ COLDESC_IDX_SHM_FIRST, ++ COL_SIZE = COLDESC_IDX_SHM_FIRST, ++ COL_NATTCH, ++ COL_STATUS, ++ COL_ATTACH, ++ COL_DETACH, ++ COL_COMMAND, ++ COL_CPID, ++ COL_LPID, ++ COLDESC_IDX_SHM_LAST = COL_LPID, ++ ++ /* sem-specific */ ++ COLDESC_IDX_SEM_FIRST, ++ COL_NSEMS = COLDESC_IDX_SEM_FIRST, ++ COL_OTIME, ++ COLDESC_IDX_SEM_LAST = COL_OTIME, ++ ++ /* summary (--global) */ ++ COLDESC_IDX_SUM_FIRST, ++ COL_RESOURCE = COLDESC_IDX_SUM_FIRST, ++ COL_DESC, ++ COL_LIMIT, ++ COL_USED, ++ COL_USEPERC, ++ COLDESC_IDX_SUM_LAST = COL_USEPERC ++}; ++ ++/* not all columns apply to all options, so we specify a legal range for each */ ++static size_t LOWER, UPPER; ++ ++/* ++ * output modes ++ */ ++enum { ++ OUT_EXPORT = 1, ++ OUT_NEWLINE, ++ OUT_RAW, ++ OUT_PRETTY, ++ OUT_LIST ++}; ++ ++struct lsipc_control { ++ int outmode; ++ unsigned int noheadings : 1, /* don't print header line */ ++ notrunc : 1, /* don't truncate columns */ ++ bytes : 1, /* SIZE in bytes */ ++ numperms : 1, /* numeric permissions */ ++ time_mode : 2; ++}; ++ ++struct lsipc_coldesc { ++ const char *name; ++ const char *help; ++ const char *pretty_name; ++ ++ double whint; /* width hint */ ++ long flag; ++}; ++ ++static const struct lsipc_coldesc coldescs[] = ++{ ++ /* common */ ++ [COL_KEY] = { "KEY", N_("Resource key"), N_("Key"), 1}, ++ [COL_ID] = { "ID", N_("Resource ID"), N_("ID"), 1}, ++ [COL_OWNER] = { "OWNER", N_("Owner's username or UID"), N_("Owner"), 1, SCOLS_FL_RIGHT}, ++ [COL_PERMS] = { "PERMS", N_("Permissions"), N_("Permissions"), 1, SCOLS_FL_RIGHT}, ++ [COL_CUID] = { "CUID", N_("Creator UID"), N_("Creator UID"), 1, SCOLS_FL_RIGHT}, ++ [COL_CUSER] = { "CUSER", N_("Creator user"), N_("Creator user"), 1 }, ++ [COL_CGID] = { "CGID", N_("Creator GID"), N_("Creator GID"), 1, SCOLS_FL_RIGHT}, ++ [COL_CGROUP] = { "CGROUP", N_("Creator group"), N_("Creator group"), 1 }, ++ [COL_UID] = { "UID", N_("User ID"), N_("UID"), 1, SCOLS_FL_RIGHT}, ++ [COL_USER] = { "USER", N_("User name"), N_("User name"), 1}, ++ [COL_GID] = { "GID", N_("Group ID"), N_("GID"), 1, SCOLS_FL_RIGHT}, ++ [COL_GROUP] = { "GROUP", N_("Group name"), N_("Group name"), 1}, ++ [COL_CTIME] = { "CTIME", N_("Time of the last change"), N_("Last change"), 1, SCOLS_FL_RIGHT}, ++ ++ /* msgq-specific */ ++ [COL_USEDBYTES] = { "USEDBYTES",N_("Bytes used"), N_("Bytes used"), 1, SCOLS_FL_RIGHT}, ++ [COL_MSGS] = { "MSGS", N_("Number of messages"), N_("Messages"), 1}, ++ [COL_SEND] = { "SEND", N_("Time of last msg sent"), N_("Msg sent"), 1, SCOLS_FL_RIGHT}, ++ [COL_RECV] = { "RECV", N_("Time of last msg received"), N_("Msg received"), 1, SCOLS_FL_RIGHT}, ++ [COL_LSPID] = { "LSPID", N_("PID of the last msg sender"), N_("Msg sender"), 1, SCOLS_FL_RIGHT}, ++ [COL_LRPID] = { "LRPID", N_("PID of the last msg receiver"), N_("Msg receiver"), 1, SCOLS_FL_RIGHT}, ++ ++ /* shm-specific */ ++ [COL_SIZE] = { "SIZE", N_("Segment size"), N_("Segment size"), 1, SCOLS_FL_RIGHT}, ++ [COL_NATTCH] = { "NATTCH", N_("Number of attached processes"), N_("Attached processes"), 1, SCOLS_FL_RIGHT}, ++ [COL_STATUS] = { "STATUS", N_("Status"), N_("Status"), 1, SCOLS_FL_NOEXTREMES}, ++ [COL_ATTACH] = { "ATTACH", N_("Attach time"), N_("Attach time"), 1, SCOLS_FL_RIGHT}, ++ [COL_DETACH] = { "DETACH", N_("Detach time"), N_("Detach time"), 1, SCOLS_FL_RIGHT}, ++ [COL_COMMAND] = { "COMMAND", N_("Creator command line"), N_("Creator command"), 0, SCOLS_FL_TRUNC}, ++ [COL_CPID] = { "CPID", N_("PID of the creator"), N_("Creator PID"), 1, SCOLS_FL_RIGHT}, ++ [COL_LPID] = { "LPID", N_("PID of last user"), N_("Last user PID"), 1, SCOLS_FL_RIGHT}, ++ ++ /* sem-specific */ ++ [COL_NSEMS] = { "NSEMS", N_("Number of semaphores"), N_("Semaphores"), 1, SCOLS_FL_RIGHT}, ++ [COL_OTIME] = { "OTIME", N_("Time of the last operation"), N_("Last operation"), 1, SCOLS_FL_RIGHT}, ++ ++ /* cols for summarized information */ ++ [COL_RESOURCE] = { "RESOURCE", N_("Resource name"), N_("Resource"), 1 }, ++ [COL_DESC] = { "DESCRIPTION",N_("Resource description"), N_("Description"), 1 }, ++ [COL_USED] = { "USED", N_("Currently used"), N_("Used"), 1, SCOLS_FL_RIGHT }, ++ [COL_USEPERC] = { "USE%", N_("Currently use percentage"), N_("Use"), 1, SCOLS_FL_RIGHT }, ++ [COL_LIMIT] = { "LIMIT", N_("System-wide limit"), N_("Limit"), 1, SCOLS_FL_RIGHT }, ++}; ++ ++ ++/* columns[] array specifies all currently wanted output column. The columns ++ * are defined by coldescs[] array and you can specify (on command line) each ++ * column twice. That's enough, dynamically allocated array of the columns is ++ * unnecessary overkill and over-engineering in this case */ ++static int columns[ARRAY_SIZE(coldescs) * 2]; ++static size_t ncolumns; ++ ++static inline size_t err_columns_index(size_t arysz, size_t idx) ++{ ++ if (idx >= arysz) ++ errx(EXIT_FAILURE, _("too many columns specified, " ++ "the limit is %zu columns"), ++ arysz - 1); ++ return idx; ++} ++ ++#define add_column(ary, n, id) \ ++ ((ary)[ err_columns_index(ARRAY_SIZE(ary), (n)) ] = (id)) ++ ++static int column_name_to_id(const char *name, size_t namesz) ++{ ++ size_t i; ++ ++ for (i = 0; i < ARRAY_SIZE(coldescs); i++) { ++ const char *cn = coldescs[i].name; ++ ++ if (!strncasecmp(name, cn, namesz) && !*(cn + namesz)) { ++ if (i > COL_CTIME) { ++ if (i >= LOWER && i <= UPPER) ++ return i; ++ else { ++ warnx(_("column %s does not apply to the specified IPC"), name); ++ return -1; ++ } ++ } else ++ return i; ++ } ++ } ++ warnx(_("unknown column: %s"), name); ++ return -1; ++} ++ ++static char *get_username(struct passwd **pw, uid_t id) ++{ ++ if (!*pw || (*pw)->pw_uid != id) ++ *pw = getpwuid(id); ++ ++ return *pw ? xstrdup((*pw)->pw_name) : NULL; ++} ++ ++static char *get_groupname(struct group **gr, gid_t id) ++{ ++ if (!*gr || (*gr)->gr_gid != id) ++ *gr = getgrgid(id); ++ ++ return *gr ? xstrdup((*gr)->gr_name) : NULL; ++} ++ ++static int parse_time_mode(const char *optarg) ++{ ++ struct lsipc_timefmt { ++ const char *name; ++ const int val; ++ }; ++ static const struct lsipc_timefmt timefmts[] = { ++ {"iso", TIME_ISO}, ++ {"full", TIME_FULL}, ++ {"short", TIME_SHORT}, ++ }; ++ size_t i; ++ ++ for (i = 0; i < ARRAY_SIZE(timefmts); i++) { ++ if (strcmp(timefmts[i].name, optarg) == 0) ++ return timefmts[i].val; ++ } ++ errx(EXIT_FAILURE, _("unknown time format: %s"), optarg); ++} ++ ++static void __attribute__ ((__noreturn__)) usage(FILE * out) ++{ ++ size_t i; ++ ++ fputs(USAGE_HEADER, out); ++ fprintf(out, _(" %s [options]\n"), program_invocation_short_name); ++ ++ fputs(USAGE_SEPARATOR, out); ++ fputs(_("Show information on IPC facilities.\n"), out); ++ ++ fputs(USAGE_SEPARATOR, out); ++ fputs(_("Resource options:\n"), out); ++ fputs(_(" -m, --shmems shared memory segments\n"), out); ++ fputs(_(" -q, --queues message queues\n"), out); ++ fputs(_(" -s, --semaphores semaphores\n"), out); ++ fputs(_(" -g, --global info about system-wide usage (may be used with -m, -q and -s)\n"), out); ++ fputs(_(" -i, --id <id> print details on resource identified by <id>\n"), out); ++ ++ fputs(USAGE_OPTIONS, out); ++ fputs(_(" --noheadings don't print headings\n"), out); ++ fputs(_(" --notruncate don't truncate output\n"), out); ++ fputs(_(" --time-format=<type> display dates in short, full or iso format\n"), out); ++ fputs(_(" -b, --bytes print SIZE in bytes rather than in human readable format\n"), out); ++ fputs(_(" -c, --creator show creator and owner\n"), out); ++ fputs(_(" -e, --export display in an export-able output format\n"), out); ++ fputs(_(" -n, --newline display each piece of information on a new line\n"), out); ++ fputs(_(" -l, --list force list output format (for example with --id)\n"), out); ++ fputs(_(" -o, --output[=<list>] define the columns to output\n"), out); ++ fputs(_(" -P, --numeric-perms print numeric permissions (PERMS column)\n"), out); ++ fputs(_(" -r, --raw display in raw mode\n"), out); ++ fputs(_(" -t, --time show attach, detach and change times\n"), out); ++ ++ fputs(USAGE_SEPARATOR, out); ++ fputs(USAGE_HELP, out); ++ fputs(USAGE_VERSION, out); ++ ++ fprintf(out, _("\nGeneric columns:\n")); ++ for (i = COLDESC_IDX_GEN_FIRST; i <= COLDESC_IDX_GEN_LAST; i++) ++ fprintf(out, " %14s %s\n", coldescs[i].name, _(coldescs[i].help)); ++ ++ fprintf(out, _("\nShared-memory columns (--shmems):\n")); ++ for (i = COLDESC_IDX_SHM_FIRST; i <= COLDESC_IDX_SHM_LAST; i++) ++ fprintf(out, " %14s %s\n", coldescs[i].name, _(coldescs[i].help)); ++ ++ fprintf(out, _("\nMessage-queue columns (--queues):\n")); ++ for (i = COLDESC_IDX_MSG_FIRST; i <= COLDESC_IDX_MSG_LAST; i++) ++ fprintf(out, " %14s %s\n", coldescs[i].name, _(coldescs[i].help)); ++ ++ fprintf(out, _("\nSemaphore columns (--semaphores):\n")); ++ for (i = COLDESC_IDX_SEM_FIRST; i <= COLDESC_IDX_SEM_LAST; i++) ++ fprintf(out, " %14s %s\n", coldescs[i].name, _(coldescs[i].help)); ++ ++ fprintf(out, _("\nSummary columns (--global):\n")); ++ for (i = COLDESC_IDX_SUM_FIRST; i <= COLDESC_IDX_SUM_LAST; i++) ++ fprintf(out, " %14s %s\n", coldescs[i].name, _(coldescs[i].help)); ++ ++ fprintf(out, USAGE_MAN_TAIL("lsipc(1)")); ++ exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); ++} ++ ++static struct libscols_table *new_table(struct lsipc_control *ctl) ++{ ++ struct libscols_table *table = scols_new_table(); ++ ++ if (!table) ++ errx(EXIT_FAILURE, _("failed to initialize output table")); ++ if (ctl->noheadings) ++ scols_table_enable_noheadings(table, 1); ++ ++ switch(ctl->outmode) { ++ case OUT_NEWLINE: ++ scols_table_set_column_separator(table, "\n"); ++ /* fallthrough */ ++ case OUT_EXPORT: ++ scols_table_enable_export(table, 1); ++ break; ++ case OUT_RAW: ++ scols_table_enable_raw(table, 1); ++ break; ++ case OUT_PRETTY: ++ scols_table_enable_noheadings(table, 1); ++ break; ++ default: ++ break; ++ } ++ return table; ++} ++ ++static struct libscols_table *setup_table(struct lsipc_control *ctl) ++{ ++ struct libscols_table *table = new_table(ctl); ++ size_t n; ++ ++ for (n = 0; n < ncolumns; n++) { ++ int flags = coldescs[columns[n]].flag; ++ ++ if (ctl->notrunc) ++ flags &= ~SCOLS_FL_TRUNC; ++ ++ if (!scols_table_new_column(table, ++ coldescs[columns[n]].name, ++ coldescs[columns[n]].whint, ++ flags)) ++ goto fail; ++ } ++ return table; ++fail: ++ scols_unref_table(table); ++ return NULL; ++} ++ ++static int print_pretty(struct libscols_table *table) ++{ ++ struct libscols_iter *itr = scols_new_iter(SCOLS_ITER_FORWARD); ++ struct libscols_column *col; ++ struct libscols_cell *data; ++ struct libscols_line *ln; ++ const char *hstr, *dstr; ++ int n = 0; ++ ++ ln = scols_table_get_line(table, 0); ++ while (!scols_table_next_column(table, itr, &col)) { ++ ++ data = scols_line_get_cell(ln, n); ++ ++ hstr = N_(coldescs[columns[n]].pretty_name); ++ dstr = scols_cell_get_data(data); ++ ++ if (dstr) ++ printf("%s:%*c%-36s\n", hstr, 35 - (int)strlen(hstr), ' ', dstr); ++ ++n; ++ } ++ ++ /* this is used to pretty-print detailed info about a semaphore array */ ++ if (ln) { ++ struct libscols_table *subtab = scols_line_get_userdata(ln); ++ if (subtab) { ++ printf(_("Elements:\n\n")); ++ scols_print_table(subtab); ++ } ++ } ++ ++ scols_free_iter(itr); ++ return 0; ++ ++} ++ ++static int print_table(struct lsipc_control *ctl, struct libscols_table *tb) ++{ ++ if (ctl->outmode == OUT_PRETTY) ++ print_pretty(tb); ++ else ++ scols_print_table(tb); ++ return 0; ++} ++static struct timeval now; ++ ++static int date_is_today(time_t t) ++{ ++ if (now.tv_sec == 0) ++ gettimeofday(&now, NULL); ++ return t / (3600 * 24) == now.tv_sec / (3600 * 24); ++} ++ ++static int date_is_thisyear(time_t t) ++{ ++ if (now.tv_sec == 0) ++ gettimeofday(&now, NULL); ++ return t / (3600 * 24 * 365) == now.tv_sec / (3600 * 24 * 365); ++} ++ ++static char *make_time(int mode, time_t time) ++{ ++ char *s; ++ struct tm tm; ++ char buf[64] = {0}; ++ ++ localtime_r(&time, &tm); ++ ++ switch(mode) { ++ case TIME_FULL: ++ asctime_r(&tm, buf); ++ if (*(s = buf + strlen(buf) - 1) == '\n') ++ *s = '\0'; ++ break; ++ case TIME_SHORT: ++ if (date_is_today(time)) ++ strftime(buf, sizeof(buf), "%H:%M", &tm); ++ else if (date_is_thisyear(time)) ++ strftime(buf, sizeof(buf), "%b%d", &tm); ++ else ++ strftime(buf, sizeof(buf), "%Y-%b%d", &tm); ++ break; ++ case TIME_ISO: ++ strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", &tm); ++ break; ++ default: ++ errx(EXIT_FAILURE, _("unsupported time type")); ++ } ++ return xstrdup(buf); ++} ++ ++static void global_set_data(struct libscols_table *tb, const char *resource, ++ const char *desc, uintmax_t used, uintmax_t limit, int usage) ++{ ++ struct libscols_line *ln; ++ size_t n; ++ ++ ln = scols_table_new_line(tb, NULL); ++ if (!ln) ++ err_oom(); ++ ++ for (n = 0; n < ncolumns; n++) { ++ int rc = 0; ++ char *arg = NULL; ++ ++ switch (columns[n]) { ++ case COL_RESOURCE: ++ rc = scols_line_set_data(ln, n, resource); ++ break; ++ case COL_DESC: ++ rc = scols_line_set_data(ln, n, desc); ++ break; ++ case COL_USED: ++ if (usage) { ++ xasprintf(&arg, "%ju", used); ++ rc = scols_line_refer_data(ln, n, arg); ++ } else ++ rc = scols_line_set_data(ln, n, "-"); ++ break; ++ case COL_USEPERC: ++ if (usage) { ++ xasprintf(&arg, "%2.2f%%", (double) used / limit * 100); ++ rc = scols_line_refer_data(ln, n, arg); ++ } else ++ rc = scols_line_set_data(ln, n, "-"); ++ break; ++ case COL_LIMIT: ++ xasprintf(&arg, "%ju", limit); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ } ++ ++ if (rc != 0) ++ err(EXIT_FAILURE, _("failed to set data")); ++ } ++} ++ ++static void setup_sem_elements_columns(struct libscols_table *tb) ++{ ++ if (!scols_table_new_column(tb, "SEMNUM", 0, SCOLS_FL_RIGHT)) ++ err_oom(); ++ if (!scols_table_new_column(tb, "VALUE", 0, SCOLS_FL_RIGHT)) ++ err_oom(); ++ if (!scols_table_new_column(tb, "NCOUNT", 0, SCOLS_FL_RIGHT)) ++ err_oom(); ++ if (!scols_table_new_column(tb, "ZCOUNT", 0, SCOLS_FL_RIGHT)) ++ err_oom(); ++ if (!scols_table_new_column(tb, "PID", 0, SCOLS_FL_RIGHT)) ++ err_oom(); ++ if (!scols_table_new_column(tb, "COMMAND", 0, SCOLS_FL_RIGHT)) ++ err_oom(); ++} ++ ++static void do_sem(int id, struct lsipc_control *ctl, struct libscols_table *tb) ++{ ++ struct libscols_line *ln; ++ struct passwd *pw = NULL, *cpw = NULL; ++ struct group *gr = NULL, *cgr = NULL; ++ struct sem_data *semds, *semdsp; ++ char *arg = NULL; ++ ++ if (ipc_sem_get_info(id, &semds) < 1) { ++ if (id > -1) ++ warnx(_("id %d not found"), id); ++ return; ++ } ++ for (semdsp = semds; semdsp->next != NULL || id > -1; semdsp = semdsp->next) { ++ size_t n; ++ ln = scols_table_new_line(tb, NULL); ++ ++ for (n = 0; n < ncolumns; n++) { ++ int rc = 0; ++ switch (columns[n]) { ++ case COL_KEY: ++ xasprintf(&arg, "0x%08x",semdsp->sem_perm.key); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_ID: ++ xasprintf(&arg, "%d",semdsp->sem_perm.id); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_OWNER: ++ arg = get_username(&pw, semdsp->sem_perm.uid); ++ if (!arg) ++ xasprintf(&arg, "%u", semdsp->sem_perm.uid); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_PERMS: ++ if (ctl->numperms) ++ xasprintf(&arg, "%#o", semdsp->sem_perm.mode & 0777); ++ else { ++ arg = xmalloc(11); ++ strmode(semdsp->sem_perm.mode & 0777, arg); ++ } ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_CUID: ++ xasprintf(&arg, "%u", semdsp->sem_perm.cuid); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_CUSER: ++ arg = get_username(&cpw, semdsp->sem_perm.cuid); ++ if (arg) ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_CGID: ++ xasprintf(&arg, "%u", semdsp->sem_perm.cgid); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_CGROUP: ++ arg = get_groupname(&cgr, semdsp->sem_perm.cgid); ++ if (arg) ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_UID: ++ xasprintf(&arg, "%u", semdsp->sem_perm.uid); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_USER: ++ arg = get_username(&pw, semdsp->sem_perm.uid); ++ if (arg) ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_GID: ++ xasprintf(&arg, "%u", semdsp->sem_perm.gid); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_GROUP: ++ arg = get_groupname(&gr, semdsp->sem_perm.gid); ++ if (arg) ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_CTIME: ++ if (semdsp->sem_ctime != 0) { ++ rc = scols_line_refer_data(ln, n, ++ make_time(ctl->time_mode, ++ (time_t)semdsp->sem_ctime)); ++ } ++ break; ++ case COL_NSEMS: ++ xasprintf(&arg, "%ju", semdsp->sem_nsems); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_OTIME: ++ if (semdsp->sem_otime != 0) { ++ rc = scols_line_refer_data(ln, n, ++ make_time(ctl->time_mode, ++ (time_t)semdsp->sem_otime)); ++ } ++ break; ++ } ++ if (rc != 0) ++ err(EXIT_FAILURE, _("failed to set data")); ++ arg = NULL; ++ } ++ ++ if (id > -1 && semds->sem_nsems) { ++ /* Create extra table with ID specific semaphore elements */ ++ struct libscols_table *sub = new_table(ctl); ++ size_t i; ++ int rc = 0; ++ ++ scols_table_enable_noheadings(sub, 0); ++ setup_sem_elements_columns(sub); ++ ++ for (i = 0; i < semds->sem_nsems; i++) { ++ struct sem_elem *e = &semds->elements[i]; ++ struct libscols_line *sln = scols_table_new_line(sub, NULL); ++ ++ /* SEMNUM */ ++ xasprintf(&arg, "%zu", i); ++ rc = scols_line_refer_data(sln, 0, arg); ++ if (rc) ++ break; ++ ++ /* VALUE */ ++ xasprintf(&arg, "%d", e->semval); ++ rc = scols_line_refer_data(sln, 1, arg); ++ if (rc) ++ break; ++ ++ /* NCOUNT */ ++ xasprintf(&arg, "%d", e->ncount); ++ rc = scols_line_refer_data(sln, 2, arg); ++ if (rc) ++ break; ++ ++ /* ZCOUNT */ ++ xasprintf(&arg, "%d", e->zcount); ++ rc = scols_line_refer_data(sln, 3, arg); ++ if (rc) ++ break; ++ ++ /* PID */ ++ xasprintf(&arg, "%d", e->pid); ++ rc = scols_line_refer_data(sln, 4, arg); ++ if (rc) ++ break; ++ ++ /* COMMAND */ ++ arg = proc_get_command(e->pid); ++ rc = scols_line_refer_data(sln, 5, arg); ++ if (rc) ++ break; ++ } ++ ++ if (rc != 0) ++ err(EXIT_FAILURE, _("failed to set data")); ++ ++ scols_line_set_userdata(ln, (void *)sub); ++ break; ++ } ++ } ++ ipc_sem_free_info(semds); ++} ++ ++static void do_sem_global(struct libscols_table *tb) ++{ ++ struct sem_data *semds, *semdsp; ++ struct ipc_limits lim; ++ int nsems = 0, nsets = 0; ++ ++ ipc_sem_get_limits(&lim); ++ ++ if (ipc_sem_get_info(-1, &semds) > 0) { ++ for (semdsp = semds; semdsp->next != NULL; semdsp = semdsp->next) { ++ ++nsets; ++ nsems += semds->sem_nsems; ++ } ++ ipc_sem_free_info(semds); ++ } ++ ++ global_set_data(tb, "SEMMNI", _("Number of semaphore identifiers"), nsets, lim.semmni, 1); ++ global_set_data(tb, "SEMMNS", _("Total number of semaphores"), nsems, lim.semmns, 1); ++ global_set_data(tb, "SEMMSL", _("Max semaphores per semaphore set."), 0, lim.semmsl, 0); ++ global_set_data(tb, "SEMOPM", _("Max number of operations per semop(2)"), 0, lim.semopm, 0); ++ global_set_data(tb, "SEMVMX", _("Semaphore max value"), 0, lim.semvmx, 0); ++} ++ ++static void do_msg(int id, struct lsipc_control *ctl, struct libscols_table *tb) ++{ ++ struct libscols_line *ln; ++ struct passwd *pw = NULL; ++ struct group *gr = NULL; ++ struct msg_data *msgds, *msgdsp; ++ char *arg = NULL; ++ ++ if (ipc_msg_get_info(id, &msgds) < 1) { ++ if (id > -1) ++ warnx(_("id %d not found"), id); ++ return; ++ } ++ ++ for (msgdsp = msgds; msgdsp->next != NULL || id > -1 ; msgdsp = msgdsp->next) { ++ size_t n; ++ ln = scols_table_new_line(tb, NULL); ++ ++ /* no need to call getpwuid() for the same user */ ++ if (!(pw && pw->pw_uid == msgdsp->msg_perm.uid)) ++ pw = getpwuid(msgdsp->msg_perm.uid); ++ ++ /* no need to call getgrgid() for the same user */ ++ if (!(gr && gr->gr_gid == msgdsp->msg_perm.gid)) ++ gr = getgrgid(msgdsp->msg_perm.gid); ++ ++ for (n = 0; n < ncolumns; n++) { ++ int rc = 0; ++ ++ switch (columns[n]) { ++ case COL_KEY: ++ xasprintf(&arg, "0x%08x",msgdsp->msg_perm.key); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_ID: ++ xasprintf(&arg, "%d",msgdsp->msg_perm.id); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_OWNER: ++ arg = get_username(&pw, msgdsp->msg_perm.uid); ++ if (!arg) ++ xasprintf(&arg, "%u", msgdsp->msg_perm.uid); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_PERMS: ++ if (ctl->numperms) ++ xasprintf(&arg, "%#o", msgdsp->msg_perm.mode & 0777); ++ else { ++ arg = xmalloc(11); ++ strmode(msgdsp->msg_perm.mode & 0777, arg); ++ rc = scols_line_refer_data(ln, n, arg); ++ } ++ break; ++ case COL_CUID: ++ xasprintf(&arg, "%u", msgdsp->msg_perm.cuid); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_CUSER: ++ arg = get_username(&pw, msgdsp->msg_perm.cuid); ++ if (arg) ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_CGID: ++ xasprintf(&arg, "%u", msgdsp->msg_perm.cuid); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_CGROUP: ++ arg = get_groupname(&gr, msgdsp->msg_perm.cgid); ++ if (arg) ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_UID: ++ xasprintf(&arg, "%u", msgdsp->msg_perm.uid); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_USER: ++ arg = get_username(&pw, msgdsp->msg_perm.uid); ++ if (arg) ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_GID: ++ xasprintf(&arg, "%u", msgdsp->msg_perm.gid); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_GROUP: ++ arg = get_groupname(&gr,msgdsp->msg_perm.gid); ++ if (arg) ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_CTIME: ++ if (msgdsp->q_ctime != 0) ++ rc = scols_line_refer_data(ln, n, ++ make_time(ctl->time_mode, ++ (time_t)msgdsp->q_ctime)); ++ break; ++ case COL_USEDBYTES: ++ xasprintf(&arg, "%ju", msgdsp->q_cbytes); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_MSGS: ++ xasprintf(&arg, "%ju", msgdsp->q_qnum); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_SEND: ++ if (msgdsp->q_stime != 0) ++ rc = scols_line_refer_data(ln, n, ++ make_time(ctl->time_mode, ++ (time_t)msgdsp->q_stime)); ++ break; ++ case COL_RECV: ++ if (msgdsp->q_rtime != 0) ++ rc = scols_line_refer_data(ln, n, ++ make_time(ctl->time_mode, ++ (time_t)msgdsp->q_rtime)); ++ break; ++ case COL_LSPID: ++ xasprintf(&arg, "%u", msgdsp->q_lspid); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_LRPID: ++ xasprintf(&arg, "%u", msgdsp->q_lrpid); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ } ++ if (rc != 0) ++ err(EXIT_FAILURE, _("failed to set data")); ++ arg = NULL; ++ } ++ if (id > -1) ++ break; ++ } ++ ipc_msg_free_info(msgds); ++} ++ ++ ++static void do_msg_global(struct libscols_table *tb) ++{ ++ struct msg_data *msgds, *msgdsp; ++ struct ipc_limits lim; ++ int msgqs = 0; ++ ++ ipc_msg_get_limits(&lim); ++ ++ /* count number of used queues */ ++ if (ipc_msg_get_info(-1, &msgds) > 0) { ++ for (msgdsp = msgds; msgdsp->next != NULL; msgdsp = msgdsp->next) ++ ++msgqs; ++ ipc_msg_free_info(msgds); ++ } ++ ++ global_set_data(tb, "MSGMNI", _("Number of message queues"), msgqs, lim.msgmni, 1); ++ global_set_data(tb, "MSGMAX", _("Max size of message (bytes)"), 0, lim.msgmax, 0); ++ global_set_data(tb, "MSGMNB", _("Default max size of queue (bytes)"), 0, lim.msgmnb, 0); ++} ++ ++ ++static void do_shm(int id, struct lsipc_control *ctl, struct libscols_table *tb) ++{ ++ struct libscols_line *ln; ++ struct passwd *pw = NULL; ++ struct group *gr = NULL; ++ struct shm_data *shmds, *shmdsp; ++ char *arg = NULL; ++ ++ if (ipc_shm_get_info(id, &shmds) < 1) { ++ if (id > -1) ++ warnx(_("id %d not found"), id); ++ return; ++ } ++ ++ for (shmdsp = shmds; shmdsp->next != NULL || id > -1 ; shmdsp = shmdsp->next) { ++ size_t n; ++ ln = scols_table_new_line(tb, NULL); ++ if (!ln) ++ err_oom(); ++ ++ for (n = 0; n < ncolumns; n++) { ++ int rc = 0; ++ ++ switch (columns[n]) { ++ case COL_KEY: ++ xasprintf(&arg, "0x%08x",shmdsp->shm_perm.key); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_ID: ++ xasprintf(&arg, "%d",shmdsp->shm_perm.id); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_OWNER: ++ arg = get_username(&pw, shmdsp->shm_perm.uid); ++ if (!arg) ++ xasprintf(&arg, "%u", shmdsp->shm_perm.uid); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_PERMS: ++ if (ctl->numperms) ++ xasprintf(&arg, "%#o", shmdsp->shm_perm.mode & 0777); ++ else { ++ arg = xmalloc(11); ++ strmode(shmdsp->shm_perm.mode & 0777, arg); ++ } ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_CUID: ++ xasprintf(&arg, "%u", shmdsp->shm_perm.cuid); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_CUSER: ++ arg = get_username(&pw, shmdsp->shm_perm.cuid); ++ if (arg) ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_CGID: ++ xasprintf(&arg, "%u", shmdsp->shm_perm.cuid); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_CGROUP: ++ arg = get_groupname(&gr, shmdsp->shm_perm.cgid); ++ if (arg) ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_UID: ++ xasprintf(&arg, "%u", shmdsp->shm_perm.uid); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_USER: ++ arg = get_username(&pw, shmdsp->shm_perm.uid); ++ if (arg) ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_GID: ++ xasprintf(&arg, "%u", shmdsp->shm_perm.gid); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_GROUP: ++ arg = get_groupname(&gr, shmdsp->shm_perm.gid); ++ if (arg) ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_CTIME: ++ if (shmdsp->shm_ctim != 0) ++ rc = scols_line_refer_data(ln, n, ++ make_time(ctl->time_mode, ++ (time_t)shmdsp->shm_ctim)); ++ break; ++ case COL_SIZE: ++ if (ctl->bytes) ++ xasprintf(&arg, "%ju", shmdsp->shm_segsz); ++ else ++ arg = size_to_human_string(SIZE_SUFFIX_1LETTER, shmdsp->shm_segsz); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_NATTCH: ++ xasprintf(&arg, "%ju", shmdsp->shm_nattch); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_STATUS: { ++ int comma = 0; ++ size_t offt = 0; ++ ++ free(arg); ++ arg = xcalloc(1, sizeof(char) * strlen(_("dest")) ++ + strlen(_("locked")) ++ + strlen(_("hugetlb")) ++ + strlen(_("noreserve")) + 4); ++#ifdef SHM_DEST ++ if (shmdsp->shm_perm.mode & SHM_DEST) { ++ offt += sprintf(arg, "%s", _("dest")); ++ comma++; ++ } ++#endif ++#ifdef SHM_LOCKED ++ if (shmdsp->shm_perm.mode & SHM_LOCKED) { ++ if (comma) ++ arg[offt++] = ','; ++ offt += sprintf(arg + offt, "%s", _("locked")); ++ } ++#endif ++#ifdef SHM_HUGETLB ++ if (shmdsp->shm_perm.mode & SHM_HUGETLB) { ++ if (comma) ++ arg[offt++] = ','; ++ offt += sprintf(arg + offt, "%s", _("hugetlb")); ++ } ++#endif ++#ifdef SHM_NORESERVE ++ if (shmdsp->shm_perm.mode & SHM_NORESERVE) { ++ if (comma) ++ arg[offt++] = ','; ++ sprintf(arg + offt, "%s", _("noreserve")); ++ } ++#endif ++ rc = scols_line_refer_data(ln, n, arg); ++ } ++ break; ++ case COL_ATTACH: ++ if (shmdsp->shm_atim != 0) ++ rc = scols_line_refer_data(ln, n, ++ make_time(ctl->time_mode, ++ (time_t)shmdsp->shm_atim)); ++ break; ++ case COL_DETACH: ++ if (shmdsp->shm_dtim != 0) ++ rc = scols_line_refer_data(ln, n, ++ make_time(ctl->time_mode, ++ (time_t)shmdsp->shm_dtim)); ++ break; ++ case COL_CPID: ++ xasprintf(&arg, "%u", shmdsp->shm_cprid); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_LPID: ++ xasprintf(&arg, "%u", shmdsp->shm_lprid); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ case COL_COMMAND: ++ arg = proc_get_command(shmdsp->shm_cprid); ++ rc = scols_line_refer_data(ln, n, arg); ++ break; ++ } ++ if (rc != 0) ++ err(EXIT_FAILURE, _("failed to set data")); ++ arg = NULL; ++ } ++ if (id > -1) ++ break; ++ } ++ ipc_shm_free_info(shmds); ++} ++ ++static void do_shm_global(struct libscols_table *tb) ++{ ++ struct shm_data *shmds, *shmdsp; ++ uint64_t nsegs = 0, sum_segsz = 0; ++ struct ipc_limits lim; ++ ++ ipc_shm_get_limits(&lim); ++ ++ if (ipc_shm_get_info(-1, &shmds) > 0) { ++ for (shmdsp = shmds; shmdsp->next != NULL; shmdsp = shmdsp->next) { ++ ++nsegs; ++ sum_segsz += shmdsp->shm_segsz; ++ } ++ ipc_shm_free_info(shmds); ++ } ++ ++ global_set_data(tb, "SHMMNI", _("Shared memory segments"), nsegs, lim.shmmni, 1); ++ global_set_data(tb, "SHMALL", _("Shared memory pages"), sum_segsz / getpagesize(), lim.shmall, 1); ++ global_set_data(tb, "SHMMAX", _("Max size of shared memory segment (bytes)"), 0, lim.shmmax, 0); ++ global_set_data(tb, "SHMMIN", _("Min size of shared memory segment (bytes)"), 0, lim.shmmin, 0); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ int opt, msg = 0, sem = 0, shm = 0, id = -1; ++ int show_time = 0, show_creat = 0, global = 0; ++ size_t i; ++ struct lsipc_control *ctl = xcalloc(1, sizeof(struct lsipc_control)); ++ static struct libscols_table *tb; ++ char *outarg = NULL; ++ ++ /* long only options. */ ++ enum { ++ OPT_NOTRUNC = CHAR_MAX + 1, ++ OPT_NOHEAD, ++ OPT_TIME_FMT ++ }; ++ ++ static const struct option longopts[] = { ++ { "bytes", no_argument, 0, 'b' }, ++ { "creator", no_argument, 0, 'c' }, ++ { "export", no_argument, 0, 'e' }, ++ { "global", no_argument, 0, 'g' }, ++ { "help", no_argument, 0, 'h' }, ++ { "id", required_argument, 0, 'i' }, ++ { "list", no_argument, 0, 'l' }, ++ { "newline", no_argument, 0, 'n' }, ++ { "noheadings", no_argument, 0, OPT_NOHEAD }, ++ { "notruncate", no_argument, 0, OPT_NOTRUNC }, ++ { "numeric-perms", no_argument, 0, 'P' }, ++ { "output", required_argument, 0, 'o' }, ++ { "pid", no_argument, 0, 'p' }, ++ { "queues", no_argument, 0, 'q' }, ++ { "raw", no_argument, 0, 'r' }, ++ { "semaphores", no_argument, 0, 's' }, ++ { "shmems", no_argument, 0, 'm' }, ++ { "time", no_argument, 0, 't' }, ++ { "time-format", required_argument, 0, OPT_TIME_FMT }, ++ { "version", no_argument, 0, 'V' }, ++ {NULL, 0, NULL, 0} ++ }; ++ ++ static const ul_excl_t excl[] = { /* rows and cols in ASCII order */ ++ { 'J', 'e', 'l', 'n', 'r' }, ++ { 'g', 'i' }, ++ { 'c', 'o', 't' }, ++ { 'm', 'q', 's' }, ++ { 0 } ++ }; ++ int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT; ++ ++ setlocale(LC_ALL, ""); ++ bindtextdomain(PACKAGE, LOCALEDIR); ++ textdomain(PACKAGE); ++ atexit(close_stdout); ++ ++ ctl->time_mode = 0; ++ ++ scols_init_debug(0); ++ ++ while ((opt = getopt_long(argc, argv, "bceghi:lmno:PqrstuV", longopts, NULL)) != -1) { ++ ++ err_exclusive_options(opt, longopts, excl, excl_st); ++ ++ switch (opt) { ++ case 'b': ++ ctl->bytes = 1; ++ break; ++ case 'i': ++ id = strtos32_or_err(optarg, _("failed to parse IPC identifier")); ++ break; ++ case 'e': ++ ctl->outmode = OUT_EXPORT; ++ break; ++ case 'r': ++ ctl->outmode = OUT_RAW; ++ break; ++ case 'o': ++ outarg = optarg; ++ break; ++ case 'g': ++ global = 1; ++ break; ++ case 'q': ++ msg = 1; ++ add_column(columns, ncolumns++, COL_KEY); ++ add_column(columns, ncolumns++, COL_ID); ++ add_column(columns, ncolumns++, COL_PERMS); ++ add_column(columns, ncolumns++, COL_OWNER); ++ add_column(columns, ncolumns++, COL_USEDBYTES); ++ add_column(columns, ncolumns++, COL_MSGS); ++ add_column(columns, ncolumns++, COL_LSPID); ++ add_column(columns, ncolumns++, COL_LRPID); ++ LOWER = COLDESC_IDX_MSG_FIRST; ++ UPPER = COLDESC_IDX_MSG_LAST; ++ break; ++ case 'l': ++ ctl->outmode = OUT_LIST; ++ break; ++ case 'm': ++ shm = 1; ++ add_column(columns, ncolumns++, COL_KEY); ++ add_column(columns, ncolumns++, COL_ID); ++ add_column(columns, ncolumns++, COL_PERMS); ++ add_column(columns, ncolumns++, COL_OWNER); ++ add_column(columns, ncolumns++, COL_SIZE); ++ add_column(columns, ncolumns++, COL_NATTCH); ++ add_column(columns, ncolumns++, COL_STATUS); ++ add_column(columns, ncolumns++, COL_CTIME); ++ add_column(columns, ncolumns++, COL_CPID); ++ add_column(columns, ncolumns++, COL_LPID); ++ add_column(columns, ncolumns++, COL_COMMAND); ++ LOWER = COLDESC_IDX_SHM_FIRST; ++ UPPER = COLDESC_IDX_SHM_LAST; ++ break; ++ case 'n': ++ ctl->outmode = OUT_NEWLINE; ++ break; ++ case 'P': ++ ctl->numperms = 1; ++ break; ++ case 's': ++ sem = 1; ++ add_column(columns, ncolumns++, COL_KEY); ++ add_column(columns, ncolumns++, COL_ID); ++ add_column(columns, ncolumns++, COL_PERMS); ++ add_column(columns, ncolumns++, COL_OWNER); ++ add_column(columns, ncolumns++, COL_NSEMS); ++ LOWER = COLDESC_IDX_SEM_FIRST; ++ UPPER = COLDESC_IDX_SEM_LAST; ++ break; ++ case OPT_NOTRUNC: ++ ctl->notrunc = 1; ++ break; ++ case OPT_NOHEAD: ++ ctl->noheadings = 1; ++ break; ++ case OPT_TIME_FMT: ++ ctl->time_mode = parse_time_mode(optarg); ++ break; ++ case 't': ++ show_time = 1; ++ break; ++ case 'c': ++ show_creat = 1; ++ break; ++ case 'h': ++ usage(stdout); ++ case 'V': ++ printf(UTIL_LINUX_VERSION); ++ return EXIT_SUCCESS; ++ default: ++ usage(stderr); ++ } ++ } ++ ++ /* default is global */ ++ if (msg + shm + sem == 0) { ++ msg = shm = sem = global = 1; ++ if (show_time || show_creat || id != -1) ++ errx(EXIT_FAILURE, _("--global is mutually exclusive with --creator, --id and --time")); ++ } ++ if (global) { ++ add_column(columns, ncolumns++, COL_RESOURCE); ++ add_column(columns, ncolumns++, COL_DESC); ++ add_column(columns, ncolumns++, COL_LIMIT); ++ add_column(columns, ncolumns++, COL_USED); ++ add_column(columns, ncolumns++, COL_USEPERC); ++ LOWER = COLDESC_IDX_SUM_FIRST; ++ UPPER = COLDESC_IDX_SUM_LAST; ++ } ++ ++ /* default to pretty-print if --id specified */ ++ if (id != -1 && !ctl->outmode) ++ ctl->outmode = OUT_PRETTY; ++ ++ if (!ctl->time_mode) ++ ctl->time_mode = ctl->outmode == OUT_PRETTY ? TIME_FULL : TIME_SHORT; ++ ++ if (ctl->outmode == OUT_PRETTY && !(optarg || show_creat || show_time)) { ++ /* all columns for lsipc --<RESOURCE> --id <ID> */ ++ for (ncolumns = 0, i = 0; i < ARRAY_SIZE(coldescs); i++) ++ columns[ncolumns++] = i; ++ } else { ++ if (show_creat) { ++ add_column(columns, ncolumns++, COL_CUID); ++ add_column(columns, ncolumns++, COL_CGID); ++ add_column(columns, ncolumns++, COL_UID); ++ add_column(columns, ncolumns++, COL_GID); ++ } ++ if (msg && show_time) { ++ add_column(columns, ncolumns++, COL_SEND); ++ add_column(columns, ncolumns++, COL_RECV); ++ add_column(columns, ncolumns++, COL_CTIME); ++ } ++ if (shm && show_time) { ++ /* keep "COMMAND" as last column */ ++ size_t cmd = columns[ncolumns - 1] == COL_COMMAND; ++ ++ if (cmd) ++ ncolumns--; ++ add_column(columns, ncolumns++, COL_ATTACH); ++ add_column(columns, ncolumns++, COL_DETACH); ++ if (cmd) ++ add_column(columns, ncolumns++, COL_COMMAND); ++ } ++ if (sem && show_time) { ++ add_column(columns, ncolumns++, COL_OTIME); ++ add_column(columns, ncolumns++, COL_CTIME); ++ } ++ } ++ ++ if (outarg && string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns), ++ (int *) &ncolumns, column_name_to_id) < 0) ++ return EXIT_FAILURE; ++ ++ tb = setup_table(ctl); ++ if (!tb) ++ return EXIT_FAILURE; ++ ++ if (msg) { ++ if (global) ++ do_msg_global(tb); ++ else ++ do_msg(id, ctl, tb); ++ } ++ if (shm) { ++ if (global) ++ do_shm_global(tb); ++ else ++ do_shm(id, ctl, tb); ++ } ++ if (sem) { ++ if (global) ++ do_sem_global(tb); ++ else ++ do_sem(id, ctl, tb); ++ } ++ ++ print_table(ctl, tb); ++ ++ scols_unref_table(tb); ++ free(ctl); ++ ++ return EXIT_SUCCESS; ++} ++ +diff --git a/tests/functions.sh b/tests/functions.sh +index 123f6c3..b2d493c 100644 +--- a/tests/functions.sh ++++ b/tests/functions.sh +@@ -50,16 +50,25 @@ function ts_skip_nonroot { + } + + function ts_failed_subtest { ++ local msg="FAILED" ++ local ret=1 ++ if [ "$TS_KNOWN_FAIL" = "yes" ]; then ++ msg="KNOWN FAILED" ++ ret=0 ++ fi ++ + if [ x"$1" == x"" ]; then +- echo " FAILED ($TS_NS)" ++ echo " $msg ($TS_NS)" + else +- echo " FAILED ($1)" ++ echo " $msg ($1)" + fi ++ ++ return $ret + } + + function ts_failed { + ts_failed_subtest "$1" +- exit 1 ++ exit $? + } + + function ts_ok_subtest { +@@ -150,6 +159,7 @@ function ts_init_env { + TS_SUBDIR=$(dirname $TS_SCRIPT) + TS_TESTNAME=$(basename $TS_SCRIPT) + TS_COMPONENT=$(basename $TS_SUBDIR) ++ TS_KNOWN_FAIL="no" + + TS_NSUBTESTS=0 + TS_NSUBFAILED=0 +diff --git a/tests/ts/ipcs/limits2 b/tests/ts/ipcs/limits2 +index f99a354..63f834d 100755 +--- a/tests/ts/ipcs/limits2 ++++ b/tests/ts/ipcs/limits2 +@@ -16,15 +16,20 @@ + # GNU General Public License for more details. + # + +-TS_TOPDIR="$(dirname $0)/../.." ++TS_TOPDIR="${0%/*}/../.." + TS_DESC="basic limits" + + . $TS_TOPDIR/functions.sh + ts_init "$*" +-type bc >/dev/null 2>&1 || ts_skip "cannot find bc command" + + . $TS_SELF/functions.sh + ++# TODO https://github.com/karelzak/util-linux/issues/51 ++SHMALL=$(</proc/sys/kernel/shmall) ++if [ $(bc <<<"(2^64 / $PAGE_SIZE) <= $SHMALL") -eq 1 ]; then ++ TS_KNOWN_FAIL="yes" ++fi ++ + ts_log "check for difference between kernel and IPC" + ipcs_limits_check >> $TS_OUTPUT + +-- +2.7.4 + diff --git a/SOURCES/0079-blkdiscard-backport-zeroout-support.patch b/SOURCES/0079-blkdiscard-backport-zeroout-support.patch new file mode 100644 index 0000000..22edece --- /dev/null +++ b/SOURCES/0079-blkdiscard-backport-zeroout-support.patch @@ -0,0 +1,278 @@ +From ca291153ff2c696696c1406aca6433aab6e412a1 Mon Sep 17 00:00:00 2001 +From: Karel Zak <kzak@redhat.com> +Date: Fri, 24 Jun 2016 13:36:32 +0200 +Subject: [PATCH 79/84] blkdiscard: backport --zeroout support + +The patch also includes upstream cleanups. + +Upstream: http://github.com/karelzak/util-linux/commit/0e765365798c54d412e355798ad584a52035f228 +Upstream: http://github.com/karelzak/util-linux/commit/a3e91e26467a0f644ee568bb0b3d481591834015 +Upstream: http://github.com/karelzak/util-linux/commit/eeae448805c0eb2ef130a6ac301750706bb80420 +Upstream: http://github.com/karelzak/util-linux/commit/7154cc892688f3c58cbbcdc2055f2635c1d0ef5b +Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1327886 +Signed-off-by: Karel Zak <kzak@redhat.com> +--- + bash-completion/blkdiscard | 2 +- + sys-utils/blkdiscard.8 | 7 +-- + sys-utils/blkdiscard.c | 122 ++++++++++++++++++++++++++++++++++----------- + 3 files changed, 98 insertions(+), 33 deletions(-) + +diff --git a/bash-completion/blkdiscard b/bash-completion/blkdiscard +index 310cdfb..fb3cb1e 100644 +--- a/bash-completion/blkdiscard ++++ b/bash-completion/blkdiscard +@@ -15,7 +15,7 @@ _blkdiscard_module() + esac + case $cur in + -*) +- OPTS="--offset --length --secure --verbose --help --version" ++ OPTS="--offset --length --secure --zeroout --verbose --help --version" + COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) ) + return 0 + ;; +diff --git a/sys-utils/blkdiscard.8 b/sys-utils/blkdiscard.8 +index 5e094d4..71180e9 100644 +--- a/sys-utils/blkdiscard.8 ++++ b/sys-utils/blkdiscard.8 +@@ -1,15 +1,13 @@ +-.\" -*- nroff -*- + .TH BLKDISCARD 8 "July 2014" "util-linux" "System Administration" + .SH NAME + blkdiscard \- discard sectors on a device + .SH SYNOPSIS + .B blkdiscard ++[options] + .RB [ \-o + .IR offset ] + .RB [ \-l + .IR length ] +-.RB [ \-s ] +-.RB [ \-v ] + .I device + .SH DESCRIPTION + .B blkdiscard +@@ -59,6 +57,9 @@ Perform a secure discard. A secure discard is the same as a regular discard + except that all copies of the discarded blocks that were possibly created by + garbage collection must also be erased. This requires support from the device. + .TP ++.BR \-z , " \-\-zeroout" ++Zero-fill rather than discard. ++.TP + .BR \-v , " \-\-verbose" + Display the aligned values of + .I offset +diff --git a/sys-utils/blkdiscard.c b/sys-utils/blkdiscard.c +index 92ca52a..0ba99ee 100644 +--- a/sys-utils/blkdiscard.c ++++ b/sys-utils/blkdiscard.c +@@ -44,43 +44,95 @@ + #include "closestream.h" + + #ifndef BLKDISCARD +-#define BLKDISCARD _IO(0x12,119) ++# define BLKDISCARD _IO(0x12,119) + #endif + + #ifndef BLKSECDISCARD +-#define BLKSECDISCARD _IO(0x12,125) ++# define BLKSECDISCARD _IO(0x12,125) + #endif + +-#define print_stats(path, stats) \ +- printf(_("%s: Discarded %" PRIu64 " bytes from the " \ +- "offset %" PRIu64"\n"), path, stats[1], stats[0]); ++#ifndef BLKZEROOUT ++# define BLKZEROOUT _IO(0x12,127) ++#endif ++ ++enum { ++ ACT_DISCARD = 0, /* default */ ++ ACT_ZEROOUT, ++ ACT_SECURE ++}; ++ ++/* RHEL: backport from upstream lib/monotonic.c */ ++static int gettime_monotonic(struct timeval *tv) ++{ ++#ifdef CLOCK_MONOTONIC ++ /* Can slew only by ntp and adjtime */ ++ int ret; ++ struct timespec ts; ++ ++# ifdef CLOCK_MONOTONIC_RAW ++ /* Linux specific, can't slew */ ++ if (!(ret = clock_gettime(CLOCK_MONOTONIC_RAW, &ts))) { ++# else ++ if (!(ret = clock_gettime(CLOCK_MONOTONIC, &ts))) { ++# endif ++ tv->tv_sec = ts.tv_sec; ++ tv->tv_usec = ts.tv_nsec / 1000; ++ } ++ return ret; ++#else ++ return gettimeofday(tv, NULL); ++#endif ++} ++ ++static void print_stats(int act, char *path, uint64_t stats[]) ++{ ++ switch (act) { ++ case ACT_ZEROOUT: ++ printf(_("%s: Zero-filled %" PRIu64 " bytes from the offset %" PRIu64"\n"), \ ++ path, stats[1], stats[0]); ++ break; ++ case ACT_SECURE: ++ case ACT_DISCARD: ++ printf(_("%s: Discarded %" PRIu64 " bytes from the offset %" PRIu64"\n"), \ ++ path, stats[1], stats[0]); ++ break; ++ } ++} + + static void __attribute__((__noreturn__)) usage(FILE *out) + { + fputs(USAGE_HEADER, out); + fprintf(out, + _(" %s [options] <device>\n"), program_invocation_short_name); ++ ++ fputs(USAGE_SEPARATOR, out); ++ fputs(_("Discard the content of sectors on a device.\n"), out); ++ + fputs(USAGE_OPTIONS, out); +- fputs(_(" -o, --offset <num> offset in bytes to discard from\n" +- " -l, --length <num> length of bytes to discard from the offset\n" +- " -p, --step <num> size of the discard iterations within the offset\n" +- " -s, --secure perform secure discard\n" +- " -v, --verbose print aligned length and offset\n"), +- out); ++ fputs(_(" -o, --offset <num> offset in bytes to discard from\n"), out); ++ fputs(_(" -l, --length <num> length of bytes to discard from the offset\n"), out); ++ fputs(_(" -p, --step <num> size of the discard iterations within the offset\n"), out); ++ fputs(_(" -s, --secure perform secure discard\n"), out); ++ fputs(_(" -z, --zeroout zero-fill rather than discard\n"), out); ++ fputs(_(" -v, --verbose print aligned length and offset\n"), out); ++ + fputs(USAGE_SEPARATOR, out); + fputs(USAGE_HELP, out); + fputs(USAGE_VERSION, out); ++ + fprintf(out, USAGE_MAN_TAIL("blkdiscard(8)")); + exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); + } + ++ + int main(int argc, char **argv) + { + char *path; +- int c, fd, verbose = 0, secure = 0, secsize; ++ int c, fd, verbose = 0, secsize; + uint64_t end, blksize, step, range[2], stats[2]; + struct stat sb; +- struct timespec now, last; ++ struct timeval now, last; ++ int act = ACT_DISCARD; + + static const struct option longopts[] = { + { "help", 0, 0, 'h' }, +@@ -90,6 +142,7 @@ int main(int argc, char **argv) + { "step", 1, 0, 'p' }, + { "secure", 0, 0, 's' }, + { "verbose", 0, 0, 'v' }, ++ { "zeroout", 0, 0, 'z' }, + { NULL, 0, 0, 0 } + }; + +@@ -102,7 +155,7 @@ int main(int argc, char **argv) + range[1] = ULLONG_MAX; + step = 0; + +- while ((c = getopt_long(argc, argv, "hVsvo:l:p:", longopts, NULL)) != -1) { ++ while ((c = getopt_long(argc, argv, "hVsvo:l:p:z", longopts, NULL)) != -1) { + switch(c) { + case 'h': + usage(stdout); +@@ -123,11 +176,14 @@ int main(int argc, char **argv) + _("failed to parse step")); + break; + case 's': +- secure = 1; ++ act = ACT_SECURE; + break; + case 'v': + verbose = 1; + break; ++ case 'z': ++ act = ACT_ZEROOUT; ++ break; + default: + usage(stderr); + break; +@@ -149,7 +205,7 @@ int main(int argc, char **argv) + err(EXIT_FAILURE, _("cannot open %s"), path); + + if (fstat(fd, &sb) == -1) +- err(EXIT_FAILURE, _("stat failed %s"), path); ++ err(EXIT_FAILURE, _("stat of %s failed"), path); + if (!S_ISBLK(sb.st_mode)) + errx(EXIT_FAILURE, _("%s: not a block device"), path); + +@@ -178,35 +234,43 @@ int main(int argc, char **argv) + "to sector size %i"), path, range[1], secsize); + + stats[0] = range[0], stats[1] = 0; +- clock_gettime(CLOCK_MONOTONIC, &last); ++ gettime_monotonic(&last); + +- for (range[0] = range[0]; range[0] < end; range[0] += range[1]) { ++ for (/* nothing */; range[0] < end; range[0] += range[1]) { + if (range[0] + range[1] > end) + range[1] = end - range[0]; + +- if (secure) { ++ switch (act) { ++ case ACT_ZEROOUT: ++ if (ioctl(fd, BLKZEROOUT, &range)) ++ err(EXIT_FAILURE, _("%s: BLKZEROOUT ioctl failed"), path); ++ break; ++ case ACT_SECURE: + if (ioctl(fd, BLKSECDISCARD, &range)) + err(EXIT_FAILURE, _("%s: BLKSECDISCARD ioctl failed"), path); +- } else { ++ break; ++ case ACT_DISCARD: + if (ioctl(fd, BLKDISCARD, &range)) + err(EXIT_FAILURE, _("%s: BLKDISCARD ioctl failed"), path); ++ break; + } + +- /* reporting progress */ ++ stats[1] += range[1]; ++ ++ /* reporting progress at most once per second */ + if (verbose && step) { +- clock_gettime(CLOCK_MONOTONIC, &now); +- if (last.tv_sec < now.tv_sec) { +- print_stats(path, stats); +- stats[0] = range[0], stats[1] = 0; ++ gettime_monotonic(&now); ++ if (now.tv_sec > last.tv_sec && ++ (now.tv_usec >= last.tv_usec || now.tv_sec > last.tv_sec + 1)) { ++ print_stats(act, path, stats); ++ stats[0] += stats[1], stats[1] = 0; + last = now; + } + } +- +- stats[1] += range[1]; + } + +- if (verbose) +- print_stats(path, stats); ++ if (verbose && stats[1]) ++ print_stats(act, path, stats); + + close(fd); + return EXIT_SUCCESS; +-- +2.7.4 + diff --git a/SOURCES/0080-sulogin-and-agetty-virtual-consoles-support-xvc-and-.patch b/SOURCES/0080-sulogin-and-agetty-virtual-consoles-support-xvc-and-.patch new file mode 100644 index 0000000..ae2bc6b --- /dev/null +++ b/SOURCES/0080-sulogin-and-agetty-virtual-consoles-support-xvc-and-.patch @@ -0,0 +1,125 @@ +From 46537bc28d48acb9ae5cac76535262e6b2ec48a2 Mon Sep 17 00:00:00 2001 +From: Werner Fink <werner@suse.de> +Date: Thu, 8 May 2014 12:09:25 +0200 +Subject: [PATCH 80/84] sulogin: (and agetty) virtual consoles support, xvc and + hvc device + +For this approach do not use the ioctl TIOCMGET anymore as this +is for real serial lines only. But switch over to use the ioctl +KDGKBMODE as this is unique to the virtual console lines only. + +Upstream: http://github.com/karelzak/util-linux/commit/b9c7390948c7850db2bee82ad64624930962cc14 +Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1029385 +Signed-off-by: Werner Fink <werner@suse.de> +Signed-off-by: Karel Zak <kzak@redhat.com> +--- + login-utils/sulogin.c | 17 ++++++++++++----- + term-utils/agetty.c | 23 +++++++++++------------ + 2 files changed, 23 insertions(+), 17 deletions(-) + +diff --git a/login-utils/sulogin.c b/login-utils/sulogin.c +index 32ae9a2..bbd67b3 100644 +--- a/login-utils/sulogin.c ++++ b/login-utils/sulogin.c +@@ -49,6 +49,11 @@ + # include <selinux/get_context_list.h> + #endif + ++#ifdef __linux__ ++# include <sys/kd.h> ++# include <sys/param.h> ++#endif ++ + #include "c.h" + #include "closestream.h" + #include "nls.h" +@@ -93,10 +98,14 @@ static void tcinit(struct console *con) + return; + } + +- /* Handle serial lines here */ +- if (ioctl(fd, TIOCMGET, (char *) &mode) == 0) { ++ /* Handle lines other than virtual consoles here */ ++#if defined(KDGKBMODE) ++ if (ioctl(fd, KDGKBMODE, &mode) < 0) ++#endif ++ { + speed_t ispeed, ospeed; + struct winsize ws; ++ errno = 0; + + /* this is a modem line */ + con->flags |= CON_SERIAL; +@@ -142,9 +151,7 @@ static void tcinit(struct console *con) + goto setattr; + } + #if defined(IUTF8) && defined(KDGKBMODE) +- /* Detect mode of current keyboard setup, e.g. for UTF-8 */ +- if (ioctl(fd, KDGKBMODE, &mode) < 0) +- mode = K_RAW; ++ /* Handle mode of current keyboard setup, e.g. for UTF-8 */ + switch(mode) { + case K_UNICODE: + setlocale(LC_CTYPE, "C.UTF-8"); +diff --git a/term-utils/agetty.c b/term-utils/agetty.c +index c7af154..5692126 100644 +--- a/term-utils/agetty.c ++++ b/term-utils/agetty.c +@@ -134,6 +134,7 @@ struct options { + int nice; /* Run login with this priority */ + int numspeed; /* number of baud rates to try */ + int clocal; /* CLOCAL_MODE_* */ ++ int kbmode; /* Keyboard mode if virtual console */ + speed_t speeds[MAX_SPEED]; /* baud rates to be tried */ + }; + +@@ -886,7 +887,7 @@ static void update_utmp(struct options *op) + static void open_tty(char *tty, struct termios *tp, struct options *op) + { + const pid_t pid = getpid(); +- int serial, closed = 0; ++ int closed = 0; + + /* Set up new standard input, unless we are given an already opened port. */ + +@@ -1016,15 +1017,18 @@ static void open_tty(char *tty, struct termios *tp, struct options *op) + + /* + * Detect if this is a virtual console or serial/modem line. +- * In case of a virtual console the ioctl TIOCMGET fails and +- * the error number will be set to EINVAL. ++ * In case of a virtual console the ioctl KDGKBMODE succeeds ++ * whereas on other lines it will fails. + */ +- if (ioctl(STDIN_FILENO, TIOCMGET, &serial) < 0 && (errno == EINVAL)) { ++ if (ioctl(STDIN_FILENO, KDGKBMODE, &op->kbmode) == 0) { + op->flags |= F_VCONSOLE; + if (!op->term) + op->term = DEFAULT_VCTERM; +- } else if (!op->term) +- op->term = DEFAULT_STERM; ++ } else { ++ op->kbmode = K_RAW; ++ if (!op->term) ++ op->term = DEFAULT_STERM; ++ } + + setenv("TERM", op->term, 1); + } +@@ -1037,12 +1041,7 @@ static void termio_init(struct options *op, struct termios *tp) + + if (op->flags & F_VCONSOLE) { + #if defined(IUTF8) && defined(KDGKBMODE) +- int mode; +- +- /* Detect mode of current keyboard setup, e.g. for UTF-8 */ +- if (ioctl(STDIN_FILENO, KDGKBMODE, &mode) < 0) +- mode = K_RAW; +- switch(mode) { ++ switch(op->kbmode) { + case K_UNICODE: + setlocale(LC_CTYPE, "C.UTF-8"); + op->flags |= F_UTF8; +-- +2.7.4 + diff --git a/SOURCES/0081-chrt-backport-DEADLINE-scheduler-support.patch b/SOURCES/0081-chrt-backport-DEADLINE-scheduler-support.patch new file mode 100644 index 0000000..fda445b --- /dev/null +++ b/SOURCES/0081-chrt-backport-DEADLINE-scheduler-support.patch @@ -0,0 +1,791 @@ +From 674769893bb8d5f1991c6a3e5d96337b37aeb86f Mon Sep 17 00:00:00 2001 +From: Karel Zak <kzak@redhat.com> +Date: Mon, 27 Jun 2016 14:14:28 +0200 +Subject: [PATCH 81/86] chrt: backport DEADLINE scheduler support + +Backport upstream commits: + +2e31d1c chrt: validate priority before trying to use it +b3a5067 chrt: make --sched-* short options to require an argument +a03eac5 chrt: restore removed ifdef SCHED_RESET_ON_FORK +59e4a38 chrt: fix case SCHED_RR +acde3a0 chrt: use sched_getattr() +1a7e639 chrt: add support for SCHED_DEADLINE +1516758 chrt: use sched_setattr() if available +a6fec53 chrt: make usage more readable +4820a73 chrt: set function refactoring +a30cf65 chrt: output function refactoring +7a4ea56 chrt: add control struct +9acbe2a chrt: slice up the usage text and normalize its layout +4e4bc0c chrt: make the usage synopsis clearer +3fabc36 chrt: fix --help inconsistency +451dbcf textual: add a docstring to most of the utilities +a587cc5 textual: use manual tail usage() macro +f627750 textual: use version printing macro everywhere +a7560c0 textual: make the license of chrt and taskset slightly more explicit +4ce393f textual: fix several typos and angular brackets in messages +6f27e44 chrt: add fallback to be usable on kernels without sched_{get,set}attr + +* Fri Jul 01 2016 re-spin [kzak]: +- add fallback for old glibc-headers without SYS_sched_{set,get}attr + +* Tue Jul 12 016 re-spin [kzak]: +- add runtime fallback for systems without sched_{get,set}attr syscalls + +Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1298384 +Signed-off-by: Karel Zak <kzak@redhat.com> +--- + configure.ac | 17 +- + m4/ul.m4 | 8 - + schedutils/chrt.c | 547 ++++++++++++++++++++++++++++++++++++++---------------- + 3 files changed, 400 insertions(+), 172 deletions(-) + +diff --git a/configure.ac b/configure.ac +index fe0a011..266ef08 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -338,6 +338,8 @@ AC_CHECK_FUNCS([ \ + scandirat \ + setresgid \ + setresuid \ ++ sched_setattr \ ++ sched_setscheduler \ + sigqueue \ + srandom \ + strnchr \ +@@ -1383,6 +1385,20 @@ UL_REQUIRES_SYSCALL_CHECK([taskset], + AM_CONDITIONAL(BUILD_TASKSET, test "x$build_taskset" = xyes) + + ++have_schedsetter=no ++AS_IF([test "x$ac_cv_func_sched_setscheduler" = xyes], [have_schedsetter=yes], ++ [test "x$ac_cv_func_sched_setattr" = xyes], [have_schedsetter=yes]) ++ ++UL_BUILD_INIT([chrt], [check]) ++UL_REQUIRES_BUILD([chrt], [schedutils]) ++UL_REQUIRES_HAVE([chrt], [schedsetter], [sched_set functions]) ++AM_CONDITIONAL([BUILD_CHRT], [test "x$build_chrt" = xyes]) ++ ++AS_IF([test "x$build_chrt" = xyes], [ ++ UL_CHECK_SYSCALL([sched_setattr]) ++]) ++ ++ + AC_ARG_ENABLE([wall], + AS_HELP_STRING([--disable-wall], [do not build wall]), + [], enable_wall=yes +@@ -1562,7 +1578,6 @@ AC_ARG_VAR([SOLIB_LDFLAGS], + + LIBS="" + +- + AC_CONFIG_HEADERS(config.h) + + # +diff --git a/m4/ul.m4 b/m4/ul.m4 +index c0082d0..db44589 100644 +--- a/m4/ul.m4 ++++ b/m4/ul.m4 +@@ -92,7 +92,6 @@ AC_DEFUN([UL_CHECK_SYSCALL], [ + ]) + ul_cv_syscall_$1=$syscall + ]) +- AM_CONDITIONAL([HAVE_]m4_toupper($1), [test "x$ul_cv_syscall_$1" != xno]) + case $ul_cv_syscall_$1 in #( + no) AC_MSG_WARN([Unable to detect syscall $1.]) ;; + SYS_*) ;; +@@ -266,13 +265,6 @@ AC_DEFUN([UL_REQUIRES_SYSCALL_CHECK], [ + m4_define([suffix], m4_default([$4],$1)) + m4_define([callname], m4_default([$3],$1)) + +- dnl This is default, $3 will redefine the condition +- dnl +- dnl TODO: remove this junk, AM_CONDITIONAL should not be used for any HAVE_* +- dnl variables, all we need is BUILD_* only. +- dnl +- AM_CONDITIONAL([HAVE_]m4_toupper(callname), [false]) +- + if test "x$[build_]suffix" != xno; then + if test "x$[enable_]suffix" = xno; then + [build_]suffix=no +diff --git a/schedutils/chrt.c b/schedutils/chrt.c +index 20df6fa..edae0d9 100644 +--- a/schedutils/chrt.c ++++ b/schedutils/chrt.c +@@ -1,13 +1,11 @@ + /* +- * chrt.c - chrt +- * Command-line utility for manipulating a task's real-time attributes ++ * chrt.c - manipulate a task's real-time attributes + * +- * Robert Love <rml@tech9.net> +- * 27-Apr-2002: initial version +- * 04-May-2011: make thread aware - Davidlohr Bueso <dave@gnu.org> ++ * 27-Apr-2002: initial version - Robert Love <rml@tech9.net> ++ * 04-May-2011: make it thread-aware - Davidlohr Bueso <dave@gnu.org> + * + * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License, v2, as ++ * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, +@@ -50,108 +48,260 @@ + # define SCHED_IDLE 5 + #endif + ++/* flag by sched_getscheduler() */ + #if defined(__linux__) && !defined(SCHED_RESET_ON_FORK) +-#define SCHED_RESET_ON_FORK 0x40000000 ++# define SCHED_RESET_ON_FORK 0x40000000 + #endif + ++/* flag by sched_getattr() */ ++#if defined(__linux__) && !defined(SCHED_FLAG_RESET_ON_FORK) ++# define SCHED_FLAG_RESET_ON_FORK 0x01 ++#endif + +-static void __attribute__((__noreturn__)) show_usage(int rc) +-{ +- FILE *out = rc == EXIT_SUCCESS ? stdout : stderr; ++#if defined (__linux__) && !defined(HAVE_SCHED_SETATTR) ++# include <sys/syscall.h> ++#endif + +- fprintf(out, _( +- "\nchrt - manipulate real-time attributes of a process\n" +- "\nSet policy:\n" +- " chrt [options] [-policy] <priority> [-p <pid> | <command> <arg> ...]\n" +- "\nGet policy:\n" +- " chrt [options] -p <pid>\n")); +- +- fprintf(out, _( +- "\nScheduling policies:\n" +- " -b | --batch set policy to SCHED_BATCH\n" +- " -f | --fifo set policy to SCHED_FIFO\n" +- " -i | --idle set policy to SCHED_IDLE\n" +- " -o | --other set policy to SCHED_OTHER\n" +- " -r | --rr set policy to SCHED_RR (default)\n")); ++/* usable kernel-headers, but old glibc-headers */ ++#if defined (__linux__) && !defined(SYS_sched_setattr) && defined(__NR_sched_setattr) ++# define SYS_sched_setattr __NR_sched_setattr ++#endif + +-#ifdef SCHED_RESET_ON_FORK +- fprintf(out, _( +- "\nScheduling flags:\n" +- " -R | --reset-on-fork set SCHED_RESET_ON_FORK for FIFO or RR\n")); ++#if defined (__linux__) && !defined(SYS_sched_getattr) && defined(__NR_sched_getattr) ++# define SYS_sched_getattr __NR_sched_getattr + #endif +- fprintf(out, _( +- "\nOptions:\n" +- " -a | --all-tasks operate on all the tasks (threads) for a given pid\n" +- " -h | --help display this help\n" +- " -m | --max show min and max valid priorities\n" +- " -p | --pid operate on existing given pid\n" +- " -v | --verbose display status information\n" +- " -V | --version output version information\n\n")); + +- exit(rc); ++#if defined (__linux__) && !defined(HAVE_SCHED_SETATTR) && defined(SYS_sched_setattr) ++# define HAVE_SCHED_SETATTR ++ ++struct sched_attr { ++ uint32_t size; ++ uint32_t sched_policy; ++ uint64_t sched_flags; ++ ++ /* SCHED_NORMAL, SCHED_BATCH */ ++ int32_t sched_nice; ++ ++ /* SCHED_FIFO, SCHED_RR */ ++ uint32_t sched_priority; ++ ++ /* SCHED_DEADLINE (nsec) */ ++ uint64_t sched_runtime; ++ uint64_t sched_deadline; ++ uint64_t sched_period; ++}; ++ ++static int sched_setattr(pid_t pid, const struct sched_attr *attr, unsigned int flags) ++{ ++ return syscall(SYS_sched_setattr, pid, attr, flags); + } + +-static void show_rt_info(pid_t pid, int isnew) ++static int sched_getattr(pid_t pid, struct sched_attr *attr, unsigned int size, unsigned int flags) + { +- struct sched_param sp; +- int policy; ++ return syscall(SYS_sched_getattr, pid, attr, size, flags); ++} ++#endif + +- /* don't display "pid 0" as that is confusing */ +- if (!pid) +- pid = getpid(); ++/* the SCHED_DEADLINE is supported since Linux 3.14 ++ * commit id aab03e05e8f7e26f51dee792beddcb5cca9215a5 ++ * -- sched_setattr() is required for this policy! ++ */ ++#if defined (__linux__) && !defined(SCHED_DEADLINE) && defined(HAVE_SCHED_SETATTR) ++# define SCHED_DEADLINE 6 ++#endif + +- policy = sched_getscheduler(pid); +- if (policy == -1) +- err(EXIT_FAILURE, _("failed to get pid %d's policy"), pid); ++/* control struct */ ++struct chrt_ctl { ++ pid_t pid; ++ int policy; /* SCHED_* */ ++ int priority; + +- if (isnew) +- printf(_("pid %d's new scheduling policy: "), pid); +- else +- printf(_("pid %d's current scheduling policy: "), pid); ++ uint64_t runtime; /* --sched-* options */ ++ uint64_t deadline; ++ uint64_t period; ++ ++ unsigned int all_tasks : 1, /* all threads of the PID */ ++ reset_on_fork : 1, /* SCHED_RESET_ON_FORK */ ++ altered : 1, /* sched_set**() used */ ++ verbose : 1; /* verbose output */ ++}; ++ ++static void __attribute__((__noreturn__)) show_usage(int rc) ++{ ++ FILE *out = rc == EXIT_SUCCESS ? stdout : stderr; + ++ fputs(_("Show or change the real-time scheduling attributes of a process.\n"), out); ++ fputs(USAGE_SEPARATOR, out); ++ fputs(_("Set policy:\n" ++ " chrt [options] <priority> <command> [<arg>...]\n" ++ " chrt [options] --pid <priority> <pid>\n"), out); ++ fputs(USAGE_SEPARATOR, out); ++ fputs(_("Get policy:\n" ++ " chrt [options] -p <pid>\n"), out); ++ ++ fputs(USAGE_SEPARATOR, out); ++ fputs(_("Policy options:\n"), out); ++ fputs(_(" -b, --batch set policy to SCHED_BATCH\n"), out); ++ fputs(_(" -d, --deadline set policy to SCHED_DEADLINE\n"), out); ++ fputs(_(" -f, --fifo set policy to SCHED_FIFO\n"), out); ++ fputs(_(" -i, --idle set policy to SCHED_IDLE\n"), out); ++ fputs(_(" -o, --other set policy to SCHED_OTHER\n"), out); ++ fputs(_(" -r, --rr set policy to SCHED_RR (default)\n"), out); ++ ++ fputs(USAGE_SEPARATOR, out); ++ fputs(_("Scheduling options:\n"), out); ++ fputs(_(" -R, --reset-on-fork set SCHED_RESET_ON_FORK for FIFO or RR\n"), out); ++ fputs(_(" -T, --sched-runtime <ns> runtime parameter for DEADLINE\n"), out); ++ fputs(_(" -P, --sched-period <ns> period parameter for DEADLINE\n"), out); ++ fputs(_(" -D, --sched-deadline <ns> deadline parameter for DEADLINE\n"), out); ++ ++ fputs(USAGE_SEPARATOR, out); ++ fputs(_("Other options:\n"), out); ++ fputs(_(" -a, --all-tasks operate on all the tasks (threads) for a given pid\n"), out); ++ fputs(_(" -m, --max show min and max valid priorities\n"), out); ++ fputs(_(" -p, --pid operate on existing given pid\n"), out); ++ fputs(_(" -v, --verbose display status information\n"), out); ++ ++ fputs(USAGE_SEPARATOR, out); ++ fputs(USAGE_HELP, out); ++ fputs(USAGE_VERSION, out); ++ ++ fprintf(out, USAGE_MAN_TAIL("chrt(1)")); ++ exit(rc); ++} ++ ++static const char *get_policy_name(int policy) ++{ + switch (policy) { + case SCHED_OTHER: +- printf("SCHED_OTHER\n"); +- break; ++ return "SCHED_OTHER"; + case SCHED_FIFO: +- printf("SCHED_FIFO\n"); +- break; + #ifdef SCHED_RESET_ON_FORK + case SCHED_FIFO | SCHED_RESET_ON_FORK: +- printf("SCHED_FIFO|SCHED_RESET_ON_FORK\n"); +- break; + #endif ++ return "SCHED_FIFO"; + #ifdef SCHED_IDLE + case SCHED_IDLE: +- printf("SCHED_IDLE\n"); +- break; ++ return "SCHED_IDLE"; + #endif + case SCHED_RR: +- printf("SCHED_RR\n"); +- break; + #ifdef SCHED_RESET_ON_FORK + case SCHED_RR | SCHED_RESET_ON_FORK: +- printf("SCHED_RR|SCHED_RESET_ON_FORK\n"); +- break; + #endif ++ return "SCHED_RR"; + #ifdef SCHED_BATCH + case SCHED_BATCH: +- printf("SCHED_BATCH\n"); +- break; ++ return "SCHED_BATCH"; ++#endif ++#ifdef SCHED_DEADLINE ++ case SCHED_DEADLINE: ++ return "SCHED_DEADLINE"; + #endif + default: +- warnx(_("unknown scheduling policy")); ++ break; ++ } ++ ++ return _("unknown"); ++} ++ ++static void show_sched_pid_info(struct chrt_ctl *ctl, pid_t pid) ++{ ++ int policy, reset_on_fork = 0, prio = 0; ++#ifdef SCHED_DEADLINE ++ uint64_t deadline = 0, runtime = 0, period = 0; ++#endif ++ ++ /* don't display "pid 0" as that is confusing */ ++ if (!pid) ++ pid = getpid(); ++ ++ errno = 0; ++ ++ /* ++ * New way ++ */ ++#ifdef HAVE_SCHED_SETATTR ++ { ++ struct sched_attr sa; ++ ++ if (sched_getattr(pid, &sa, sizeof(sa), 0) != 0) { ++ if (errno == ENOSYS) ++ goto fallback; ++ err(EXIT_FAILURE, _("failed to get pid %d's policy"), pid); ++ } ++ ++ policy = sa.sched_policy; ++ prio = sa.sched_priority; ++ reset_on_fork = sa.sched_flags & SCHED_FLAG_RESET_ON_FORK; ++ deadline = sa.sched_deadline; ++ runtime = sa.sched_runtime; ++ period = sa.sched_period; + } ++#endif ++ ++ /* ++ * Old way ++ */ ++fallback: ++ if (errno == ENOSYS) { ++ struct sched_param sp; + +- if (sched_getparam(pid, &sp)) +- err(EXIT_FAILURE, _("failed to get pid %d's attributes"), pid); ++ policy = sched_getscheduler(pid); ++ if (policy == -1) ++ err(EXIT_FAILURE, _("failed to get pid %d's policy"), pid); + +- if (isnew) +- printf(_("pid %d's new scheduling priority: %d\n"), +- pid, sp.sched_priority); ++ if (sched_getparam(pid, &sp) != 0) ++ err(EXIT_FAILURE, _("failed to get pid %d's attributes"), pid); ++ else ++ prio = sp.sched_priority; ++# ifdef SCHED_RESET_ON_FORK ++ if (policy == (SCHED_FIFO|SCHED_RESET_ON_FORK) || policy == (SCHED_BATCH|SCHED_RESET_ON_FORK)) ++ reset_on_fork = 1; ++# endif ++ } ++ ++ if (ctl->altered) ++ printf(_("pid %d's new scheduling policy: %s"), pid, get_policy_name(policy)); ++ else ++ printf(_("pid %d's current scheduling policy: %s"), pid, get_policy_name(policy)); ++ ++ if (reset_on_fork) ++ printf("|SCHED_RESET_ON_FORK"); ++ putchar('\n'); ++ ++ if (ctl->altered) ++ printf(_("pid %d's new scheduling priority: %d\n"), pid, prio); + else +- printf(_("pid %d's current scheduling priority: %d\n"), +- pid, sp.sched_priority); ++ printf(_("pid %d's current scheduling priority: %d\n"), pid, prio); ++ ++#ifdef SCHED_DEADLINE ++ if (policy == SCHED_DEADLINE) { ++ if (ctl->altered) ++ printf(_("pid %d's new runtime/deadline/period parameters: %ju/%ju/%ju\n"), ++ pid, runtime, deadline, period); ++ else ++ printf(_("pid %d's current runtime/deadline/period parameters: %ju/%ju/%ju\n"), ++ pid, runtime, deadline, period); ++ } ++#endif ++} ++ ++ ++static void show_sched_info(struct chrt_ctl *ctl) ++{ ++ if (ctl->all_tasks) { ++ pid_t tid; ++ struct proc_tasks *ts = proc_open_tasks(ctl->pid); ++ ++ if (!ts) ++ err(EXIT_FAILURE, _("cannot obtain the list of tasks")); ++ ++ while (!proc_next_tid(ts, &tid)) ++ show_sched_pid_info(ctl, tid); ++ ++ proc_close_tasks(ts); ++ } else ++ show_sched_pid_info(ctl, ctl->pid); + } + + static void show_min_max(void) +@@ -167,52 +317,116 @@ static void show_min_max(void) + #ifdef SCHED_IDLE + SCHED_IDLE, + #endif +- }; +- const char *names[] = { +- "OTHER", +- "FIFO", +- "RR", +-#ifdef SCHED_BATCH +- "BATCH", +-#endif +-#ifdef SCHED_IDLE +- "IDLE", ++#ifdef SCHED_DEADLINE ++ SCHED_DEADLINE, + #endif + }; + + for (i = 0; i < ARRAY_SIZE(policies); i++) { +- int max = sched_get_priority_max(policies[i]); +- int min = sched_get_priority_min(policies[i]); ++ int plc = policies[i]; ++ int max = sched_get_priority_max(plc); ++ int min = sched_get_priority_min(plc); + + if (max >= 0 && min >= 0) +- printf(_("SCHED_%s min/max priority\t: %d/%d\n"), +- names[i], min, max); ++ printf(_("%s min/max priority\t: %d/%d\n"), ++ get_policy_name(plc), min, max); + else +- printf(_("SCHED_%s not supported?\n"), names[i]); ++ printf(_("%s not supported?\n"), get_policy_name(plc)); + } + } + ++static int set_sched_one_by_setscheduler(struct chrt_ctl *ctl, pid_t pid) ++{ ++ struct sched_param sp = { .sched_priority = ctl->priority }; ++ int policy = ctl->policy; ++ ++# ifdef SCHED_RESET_ON_FORK ++ if (ctl->reset_on_fork) ++ policy |= SCHED_RESET_ON_FORK; ++# endif ++ return sched_setscheduler(pid, policy, &sp); ++} ++ ++ ++#ifndef HAVE_SCHED_SETATTR ++static int set_sched_one(struct chrt_ctl *ctl, pid_t pid) ++{ ++ return set_sched_one_by_setscheduler(ctl, pid); ++} ++ ++#else /* !HAVE_SCHED_SETATTR */ ++static int set_sched_one(struct chrt_ctl *ctl, pid_t pid) ++{ ++ /* use main() to check if the setting makes sense */ ++ struct sched_attr sa = { ++ .size = sizeof(struct sched_attr), ++ .sched_policy = ctl->policy, ++ .sched_priority = ctl->priority, ++ .sched_runtime = ctl->runtime, ++ .sched_period = ctl->period, ++ .sched_deadline = ctl->deadline ++ }; ++ int rc; ++ ++# ifdef SCHED_RESET_ON_FORK ++ if (ctl->reset_on_fork) ++ sa.sched_flags |= SCHED_RESET_ON_FORK; ++# endif ++ errno = 0; ++ rc = sched_setattr(pid, &sa, 0); ++ ++ if (rc != 0 && errno == ENOSYS && ctl->policy != SCHED_DEADLINE) ++ /* fallback -- build with new kernel/libc, but executed on old kernels */ ++ rc = set_sched_one_by_setscheduler(ctl, pid); ++ ++ return rc; ++} ++#endif /* HAVE_SCHED_SETATTR */ ++ ++static void set_sched(struct chrt_ctl *ctl) ++{ ++ if (ctl->all_tasks) { ++ pid_t tid; ++ struct proc_tasks *ts = proc_open_tasks(ctl->pid); ++ ++ if (!ts) ++ err(EXIT_FAILURE, _("cannot obtain the list of tasks")); ++ ++ while (!proc_next_tid(ts, &tid)) ++ if (set_sched_one(ctl, tid) == -1) ++ err(EXIT_FAILURE, _("failed to set tid %d's policy"), tid); ++ ++ proc_close_tasks(ts); ++ ++ } else if (set_sched_one(ctl, ctl->pid) == -1) ++ err(EXIT_FAILURE, _("failed to set pid %d's policy"), ctl->pid); ++ ++ ctl->altered = 1; ++} ++ + int main(int argc, char **argv) + { +- int i, policy = SCHED_RR, priority = 0, verbose = 0, policy_flag = 0, +- all_tasks = 0; +- struct sched_param sp; +- pid_t pid = -1; ++ struct chrt_ctl _ctl = { .pid = -1 }, *ctl = &_ctl; ++ int c; + + static const struct option longopts[] = { +- { "all-tasks", 0, NULL, 'a' }, +- { "batch", 0, NULL, 'b' }, +- { "fifo", 0, NULL, 'f' }, +- { "idle", 0, NULL, 'i' }, +- { "pid", 0, NULL, 'p' }, +- { "help", 0, NULL, 'h' }, +- { "max", 0, NULL, 'm' }, +- { "other", 0, NULL, 'o' }, +- { "rr", 0, NULL, 'r' }, +- { "reset-on-fork", 0, NULL, 'R' }, +- { "verbose", 0, NULL, 'v' }, +- { "version", 0, NULL, 'V' }, +- { NULL, 0, NULL, 0 } ++ { "all-tasks", no_argument, NULL, 'a' }, ++ { "batch", no_argument, NULL, 'b' }, ++ { "deadline", no_argument, NULL, 'd' }, ++ { "fifo", no_argument, NULL, 'f' }, ++ { "idle", no_argument, NULL, 'i' }, ++ { "pid", no_argument, NULL, 'p' }, ++ { "help", no_argument, NULL, 'h' }, ++ { "max", no_argument, NULL, 'm' }, ++ { "other", no_argument, NULL, 'o' }, ++ { "rr", no_argument, NULL, 'r' }, ++ { "sched-runtime", required_argument, NULL, 'T' }, ++ { "sched-period", required_argument, NULL, 'P' }, ++ { "sched-deadline", required_argument, NULL, 'D' }, ++ { "reset-on-fork", no_argument, NULL, 'R' }, ++ { "verbose", no_argument, NULL, 'v' }, ++ { "version", no_argument, NULL, 'V' }, ++ { NULL, no_argument, NULL, 0 } + }; + + setlocale(LC_ALL, ""); +@@ -220,51 +434,63 @@ int main(int argc, char **argv) + textdomain(PACKAGE); + atexit(close_stdout); + +- while((i = getopt_long(argc, argv, "+abfiphmoRrvV", longopts, NULL)) != -1) ++ while((c = getopt_long(argc, argv, "+abdD:fiphmoP:T:rRvV", longopts, NULL)) != -1) + { + int ret = EXIT_FAILURE; + +- switch (i) { ++ switch (c) { + case 'a': +- all_tasks = 1; ++ ctl->all_tasks = 1; + break; + case 'b': + #ifdef SCHED_BATCH +- policy = SCHED_BATCH; ++ ctl->policy = SCHED_BATCH; ++#endif ++ break; ++ ++ case 'd': ++#ifdef SCHED_DEADLINE ++ ctl->policy = SCHED_DEADLINE; + #endif + break; + case 'f': +- policy = SCHED_FIFO; ++ ctl->policy = SCHED_FIFO; + break; + case 'R': +-#ifdef SCHED_RESET_ON_FORK +- policy_flag |= SCHED_RESET_ON_FORK; +-#endif ++ ctl->reset_on_fork = 1; + break; + case 'i': + #ifdef SCHED_IDLE +- policy = SCHED_IDLE; ++ ctl->policy = SCHED_IDLE; + #endif + break; + case 'm': + show_min_max(); + return EXIT_SUCCESS; + case 'o': +- policy = SCHED_OTHER; ++ ctl->policy = SCHED_OTHER; + break; + case 'p': + errno = 0; +- pid = strtos32_or_err(argv[argc - 1], _("invalid PID argument")); ++ ctl->pid = strtos32_or_err(argv[argc - 1], _("invalid PID argument")); + break; + case 'r': +- policy = SCHED_RR; ++ ctl->policy = SCHED_RR; + break; + case 'v': +- verbose = 1; ++ ctl->verbose = 1; ++ break; ++ case 'T': ++ ctl->runtime = strtou64_or_err(optarg, _("invalid runtime argument")); ++ break; ++ case 'P': ++ ctl->period = strtou64_or_err(optarg, _("invalid period argument")); ++ break; ++ case 'D': ++ ctl->deadline = strtou64_or_err(optarg, _("invalid deadline argument")); + break; + case 'V': +- printf(_("%s from %s\n"), program_invocation_short_name, +- PACKAGE_STRING); ++ printf(UTIL_LINUX_VERSION); + return EXIT_SUCCESS; + case 'h': + ret = EXIT_SUCCESS; +@@ -274,61 +500,56 @@ int main(int argc, char **argv) + } + } + +- if (((pid > -1) && argc - optind < 1) || +- ((pid == -1) && argc - optind < 2)) ++ if (((ctl->pid > -1) && argc - optind < 1) || ++ ((ctl->pid == -1) && argc - optind < 2)) + show_usage(EXIT_FAILURE); + +- if ((pid > -1) && (verbose || argc - optind == 1)) { +- if (all_tasks) { +- pid_t tid; +- struct proc_tasks *ts = proc_open_tasks(pid); +- +- if (!ts) +- err(EXIT_FAILURE, _("cannot obtain the list of tasks")); +- while (!proc_next_tid(ts, &tid)) +- show_rt_info(tid, FALSE); +- proc_close_tasks(ts); +- } else +- show_rt_info(pid, FALSE); +- ++ if ((ctl->pid > -1) && (ctl->verbose || argc - optind == 1)) { ++ show_sched_info(ctl); + if (argc - optind == 1) + return EXIT_SUCCESS; + } + + errno = 0; +- priority = strtos32_or_err(argv[optind], _("invalid priority argument")); ++ ctl->priority = strtos32_or_err(argv[optind], _("invalid priority argument")); + + #ifdef SCHED_RESET_ON_FORK +- /* sanity check */ +- if ((policy_flag & SCHED_RESET_ON_FORK) && +- !(policy == SCHED_FIFO || policy == SCHED_RR)) +- errx(EXIT_FAILURE, _("SCHED_RESET_ON_FORK flag is supported for " ++ if (ctl->reset_on_fork && ctl->policy != SCHED_FIFO && ctl->policy != SCHED_RR) ++ errx(EXIT_FAILURE, _("--reset-on-fork option is supported for " + "SCHED_FIFO and SCHED_RR policies only")); + #endif +- +- policy |= policy_flag; +- +- if (pid == -1) +- pid = 0; +- sp.sched_priority = priority; +- +- if (all_tasks) { +- pid_t tid; +- struct proc_tasks *ts = proc_open_tasks(pid); +- +- if (!ts) +- err(EXIT_FAILURE, _("cannot obtain the list of tasks")); +- while (!proc_next_tid(ts, &tid)) +- if (sched_setscheduler(tid, policy, &sp) == -1) +- err(EXIT_FAILURE, _("failed to set tid %d's policy"), tid); +- proc_close_tasks(ts); +- } else if (sched_setscheduler(pid, policy, &sp) == -1) +- err(EXIT_FAILURE, _("failed to set pid %d's policy"), pid); +- +- if (verbose) +- show_rt_info(pid, TRUE); +- +- if (!pid) { ++#ifdef SCHED_DEADLINE ++ if ((ctl->runtime || ctl->deadline || ctl->period) && ctl->policy != SCHED_DEADLINE) ++ errx(EXIT_FAILURE, _("--sched-{runtime,deadline,period} options " ++ "are supported for SCHED_DEADLINE only")); ++ if (ctl->policy == SCHED_DEADLINE) { ++ /* The basic rule is runtime <= deadline <= period, so we can ++ * make deadline and runtime optional on command line. Note we ++ * don't check any values or set any defaults, it's kernel ++ * responsibility. ++ */ ++ if (ctl->deadline == 0) ++ ctl->deadline = ctl->period; ++ if (ctl->runtime == 0) ++ ctl->runtime = ctl->deadline; ++ } ++#else ++ if (ctl->runtime || ctl->deadline || ctl->period) ++ errx(EXIT_FAILURE, _("SCHED_DEADLINE is unsupported")); ++#endif ++ if (ctl->pid == -1) ++ ctl->pid = 0; ++ if (ctl->priority < sched_get_priority_min(ctl->policy) || ++ sched_get_priority_max(ctl->policy) < ctl->priority) ++ errx(EXIT_FAILURE, ++ _("unsupported priority value for the policy: %d: see --max for valid range"), ++ ctl->priority); ++ set_sched(ctl); ++ ++ if (ctl->verbose) ++ show_sched_info(ctl); ++ ++ if (!ctl->pid) { + argv += optind + 1; + execvp(argv[0], argv); + err(EXIT_FAILURE, _("failed to execute %s"), argv[0]); +-- +2.7.4 + diff --git a/SOURCES/0082-fdisk-backport-DOS-logical-partitions-chain-reorder.patch b/SOURCES/0082-fdisk-backport-DOS-logical-partitions-chain-reorder.patch new file mode 100644 index 0000000..23b1f47 --- /dev/null +++ b/SOURCES/0082-fdisk-backport-DOS-logical-partitions-chain-reorder.patch @@ -0,0 +1,211 @@ +From 28b08b639aeaadbfcc3fb66558e6b392b2b5d44c Mon Sep 17 00:00:00 2001 +From: Karel Zak <kzak@redhat.com> +Date: Tue, 28 Jun 2016 11:30:21 +0200 +Subject: [PATCH 82/86] fdisk: backport DOS logical partitions chain reorder + +... from the current upstream. + +Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1304246 +Signed-off-by: Karel Zak <kzak@redhat.com> +--- + fdisks/fdiskdoslabel.c | 170 +++++++++++++++++++++++++++++++++---------------- + 1 file changed, 116 insertions(+), 54 deletions(-) + +diff --git a/fdisks/fdiskdoslabel.c b/fdisks/fdiskdoslabel.c +index fe04ac7..b7eb35a 100644 +--- a/fdisks/fdiskdoslabel.c ++++ b/fdisks/fdiskdoslabel.c +@@ -55,6 +55,22 @@ static int MBRbuffer_changed; + #define cround(c, n) (fdisk_context_use_cylinders(c) ? \ + ((n) / fdisk_context_get_units_per_sector(c)) + 1 : (n)) + ++ ++static unsigned long long ++get_abs_partition_start(struct pte *pe) ++{ ++ return pe->offset + get_start_sect(pe->part_table); ++} ++ ++static unsigned long long ++get_abs_partition_end(struct pte *pe) ++{ ++ unsigned long long size; ++ ++ size = get_nr_sects(pe->part_table); ++ return get_abs_partition_start(pe) + size - (size ? 1 : 0); ++} ++ + static void warn_alignment(struct fdisk_context *cxt) + { + if (nowarn) +@@ -1254,67 +1270,113 @@ void dos_list_table_expert(struct fdisk_context *cxt, int extend) + } + } + +-/* +- * Fix the chain of logicals. +- * extended_offset is unchanged, the set of sectors used is unchanged +- * The chain is sorted so that sectors increase, and so that +- * starting sectors increase. +- * +- * After this it may still be that cfdisk doesn't like the table. +- * (This is because cfdisk considers expanded parts, from link to +- * end of partition, and these may still overlap.) +- * Now +- * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda +- * may help. +- */ ++ ++static void print_chain_of_logicals(struct fdisk_context *cxt) ++{ ++ size_t i; ++ ++ fputc('\n', stdout); ++ ++ for (i = 4; i < cxt->label->nparts_max; i++) { ++ struct pte *pe = &ptes[i]; ++ ++ fprintf(stderr, "#%02zu EBR [%10ju], " ++ "data[start=%10ju (%10ju), size=%10ju], " ++ "link[start=%10ju (%10ju), size=%10ju]\n", ++ i, (uintmax_t) pe->offset, ++ /* data */ ++ (uintmax_t) get_start_sect(pe->part_table), ++ (uintmax_t) get_abs_partition_start(pe), ++ (uintmax_t) get_nr_sects(pe->part_table), ++ /* link */ ++ (uintmax_t) get_start_sect(pe->ext_pointer), ++ (uintmax_t) (extended_offset + get_start_sect(pe->ext_pointer)), ++ (uintmax_t) get_nr_sects(pe->ext_pointer)); ++ } ++} ++ ++static int cmp_ebr_offsets(const void *a, const void *b) ++{ ++ struct pte *ae = (struct pte *) a, ++ *be = (struct pte *) b; ++ ++ if (ae->offset == 0 && be->offset == 0) ++ return 0; ++ if (ae->offset == 0) ++ return 1; ++ if (be->offset == 0) ++ return -1; ++ ++ return cmp_numbers(ae->offset, be->offset); ++} ++ + static void fix_chain_of_logicals(struct fdisk_context *cxt) + { +- size_t j, oj, ojj, sj, sjj; +- struct partition *pj,*pjj,tmp; +- +- /* Stage 1: sort sectors but leave sector of part 4 */ +- /* (Its sector is the global extended_offset.) */ +- stage1: +- for (j = 5; j < cxt->label->nparts_max - 1; j++) { +- oj = ptes[j].offset; +- ojj = ptes[j+1].offset; +- if (oj > ojj) { +- ptes[j].offset = ojj; +- ptes[j+1].offset = oj; +- pj = ptes[j].part_table; +- set_start_sect(pj, get_start_sect(pj)+oj-ojj); +- pjj = ptes[j+1].part_table; +- set_start_sect(pjj, get_start_sect(pjj)+ojj-oj); +- set_start_sect(ptes[j-1].ext_pointer, +- ojj-extended_offset); +- set_start_sect(ptes[j].ext_pointer, +- oj-extended_offset); +- goto stage1; ++ struct pte *last; ++ size_t i; ++ ++ DBG(CONTEXT, print_chain_of_logicals(cxt)); ++ ++ /* Sort chain by EBR offsets */ ++ qsort(&ptes[4], cxt->label->nparts_max - 4, sizeof(struct pte), ++ cmp_ebr_offsets); ++ ++again: ++ /* Sort data partitions by start */ ++ for (i = 4; i < cxt->label->nparts_max - 1; i++) { ++ struct pte *cur = &ptes[i], ++ *nxt = &ptes[i + 1]; ++ ++ if (get_abs_partition_start(cur) > ++ get_abs_partition_start(nxt)) { ++ ++ struct partition tmp = *cur->part_table; ++ sector_t cur_start = get_abs_partition_start(cur), ++ nxt_start = get_abs_partition_start(nxt); ++ ++ /* swap data partitions */ ++ *cur->part_table = *nxt->part_table; ++ *nxt->part_table = tmp; ++ ++ /* Recount starts according to EBR offsets, the absolute ++ * address still has to be the same! */ ++ set_start_sect(cur->part_table, nxt_start - cur->offset); ++ set_start_sect(nxt->part_table, cur_start - nxt->offset); ++ ++ cur->changed = 1; ++ nxt->changed = 1; ++ goto again; + } + } + +- /* Stage 2: sort starting sectors */ +- stage2: +- for (j = 4; j < cxt->label->nparts_max - 1; j++) { +- pj = ptes[j].part_table; +- pjj = ptes[j+1].part_table; +- sj = get_start_sect(pj); +- sjj = get_start_sect(pjj); +- oj = ptes[j].offset; +- ojj = ptes[j+1].offset; +- if (oj+sj > ojj+sjj) { +- tmp = *pj; +- *pj = *pjj; +- *pjj = tmp; +- set_start_sect(pj, ojj+sjj-oj); +- set_start_sect(pjj, oj+sj-ojj); +- goto stage2; +- } ++ /* Update EBR links */ ++ for (i = 4; i < cxt->label->nparts_max - 1; i++) { ++ struct pte *cur = &ptes[i], ++ *nxt = &ptes[i + 1]; ++ ++ sector_t noff = nxt->offset - extended_offset, ++ ooff = get_start_sect(cur->ext_pointer); ++ ++ if (noff == ooff) ++ continue; ++ ++ DBG(CONTEXT, dbgprint("DOS: fix EBR [%10ju] link %ju -> %ju", ++ (uintmax_t) cur->offset, ++ (uintmax_t) ooff, (uintmax_t) noff)); ++ ++ set_partition(cxt, i, 1, nxt->offset, ++ get_abs_partition_end(nxt), ++ EXTENDED); ++ } ++ ++ /* always terminate the chain ! */ ++ last = &ptes[cxt->label->nparts_max - 1]; ++ if (last) { ++ clear_partition(last->ext_pointer); ++ last->changed = 1; + } + +- /* Probably something was changed */ +- for (j = 4; j < cxt->label->nparts_max; j++) +- ptes[j].changed = 1; ++ DBG(CONTEXT, print_chain_of_logicals(cxt)); + } + + void dos_fix_partition_table_order(struct fdisk_context *cxt) +-- +2.7.4 + diff --git a/SOURCES/0083-tests-cleanup-tests.patch b/SOURCES/0083-tests-cleanup-tests.patch new file mode 100644 index 0000000..10da5f2 --- /dev/null +++ b/SOURCES/0083-tests-cleanup-tests.patch @@ -0,0 +1,276 @@ +From d35dfbe11f7c6b84d40a6e54611dc3a8c9c27b4d Mon Sep 17 00:00:00 2001 +From: Karel Zak <kzak@redhat.com> +Date: Thu, 30 Jun 2016 11:00:54 +0200 +Subject: [PATCH 83/86] tests: cleanup tests + +... mostly to be more portable to the new kernels and userspace. + +Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1153770 +Signed-off-by: Karel Zak <kzak@redhat.com> +--- + tests/commands.sh | 1 + + tests/expected/blkid/md-raid0-whole | 2 +- + tests/expected/blkid/md-raid1-part | 2 +- + tests/expected/blkid/md-raid1-whole | 2 +- + tests/expected/fdisk/align-512-4K | 2 +- + tests/expected/fdisk/align-512-4K-63 | 2 +- + tests/expected/fdisk/align-512-4K-md | 4 ++-- + tests/expected/fdisk/align-512-512 | 2 +- + tests/expected/fdisk/align-512-512-topology | 2 +- + tests/expected/ipcs/limits | 4 ---- + tests/functions.sh | 29 +++++++++++++++++++++++------ + tests/ts/ipcs/limits | 5 +---- + tests/ts/ipcs/limits2 | 2 ++ + tests/ts/libmount/context-utab | 10 ++++++++-- + 14 files changed, 44 insertions(+), 25 deletions(-) + +diff --git a/tests/commands.sh b/tests/commands.sh +index a2948c9..e769b5d 100644 +--- a/tests/commands.sh ++++ b/tests/commands.sh +@@ -64,3 +64,4 @@ TS_CMD_UL=${TS_CMD_UL-"$top_builddir/ul"} + TS_CMD_UMOUNT=${TS_CMD_UMOUNT:-"$top_builddir/umount"} + TS_CMD_UTMPDUMP=${TS_CMD_UTMPDUMP-"$top_builddir/utmpdump"} + TS_CMD_WHEREIS=${TS_CMD_WHEREIS-"$top_builddir/whereis"} ++TS_CMD_WIPEFS=${TS_CMD_WIPEFS-"$top_builddir/wipefs"} +diff --git a/tests/expected/blkid/md-raid0-whole b/tests/expected/blkid/md-raid0-whole +index 37dabf3..30825de 100644 +--- a/tests/expected/blkid/md-raid0-whole ++++ b/tests/expected/blkid/md-raid0-whole +@@ -26,7 +26,7 @@ Command (m for help): + Disk /dev/md8: 104 MB, 104726528 bytes, 204544 sectors + Units = sectors of 1 * 512 = 512 bytes + Sector size (logical/physical): 512 bytes / 512 bytes +-I/O size (minimum/optimal): 65536 bytes / 131072 bytes ++I/O size (minimum/optimal): 65536 bytes / <removed> bytes + Disk label type: dos + + +diff --git a/tests/expected/blkid/md-raid1-part b/tests/expected/blkid/md-raid1-part +index f409952..3d1b38c 100644 +--- a/tests/expected/blkid/md-raid1-part ++++ b/tests/expected/blkid/md-raid1-part +@@ -24,7 +24,7 @@ Command (m for help): + Disk /dev/...: 53 MB, 53477376 bytes, 104448 sectors + Units = sectors of 1 * 512 = 512 bytes + Sector size (logical/physical): 512 bytes / 512 bytes +-I/O size (minimum/optimal): 512 bytes / 32768 bytes ++I/O size (minimum/optimal): 512 bytes / <removed> bytes + Disk label type: dos + + +diff --git a/tests/expected/blkid/md-raid1-whole b/tests/expected/blkid/md-raid1-whole +index 8977312..8ab1da2 100644 +--- a/tests/expected/blkid/md-raid1-whole ++++ b/tests/expected/blkid/md-raid1-whole +@@ -25,7 +25,7 @@ Command (m for help): + Disk /dev/md8: 52 MB, 52363264 bytes, 102272 sectors + Units = sectors of 1 * 512 = 512 bytes + Sector size (logical/physical): 512 bytes / 512 bytes +-I/O size (minimum/optimal): 512 bytes / 512 bytes ++I/O size (minimum/optimal): 512 bytes / <removed> bytes + Disk label type: dos + + +diff --git a/tests/expected/fdisk/align-512-4K b/tests/expected/fdisk/align-512-4K +index e5a28f5..7b52fd2 100644 +--- a/tests/expected/fdisk/align-512-4K ++++ b/tests/expected/fdisk/align-512-4K +@@ -57,7 +57,7 @@ Command (m for help): + Disk /dev/...: 52 MB, 52428800 bytes, 102400 sectors + Units = sectors of 1 * 512 = 512 bytes + Sector size (logical/physical): 512 bytes / 4096 bytes +-I/O size (minimum/optimal): 4096 bytes / 32768 bytes ++I/O size (minimum/optimal): 4096 bytes / <removed> bytes + Disk label type: dos + + +diff --git a/tests/expected/fdisk/align-512-4K-63 b/tests/expected/fdisk/align-512-4K-63 +index 7e236ce..302a429 100644 +--- a/tests/expected/fdisk/align-512-4K-63 ++++ b/tests/expected/fdisk/align-512-4K-63 +@@ -57,7 +57,7 @@ Command (m for help): + Disk /dev/...: 52 MB, 52428800 bytes, 102400 sectors + Units = sectors of 1 * 512 = 512 bytes + Sector size (logical/physical): 512 bytes / 4096 bytes +-I/O size (minimum/optimal): 4096 bytes / 32768 bytes ++I/O size (minimum/optimal): 4096 bytes / <removed> bytes + Alignment offset: 3584 bytes + Disk label type: dos + +diff --git a/tests/expected/fdisk/align-512-4K-md b/tests/expected/fdisk/align-512-4K-md +index dbbbc05..e8f6ba1 100644 +--- a/tests/expected/fdisk/align-512-4K-md ++++ b/tests/expected/fdisk/align-512-4K-md +@@ -28,7 +28,7 @@ Command (m for help): + Disk /dev/...: 52 MB, 52428800 bytes, 102400 sectors + Units = sectors of 1 * 512 = 512 bytes + Sector size (logical/physical): 512 bytes / 4096 bytes +-I/O size (minimum/optimal): 4096 bytes / 32768 bytes ++I/O size (minimum/optimal): 4096 bytes / <removed> bytes + Disk label type: dos + + +@@ -72,7 +72,7 @@ Command (m for help): + Disk /dev/md8: 51 MB, 51249152 bytes, 100096 sectors + Units = sectors of 1 * 512 = 512 bytes + Sector size (logical/physical): 512 bytes / 4096 bytes +-I/O size (minimum/optimal): 65536 bytes / 131072 bytes ++I/O size (minimum/optimal): 65536 bytes / <removed> bytes + Disk label type: dos + + +diff --git a/tests/expected/fdisk/align-512-512 b/tests/expected/fdisk/align-512-512 +index 018322f..8e03d90 100644 +--- a/tests/expected/fdisk/align-512-512 ++++ b/tests/expected/fdisk/align-512-512 +@@ -53,7 +53,7 @@ Command (m for help): + Disk /dev/loop0: 52 MB, 52428800 bytes, 102400 sectors + Units = sectors of 1 * 512 = 512 bytes + Sector size (logical/physical): 512 bytes / 512 bytes +-I/O size (minimum/optimal): 512 bytes / 512 bytes ++I/O size (minimum/optimal): 512 bytes / <removed> bytes + Disk label type: dos + + +diff --git a/tests/expected/fdisk/align-512-512-topology b/tests/expected/fdisk/align-512-512-topology +index b3d3114..fd57f60 100644 +--- a/tests/expected/fdisk/align-512-512-topology ++++ b/tests/expected/fdisk/align-512-512-topology +@@ -53,7 +53,7 @@ Command (m for help): + Disk /dev/...: 52 MB, 52428800 bytes, 102400 sectors + Units = sectors of 1 * 512 = 512 bytes + Sector size (logical/physical): 512 bytes / 512 bytes +-I/O size (minimum/optimal): 512 bytes / 32768 bytes ++I/O size (minimum/optimal): 512 bytes / <removed> bytes + Disk label type: dos + + +diff --git a/tests/expected/ipcs/limits b/tests/expected/ipcs/limits +index 7480a1e..e08fa54 100644 +--- a/tests/expected/ipcs/limits ++++ b/tests/expected/ipcs/limits +@@ -1,8 +1,4 @@ + load original values +-check for difference between kernel and IPC +-/proc/sys/kernel/shmmni OK +-/proc/sys/kernel/shmall OK +-/proc/sys/kernel/shmmax OK + maximalize kernel setting + re-check for difference between kernel and IPC + /proc/sys/kernel/shmmni OK +diff --git a/tests/functions.sh b/tests/functions.sh +index b2d493c..0d1c9c8 100644 +--- a/tests/functions.sh ++++ b/tests/functions.sh +@@ -31,6 +31,17 @@ function ts_canonicalize { + fi + } + ++function ts_check_test_command { ++ if [ ! -x "$1" ]; then ++ ts_skip "${1##*/} not found" ++ fi ++} ++ ++function ts_check_prog { ++ local cmd=$1 ++ type "$cmd" >/dev/null 2>&1 || ts_skip "missing in PATH: $cmd" ++} ++ + function ts_skip_subtest { + echo " IGNORE ($1)" + } +@@ -474,14 +485,20 @@ function ts_fdisk_clean { + local DEVNAME=$(basename "$1") + + # remove non comparable parts of fdisk output +- if [ x"${DEVNAME}" != x"" ]; then +- sed -i -e "s/\/dev\/${DEVNAME}/\/dev\/.../g" $TS_OUTPUT ++ if [ -n "${DEVNAME}" ]; then ++ sed -i -e "s@${DEVNAME}@...@;" $TS_OUTPUT + fi + +- sed -i -e 's/Disk identifier:.*//g' \ +- -e 's/Building a new.*//g' \ +- -e 's/Welcome to fdisk.*//g' \ +- $TS_OUTPUT ++ sed -i \ ++ -e 's/Disk identifier:.*//' \ ++ -e 's/Building a new.*//' \ ++ -e 's/Created a new.*//' \ ++ -e 's/^Device[[:blank:]]*Start/Device Start/' \ ++ -e 's/^Device[[:blank:]]*Boot/Device Boot/' \ ++ -e 's/Welcome to fdisk.*//' \ ++ -e 's/typescript file.*/typescript file <removed>./' \ ++ -e 's@^\(I/O size (minimum/op.* bytes /\) [1-9][0-9]* @\1 <removed> @' \ ++ $TS_OUTPUT + } + + function ts_scsi_debug_init { +diff --git a/tests/ts/ipcs/limits b/tests/ts/ipcs/limits +index b44adb1..c4717c3 100755 +--- a/tests/ts/ipcs/limits ++++ b/tests/ts/ipcs/limits +@@ -23,7 +23,7 @@ TS_DESC="limits overflow" + + ts_init "$*" + ts_skip_nonroot +-type bc >/dev/null 2>&1 || ts_skip "cannot find bc command" ++ts_check_prog "bc" + + . $TS_SELF/functions.sh + +@@ -32,9 +32,6 @@ for i in $IPCS_IDX; do + SHM_ORG[$i]=$(cat ${IPCS_PROCFILES[$i]}) + done >> $TS_OUTPUT + +-ts_log "check for difference between kernel and IPC" +-ipcs_limits_check >> $TS_OUTPUT +- + ts_log "maximalize kernel setting" + for i in $IPCS_IDX; do + echo ${IPCS_LIMITS[$i]} >> ${IPCS_PROCFILES[$i]} +diff --git a/tests/ts/ipcs/limits2 b/tests/ts/ipcs/limits2 +index 63f834d..2eabfd2 100755 +--- a/tests/ts/ipcs/limits2 ++++ b/tests/ts/ipcs/limits2 +@@ -22,6 +22,8 @@ TS_DESC="basic limits" + . $TS_TOPDIR/functions.sh + ts_init "$*" + ++ts_check_prog "bc" ++ + . $TS_SELF/functions.sh + + # TODO https://github.com/karelzak/util-linux/issues/51 +diff --git a/tests/ts/libmount/context-utab b/tests/ts/libmount/context-utab +index 859fc2b..b2bfefc 100755 +--- a/tests/ts/libmount/context-utab ++++ b/tests/ts/libmount/context-utab +@@ -87,14 +87,20 @@ ts_finalize_subtest + + + if [ -x "/sbin/mkfs.btrfs" ]; then ++ + $TS_CMD_WIPEFS -a $DEVICE &> /dev/null + ts_log "Create filesystem [btrfs]" + /sbin/mkfs.btrfs -L "$LABEL" $DEVICE &> /dev/null + udevadm settle + + mount -t btrfs $DEVICE $MOUNTPOINT &> /dev/null +- /sbin/btrfsctl -S sub $MOUNTPOINT &> /dev/null +- umount $MOUNTPOINT &> /dev/null ++ ++ if [ -x "/sbin/btrfsctl" ]; then ++ /sbin/btrfsctl -S sub $MOUNTPOINT &> /dev/null ++ else ++ btrfs subvolume create $MOUNTPOINT/sub &> /dev/null ++ fi ++ umount $MOUNTPOINT #&> /dev/null + + udevadm settle + +-- +2.7.4 + diff --git a/SOURCES/0084-libmount-add-support-for-bind-ro.patch b/SOURCES/0084-libmount-add-support-for-bind-ro.patch new file mode 100644 index 0000000..f86edbb --- /dev/null +++ b/SOURCES/0084-libmount-add-support-for-bind-ro.patch @@ -0,0 +1,160 @@ +From 2218dc0d130bb72809e2d8b26a36402bf6293727 Mon Sep 17 00:00:00 2001 +From: Karel Zak <kzak@redhat.com> +Date: Mon, 17 Aug 2015 11:54:26 +0200 +Subject: [PATCH 84/86] libmount: add support for "bind,ro" + +Now it's necessary to use two mount(8) calls to create a read-only +mount: + + mount /foo /bar -o bind + mount /bar -o remount,ro,bind + +This patch allows to specify "bind,ro" and the remount is done +automatically by libmount by additional mount(2) syscall. It's not +atomic of course. + +Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1281839 +Signed-off-by: Karel Zak <kzak@redhat.com> +--- + libmount/src/context_mount.c | 46 ++++++++++++++++++++++++++++++++++++++++++++ + sys-utils/mount.8 | 37 ++++++++++++++++++----------------- + 2 files changed, 65 insertions(+), 18 deletions(-) + +diff --git a/libmount/src/context_mount.c b/libmount/src/context_mount.c +index d6691eb..4df2646 100644 +--- a/libmount/src/context_mount.c ++++ b/libmount/src/context_mount.c +@@ -62,6 +62,10 @@ static int mnt_context_append_additional_mount(struct libmnt_context *cxt, + return 0; + } + ++/* ++ * add additional mount(2) syscall requests when necessary to set propagation flags ++ * after regular mount(2). ++ */ + static int init_propagation(struct libmnt_context *cxt) + { + char *name; +@@ -102,6 +106,41 @@ static int init_propagation(struct libmnt_context *cxt) + } + + /* ++ * add additional mount(2) syscall request to implement "ro,bind", the first regular ++ * mount(2) is the "bind" operation, the second is "remount,ro,bind" call. ++ * ++ * Note that we don't remove "ro" from the first syscall (kernel silently ++ * ignores this flags for bind operation) -- maybe one day kernel will support ++ * read-only binds in one step and then all will be done by the firts mount(2) and the ++ * second remount will be noop... ++ */ ++static int init_robind(struct libmnt_context *cxt) ++{ ++ struct libmnt_addmount *ad; ++ int rc; ++ ++ assert(cxt); ++ assert(cxt->mountflags & MS_BIND); ++ assert(cxt->mountflags & MS_RDONLY); ++ assert(!(cxt->mountflags & MS_REMOUNT)); ++ ++ DBG(CXT, mnt_debug_h(cxt, "mount: initialize additional ro,bind mount")); ++ ++ ad = mnt_new_addmount(); ++ if (!ad) ++ return -ENOMEM; ++ ++ ad->mountflags = MS_REMOUNT | MS_BIND | MS_RDONLY; ++ if (cxt->mountflags & MS_REC) ++ ad->mountflags |= MS_REC; ++ rc = mnt_context_append_additional_mount(cxt, ad); ++ if (rc) ++ return rc; ++ ++ return 0; ++} ++ ++/* + * this has to be called after mnt_context_evaluate_permissions() + */ + static int fix_optstr(struct libmnt_context *cxt) +@@ -174,6 +213,13 @@ static int fix_optstr(struct libmnt_context *cxt) + if (rc) + return rc; + } ++ if ((cxt->mountflags & MS_BIND) ++ && (cxt->mountflags & MS_RDONLY) ++ && !(cxt->mountflags & MS_REMOUNT)) { ++ rc = init_robind(cxt); ++ if (rc) ++ return rc; ++ } + + next = fs->fs_optstr; + +diff --git a/sys-utils/mount.8 b/sys-utils/mount.8 +index 3648870..49cb281 100644 +--- a/sys-utils/mount.8 ++++ b/sys-utils/mount.8 +@@ -388,25 +388,25 @@ or shortoption + .\" available since Linux 2.4.11. + + Note that the filesystem mount options will remain the same as those +-on the original mount point, and cannot be changed by passing the -o +-option along with --bind/--rbind. The mount options can be +-changed by a separate remount command, for example: ++on the original mount point. ++ ++.BR mount(8) ++since v2.27 (backported to RHEL7.3) allow to change the options by passing the ++.B \-o ++option along with ++.BR \-\-bind ++for example: + + .RS + .br +-.B mount --bind +-.I olddir newdir +-.br +-.B mount -o remount,ro +-.I newdir ++.B mount \-\-bind,ro foo foo + .RE + +-Note that behavior of the remount operation depends on the /etc/mtab file. The +-first command stores the 'bind' flag to the /etc/mtab file and the second +-command reads the flag from the file. If you have a system without the +-/etc/mtab file or if you explicitly define source and target for the remount +-command (then mount(8) does not read /etc/mtab), then you have to use bind flag +-(or option) for the remount command too. For example: ++This feature is not supported by Linux kernel and it is implemented in userspace ++by additional remount mount(2) syscall. This solution is not atomic. ++ ++The alternative (classic) way to create a read-only bind mount is to use remount ++operation, for example: + + .RS + .br +@@ -417,14 +417,15 @@ command (then mount(8) does not read /etc/mtab), then you have to use bind flag + .I olddir newdir + .RE + +-Note that +-.I remount,ro,bind +-will create a read-only mountpoint (VFS entry), but the original filesystem suberblock +-will be still writable, it means that the ++Note that read-only bind will create a read-only mountpoint (VFS entry), but the ++original filesystem superblock will still be writable, meaning that the + .I olddir + will be writable, but the + .I newdir + will be read-only. ++ ++It's impossible to change mount options recursively ++(for example with \fB -o rbind,ro\fR). + .RE + + .B The move operation. +-- +2.7.4 + diff --git a/SOURCES/0085-libblkid-store-only-canonical-devnames-to-the-cache.patch b/SOURCES/0085-libblkid-store-only-canonical-devnames-to-the-cache.patch new file mode 100644 index 0000000..0ee3aa3 --- /dev/null +++ b/SOURCES/0085-libblkid-store-only-canonical-devnames-to-the-cache.patch @@ -0,0 +1,176 @@ +From 75b6c0e045abb7e07773b924237c562ab9920c60 Mon Sep 17 00:00:00 2001 +From: Karel Zak <kzak@redhat.com> +Date: Thu, 26 May 2016 12:02:12 +0200 +Subject: [PATCH 85/86] libblkid: store only canonical devnames to the cache + +Let's try to use symlink: + + # ls -la /dev/block/8\:1 + # lrwxrwxrwx 1 root root 7 May 25 16:42 /dev/block/8:1 -> ../sda1 + + # blkid /dev/block/8:1 + /dev/block/8:3: LABEL="HOME" UUID="196972ad-3b13-4bba-ac54-4cb3f7b409a4" TYPE="ext4" PARTUUID="6073277f-87bc-43ff-bcfd-724c4484a63a" + +unfortunately the symlink is stored to the cache: + + <device DEVNO="0x0803" TIME="1464253300.715279" LABEL="HOME" UUID="196972ad-3b13-4bba-ac54-4cb3f7b409a4" TYPE="ext4" PARTUUID="6073277f-87bc-43ff-bcfd-724c4484a63a">/dev/block/8:3</device> + +next time if you ask for LABEL=HOME the answer will be /dev/block/8:3 +rather than /dev/sda3. + +It seems better to canonicalize the paths we store to the cache. + +Unfortunately if you ask for /dev/block/8:3 then you probably expect +that blkid_dev_devname() returns the same path. This patch introduces +dev->bid_xname, this is the path used by application (and never stored +in the cache). + +Upstream: http://github.com/karelzak/util-linux/commit/924c93d9df118338fd54cd73b4a45ccddc4ac103 +Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1007734 +Signed-off-by: Karel Zak <kzak@redhat.com> +--- + libblkid/src/blkidP.h | 4 +++- + libblkid/src/dev.c | 11 +++++++++-- + libblkid/src/devname.c | 43 +++++++++++++++++++++++++++++++++++++------ + 3 files changed, 49 insertions(+), 9 deletions(-) + +diff --git a/libblkid/src/blkidP.h b/libblkid/src/blkidP.h +index 7de84b4..8183c12 100644 +--- a/libblkid/src/blkidP.h ++++ b/libblkid/src/blkidP.h +@@ -44,7 +44,7 @@ struct blkid_struct_dev + struct list_head bid_devs; /* All devices in the cache */ + struct list_head bid_tags; /* All tags for this device */ + blkid_cache bid_cache; /* Dev belongs to this cache */ +- char *bid_name; /* Device inode pathname */ ++ char *bid_name; /* Device real pathn (as used in cache) */ + char *bid_type; /* Preferred device TYPE */ + int bid_pri; /* Device priority */ + dev_t bid_devno; /* Device major/minor number */ +@@ -53,6 +53,8 @@ struct blkid_struct_dev + unsigned int bid_flags; /* Device status bitflags */ + char *bid_label; /* Shortcut to device LABEL */ + char *bid_uuid; /* Shortcut to binary UUID */ ++ ++ char *bid_xname; /* Device path as used by application (maybe symlink..) */ + }; + + #define BLKID_BID_FL_VERIFIED 0x0001 /* Device data validated from disk */ +diff --git a/libblkid/src/dev.c b/libblkid/src/dev.c +index a4b2aea..d2fd3f4 100644 +--- a/libblkid/src/dev.c ++++ b/libblkid/src/dev.c +@@ -60,16 +60,23 @@ void blkid_free_dev(blkid_dev dev) + bit_tags); + blkid_free_tag(tag); + } ++ free(dev->bid_xname); + free(dev->bid_name); + free(dev); + } + + /* +- * Given a blkid device, return its name ++ * Given a blkid device, return its name. The function returns the name ++ * previously used for blkid_get_dev(). This name does not have to be canonical ++ * (real path) name, but for example symlink. + */ + const char *blkid_dev_devname(blkid_dev dev) + { +- return dev ? dev->bid_name : NULL; ++ if (!dev) ++ return NULL; ++ if (dev->bid_xname) ++ return dev->bid_xname; ++ return dev->bid_name; + } + + #ifdef CONFIG_BLKID_DEBUG +diff --git a/libblkid/src/devname.c b/libblkid/src/devname.c +index 497deaf..55b9594 100644 +--- a/libblkid/src/devname.c ++++ b/libblkid/src/devname.c +@@ -51,28 +51,55 @@ blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags) + { + blkid_dev dev = NULL, tmp; + struct list_head *p, *pnext; ++ char *cn = NULL; + + if (!cache || !devname) + return NULL; + ++ /* search by name */ + list_for_each(p, &cache->bic_devs) { + tmp = list_entry(p, struct blkid_struct_dev, bid_devs); + if (strcmp(tmp->bid_name, devname)) + continue; +- +- DBG(DEVNAME, blkid_debug("found devname %s in cache", tmp->bid_name)); + dev = tmp; + break; + } + ++ /* try canonicalize the name */ ++ if (!dev && (cn = canonicalize_path(devname))) { ++ if (strcmp(cn, devname) != 0) { ++ DBG(DEVNAME, blkid_debug("search cannonical %s", cn)); ++ list_for_each(p, &cache->bic_devs) { ++ tmp = list_entry(p, struct blkid_struct_dev, bid_devs); ++ if (strcmp(tmp->bid_name, cn)) ++ continue; ++ dev = tmp; ++ ++ /* update name returned by blkid_dev_devname() */ ++ free(dev->bid_xname); ++ dev->bid_xname = strdup(devname); ++ break; ++ } ++ } else { ++ free(cn); ++ cn = NULL; ++ } ++ } ++ + if (!dev && (flags & BLKID_DEV_CREATE)) { + if (access(devname, F_OK) < 0) +- return NULL; ++ goto done; + dev = blkid_new_dev(); + if (!dev) +- return NULL; ++ goto done; + dev->bid_time = INT_MIN; +- dev->bid_name = strdup(devname); ++ if (cn) { ++ dev->bid_name = cn; ++ dev->bid_xname = strdup(devname); ++ cn = NULL; /* see free() below */ ++ } else ++ dev->bid_name = strdup(devname); ++ + dev->bid_cache = cache; + list_add_tail(&dev->bid_devs, &cache->bic_devs); + cache->bic_flags |= BLKID_BIC_FL_CHANGED; +@@ -81,7 +108,7 @@ blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags) + if (flags & BLKID_DEV_VERIFY) { + dev = blkid_verify(cache, dev); + if (!dev || !(dev->bid_flags & BLKID_BID_FL_VERIFIED)) +- return dev; ++ goto done; + /* + * If the device is verified, then search the blkid + * cache for any entries that match on the type, uuid, +@@ -112,6 +139,10 @@ blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags) + blkid_free_dev(dev2); + } + } ++done: ++ if (dev) ++ DBG(DEVNAME, blkid_debug("%s requested, found %s in cache", devname, dev->bid_name)); ++ free(cn); + return dev; + } + +-- +2.7.4 + diff --git a/SOURCES/0086-libblkid-avoid-recursion-in-EBR.patch b/SOURCES/0086-libblkid-avoid-recursion-in-EBR.patch new file mode 100644 index 0000000..32b7f17 --- /dev/null +++ b/SOURCES/0086-libblkid-avoid-recursion-in-EBR.patch @@ -0,0 +1,102 @@ +From 8125a64ff9e98d09c659dbd5adbca521d63a268b Mon Sep 17 00:00:00 2001 +From: Karel Zak <kzak@redhat.com> +Date: Thu, 7 Jul 2016 14:22:41 +0200 +Subject: [PATCH 86/86] libblkid: avoid recursion in EBR + +Upstream: http://github.com/karelzak/util-linux/commit/7164a1c34d18831ac61c6744ad14ce916d389b3f +Upstream: http://github.com/karelzak/util-linux/commit/50d1594c2e6142a3b51d2143c74027480df082e0 +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1349536 +Signed-off-by: Karel Zak <kzak@redhat.com> +--- + libblkid/src/partitions/dos.c | 21 +++++++++++++++++++-- + libblkid/src/partitions/partitions.c | 14 ++++++++++++++ + libblkid/src/partitions/partitions.h | 2 ++ + 3 files changed, 35 insertions(+), 2 deletions(-) + +diff --git a/libblkid/src/partitions/dos.c b/libblkid/src/partitions/dos.c +index 2d4a537..563fe9a 100644 +--- a/libblkid/src/partitions/dos.c ++++ b/libblkid/src/partitions/dos.c +@@ -48,6 +48,12 @@ static int parse_dos_extended(blkid_probe pr, blkid_parttable tab, + int ct_nodata = 0; /* count ext.partitions without data partitions */ + int i; + ++ DBG(LOWPROBE, blkid_debug("parse EBR [start=%d, size=%d]", ex_start/ssf, ex_size/ssf)); ++ if (ex_start == 0) { ++ DBG(LOWPROBE, blkid_debug("Bad offset in primary extended partition -- ignore")); ++ return 0; ++ } ++ + while (1) { + struct dos_partition *p, *p0; + uint32_t start, size; +@@ -100,6 +106,13 @@ static int parse_dos_extended(blkid_probe pr, blkid_parttable tab, + continue; + } + ++ /* Avoid recursive non-empty links, see ct_nodata counter */ ++ if (blkid_partlist_get_partition_by_start(ls, abs_start)) { ++ DBG(LOWPROBE, blkid_debug("#%d: EBR duplicate data partition [abs start=%u] -- ignore", ++ i + 1, abs_start)); ++ continue; ++ } ++ + par = blkid_partlist_add_partition(ls, tab, abs_start, size); + if (!par) + return -ENOMEM; +@@ -116,8 +129,12 @@ static int parse_dos_extended(blkid_probe pr, blkid_parttable tab, + start = dos_partition_start(p) * ssf; + size = dos_partition_size(p) * ssf; + +- if (size && is_extended(p)) +- break; ++ if (size && is_extended(p)) { ++ if (start == 0) ++ DBG(LOWPROBE, blkid_debug("#%d: EBR link offset is zero -- ignore", i + 1)); ++ else ++ break; ++ } + } + if (i == 4) + goto leave; +diff --git a/libblkid/src/partitions/partitions.c b/libblkid/src/partitions/partitions.c +index 752fc95..9d846ff 100644 +--- a/libblkid/src/partitions/partitions.c ++++ b/libblkid/src/partitions/partitions.c +@@ -928,6 +928,20 @@ blkid_partition blkid_partlist_get_partition(blkid_partlist ls, int n) + return &ls->parts[n]; + } + ++blkid_partition blkid_partlist_get_partition_by_start(blkid_partlist ls, uint64_t start) ++{ ++ int i, nparts; ++ blkid_partition par; ++ ++ nparts = blkid_partlist_numof_partitions(ls); ++ for (i = 0; i < nparts; i++) { ++ par = blkid_partlist_get_partition(ls, i); ++ if ((uint64_t) blkid_partition_get_start(par) == start) ++ return par; ++ } ++ return NULL; ++} ++ + /** + * blkid_partlist_devno_to_partition: + * @ls: partitions list +diff --git a/libblkid/src/partitions/partitions.h b/libblkid/src/partitions/partitions.h +index 61763bf..4e99e2a 100644 +--- a/libblkid/src/partitions/partitions.h ++++ b/libblkid/src/partitions/partitions.h +@@ -20,6 +20,8 @@ extern int blkid_partlist_increment_partno(blkid_partlist ls); + + extern blkid_partition blkid_partlist_get_parent(blkid_partlist ls); + ++extern blkid_partition blkid_partlist_get_partition_by_start(blkid_partlist ls, uint64_t start); ++ + extern int blkid_partitions_do_subprobe(blkid_probe pr, + blkid_partition parent, const struct blkid_idinfo *id); + +-- +2.7.4 + diff --git a/SOURCES/2.28-lslogins-1317953.patch b/SOURCES/2.28-lslogins-1317953.patch deleted file mode 100644 index db7589a..0000000 --- a/SOURCES/2.28-lslogins-1317953.patch +++ /dev/null @@ -1,210 +0,0 @@ -diff -up util-linux-2.23.2/include/pathnames.h.kzak util-linux-2.23.2/include/pathnames.h ---- util-linux-2.23.2/include/pathnames.h.kzak 2016-03-16 17:17:02.980243390 +0100 -+++ util-linux-2.23.2/include/pathnames.h 2016-03-16 17:17:37.129015363 +0100 -@@ -36,6 +36,7 @@ - #endif - #define _PATH_MOTDFILE "/etc/motd" - #define _PATH_NOLOGIN "/etc/nologin" -+#define _PATH_VAR_NOLOGIN "/var/run/nologin" - - #define _PATH_LOGIN "/bin/login" - #define _PATH_INITTAB "/etc/inittab" -diff -up util-linux-2.23.2/login-utils/lslogins.1.kzak util-linux-2.23.2/login-utils/lslogins.1 ---- util-linux-2.23.2/login-utils/lslogins.1.kzak 2016-03-16 17:17:02.970243457 +0100 -+++ util-linux-2.23.2/login-utils/lslogins.1 2016-03-16 17:17:37.129015363 +0100 -@@ -5,7 +5,10 @@ - lslogins \- display information about known users in the system - .SH SYNOPSIS - .B lslogins --[\fIoptions\fR] [\fB-s\fR|\fB-u\fR[=\fIUID\fR]] [\fB-g \fIgroups\fR] [\fB-l \fIlogins\fR] -+[options] -+.RB [ \-s | \-u [ =\fIUID ]] -+.RB [ \-g " \fIgroups\fR]" -+.RB [ \-l " \fIlogins\fR]" - .SH DESCRIPTION - .PP - Examine the wtmp and btmp logs, /etc/shadow (if necessary) and /etc/passwd -@@ -17,7 +20,7 @@ Mandatory arguments to long options are - .TP - \fB\-a\fR, \fB\-\-acc\-expiration\fR - Display data about the date of last password change and the account expiration --date (see \fBshadow\fR(5) for more info). (Requires root priviliges.) -+date (see \fBshadow\fR(5) for more info). (Requires root privileges.) - .TP - \fB\-\-btmp\-file \fIpath\fP - Alternate path for btmp. -@@ -31,7 +34,7 @@ Output data in the format of NAME=VALUE. - \fB\-f\fR, \fB\-\-failed\fR - Display data about the users' last failed login attempts. - .TP --\fB\-G\fR, \fB\-\-groups\-info\fR -+\fB\-G\fR, \fB\-\-supp\-groups\fR - Show information about groups. - .TP - \fB\-g\fR, \fB\-\-groups\fR=\fIgroups\fR -@@ -48,9 +51,6 @@ Display data containing information abou - Only show data of users with a login specified in \fIlogins\fR (user names or user - IDS). More than one login may be specified; the list has to be comma-separated. - .TP --\fB\-m\fR, \fB\-\-supp\-groups\fR --Show supplementary groups. --.TP - \fB\-n\fR, \fB\-\-newline\fR - Display each piece of information on a separate line. - .TP -@@ -71,21 +71,21 @@ Display information related to login by - \fB\-r\fR, \fB\-\-raw\fR - Raw output (no columnation). - .TP --\fB\-s\fR, \fB\-\-system\-accs\fR[=\fIthreshold\fR] -+\fB\-s\fR, \fB\-\-system\-accs\fR - Show system accounts. These are by default all accounts with a UID below 1000 --(non-inclusive), with the exception of either nobody or nfsnobody (UID 65534). The UID --threshold can also be specified explicitly (necessary for some distributions that --allocate UIDs starting from 100, 500 - or an entirely different value - rather than 1000). -+(non-inclusive), with the exception of either nobody or nfsnobody (UID 65534). -+This hardcoded default maybe overwritten by parameters SYS_UID_MIN and SYS_UID_MAX in -+the file /etc/login.defs. - .TP --\fB\-\-time-format\fR \fItype\fP -+\fB\-\-time\-format\fR \fItype\fP - Display dates in short, full or iso format. The default is short, this time - format is designed to be space efficient and human readable. - .TP --\fB\-u\fR, \fB\-\-user\-accs\fR[=\fIthreshold\fR] -+\fB\-u\fR, \fB\-\-user\-accs\fR - Show user accounts. These are by default all accounts with UID above 1000 --(inclusive), with the exception of either nobody or nfsnobody (UID 65534). The UID --threshold can also be specified explicitly (necessary for some distributions that --allocate UIDs starting from 100, 500 - or an entirely different value - rather than 1000). -+(inclusive), with the exception of either nobody or nfsnobody (UID 65534). -+This hardcoded default maybe overwritten by parameters UID_MIN and UID_MAX in -+the file /etc/login.defs. - .TP - \fB\-V\fR, \fB\-\-version\fR - Display version information and exit. -diff -up util-linux-2.23.2/login-utils/lslogins.c.kzak util-linux-2.23.2/login-utils/lslogins.c ---- util-linux-2.23.2/login-utils/lslogins.c.kzak 2016-03-16 17:17:02.970243457 +0100 -+++ util-linux-2.23.2/login-utils/lslogins.c 2016-03-16 17:23:47.191484521 +0100 -@@ -396,7 +396,7 @@ again: - x = snprintf(p, len, "%s,", grp->gr_name); - } - -- if (x < 0 || (size_t) x + 1 > len) { -+ if (x < 0 || (size_t) x >= len) { - size_t cur = p - res; - - maxlen *= 2; -@@ -496,21 +496,24 @@ static int parse_btmp(struct lslogins_co - static int get_sgroups(gid_t **list, size_t *len, struct passwd *pwd) - { - size_t n = 0; -+ int ngroups = 0; - - *len = 0; - *list = NULL; - - /* first let's get a supp. group count */ -- getgrouplist(pwd->pw_name, pwd->pw_gid, *list, (int *) len); -- if (!*len) -+ getgrouplist(pwd->pw_name, pwd->pw_gid, *list, &ngroups); -+ if (!ngroups) - return -1; - -- *list = xcalloc(1, *len * sizeof(gid_t)); -+ *list = xcalloc(1, ngroups * sizeof(gid_t)); - - /* now for the actual list of GIDs */ -- if (-1 == getgrouplist(pwd->pw_name, pwd->pw_gid, *list, (int *) len)) -+ if (-1 == getgrouplist(pwd->pw_name, pwd->pw_gid, *list, &ngroups)) - return -1; - -+ *len = (size_t) ngroups; -+ - /* getgroups also returns the user's primary GID - dispose of it */ - while (n < *len) { - if ((*list)[n] == pwd->pw_gid) -@@ -852,7 +855,7 @@ static int get_user(struct lslogins_cont - const char *username) - { - *user = get_user_info(ctl, username); -- if (!*user && errno) -+ if (!*user) - if (IS_REAL_ERRNO(errno)) - return -1; - return 0; -@@ -1193,16 +1196,18 @@ static void __attribute__((__noreturn__) - fputs(USAGE_HEADER, out); - fprintf(out, _(" %s [options]\n"), program_invocation_short_name); - -+ fputs(USAGE_SEPARATOR, out); -+ fputs(_("Display information about known users in the system.\n"), out); -+ - fputs(USAGE_OPTIONS, out); - fputs(_(" -a, --acc-expiration display info about passwords expiration\n"), out); - fputs(_(" -c, --colon-separate display data in a format similar to /etc/passwd\n"), out); - fputs(_(" -e, --export display in an export-able output format\n"), out); - fputs(_(" -f, --failed display data about the users' last failed logins\n"), out); -- fputs(_(" -G, --groups-info display information about groups\n"), out); -+ fputs(_(" -G, --supp-groups display information about groups\n"), out); - fputs(_(" -g, --groups=<groups> display users belonging to a group in <groups>\n"), out); - fputs(_(" -L, --last show info about the users' last login sessions\n"), out); - fputs(_(" -l, --logins=<logins> display only users from <logins>\n"), out); -- fputs(_(" -m, --supp-groups display supplementary groups as well\n"), out); - fputs(_(" -n, --newline display each piece of information on a new line\n"), out); - fputs(_(" --noheadings don't print headings\n"), out); - fputs(_(" --notruncate don't truncate output\n"), out); -@@ -1226,7 +1231,7 @@ static void __attribute__((__noreturn__) - fprintf(out, " %14s %s\n", coldescs[i].name, - _(coldescs[i].help)); - -- fprintf(out, _("\nFor more details see lslogins(1).\n")); -+ fprintf(out, USAGE_MAN_TAIL("lslogins(1)")); - - exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); - } -@@ -1241,8 +1246,7 @@ int main(int argc, char *argv[]) - - /* long only options. */ - enum { -- OPT_VER = CHAR_MAX + 1, -- OPT_WTMP, -+ OPT_WTMP = CHAR_MAX + 1, - OPT_BTMP, - OPT_NOTRUNC, - OPT_NOHEAD, -@@ -1300,7 +1304,7 @@ int main(int argc, char *argv[]) - add_column(columns, ncolumns++, COL_UID); - add_column(columns, ncolumns++, COL_USER); - -- while ((c = getopt_long(argc, argv, "acfGg:hLl:no:prsuVxzZ", -+ while ((c = getopt_long(argc, argv, "acefGg:hLl:no:prsuVzZ", - longopts, NULL)) != -1) { - - err_exclusive_options(c, longopts, excl, excl_st); -@@ -1397,6 +1401,7 @@ int main(int argc, char *argv[]) - { - size_t i; - -+ ctl->time_mode = TIME_INVALID; - for (i = 0; i < ARRAY_SIZE(timefmts); i++) { - if (strcmp(timefmts[i].name, optarg) == 0) { - ctl->time_mode = timefmts[i].val; -@@ -1404,7 +1409,7 @@ int main(int argc, char *argv[]) - } - } - if (ctl->time_mode == TIME_INVALID) -- usage(stderr); -+ errx(EXIT_FAILURE, _("unknown time format: %s"), optarg); - } - break; - case 'V': -@@ -1433,7 +1438,7 @@ int main(int argc, char *argv[]) - logins = argv[optind]; - outmode = OUT_PRETTY; - } else if (argc != optind) -- usage(stderr); -+ errx(EXIT_FAILURE, _("Only one user may be specified. Use -l for multiple users.")); - - scols_init_debug(0); - diff --git a/SOURCES/2.28-lslogins-rebase.patch b/SOURCES/2.28-lslogins-rebase.patch new file mode 100644 index 0000000..fd0cdb4 --- /dev/null +++ b/SOURCES/2.28-lslogins-rebase.patch @@ -0,0 +1,460 @@ +diff -up util-linux-2.23.2/include/pathnames.h.kzak util-linux-2.23.2/include/pathnames.h +--- util-linux-2.23.2/include/pathnames.h.kzak 2016-03-16 15:17:42.648298525 +0100 ++++ util-linux-2.23.2/include/pathnames.h 2016-03-16 15:18:13.769055345 +0100 +@@ -36,6 +36,7 @@ + #endif + #define _PATH_MOTDFILE "/etc/motd" + #define _PATH_NOLOGIN "/etc/nologin" ++#define _PATH_VAR_NOLOGIN "/var/run/nologin" + + #define _PATH_LOGIN "/bin/login" + #define _PATH_INITTAB "/etc/inittab" +diff -up util-linux-2.23.2/login-utils/lslogins.1.kzak util-linux-2.23.2/login-utils/lslogins.1 +--- util-linux-2.23.2/login-utils/lslogins.1.kzak 2016-03-16 15:17:42.639298595 +0100 ++++ util-linux-2.23.2/login-utils/lslogins.1 2016-03-16 15:18:13.769055345 +0100 +@@ -5,7 +5,10 @@ + lslogins \- display information about known users in the system + .SH SYNOPSIS + .B lslogins +-[\fIoptions\fR] [\fB-s\fR|\fB-u\fR[=\fIUID\fR]] [\fB-g \fIgroups\fR] [\fB-l \fIlogins\fR] ++[options] ++.RB [ \-s | \-u [ =\fIUID ]] ++.RB [ \-g " \fIgroups\fR]" ++.RB [ \-l " \fIlogins\fR]" + .SH DESCRIPTION + .PP + Examine the wtmp and btmp logs, /etc/shadow (if necessary) and /etc/passwd +@@ -17,7 +20,7 @@ Mandatory arguments to long options are + .TP + \fB\-a\fR, \fB\-\-acc\-expiration\fR + Display data about the date of last password change and the account expiration +-date (see \fBshadow\fR(5) for more info). (Requires root priviliges.) ++date (see \fBshadow\fR(5) for more info). (Requires root privileges.) + .TP + \fB\-\-btmp\-file \fIpath\fP + Alternate path for btmp. +@@ -31,7 +34,7 @@ Output data in the format of NAME=VALUE. + \fB\-f\fR, \fB\-\-failed\fR + Display data about the users' last failed login attempts. + .TP +-\fB\-G\fR, \fB\-\-groups\-info\fR ++\fB\-G\fR, \fB\-\-supp\-groups\fR + Show information about groups. + .TP + \fB\-g\fR, \fB\-\-groups\fR=\fIgroups\fR +@@ -48,9 +51,6 @@ Display data containing information abou + Only show data of users with a login specified in \fIlogins\fR (user names or user + IDS). More than one login may be specified; the list has to be comma-separated. + .TP +-\fB\-m\fR, \fB\-\-supp\-groups\fR +-Show supplementary groups. +-.TP + \fB\-n\fR, \fB\-\-newline\fR + Display each piece of information on a separate line. + .TP +@@ -71,21 +71,21 @@ Display information related to login by + \fB\-r\fR, \fB\-\-raw\fR + Raw output (no columnation). + .TP +-\fB\-s\fR, \fB\-\-system\-accs\fR[=\fIthreshold\fR] ++\fB\-s\fR, \fB\-\-system\-accs\fR + Show system accounts. These are by default all accounts with a UID below 1000 +-(non-inclusive), with the exception of either nobody or nfsnobody (UID 65534). The UID +-threshold can also be specified explicitly (necessary for some distributions that +-allocate UIDs starting from 100, 500 - or an entirely different value - rather than 1000). ++(non-inclusive), with the exception of either nobody or nfsnobody (UID 65534). ++This hardcoded default maybe overwritten by parameters SYS_UID_MIN and SYS_UID_MAX in ++the file /etc/login.defs. + .TP +-\fB\-\-time-format\fR \fItype\fP ++\fB\-\-time\-format\fR \fItype\fP + Display dates in short, full or iso format. The default is short, this time + format is designed to be space efficient and human readable. + .TP +-\fB\-u\fR, \fB\-\-user\-accs\fR[=\fIthreshold\fR] ++\fB\-u\fR, \fB\-\-user\-accs\fR + Show user accounts. These are by default all accounts with UID above 1000 +-(inclusive), with the exception of either nobody or nfsnobody (UID 65534). The UID +-threshold can also be specified explicitly (necessary for some distributions that +-allocate UIDs starting from 100, 500 - or an entirely different value - rather than 1000). ++(inclusive), with the exception of either nobody or nfsnobody (UID 65534). ++This hardcoded default maybe overwritten by parameters UID_MIN and UID_MAX in ++the file /etc/login.defs. + .TP + \fB\-V\fR, \fB\-\-version\fR + Display version information and exit. +diff -up util-linux-2.23.2/login-utils/lslogins.c.kzak util-linux-2.23.2/login-utils/lslogins.c +--- util-linux-2.23.2/login-utils/lslogins.c.kzak 2016-03-16 15:17:42.639298595 +0100 ++++ util-linux-2.23.2/login-utils/lslogins.c 2016-03-16 15:22:49.845899268 +0100 +@@ -144,6 +144,7 @@ enum { + TIME_SHORT, + TIME_FULL, + TIME_ISO, ++ TIME_ISO_SHORT, + }; + + /* +@@ -350,6 +351,9 @@ static char *make_time(int mode, time_t + case TIME_ISO: + strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", &tm); + break; ++ case TIME_ISO_SHORT: ++ strftime(buf, sizeof(buf), "%Y-%m-%d", &tm); ++ break; + default: + errx(EXIT_FAILURE, _("unsupported time type")); + } +@@ -396,7 +400,7 @@ again: + x = snprintf(p, len, "%s,", grp->gr_name); + } + +- if (x < 0 || (size_t) x + 1 > len) { ++ if (x < 0 || (size_t) x >= len) { + size_t cur = p - res; + + maxlen *= 2; +@@ -496,21 +500,24 @@ static int parse_btmp(struct lslogins_co + static int get_sgroups(gid_t **list, size_t *len, struct passwd *pwd) + { + size_t n = 0; ++ int ngroups = 0; + + *len = 0; + *list = NULL; + + /* first let's get a supp. group count */ +- getgrouplist(pwd->pw_name, pwd->pw_gid, *list, (int *) len); +- if (!*len) ++ getgrouplist(pwd->pw_name, pwd->pw_gid, *list, &ngroups); ++ if (!ngroups) + return -1; + +- *list = xcalloc(1, *len * sizeof(gid_t)); ++ *list = xcalloc(1, ngroups * sizeof(gid_t)); + + /* now for the actual list of GIDs */ +- if (-1 == getgrouplist(pwd->pw_name, pwd->pw_gid, *list, (int *) len)) ++ if (-1 == getgrouplist(pwd->pw_name, pwd->pw_gid, *list, &ngroups)) + return -1; + ++ *len = (size_t) ngroups; ++ + /* getgroups also returns the user's primary GID - dispose of it */ + while (n < *len) { + if ((*list)[n] == pwd->pw_gid) +@@ -520,6 +527,7 @@ static int get_sgroups(gid_t **list, siz + + if (*len) + (*list)[n] = (*list)[--(*len)]; ++ + return 0; + } + +@@ -685,8 +693,8 @@ static struct lslogins_user *get_user_in + if (strstr(pwd->pw_shell, "nologin")) + user->nologin = 1; + else if (pwd->pw_uid) +- user->nologin = access("/etc/nologin", F_OK) == 0 || +- access("/var/run/nologin", F_OK) == 0; ++ user->nologin = access(_PATH_NOLOGIN, F_OK) == 0 || ++ access(_PATH_VAR_NOLOGIN, F_OK) == 0; + break; + case COL_PWD_WARN: + if (shadow && shadow->sp_warn >= 0) +@@ -694,7 +702,8 @@ static struct lslogins_user *get_user_in + break; + case COL_PWD_EXPIR: + if (shadow && shadow->sp_expire >= 0) +- user->pwd_expire = make_time(TIME_SHORT, ++ user->pwd_expire = make_time(ctl->time_mode == TIME_ISO ? ++ TIME_ISO_SHORT : ctl->time_mode, + shadow->sp_expire * 86400); + break; + case COL_PWD_CTIME: +@@ -702,7 +711,8 @@ static struct lslogins_user *get_user_in + * (especially in non-GMT timezones) would only serve + * to confuse */ + if (shadow) +- user->pwd_ctime = make_time(TIME_SHORT, ++ user->pwd_ctime = make_time(ctl->time_mode == TIME_ISO ? ++ TIME_ISO_SHORT : ctl->time_mode, + shadow->sp_lstchg * 86400); + break; + case COL_PWD_CTIME_MIN: +@@ -852,7 +862,7 @@ static int get_user(struct lslogins_cont + const char *username) + { + *user = get_user_info(ctl, username); +- if (!*user && errno) ++ if (!*user) + if (IS_REAL_ERRNO(errno)) + return -1; + return 0; +@@ -887,33 +897,33 @@ static int create_usertree(struct lslogi + + static struct libscols_table *setup_table(struct lslogins_control *ctl) + { +- struct libscols_table *tb = scols_new_table(); ++ struct libscols_table *table = scols_new_table(); + int n = 0; + +- if (!tb) ++ if (!table) + errx(EXIT_FAILURE, _("failed to initialize output table")); + if (ctl->noheadings) +- scols_table_enable_noheadings(tb, 1); ++ scols_table_enable_noheadings(table, 1); + + switch(outmode) { + case OUT_COLON: +- scols_table_enable_raw(tb, 1); +- scols_table_set_column_separator(tb, ":"); ++ scols_table_enable_raw(table, 1); ++ scols_table_set_column_separator(table, ":"); + break; + case OUT_NEWLINE: +- scols_table_set_column_separator(tb, "\n"); ++ scols_table_set_column_separator(table, "\n"); + /* fallthrough */ + case OUT_EXPORT: +- scols_table_enable_export(tb, 1); ++ scols_table_enable_export(table, 1); + break; + case OUT_NUL: +- scols_table_set_line_separator(tb, "\0"); ++ scols_table_set_line_separator(table, "\0"); + /* fallthrough */ + case OUT_RAW: +- scols_table_enable_raw(tb, 1); ++ scols_table_enable_raw(table, 1); + break; + case OUT_PRETTY: +- scols_table_enable_noheadings(tb, 1); ++ scols_table_enable_noheadings(table, 1); + default: + break; + } +@@ -924,7 +934,7 @@ static struct libscols_table *setup_tabl + if (ctl->notrunc) + flags &= ~SCOLS_FL_TRUNC; + +- if (!scols_table_new_column(tb, ++ if (!scols_table_new_column(table, + coldescs[columns[n]].name, + coldescs[columns[n]].whint, + flags)) +@@ -932,9 +942,9 @@ static struct libscols_table *setup_tabl + ++n; + } + +- return tb; ++ return table; + fail: +- scols_unref_table(tb); ++ scols_unref_table(table); + return NULL; + } + +@@ -1050,10 +1060,10 @@ static void fill_table(const void *u, co + return; + } + #ifdef HAVE_LIBSYSTEMD +-static void print_journal_tail(const char *journal_path, uid_t uid, size_t len) ++static void print_journal_tail(const char *journal_path, uid_t uid, size_t len, int time_mode) + { + sd_journal *j; +- char *match, *buf; ++ char *match, *timestamp; + uint64_t x; + time_t t; + const char *identifier, *pid, *message; +@@ -1064,7 +1074,6 @@ static void print_journal_tail(const cha + else + sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY); + +- buf = xmalloc(sizeof(char) * 16); + xasprintf(&match, "_UID=%d", uid); + + sd_journal_add_match(j, match, 0); +@@ -1074,37 +1083,35 @@ static void print_journal_tail(const cha + do { + if (0 > sd_journal_get_data(j, "SYSLOG_IDENTIFIER", + (const void **) &identifier, &identifier_len)) +- return; ++ goto done; + if (0 > sd_journal_get_data(j, "_PID", + (const void **) &pid, &pid_len)) +- return; ++ goto done; + if (0 > sd_journal_get_data(j, "MESSAGE", + (const void **) &message, &message_len)) +- return; ++ goto done; + + sd_journal_get_realtime_usec(j, &x); + t = x / 1000000; +- strftime(buf, 16, "%b %d %H:%M:%S", localtime(&t)); +- +- fprintf(stdout, "%s", buf); +- ++ timestamp = make_time(time_mode, t); ++ /* Get rid of journal entry field identifiers */ + identifier = strchr(identifier, '=') + 1; +- pid = strchr(pid, '=') + 1 ; ++ pid = strchr(pid, '=') + 1; + message = strchr(message, '=') + 1; + +- fprintf(stdout, " %s", identifier); +- fprintf(stdout, "[%s]:", pid); +- fprintf(stdout, "%s\n", message); ++ fprintf(stdout, "%s %s[%s]: %s\n", timestamp, identifier, pid, ++ message); ++ free(timestamp); + } while (sd_journal_next(j)); + +- free(buf); ++done: + free(match); + sd_journal_flush_matches(j); + sd_journal_close(j); + } + #endif + +-static int print_pretty(struct libscols_table *tb) ++static int print_pretty(struct libscols_table *table) + { + struct libscols_iter *itr = scols_new_iter(SCOLS_ITER_FORWARD); + struct libscols_column *col; +@@ -1113,8 +1120,8 @@ static int print_pretty(struct libscols_ + const char *hstr, *dstr; + int n = 0; + +- ln = scols_table_get_line(tb, 0); +- while (!scols_table_next_column(tb, itr, &col)) { ++ ln = scols_table_get_line(table, 0); ++ while (!scols_table_next_column(table, itr, &col)) { + + data = scols_line_get_cell(ln, n); + +@@ -1142,7 +1149,7 @@ static int print_user_table(struct lslog + print_pretty(tb); + #ifdef HAVE_LIBSYSTEMD + fprintf(stdout, _("\nLast logs:\n")); +- print_journal_tail(ctl->journal_path, ctl->uid, 3); ++ print_journal_tail(ctl->journal_path, ctl->uid, 3, ctl->time_mode); + fputc('\n', stdout); + #endif + } else +@@ -1175,16 +1182,25 @@ static void free_user(void *f) + free(u); + } + +-struct lslogins_timefmt { +- const char *name; +- int val; +-}; ++static int parse_time_mode(const char *optarg) ++{ ++ struct lslogins_timefmt { ++ const char *name; ++ const int val; ++ }; ++ static const struct lslogins_timefmt timefmts[] = { ++ {"iso", TIME_ISO}, ++ {"full", TIME_FULL}, ++ {"short", TIME_SHORT}, ++ }; ++ size_t i; + +-static struct lslogins_timefmt timefmts[] = { +- { "short", TIME_SHORT }, +- { "full", TIME_FULL }, +- { "iso", TIME_ISO }, +-}; ++ for (i = 0; i < ARRAY_SIZE(timefmts); i++) { ++ if (strcmp(timefmts[i].name, optarg) == 0) ++ return timefmts[i].val; ++ } ++ errx(EXIT_FAILURE, _("unknown time format: %s"), optarg); ++} + + static void __attribute__((__noreturn__)) usage(FILE *out) + { +@@ -1193,16 +1209,18 @@ static void __attribute__((__noreturn__) + fputs(USAGE_HEADER, out); + fprintf(out, _(" %s [options]\n"), program_invocation_short_name); + ++ fputs(USAGE_SEPARATOR, out); ++ fputs(_("Display information about known users in the system.\n"), out); ++ + fputs(USAGE_OPTIONS, out); + fputs(_(" -a, --acc-expiration display info about passwords expiration\n"), out); + fputs(_(" -c, --colon-separate display data in a format similar to /etc/passwd\n"), out); + fputs(_(" -e, --export display in an export-able output format\n"), out); + fputs(_(" -f, --failed display data about the users' last failed logins\n"), out); +- fputs(_(" -G, --groups-info display information about groups\n"), out); ++ fputs(_(" -G, --supp-groups display information about groups\n"), out); + fputs(_(" -g, --groups=<groups> display users belonging to a group in <groups>\n"), out); + fputs(_(" -L, --last show info about the users' last login sessions\n"), out); + fputs(_(" -l, --logins=<logins> display only users from <logins>\n"), out); +- fputs(_(" -m, --supp-groups display supplementary groups as well\n"), out); + fputs(_(" -n, --newline display each piece of information on a new line\n"), out); + fputs(_(" --noheadings don't print headings\n"), out); + fputs(_(" --notruncate don't truncate output\n"), out); +@@ -1226,7 +1244,7 @@ static void __attribute__((__noreturn__) + fprintf(out, " %14s %s\n", coldescs[i].name, + _(coldescs[i].help)); + +- fprintf(out, _("\nFor more details see lslogins(1).\n")); ++ fprintf(out, USAGE_MAN_TAIL("lslogins(1)")); + + exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); + } +@@ -1241,8 +1259,7 @@ int main(int argc, char *argv[]) + + /* long only options. */ + enum { +- OPT_VER = CHAR_MAX + 1, +- OPT_WTMP, ++ OPT_WTMP = CHAR_MAX + 1, + OPT_BTMP, + OPT_NOTRUNC, + OPT_NOHEAD, +@@ -1300,7 +1317,7 @@ int main(int argc, char *argv[]) + add_column(columns, ncolumns++, COL_UID); + add_column(columns, ncolumns++, COL_USER); + +- while ((c = getopt_long(argc, argv, "acfGg:hLl:no:prsuVxzZ", ++ while ((c = getopt_long(argc, argv, "acefGg:hLl:no:prsuVzZ", + longopts, NULL)) != -1) { + + err_exclusive_options(c, longopts, excl, excl_st); +@@ -1394,18 +1411,7 @@ int main(int argc, char *argv[]) + ctl->noheadings = 1; + break; + case OPT_TIME_FMT: +- { +- size_t i; +- +- for (i = 0; i < ARRAY_SIZE(timefmts); i++) { +- if (strcmp(timefmts[i].name, optarg) == 0) { +- ctl->time_mode = timefmts[i].val; +- break; +- } +- } +- if (ctl->time_mode == TIME_INVALID) +- usage(stderr); +- } ++ ctl->time_mode = parse_time_mode(optarg); + break; + case 'V': + printf(UTIL_LINUX_VERSION); +@@ -1433,7 +1439,7 @@ int main(int argc, char *argv[]) + logins = argv[optind]; + outmode = OUT_PRETTY; + } else if (argc != optind) +- usage(stderr); ++ errx(EXIT_FAILURE, _("Only one user may be specified. Use -l for multiple users.")); + + scols_init_debug(0); + diff --git a/SPECS/util-linux.spec b/SPECS/util-linux.spec index dd22223..1299dea 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: 26%{?dist}.3 +Release: 33%{?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 @@ -199,14 +199,67 @@ Patch56: 2.25-libblkid-return-codes.patch Patch57: 2.26-libblkid-fat.patch # -# RHEL 7.2.Z +# RHEL7.3 # -# 1302332 - [libblkid] Failed to get offset of the xfs_external_log signature +# 1301091 - [libblkid] Failed to get offset of the xfs_external_log signature Patch58: 2.27-libblkid-xfs-log.patch -# 1317953 - lslogins crash when executed with buggy username -Patch59: 2.28-lslogins-1317953.patch -# 1350777 - fdisk 'f' subcommand updates partition ranges wrongly -Patch60: 0060-fdisk-backport-DOS-logical-partitions-chain-reorder.patch +# 1291554 - lslogins crash when executed with buggy username +Patch59: 2.28-lslogins-rebase.patch +# 1092520 - util-linux - PIE and RELRO check +Patch60: 0060-build-sys-add-CFLAGS-and-LDFLAGS-for-daemons-and-sha.patch +# 1248003 - mount only parses <param>=<value> lines from fstab fs_spec field available from blkid block device +Patch61: 0061-libmount-be-more-restrictive-about-valid-tag-names.patch +# 1271850 - mount -a doesn't catch a typo in /etc/fstab and a typo in /etc/fstab can make a system not reboot properly +Patch62: 0062-mount-umount-swapon-fsck-lsblk-findmnt-ignore-malfor.patch +# 1290689 - util-linux: /bin/login does not retry getpwnam_r with larger buffers, leading to login failure +Patch63: 0063-login-mount-fix-__SC_GETPW_R_SIZE_MAX-usage.patch +# 1296366 - Bash completion for more(1) handles file names with spaces incorrectly +Patch64: 0064-bash-completion-use-n-as-IFS-when-ask-for-filenames.patch +# 1296521 - RHEL7: update audit event in hwclock +Patch65: 0065-hwclock-change-audit-message.patch +# 1304426 - [rfe] /bin/su should be improved to reduce stack use +Patch66: 0066-su-clean-up-groups-initialization.patch +# 1326615 - util-linux/lscpu: Fix model and model name on Power Systems +Patch67: 0067-lscpu-Fix-model-and-model-name-on-Power-Systems.patch +# 1326615 - util-linux/lscpu: Fix model and model name on Power Systems +Patch68: 0068-lscpu-use-cpu-and-revision-tag-if-available.patch +# 1335671 - extra quotes around UUID confuses findfs in RHEL (but not in Fedora) +Patch69: 0069-findfs-add-ability-to-work-with-PART-UUID-LABEL-too.patch +# 1335671 - extra quotes around UUID confuses findfs in RHEL (but not in Fedora) +Patch70: 0070-libblkid-fix-memory-leak-in-blkid_parse_tag_string.patch +# 587393 - [RFE] Make sure util-linux is ready for writable overlays +Patch71: 0071-findmnt-don-t-rely-on-st_dev-for-target.patch +# 587393 - [RFE] Make sure util-linux is ready for writable overlays +Patch72: 0072-libmount-cleanup-fs-root-detection-code.patch +# 587393 - [RFE] Make sure util-linux is ready for writable overlays +Patch73: 0073-libmount-mark-overlay-as-pseudo-FS.patch +# 1344222 - logger port option in help is misleading +Patch74: 0074-logger-be-more-precise-about-port-description.patch +# 1344482 - util-linux fails valid_pmbr() size checks if device is > 2.14TB, Device label type: dos instead of gpt +Patch75: 0075-libfdisk-gpt-be-more-careful-with-64bit-constants.patch +# 1332084 - [RFE] Inclusion of lsns command in util-linux Package +Patch76: 0076-lsns-backport-new-command.patch +# 1153770 - backport lsipc +Patch77: 0077-lib-strutils-make-strmode-more-generic.patch +# 1153770 - backport lsipc +Patch78: 0078-lsipc-backport-new-command.patch +# 1327886 - Backport blkdiscard's "-z" flag to RHEL +Patch79: 0079-blkdiscard-backport-zeroout-support.patch +# 1029385 - lack of non-ascii support +Patch80: 0080-sulogin-and-agetty-virtual-consoles-support-xvc-and-.patch +# 1298384 - RFE: add SCHED_DEADLINE support to chrt +Patch81: 0081-chrt-backport-DEADLINE-scheduler-support.patch +# 1304246 - fdisk 'f' subcommand updates partition ranges wrongly +Patch82: 0082-fdisk-backport-DOS-logical-partitions-chain-reorder.patch +# 1153770 - backport lsipc +Patch83: 0083-tests-cleanup-tests.patch +# 1281839 - [RFE]Bind mounts should be handled gracefully by the operating system +Patch84: 0084-libmount-add-support-for-bind-ro.patch +# 1007734 - blkid shows devices as /dev/block/$MAJOR:$MINOR +Patch85: 0085-libblkid-store-only-canonical-devnames-to-the-cache.patch +# 1349536 - Extended partition loop in MBR partition table leads to DOS +Patch86: 0086-libblkid-avoid-recursion-in-EBR.patch + %description The util-linux package contains a large variety of low-level system @@ -331,6 +384,8 @@ unset LINGUAS || : export CFLAGS="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 $RPM_OPT_FLAGS" export SUID_CFLAGS="-fpie" export SUID_LDFLAGS="-pie -Wl,-z,relro -Wl,-z,now" +export DAEMON_CFLAGS="$SUID_CFLAGS" +export DAEMON_LDFLAGS="$SUID_LDFLAGS" %configure \ --with-systemdsystemunitdir=%{_unitdir} \ --disable-silent-rules \ @@ -595,6 +650,8 @@ fi %{_bindir}/ipcs %{_bindir}/isosize %{_bindir}/kill +%{_bindir}/lsipc +%{_bindir}/lsns %{_bindir}/logger %{_bindir}/look %{_bindir}/lsblk @@ -649,6 +706,7 @@ fi %{_mandir}/man1/look.1* %{_mandir}/man1/lscpu.1* %{_mandir}/man1/lslogins.1* +%{_mandir}/man1/lsipc.1* %{_mandir}/man1/mcookie.1* %{_mandir}/man1/more.1* %{_mandir}/man1/mountpoint.1* @@ -694,7 +752,8 @@ fi %{_mandir}/man8/ldattach.8* %{_mandir}/man8/losetup.8* %{_mandir}/man8/lsblk.8* -%{_mandir}/man8/lslocks.8.gz +%{_mandir}/man8/lslocks.8* +%{_mandir}/man8/lsns.8* %{_mandir}/man8/mkfs.8* %{_mandir}/man8/mkfs.cramfs.8* %{_mandir}/man8/mkfs.minix.8* @@ -926,14 +985,47 @@ fi %{_libdir}/pkgconfig/uuid.pc %changelog -* Thu Jun 30 2016 Karel Zak <kzak@redhat.com> 2.23.2-26.el7_2.3 -- fix #1350777 - fdisk 'f' subcommand updates partition ranges wrongly - -* Wed Mar 16 2016 Karel Zak <kzak@redhat.com> 2.23.2-26.el7_2.2 -- fix #1317953 - lslogins crash when executed with buggy username - -* Thu Jan 28 2016 Karel Zak <kzak@redhat.com> 2.23.2-26.el7_2.1 -- fix #1302332 - [libblkid] Failed to get offset of the xfs_external_log signature +* Tue Jul 12 2016 Karel Zak <kzak@redhat.com> 2.23.2-33 +- improve patch for #1007734 (libblkid realpaths) + +* Tue Jul 12 2016 Karel Zak <kzak@redhat.com> 2.23.2-32 +- improve patch for chrt(1) deadline support #1298384 +- fix #1007734 - blkid shows devices as /dev/block/$MAJOR:$MINOR +- fix #1349536 - Extended partition loop in MBR partition table leads to DOS + +* Mon Jul 04 2016 Karel Zak <kzak@redhat.com> 2.23.2-31 +- improve spec file for #1092520 + +* Fri Jul 01 2016 Karel Zak <kzak@redhat.com> 2.23.2-30 +- improve patch for chrt(1) deadline support #1298384 +- improve regression tests + +* Thu Jun 30 2016 Karel Zak <kzak@redhat.com> 2.23.2-29 +- fix #1029385 - lack of non-ascii support +- fix #1092520 - util-linux - PIE and RELRO check +- fix #1153770 - backport lsipc +- fix #1248003 - mount only parses <param>=<value> lines from fstab fs_spec field available from blkid block device +- fix #1271850 - mount -a doesn't catch a typo in /etc/fstab and a typo in /etc/fstab can make a system not reboot properly +- fix #1281839 - [RFE]Bind mounts should be handled gracefully by the operating system +- fix #1290689 - util-linux: /bin/login does not retry getpwnam_r with larger buffers, leading to login failure +- fix #1296366 - Bash completion for more(1) handles file names with spaces incorrectly +- fix #1296521 - RHEL7: update audit event in hwclock +- fix #1298384 - RFE: add SCHED_DEADLINE support to chrt +- fix #1304246 - fdisk 'f' subcommand updates partition ranges wrongly +- fix #1304426 - [rfe] /bin/su should be improved to reduce stack use +- fix #1326615 - util-linux/lscpu: Fix model and model name on Power Systems +- fix #1327886 - Backport blkdiscard's "-z" flag to RHEL +- fix #1332084 - [RFE] Inclusion of lsns command in util-linux Package +- fix #1335671 - extra quotes around UUID confuses findfs in RHEL (but not in Fedora) +- fix #1344222 - logger port option in help is misleading +- fix #1344482 - util-linux fails valid_pmbr() size checks if device is > 2.14TB, Device label type: dos instead of gpt +- fix #587393 - [RFE] Make sure util-linux is ready for writable overlays + +* Wed Mar 16 2016 Karel Zak <kzak@redhat.com> 2.23.2-28 +- fix #1291554 - lslogins crash when executed with buggy username + +* Thu Jan 28 2016 Karel Zak <kzak@redhat.com> 2.23.2-27 +- fix #1301091 - [libblkid] Failed to get offset of the xfs_external_log signature * Fri Aug 21 2015 Karel Zak <kzak@redhat.com> 2.23.2-26 - fix #1182831 - blkid incorrectly detects boot sec + MBR as FAT