diff --git a/SOURCES/0085-libuuid-Implement-continuous-clock-handling-for-time.patch b/SOURCES/0085-libuuid-Implement-continuous-clock-handling-for-time.patch new file mode 100644 index 0000000..9495ff0 --- /dev/null +++ b/SOURCES/0085-libuuid-Implement-continuous-clock-handling-for-time.patch @@ -0,0 +1,375 @@ +From ccc5db8102728d37e2e28dd50da3370e8c8de33a Mon Sep 17 00:00:00 2001 +From: Michael Trapp +Date: Mon, 20 Jun 2022 17:10:36 +0200 +Subject: libuuid: Implement continuous clock handling for time based UUIDs + +In a uuidd setup, the daemon is a singleton and can maintain it's own +resources for time based UUID generation. This requires a dedicated +'clock sequence range' but does not need any further lock/update of +the LIBUUID_CLOCK_FILE from uuidd. The range of available clock values +is extended by a continuous handling of the clock updates - instead of +updating the value to the current timestamp, it is incremented by +the number of requested UUIDs. + +[kzak@redhat.com: - backport from upstream v2.39 to to RHEL-8] + +Upstream: http://github.com/util-linux/util-linux/commit/3cfba7d39b66eff4307218fefd8bb34bb1621f83 +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=2141969 +Signed-off-by: Karel Zak +--- + libuuid/src/gen_uuid.c | 91 ++++++++++++++++++++++++++++++++++++++--- + libuuid/src/libuuid.sym | 1 + + libuuid/src/uuidd.h | 1 + + misc-utils/uuidd.8.in | 12 ++++++ + misc-utils/uuidd.c | 86 ++++++++++++++++++++++++++++++++++++-- + 5 files changed, 182 insertions(+), 9 deletions(-) + +diff --git a/libuuid/src/gen_uuid.c b/libuuid/src/gen_uuid.c +index 27c135db5..f557053f7 100644 +--- a/libuuid/src/gen_uuid.c ++++ b/libuuid/src/gen_uuid.c +@@ -209,6 +209,8 @@ static int get_node_id(unsigned char *node_id) + + /* Assume that the gettimeofday() has microsecond granularity */ + #define MAX_ADJUSTMENT 10 ++/* Reserve a clock_seq value for the 'continuous clock' implementation */ ++#define CLOCK_SEQ_CONT 0 + + /* + * Get clock from global sequence clock counter. +@@ -275,8 +277,10 @@ static int get_clock(uint32_t *clock_high, uint32_t *clock_low, + } + + if ((last.tv_sec == 0) && (last.tv_usec == 0)) { +- random_get_bytes(&clock_seq, sizeof(clock_seq)); +- clock_seq &= 0x3FFF; ++ do { ++ random_get_bytes(&clock_seq, sizeof(clock_seq)); ++ clock_seq &= 0x3FFF; ++ } while (clock_seq == CLOCK_SEQ_CONT); + gettimeofday(&last, NULL); + last.tv_sec--; + } +@@ -286,7 +290,9 @@ try_again: + if ((tv.tv_sec < last.tv_sec) || + ((tv.tv_sec == last.tv_sec) && + (tv.tv_usec < last.tv_usec))) { +- clock_seq = (clock_seq+1) & 0x3FFF; ++ do { ++ clock_seq = (clock_seq+1) & 0x3FFF; ++ } while (clock_seq == CLOCK_SEQ_CONT); + adjustment = 0; + last = tv; + } else if ((tv.tv_sec == last.tv_sec) && +@@ -331,6 +337,64 @@ try_again: + return ret; + } + ++/* ++ * Get current time in 100ns ticks. ++ */ ++static uint64_t get_clock_counter(void) ++{ ++ struct timeval tv; ++ uint64_t clock_reg; ++ ++ gettimeofday(&tv, NULL); ++ clock_reg = tv.tv_usec*10; ++ clock_reg += ((uint64_t) tv.tv_sec) * 10000000ULL; ++ ++ return clock_reg; ++} ++ ++/* ++ * Get continuous clock value. ++ * ++ * Return -1 if there is no further clock counter available, ++ * otherwise return 0. ++ * ++ * This implementation doesn't deliver clock counters based on ++ * the current time because last_clock_reg is only incremented ++ * by the number of requested UUIDs. ++ * max_clock_offset is used to limit the offset of last_clock_reg. ++ */ ++static int get_clock_cont(uint32_t *clock_high, ++ uint32_t *clock_low, ++ int num, ++ uint32_t max_clock_offset) ++{ ++ /* 100ns based time offset according to RFC 4122. 4.1.4. */ ++ const uint64_t reg_offset = (((uint64_t) 0x01B21DD2) << 32) + 0x13814000; ++ static uint64_t last_clock_reg = 0; ++ uint64_t clock_reg; ++ ++ if (last_clock_reg == 0) ++ last_clock_reg = get_clock_counter(); ++ ++ clock_reg = get_clock_counter(); ++ if (max_clock_offset) { ++ uint64_t clock_offset = max_clock_offset * 10000000ULL; ++ if (last_clock_reg < (clock_reg - clock_offset)) ++ last_clock_reg = clock_reg - clock_offset; ++ } ++ ++ clock_reg += MAX_ADJUSTMENT; ++ ++ if ((last_clock_reg + num) >= clock_reg) ++ return -1; ++ ++ *clock_high = (last_clock_reg + reg_offset) >> 32; ++ *clock_low = last_clock_reg + reg_offset; ++ last_clock_reg += num; ++ ++ return 0; ++} ++ + #if defined(HAVE_UUIDD) && defined(HAVE_SYS_UN_H) + + /* +@@ -403,7 +467,7 @@ static int get_uuid_via_daemon(int op __attribute__((__unused__)), + } + #endif + +-int __uuid_generate_time(uuid_t out, int *num) ++static int __uuid_generate_time_internal(uuid_t out, int *num, uint32_t cont_offset) + { + static unsigned char node_id[6]; + static int has_init = 0; +@@ -423,7 +487,14 @@ int __uuid_generate_time(uuid_t out, int *num) + } + has_init = 1; + } +- ret = get_clock(&clock_mid, &uu.time_low, &uu.clock_seq, num); ++ if (cont_offset) { ++ ret = get_clock_cont(&clock_mid, &uu.time_low, *num, cont_offset); ++ uu.clock_seq = CLOCK_SEQ_CONT; ++ if (ret != 0) /* fallback to previous implpementation */ ++ ret = get_clock(&clock_mid, &uu.time_low, &uu.clock_seq, num); ++ } else { ++ ret = get_clock(&clock_mid, &uu.time_low, &uu.clock_seq, num); ++ } + uu.clock_seq |= 0x8000; + uu.time_mid = (uint16_t) clock_mid; + uu.time_hi_and_version = ((clock_mid >> 16) & 0x0FFF) | 0x1000; +@@ -432,6 +503,16 @@ int __uuid_generate_time(uuid_t out, int *num) + return ret; + } + ++int __uuid_generate_time(uuid_t out, int *num) ++{ ++ return __uuid_generate_time_internal(out, num, 0); ++} ++ ++int __uuid_generate_time_cont(uuid_t out, int *num, uint32_t cont_offset) ++{ ++ return __uuid_generate_time_internal(out, num, cont_offset); ++} ++ + /* + * Generate time-based UUID and store it to @out + * +diff --git a/libuuid/src/libuuid.sym b/libuuid/src/libuuid.sym +index 9e3e80035..0a072b703 100644 +--- a/libuuid/src/libuuid.sym ++++ b/libuuid/src/libuuid.sym +@@ -51,6 +51,7 @@ global: + UUIDD_PRIVATE { + global: + __uuid_generate_time; ++ __uuid_generate_time_cont; + __uuid_generate_random; + local: + *; +diff --git a/libuuid/src/uuidd.h b/libuuid/src/uuidd.h +index e55c86f2f..14a01ade2 100644 +--- a/libuuid/src/uuidd.h ++++ b/libuuid/src/uuidd.h +@@ -50,5 +50,6 @@ + + extern int __uuid_generate_time(uuid_t out, int *num); + extern void __uuid_generate_random(uuid_t out, int *num); ++extern int __uuid_generate_time_cont(uuid_t out, int *num, uint32_t cont); + + #endif /* _UUID_UUID_H */ +diff --git a/misc-utils/uuidd.8.in b/misc-utils/uuidd.8.in +index 0a5cf471b..28bcb48b5 100644 +--- a/misc-utils/uuidd.8.in ++++ b/misc-utils/uuidd.8.in +@@ -16,6 +16,18 @@ universally unique identifiers (UUIDs), especially time-based UUIDs, + in a secure and guaranteed-unique fashion, even in the face of large + numbers of threads running on different CPUs trying to grab UUIDs. + .SH OPTIONS ++ ++.TP ++.BR \-C , " \-\-cont\-clock " [\fInumber\fR] ++Activate continuous clock handling for time based UUIDs. uuidd could use all ++possible clock values, beginning with the daemon's start time. The optional ++argument can be used to set a value for the max_clock_offset. This gurantees, ++that a clock value of a UUID will always be within the range of the ++max_clock_offset. '-C' or '--cont-clock' enables the feature with a default ++max_clock_offset of 2 hours. '-C[hd]' or '--cont-clock=[hd]' enables ++the feature with a max_clock_offset of NUM seconds. In case of an appended h or ++d, the NUM value is read in hours or days. The minimum value is 60 seconds, the ++maximum value is 365 days. + .TP + .BR \-d , " \-\-debug " + Run uuidd in debugging mode. This prevents uuidd from running as a daemon. +diff --git a/misc-utils/uuidd.c b/misc-utils/uuidd.c +index 8b83d91c0..e3c0abad7 100644 +--- a/misc-utils/uuidd.c ++++ b/misc-utils/uuidd.c +@@ -49,6 +49,8 @@ struct uuidd_cxt_t { + const char *cleanup_pidfile; + const char *cleanup_socket; + uint32_t timeout; ++ uint32_t cont_clock_offset; ++ + unsigned int debug: 1, + quiet: 1, + no_fork: 1, +@@ -73,6 +75,8 @@ static void __attribute__((__noreturn__)) usage(void) + fputs(_(" -P, --no-pid do not create pid file\n"), out); + fputs(_(" -F, --no-fork do not daemonize using double-fork\n"), out); + fputs(_(" -S, --socket-activation do not create listening socket\n"), out); ++ fputs(_(" -C, --cont-clock[=[hd]]\n"), out); ++ fputs(_(" activate continuous clock handling\n"), out); + fputs(_(" -d, --debug run in debugging mode\n"), out); + fputs(_(" -q, --quiet turn on quiet mode\n"), out); + fputs(USAGE_SEPARATOR, out); +@@ -401,6 +405,15 @@ static void server_loop(const char *socket_path, const char *pidfile_path, + pfd[POLLFD_SOCKET].fd = s; + pfd[POLLFD_SIGNAL].events = pfd[POLLFD_SOCKET].events = POLLIN | POLLERR | POLLHUP; + ++ num = 1; ++ if (uuidd_cxt->cont_clock_offset) { ++ /* trigger initialization */ ++ (void) __uuid_generate_time_cont(uu, &num, uuidd_cxt->cont_clock_offset); ++ if (uuidd_cxt->debug) ++ fprintf(stderr, _("max_clock_offset = %u sec\n"), ++ uuidd_cxt->cont_clock_offset); ++ } ++ + while (1) { + ret = poll(pfd, ARRAY_SIZE(pfd), + uuidd_cxt->timeout ? +@@ -458,7 +471,7 @@ static void server_loop(const char *socket_path, const char *pidfile_path, + break; + case UUIDD_OP_TIME_UUID: + num = 1; +- __uuid_generate_time(uu, &num); ++ __uuid_generate_time_cont(uu, &num, uuidd_cxt->cont_clock_offset); + if (uuidd_cxt->debug) { + uuid_unparse(uu, str); + fprintf(stderr, _("Generated time UUID: %s\n"), str); +@@ -477,7 +490,7 @@ static void server_loop(const char *socket_path, const char *pidfile_path, + reply_len = sizeof(uu); + break; + case UUIDD_OP_BULK_TIME_UUID: +- __uuid_generate_time(uu, &num); ++ __uuid_generate_time_cont(uu, &num, uuidd_cxt->cont_clock_offset); + if (uuidd_cxt->debug) { + uuid_unparse(uu, str); + fprintf(stderr, P_("Generated time UUID %s " +@@ -530,6 +543,64 @@ static void __attribute__ ((__noreturn__)) unexpected_size(int size) + errx(EXIT_FAILURE, _("Unexpected reply length from server %d"), size); + } + ++/* Backport from v2.39 lib/strutils.c */ ++static int ul_strtos64(const char *str, int64_t *num, int base) ++{ ++ char *end = NULL; ++ ++ if (str == NULL || *str == '\0') ++ return -(errno = EINVAL); ++ ++ errno = 0; ++ *num = (int64_t) strtoimax(str, &end, base); ++ ++ if (errno != 0) ++ return -errno; ++ if (str == end || (end && *end)) ++ return -(errno = EINVAL); ++ return 0; ++} ++ ++/* Backport from v2.39 lib/strutils.c */ ++static int64_t str2num_or_err(const char *str, int base, const char *errmesg, ++ int64_t low, int64_t up) ++{ ++ int64_t num = 0; ++ int rc; ++ ++ rc = ul_strtos64(str, &num, base); ++ if (rc == 0 && ((low && num < low) || (up && num > up))) ++ rc = -(errno = ERANGE); ++ ++ if (rc) { ++ if (errno == ERANGE) ++ err(EXIT_FAILURE, "%s: '%s'", errmesg, str); ++ errx(EXIT_FAILURE, "%s: '%s'", errmesg, str); ++ } ++ return num; ++} ++ ++static uint32_t parse_cont_clock(char *arg) ++{ ++ uint32_t min_val = 60, ++ max_val = (3600 * 24 * 365), ++ factor = 1; ++ char *p = &arg[strlen(arg)-1]; ++ ++ if ('h' == *p) { ++ *p = '\0'; ++ factor = 3600; ++ min_val = 1; ++ } ++ if ('d' == *p) { ++ *p = '\0'; ++ factor = 24 * 3600; ++ min_val = 1; ++ } ++ return factor * str2num_or_err(optarg, 10, _("failed to parse --cont-clock/-C"), ++ min_val, max_val / factor); ++} ++ + int main(int argc, char **argv) + { + const char *socket_path = UUIDD_SOCKET_PATH; +@@ -543,7 +614,7 @@ int main(int argc, char **argv) + int no_pid = 0; + int s_flag = 0; + +- struct uuidd_cxt_t uuidd_cxt = { .timeout = 0 }; ++ struct uuidd_cxt_t uuidd_cxt = { .timeout = 0, .cont_clock_offset = 0 }; + + static const struct option longopts[] = { + {"pid", required_argument, NULL, 'p'}, +@@ -556,6 +627,7 @@ int main(int argc, char **argv) + {"no-pid", no_argument, NULL, 'P'}, + {"no-fork", no_argument, NULL, 'F'}, + {"socket-activation", no_argument, NULL, 'S'}, ++ {"cont-clock", optional_argument, NULL, 'C'}, + {"debug", no_argument, NULL, 'd'}, + {"quiet", no_argument, NULL, 'q'}, + {"version", no_argument, NULL, 'V'}, +@@ -576,10 +648,16 @@ int main(int argc, char **argv) + atexit(close_stdout); + + while ((c = +- getopt_long(argc, argv, "p:s:T:krtn:PFSdqVh", longopts, ++ getopt_long(argc, argv, "p:s:T:krtn:PFSC::dqVh", longopts, + NULL)) != -1) { + err_exclusive_options(c, longopts, excl, excl_st); + switch (c) { ++ case 'C': ++ if (optarg != NULL) ++ uuidd_cxt.cont_clock_offset = parse_cont_clock(optarg); ++ else ++ uuidd_cxt.cont_clock_offset = 7200; /* default 2h */ ++ break; + case 'd': + uuidd_cxt.debug = 1; + break; +-- +2.38.1 + diff --git a/SOURCES/0086-libuuid-check-clock-value-from-LIBUUID_CLOCK_FILE.patch b/SOURCES/0086-libuuid-check-clock-value-from-LIBUUID_CLOCK_FILE.patch new file mode 100644 index 0000000..4352651 --- /dev/null +++ b/SOURCES/0086-libuuid-check-clock-value-from-LIBUUID_CLOCK_FILE.patch @@ -0,0 +1,35 @@ +From 44cebf3e692053541f362b62f88f327c2c96e70e Mon Sep 17 00:00:00 2001 +From: Michael Trapp +Date: Tue, 2 Aug 2022 14:16:43 +0200 +Subject: libuuid: check clock value from LIBUUID_CLOCK_FILE + +The clock value from the LIBUUID_CLOCK_FILE must be checked in +case of an update of libuuid. If clock==CLOCK_SEQ_CONT it must +be set to a new value. + +Signed-off-by: Karel Zak +Upstream: http://github.com/util-linux/util-linux/commit/5d1424d85ac9e2a1369ee920038825c154ee5443 +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=2141969 +--- + libuuid/src/gen_uuid.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/libuuid/src/gen_uuid.c b/libuuid/src/gen_uuid.c +index f557053f7..8dc38559f 100644 +--- a/libuuid/src/gen_uuid.c ++++ b/libuuid/src/gen_uuid.c +@@ -274,6 +274,11 @@ static int get_clock(uint32_t *clock_high, uint32_t *clock_low, + last.tv_usec = tv2; + adjustment = a; + } ++ // reset in case of reserved CLOCK_SEQ_CONT ++ if (clock_seq == CLOCK_SEQ_CONT) { ++ last.tv_sec = 0; ++ last.tv_usec = 0; ++ } + } + + if ((last.tv_sec == 0) && (last.tv_usec == 0)) { +-- +2.38.1 + diff --git a/SOURCES/0087-fstrim-backport-entries-de-duplication.patch b/SOURCES/0087-fstrim-backport-entries-de-duplication.patch new file mode 100644 index 0000000..921ad25 --- /dev/null +++ b/SOURCES/0087-fstrim-backport-entries-de-duplication.patch @@ -0,0 +1,190 @@ +From 9272023b42febae7db1ec828016a980146095a83 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Thu, 2 Feb 2023 13:21:33 +0100 +Subject: fstrim: backport entries de-duplication + +Upstream: http://github.com/util-linux/util-linux/commit/9dbc073e4c58a56f68da8209df19789131446f5e +Upstream: http://github.com/util-linux/util-linux/commit/67f974d41d62c8b521fe81e1aac92562366f6a0a +Upstream: http://github.com/util-linux/util-linux/commit/20af6cee463cd6329b4f06db3282a09be942bd7a +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=2121699 +Signed-off-by: Karel Zak +--- + sys-utils/fstrim.c | 88 ++++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 74 insertions(+), 14 deletions(-) + +diff --git a/sys-utils/fstrim.c b/sys-utils/fstrim.c +index 70870ef69..6aa523d72 100644 +--- a/sys-utils/fstrim.c ++++ b/sys-utils/fstrim.c +@@ -35,6 +35,7 @@ + + #include + #include ++#include + #include + + #include "nls.h" +@@ -43,6 +44,7 @@ + #include "closestream.h" + #include "pathnames.h" + #include "sysfs.h" ++#include "statfs_magic.h" + + #include + +@@ -84,6 +86,7 @@ static int fstrim_filesystem(const char *path, struct fstrim_range *rangetpl, + goto done; + } + errno = 0; ++ + if (ioctl(fd, FITRIM, &range)) { + rc = errno == EOPNOTSUPP || errno == ENOTTY ? 1 : -errno; + +@@ -114,7 +117,7 @@ static int has_discard(const char *devname, struct sysfs_cxt *wholedisk) + struct sysfs_cxt cxt, *parent = NULL; + uint64_t dg = 0; + dev_t disk = 0, dev; +- int rc; ++ int rc, rdonly = 0; + + dev = sysfs_devname_to_devno(devname, NULL); + if (!dev) +@@ -139,11 +142,46 @@ static int has_discard(const char *devname, struct sysfs_cxt *wholedisk) + rc = sysfs_init(&cxt, dev, parent); + if (!rc) + rc = sysfs_read_u64(&cxt, "queue/discard_granularity", &dg); ++ if (!rc) ++ sysfs_scanf(&cxt, "ro", "%d", &rdonly); + + sysfs_deinit(&cxt); +- return rc == 0 && dg > 0; ++ return rc == 0 && dg > 0 && rdonly == 0; + } + ++static int is_unwanted_fs(struct libmnt_fs *fs, const char *tgt) ++{ ++ struct statfs vfs; ++ int fd, rc; ++ ++ if (mnt_fs_is_pseudofs(fs)) ++ return 1; ++ if (mnt_fs_is_netfs(fs)) ++ return 1; ++ if (mnt_fs_is_swaparea(fs)) ++ return 1; ++ if (mnt_fs_match_fstype(fs, "autofs")) ++ return 1; ++ if (mnt_fs_match_options(fs, "ro")) ++ return 1; ++ ++ fd = open(tgt, O_PATH); ++ if (fd < 0) ++ return 1; ++ rc = fstatfs(fd, &vfs) != 0 || vfs.f_type == STATFS_AUTOFS_MAGIC; ++ close(fd); ++ if (rc) ++ return 1; ++ ++ /* FITRIM on read-only filesystem can fail, and it can fail */ ++ if (access(tgt, W_OK) != 0) { ++ if (errno == EROFS) ++ return 1; ++ if (errno == EACCES) ++ return 1; ++ } ++ return 0; ++} + + static int uniq_fs_target_cmp( + struct libmnt_table *tb __attribute__((__unused__)), +@@ -182,30 +220,38 @@ static int fstrim_all(struct fstrim_range *rangetpl, int verbose) + + mnt_init_debug(0); + +- itr = mnt_new_iter(MNT_ITER_BACKWARD); +- if (!itr) +- err(MNT_EX_FAIL, _("failed to initialize libmount iterator")); +- + tab = mnt_new_table_from_file(_PATH_PROC_MOUNTINFO); + if (!tab) + err(MNT_EX_FAIL, _("failed to parse %s"), _PATH_PROC_MOUNTINFO); + ++ if (mnt_table_is_empty(tab)) { ++ mnt_unref_table(tab); ++ return MNT_EX_SUCCESS; ++ } ++ + /* de-duplicate by mountpoints */ + mnt_table_uniq_fs(tab, 0, uniq_fs_target_cmp); + +- /* de-duplicate by source */ +- mnt_table_uniq_fs(tab, MNT_UNIQ_FORWARD, uniq_fs_source_cmp); ++ itr = mnt_new_iter(MNT_ITER_BACKWARD); ++ if (!itr) ++ err(MNT_EX_FAIL, _("failed to initialize libmount iterator")); + ++ /* Remove useless entries and canonicalize the table */ + while (mnt_table_next_fs(tab, itr, &fs) == 0) { + const char *src = mnt_fs_get_srcpath(fs), + *tgt = mnt_fs_get_target(fs); + char *path; + int rc = 1; + +- if (!src || !tgt || *src != '/' || +- mnt_fs_is_pseudofs(fs) || +- mnt_fs_is_netfs(fs)) ++ if (!tgt || is_unwanted_fs(fs, tgt)) { ++ mnt_table_remove_fs(tab, fs); + continue; ++ } ++ ++ if (!src || *src != '/') { ++ mnt_table_remove_fs(tab, fs); ++ continue; ++ } + + /* Is it really accessible mountpoint? Not all mountpoints are + * accessible (maybe over mounted by another filesystem) */ +@@ -213,11 +259,25 @@ static int fstrim_all(struct fstrim_range *rangetpl, int verbose) + if (path && strcmp(path, tgt) == 0) + rc = 0; + free(path); +- if (rc) ++ if (rc) { ++ mnt_table_remove_fs(tab, fs); + continue; /* overlaying mount */ ++ } + +- if (!has_discard(src, &wholedisk)) ++ if (!has_discard(src, &wholedisk)) { ++ mnt_table_remove_fs(tab, fs); + continue; ++ } ++ } ++ ++ /* de-duplicate by source */ ++ mnt_table_uniq_fs(tab, MNT_UNIQ_FORWARD, uniq_fs_source_cmp); ++ ++ mnt_reset_iter(itr, MNT_ITER_BACKWARD); ++ ++ /* Do FITRIM */ ++ while (mnt_table_next_fs(tab, itr, &fs) == 0) { ++ const char *tgt = mnt_fs_get_target(fs); + cnt++; + + /* +@@ -231,10 +291,10 @@ static int fstrim_all(struct fstrim_range *rangetpl, int verbose) + if (fstrim_filesystem(tgt, rangetpl, verbose) < 0) + cnt_err++; + } ++ mnt_free_iter(itr); + + sysfs_deinit(&wholedisk); + mnt_unref_table(tab); +- mnt_free_iter(itr); + + if (cnt && cnt == cnt_err) + return MNT_EX_FAIL; /* all failed */ +-- +2.39.1 + diff --git a/SOURCES/0088-tests-don-t-reply-on-scsi_debug-partitions.patch b/SOURCES/0088-tests-don-t-reply-on-scsi_debug-partitions.patch new file mode 100644 index 0000000..2ed72a4 --- /dev/null +++ b/SOURCES/0088-tests-don-t-reply-on-scsi_debug-partitions.patch @@ -0,0 +1,66 @@ +From a95ff5ed155c29734824f3a79350678901b22e43 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Thu, 11 Feb 2021 12:44:44 +0100 +Subject: tests: don't reply on scsi_debug partitions + +The disk layout as created by scsi_debug depends on kernel version. +Let's make the partition sizes hardcoded in our tests than rely on +kernel. + +Signed-off-by: Karel Zak +Upstream: http://github.com/util-linux/util-linux/commit/15a37d00e5e59f0f628d0a6b6cd2f9636702fd7c +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=2142496 +--- + tests/expected/partx/partx-detect-parts | 6 +++--- + tests/ts/partx/partx | 14 +++++++++++--- + 2 files changed, 14 insertions(+), 6 deletions(-) + +diff --git a/tests/expected/partx/partx-detect-parts b/tests/expected/partx/partx-detect-parts +index 33d42a58c..0adc85577 100644 +--- a/tests/expected/partx/partx-detect-parts ++++ b/tests/expected/partx/partx-detect-parts +@@ -1,5 +1,5 @@ + NR START END SECTORS SIZE NAME UUID +- 1 32 33791 33760 16.5M +- 2 33792 67583 33792 16.5M +- 3 67584 102399 34816 17M ++ 1 32 33791 33760 16.5M 1ddc8a79-01 ++ 2 33792 67583 33792 16.5M 1ddc8a79-02 ++ 3 67584 102399 34816 17M 1ddc8a79-03 + OK +diff --git a/tests/ts/partx/partx b/tests/ts/partx/partx +index 84c286a94..6514ae62c 100755 +--- a/tests/ts/partx/partx ++++ b/tests/ts/partx/partx +@@ -26,6 +26,7 @@ ts_init "$*" + ts_check_test_command "$TS_CMD_PARTX" + ts_check_test_command "$TS_CMD_ADDPART" + ts_check_test_command "$TS_CMD_DELPART" ++ts_check_test_command "$TS_CMD_SFDISK" + + ts_skip_nonroot + +@@ -70,10 +71,17 @@ ts_init_subtest "delpart" + } >$TS_OUTPUT 2>&1 + ts_finalize_subtest + +-ts_scsi_debug_rmmod + +-# set global variable TS_DEVICE +-ts_scsi_debug_init dev_size_mb=50 num_parts=$PARTS ++udevadm settle ++$TS_CMD_SFDISK $TS_DEVICE &> /dev/null < +Date: Thu, 2 Feb 2023 14:47:04 +0100 +Subject: libmount: use generic error message for EACCES on umount + +Signed-off-by: Karel Zak +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=2149394 +--- + libmount/src/context_umount.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libmount/src/context_umount.c b/libmount/src/context_umount.c +index 240ec3be6..23aaae395 100644 +--- a/libmount/src/context_umount.c ++++ b/libmount/src/context_umount.c +@@ -1123,7 +1123,7 @@ int mnt_context_get_umount_excode( + snprintf(buf, bufsz, _("must be superuser to unmount")); + break; + case EACCES: +- snprintf(buf, bufsz, _("block devices are not permitted on filesystem")); ++ snprintf(buf, bufsz, _("filesystem not accessible")); + break; + default: + return mnt_context_get_generic_excode(syserr, buf, bufsz,_("umount(2) system call failed: %m")); +-- +2.39.1 + diff --git a/SOURCES/0090-lslogins-man-explain-password-statuses.patch b/SOURCES/0090-lslogins-man-explain-password-statuses.patch new file mode 100644 index 0000000..7dbc434 --- /dev/null +++ b/SOURCES/0090-lslogins-man-explain-password-statuses.patch @@ -0,0 +1,45 @@ +From ea1ad5e7260c770b21e547702b1e0acef9e4854c Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Thu, 2 Feb 2023 14:52:35 +0100 +Subject: lslogins: (man) explain password statuses + +Upstream: http://github.com/util-linux/util-linux/commit/95ea3dd4128b625ab12691229020ebc50d578e71 +Upstream: http://github.com/util-linux/util-linux/commit/8001bffb03eda8d23d6a04a5dc1469cce932ae36 +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=2159544 +Signed-off-by: Karel Zak +--- + login-utils/lslogins.1 | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/login-utils/lslogins.1 b/login-utils/lslogins.1 +index c831739d9..5c327caf5 100644 +--- a/login-utils/lslogins.1 ++++ b/login-utils/lslogins.1 +@@ -116,6 +116,24 @@ Delimit user entries with a nul character, instead of a newline. + + .SH NOTES + The default UID thresholds are read from /etc/login.defs. ++.SS "Password status" ++.sp ++Multiple fields describe password status. ++.sp ++\fB"Login by password disabled"\fP ++.RS 4 ++\*(Aqyes\*(Aq means that there is no valid password. The password hash is missing, or the hash method is unknown or contains invalid chars. ++.RE ++.sp ++\fB"Password not required (empty)"\fP ++.RS 4 ++The password is not set (hash is missing); this is common for locked system accounts. Not requiring a password does not mean the user can log\-in without a password. It depends on the password "lock" status. ++.RE ++.sp ++\fB"Password is locked"\fP ++.RS 4 ++The password is prefixed by \*(Aq!!\*(Aq, and the user cannot login although the password is set or empty. This is common for new accounts without a set password. ++.RE + + .SH EXIT STATUS + .TP +-- +2.39.1 + diff --git a/SOURCES/0091-last-sync-utmp-strings-use-with-upstream-code.patch b/SOURCES/0091-last-sync-utmp-strings-use-with-upstream-code.patch new file mode 100644 index 0000000..6e0abc3 --- /dev/null +++ b/SOURCES/0091-last-sync-utmp-strings-use-with-upstream-code.patch @@ -0,0 +1,245 @@ +From 25f7136d326753cb0bb7612a98db6542c9fdc3bd Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Thu, 2 Feb 2023 15:22:52 +0100 +Subject: last: sync utmp strings use with upstream code + +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=2160321 +Signed-off-by: Karel Zak +--- + include/strutils.h | 30 +++++++++++++++++++ + include/timeutils.h | 1 + + login-utils/last.c | 73 +++++++++++++++++++++++---------------------- + 3 files changed, 69 insertions(+), 35 deletions(-) + +diff --git a/include/strutils.h b/include/strutils.h +index 5d07fcc7c..193f1acbc 100644 +--- a/include/strutils.h ++++ b/include/strutils.h +@@ -65,6 +65,36 @@ static inline void xstrncpy(char *dest, const char *src, size_t n) + dest[n-1] = 0; + } + ++/* This is like strncpy(), but based on memcpy(), so compilers and static ++ * analyzers do not complain when sizeof(destination) is the same as 'n' and ++ * result is not terminated by zero. ++ * ++ * Use this function to copy string to logs with fixed sizes (wtmp/utmp. ...) ++ * where string terminator is optional. ++ */ ++static inline void * __attribute__((nonnull (1))) ++str2memcpy(void *dest, const char *src, size_t n) ++{ ++ size_t bytes = strlen(src) + 1; ++ ++ if (bytes > n) ++ bytes = n; ++ ++ memcpy(dest, src, bytes); ++ return dest; ++} ++ ++static inline char * __attribute__((nonnull (1))) ++mem2strcpy(char *dest, const void *src, size_t n, size_t nmax) ++{ ++ if (n + 1 > nmax) ++ n = nmax - 1; ++ ++ memset(dest, '\0', nmax); ++ memcpy(dest, src, n); ++ return dest; ++} ++ + static inline int strdup_to_offset(void *stru, size_t offset, const char *str) + { + char *n = NULL; +diff --git a/include/timeutils.h b/include/timeutils.h +index 230e6db5f..f1540a183 100644 +--- a/include/timeutils.h ++++ b/include/timeutils.h +@@ -74,6 +74,7 @@ enum { + ISO_TIMESTAMP_COMMA_GT = ISO_TIMESTAMP_COMMA_G | ISO_T + }; + ++#define CTIME_BUFSIZ 26 + #define ISO_BUFSIZ 42 + + int strtimeval_iso(struct timeval *tv, int flags, char *buf, size_t bufsz); +diff --git a/login-utils/last.c b/login-utils/last.c +index 80d77d20b..8f7c36984 100644 +--- a/login-utils/last.c ++++ b/login-utils/last.c +@@ -339,15 +339,22 @@ static int time_formatter(int fmt, char *dst, size_t dlen, time_t *when) + break; + case LAST_TIMEFTM_HHMM: + { +- struct tm *tm = localtime(when); +- if (!snprintf(dst, dlen, "%02d:%02d", tm->tm_hour, tm->tm_min)) ++ struct tm tm; ++ ++ localtime_r(when, &tm); ++ if (!snprintf(dst, dlen, "%02d:%02d", tm.tm_hour, tm.tm_min)) + ret = -1; + break; + } + case LAST_TIMEFTM_CTIME: +- snprintf(dst, dlen, "%s", ctime(when)); ++ { ++ char buf[CTIME_BUFSIZ]; ++ ++ ctime_r(when, buf); ++ snprintf(dst, dlen, "%s", buf); + ret = rtrim_whitespace((unsigned char *) dst); + break; ++ } + case LAST_TIMEFTM_ISO8601: + ret = strtime_iso(when, ISO_TIMESTAMP_T, dst, dlen); + break; +@@ -394,8 +401,7 @@ static int list(const struct last_control *ctl, struct utmpx *p, time_t logout_t + /* + * uucp and ftp have special-type entries + */ +- utline[0] = 0; +- strncat(utline, p->ut_line, sizeof(p->ut_line)); ++ mem2strcpy(utline, p->ut_line, sizeof(p->ut_line), sizeof(utline)); + if (strncmp(utline, "ftp", 3) == 0 && isdigit(utline[3])) + utline[3] = 0; + if (strncmp(utline, "uucp", 4) == 0 && isdigit(utline[4])) +@@ -447,48 +453,48 @@ static int list(const struct last_control *ctl, struct utmpx *p, time_t logout_t + + if (logout_time == currentdate) { + if (ctl->time_fmt > LAST_TIMEFTM_SHORT) { +- sprintf(logouttime, " still running"); ++ snprintf(logouttime, sizeof(logouttime), " still running"); + length[0] = 0; + } else { +- sprintf(logouttime, " still"); +- sprintf(length, "running"); ++ snprintf(logouttime, sizeof(logouttime), " still"); ++ snprintf(length, sizeof(length), "running"); + } + } else if (days) { +- sprintf(length, "(%d+%02d:%02d)", days, abs(hours), abs(mins)); /* hours and mins always shown as positive (w/o minus sign!) even if secs < 0 */ ++ snprintf(length, sizeof(length), "(%d+%02d:%02d)", days, abs(hours), abs(mins)); /* hours and mins always shown as positive (w/o minus sign!) even if secs < 0 */ + } else if (hours) { +- sprintf(length, " (%02d:%02d)", hours, abs(mins)); /* mins always shown as positive (w/o minus sign!) even if secs < 0 */ ++ snprintf(length, sizeof(length), " (%02d:%02d)", hours, abs(mins)); /* mins always shown as positive (w/o minus sign!) even if secs < 0 */ + } else if (secs >= 0) { +- sprintf(length, " (%02d:%02d)", hours, mins); ++ snprintf(length, sizeof(length), " (%02d:%02d)", hours, mins); + } else { +- sprintf(length, " (-00:%02d)", abs(mins)); /* mins always shown as positive (w/o minus sign!) even if secs < 0 */ ++ snprintf(length, sizeof(length), " (-00:%02d)", abs(mins)); /* mins always shown as positive (w/o minus sign!) even if secs < 0 */ + } + + switch(what) { + case R_CRASH: +- sprintf(logouttime, "- crash"); ++ snprintf(logouttime, sizeof(logouttime), "- crash"); + break; + case R_DOWN: +- sprintf(logouttime, "- down "); ++ snprintf(logouttime, sizeof(logouttime), "- down "); + break; + case R_NOW: + if (ctl->time_fmt > LAST_TIMEFTM_SHORT) { +- sprintf(logouttime, " still logged in"); ++ snprintf(logouttime, sizeof(logouttime), " still logged in"); + length[0] = 0; + } else { +- sprintf(logouttime, " still"); +- sprintf(length, "logged in"); ++ snprintf(logouttime, sizeof(logouttime), " still"); ++ snprintf(length, sizeof(length), "logged in"); + } + break; + case R_PHANTOM: + if (ctl->time_fmt > LAST_TIMEFTM_SHORT) { +- sprintf(logouttime, " gone - no logout"); ++ snprintf(logouttime, sizeof(logouttime), " gone - no logout"); + length[0] = 0; + } else if (ctl->time_fmt == LAST_TIMEFTM_SHORT) { +- sprintf(logouttime, " gone"); +- sprintf(length, "- no logout"); ++ snprintf(logouttime, sizeof(logouttime), " gone"); ++ snprintf(length, sizeof(length), "- no logout"); + } else { + logouttime[0] = 0; +- sprintf(length, "no logout"); ++ snprintf(length, sizeof(length), "no logout"); + } + break; + case R_TIMECHANGE: +@@ -508,15 +514,8 @@ static int list(const struct last_control *ctl, struct utmpx *p, time_t logout_t + r = -1; + if (ctl->usedns || ctl->useip) + r = dns_lookup(domain, sizeof(domain), ctl->useip, (int32_t*)p->ut_addr_v6); +- if (r < 0) { +- size_t sz = sizeof(p->ut_host); +- +- if (sz > sizeof(domain)) +- sz = sizeof(domain); +- +- xstrncpy(domain, p->ut_host, sz); +- } +- ++ if (r < 0) ++ mem2strcpy(domain, p->ut_host, sizeof(p->ut_host), sizeof(domain)); + + if (ctl->showhost) { + if (!ctl->altlist) { +@@ -607,10 +606,11 @@ static int is_phantom(const struct last_control *ctl, struct utmpx *ut) + + if (ut->ut_tv.tv_sec < ctl->boot_time.tv_sec) + return 1; ++ ut->ut_user[sizeof(ut->ut_user) - 1] = '\0'; + pw = getpwnam(ut->ut_user); + if (!pw) + return 1; +- sprintf(path, "/proc/%u/loginuid", ut->ut_pid); ++ snprintf(path, sizeof(path), "/proc/%u/loginuid", ut->ut_pid); + if (access(path, R_OK) == 0) { + unsigned int loginuid; + FILE *f = NULL; +@@ -624,8 +624,11 @@ static int is_phantom(const struct last_control *ctl, struct utmpx *ut) + return 1; + } else { + struct stat st; ++ char utline[sizeof(ut->ut_line) + 1]; ++ ++ mem2strcpy(utline, ut->ut_line, sizeof(ut->ut_line), sizeof(utline)); + +- sprintf(path, "/dev/%s", ut->ut_line); ++ snprintf(path, sizeof(path), "/dev/%s", utline); + if (stat(path, &st)) + return 1; + if (pw->pw_uid != st.st_uid) +@@ -736,7 +739,7 @@ static void process_wtmp_file(const struct last_control *ctl, + else { + if (ut.ut_type != DEAD_PROCESS && + ut.ut_user[0] && ut.ut_line[0] && +- strcmp(ut.ut_user, "LOGIN") != 0) ++ strncmp(ut.ut_user, "LOGIN", 5) != 0) + ut.ut_type = USER_PROCESS; + /* + * Even worse, applications that write ghost +@@ -749,7 +752,7 @@ static void process_wtmp_file(const struct last_control *ctl, + /* + * Clock changes. + */ +- if (strcmp(ut.ut_user, "date") == 0) { ++ if (strncmp(ut.ut_user, "date", 4) == 0) { + if (ut.ut_line[0] == '|') + ut.ut_type = OLD_TIME; + if (ut.ut_line[0] == '{') +@@ -784,7 +787,7 @@ static void process_wtmp_file(const struct last_control *ctl, + case RUN_LVL: + x = ut.ut_pid & 255; + if (ctl->extended) { +- sprintf(ut.ut_line, "(to lvl %c)", x); ++ snprintf(ut.ut_line, sizeof(ut.ut_line), "(to lvl %c)", x); + quit = list(ctl, &ut, lastrch, R_NORMAL); + } + if (x == '0' || x == '6') { +-- +2.39.1 + diff --git a/SOURCES/0092-last-use-full-size-of-the-username.patch b/SOURCES/0092-last-use-full-size-of-the-username.patch new file mode 100644 index 0000000..a676580 --- /dev/null +++ b/SOURCES/0092-last-use-full-size-of-the-username.patch @@ -0,0 +1,55 @@ +From f435f80b9ae88caf9fe8af2e9b705dc8296ad6f3 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Mon, 13 Feb 2023 16:22:23 +0100 +Subject: last: use full size of the username + +utmp uses 32 bytes for username, last(1) truncates it to 31 when calls getpwnam(). + +Reported-by: Radka Skvarilova +Signed-off-by: Karel Zak +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=2160321 +Upstream: http://github.com/util-linux/util-linux/commit/4b646f01600a5efcf16e8e8991010b49b250bdfe +--- + login-utils/last.1 | 4 ++++ + login-utils/last.c | 6 ++++-- + 2 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/login-utils/last.1 b/login-utils/last.1 +index 94b4ed012..9169abd35 100644 +--- a/login-utils/last.1 ++++ b/login-utils/last.1 +@@ -178,6 +178,10 @@ files to be used, they can be created with a simple + .BR touch (1) + command (for example, + .IR "touch /var/log/wtmp" ). ++ ++The utmp file format uses fixed sizes of strings, which means that very long strings are ++impossible to store in the file and impossible to display by last. The usual limits are 32 ++bytes for a user and line name and 256 bytes for a hostname. + .SH FILES + /var/log/wtmp + .br +diff --git a/login-utils/last.c b/login-utils/last.c +index 8f7c36984..41ce03894 100644 +--- a/login-utils/last.c ++++ b/login-utils/last.c +@@ -602,12 +602,14 @@ static int is_phantom(const struct last_control *ctl, struct utmpx *ut) + { + struct passwd *pw; + char path[sizeof(ut->ut_line) + 16]; ++ char user[sizeof(ut->ut_user) + 1]; + int ret = 0; + + if (ut->ut_tv.tv_sec < ctl->boot_time.tv_sec) + return 1; +- ut->ut_user[sizeof(ut->ut_user) - 1] = '\0'; +- pw = getpwnam(ut->ut_user); ++ ++ mem2strcpy(user, ut->ut_user, sizeof(ut->ut_user), sizeof(user)); ++ pw = getpwnam(user); + if (!pw) + return 1; + snprintf(path, sizeof(path), "/proc/%u/loginuid", ut->ut_pid); +-- +2.39.1 + diff --git a/SPECS/util-linux.spec b/SPECS/util-linux.spec index 09a9cf1..b3bccbd 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.32.1 -Release: 38%{?dist} +Release: 41%{?dist} License: GPLv2 and GPLv2+ and LGPLv2+ and BSD with advertising and Public Domain Group: System Environment/Base URL: http://en.wikipedia.org/wiki/Util-linux @@ -261,6 +261,23 @@ Patch82: 0082-lslogins-improve-prefixes-interpretation.patch Patch83: 0083-tests-update-atari-blkid-tests.patch Patch84: 0084-tests-update-atari-partx-tests.patch +### RHEL-8.8 +### +# 2141969 - Add --cont-clock feature for libuuid and uuidd [rhel-8] +Patch85: 0085-libuuid-Implement-continuous-clock-handling-for-time.patch +Patch86: 0086-libuuid-check-clock-value-from-LIBUUID_CLOCK_FILE.patch +# 2121699 - fstrim -av fails to trim root filesystem on Red Hat Coreos +Patch87: 0087-fstrim-backport-entries-de-duplication.patch +# 2142496 - update upstream tests +Patch88: 0088-tests-don-t-reply-on-scsi_debug-partitions.patch +# 2149394 - umount outputs inaccurate error message when umount() fails with EACCES +Patch89: 0089-libmount-use-generic-error-message-for-EACCES-on-umo.patch +# 2159544 - lslogins "Password is locked" status changed in util-linux-2.32.1-38 +Patch90: 0090-lslogins-man-explain-password-statuses.patch +# 2160321 - [last] ut->ut_user is not null terminated +Patch91: 0091-last-sync-utmp-strings-use-with-upstream-code.patch +Patch92: 0092-last-use-full-size-of-the-username.patch + %description The util-linux package contains a large variety of low-level system @@ -1109,6 +1126,19 @@ fi %{_libdir}/python*/site-packages/libmount/ %changelog +* Mon Feb 13 2023 Karel Zak 2.32.1-41 +- improve #2160321 - [last] ut->ut_user is not null terminated + +* Mon Feb 06 2023 Karel Zak 2.32.1-40 +- fix #2121699 - fstrim -av fails to trim root filesystem on Red Hat Coreos +- fix #2142496 - update upstream tests +- fix #2149394 - umount outputs inaccurate error message when umount() fails with EACCES +- fix #2159544 - lslogins "Password is locked" status changed in util-linux-2.32.1-38 +- fix #2160321 - [last] ut->ut_user is not null terminated + +* Fri Nov 11 2022 Karel Zak 2.32.1-39 +- fix #2141969 - Add --cont-clock feature for libuuid and uuidd + * Mon Aug 22 2022 Karel Zak 2.32.1-38 - improve tmpfiles.d use in spec file (related to #2059241)