From 79c3fabf03a3a817db4b8e078b9c373083a2efda Mon Sep 17 00:00:00 2001 From: Chris Hofstaedtler Date: Wed, 22 Oct 2025 17:55:33 +0200 Subject: [PATCH 001/174] swapon: (man page) use "defaults" (plural) A lot of documentation on the Internet seems to assume "defaults" is the /correct/ default value when no other options are intended. Documentation/example.files/fstab does not have an entry for swap, but it shows "defaults" for other file systems. It seems prudent to align on a single variant, at least in the documentation, even if both are accepted by swapon. Signed-off-by: Chris Hofstaedtler --- sys-utils/swapon.8.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys-utils/swapon.8.adoc b/sys-utils/swapon.8.adoc index 5798925ec5b..7a6038acf61 100644 --- a/sys-utils/swapon.8.adoc +++ b/sys-utils/swapon.8.adoc @@ -116,7 +116,7 @@ Requires "swap" as the filesystem type. === The fourth field (options) -It is formatted as a comma-separated list of options. All unknown options are silently ignored. If options are unnecessary, the recommended convention is to use "default". The options specified in _fstab_ extend or overwrite settings specified on the *swapon* command line. +It is formatted as a comma-separated list of options. All unknown options are silently ignored. If options are unnecessary, the recommended convention is to use "defaults". The options specified in _fstab_ extend or overwrite settings specified on the *swapon* command line. Supported swap options: From 47344ed614cb6adfbf9e0eec7f7c18a672e1057b Mon Sep 17 00:00:00 2001 From: fortunate-lee Date: Thu, 23 Oct 2025 15:01:31 +0800 Subject: [PATCH 002/174] Fix memory leak issue in read_Subid_range() --- sys-utils/unshare.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sys-utils/unshare.c b/sys-utils/unshare.c index e7c8c0f26f6..11aeae48ed5 100644 --- a/sys-utils/unshare.c +++ b/sys-utils/unshare.c @@ -469,6 +469,7 @@ static struct map_range read_subid_range(char *filename, uid_t uid, int identity fclose(idmap); free(pw); free(pwbuf); + free(line); return map; } From a268328ac23588065ea7a8bf4b457f2d9147d130 Mon Sep 17 00:00:00 2001 From: Fabian Vogt Date: Tue, 28 Oct 2025 11:19:17 +0100 Subject: [PATCH 003/174] agetty: Fix reading /run/issue.d/ again Commit 63f7dcb5b072 ("lib/config: Make /run path configurable") added a second _PATH_SYSCONFDIR instead of _PATH_RUNSTATEDIR. Fix that. --- term-utils/agetty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/term-utils/agetty.c b/term-utils/agetty.c index 7a97167cd8c..f4d720448be 100644 --- a/term-utils/agetty.c +++ b/term-utils/agetty.c @@ -1952,7 +1952,7 @@ static void eval_issue_file(struct issue *ie, ul_configs_file_list(&file_list, NULL, _PATH_SYSCONFDIR, - _PATH_SYSCONFDIR, + _PATH_RUNSTATEDIR, _PATH_SYSCONFSTATICDIR, "issue", ISSUEDIR_EXT); From 3f3f7298347c88cc5e2265f949d60bc40e0d0ebe Mon Sep 17 00:00:00 2001 From: Bastian Krause Date: Fri, 24 Oct 2025 17:32:20 +0200 Subject: [PATCH 004/174] hwclock: skip RTC_PARAM_SET for --param-set with unchanged value Parameters set with `hwclock --param-set` tend to be persisted in the RTC's EEPROM. Writing the same value over and over again can wear out the EEPROM (e.g. on each boot). So read the current value first. Only if the parameter is changed, actually write the new value. This allows for easier integrations, especially since there is no machine-readable way of retrieving the current value via hwclock. Signed-off-by: Bastian Krause --- sys-utils/hwclock-rtc.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/sys-utils/hwclock-rtc.c b/sys-utils/hwclock-rtc.c index f8af5545dc5..318e692e97c 100644 --- a/sys-utils/hwclock-rtc.c +++ b/sys-utils/hwclock-rtc.c @@ -498,6 +498,7 @@ int get_param_rtc(const struct hwclock_control *ctl, int set_param_rtc(const struct hwclock_control *ctl, const char *opt0) { int rtc_fd, rc = 1; + struct rtc_param current_param = { .index = ctl->param_idx }; struct rtc_param param = { .index = ctl->param_idx }; char *tok, *opt = xstrdup(opt0); @@ -520,13 +521,25 @@ int set_param_rtc(const struct hwclock_control *ctl, const char *opt0) goto done; } - /* set parameter */ rtc_fd = open_rtc(ctl); if (rtc_fd < 0) { warnx(_("cannot open %s"), rtc_dev_name); goto done; } + /* get parameter and compare with value */ + current_param.param = param.param; + if (!ioctl(rtc_fd, RTC_PARAM_GET, ¤t_param) + && current_param.uvalue == param.uvalue) { + /* value to be written matches current value, skip write */ + if (ctl->verbose) + printf(_("skipping ioctl(%d, RTC_PARAM_GET, param) to %s: value unchanged\n"), + rtc_fd, rtc_dev_name); + rc = 0; + goto done; + } + + /* set parameter */ if (ioctl(rtc_fd, RTC_PARAM_SET, ¶m) == -1) { warn(_("ioctl(%d, RTC_PARAM_SET, param) to %s failed"), rtc_fd, rtc_dev_name); From 578923fe582903628ecc0d2a434af0affa3660d2 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Thu, 30 Oct 2025 12:11:43 +0100 Subject: [PATCH 005/174] libfdisk: (dos) fix off-by-one in maximum last sector calculation The get_disk_ranges() function incorrectly capped the last usable sector at UINT_MAX, which could cause an overflow when calculating partition size for MBR partition tables. MBR stores partition size as a 32-bit value with maximum UINT_MAX. The partition size is calculated as: size = stop - start + 1 For a partition starting at sector 0: - If stop = UINT_MAX: size = UINT_MAX + 1 (overflow!) - If stop = UINT_MAX - 1: size = UINT_MAX (correct maximum) This fixes the inconsistency where dos_init() correctly warns about disks larger than UINT_MAX sectors (2TiB - 512 bytes for 512-byte sectors), but get_disk_ranges() allowed creating partitions that would overflow the 32-bit size field. Addresses: https://issues.redhat.com/browse/RHEL-122367 Signed-off-by: Karel Zak --- libfdisk/src/dos.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libfdisk/src/dos.c b/libfdisk/src/dos.c index db7e257164b..c88d2a4f213 100644 --- a/libfdisk/src/dos.c +++ b/libfdisk/src/dos.c @@ -1241,8 +1241,8 @@ static int get_disk_ranges(struct fdisk_context *cxt, int logical, else *last = cxt->total_sectors - 1; - if (*last > UINT_MAX) - *last = UINT_MAX; + if (*last >= UINT_MAX) + *last = UINT_MAX - 1; *first = cxt->first_lba; } From e4c5943860305dba3de21d55c4c7573e3692dabe Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 12:14:38 -0400 Subject: [PATCH 006/174] bash-completion: (bits) add missing --binary Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/bits | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bash-completion/bits b/bash-completion/bits index 786be4d92f5..c0e9fe63bd6 100644 --- a/bash-completion/bits +++ b/bash-completion/bits @@ -11,7 +11,7 @@ _bits_module() esac case $cur in -*) - OPTS="--version --help --width --mask --grouped-mask --bit --list" + OPTS="--version --help --width --mask --grouped-mask --bit --binary --list" COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) ) return 0 ;; From 0351a75782244af9d7c297801ba9fa472fe930c5 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 12:16:22 -0400 Subject: [PATCH 007/174] bash-completion: (blkid) add missing --hint Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/blkid | 1 + 1 file changed, 1 insertion(+) diff --git a/bash-completion/blkid b/bash-completion/blkid index a7e4ef5da22..de1c2c22a8d 100644 --- a/bash-completion/blkid +++ b/bash-completion/blkid @@ -86,6 +86,7 @@ _blkid_module() --usages --match-types --no-part-details + --hint --help --version " From 5dfd142c99f927ed36e05e7b0f447003a69ff674 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 12:17:31 -0400 Subject: [PATCH 008/174] bash-completion: (blockdev) add missing long options Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/blockdev | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bash-completion/blockdev b/bash-completion/blockdev index f37cf034d8b..6244e8f2be8 100644 --- a/bash-completion/blockdev +++ b/bash-completion/blockdev @@ -29,7 +29,9 @@ _blockdev_module() --getfra --flushbufs --rereadpt - $DEVS" + $DEVS + --help + --version" case $prev in '--setbsz') COMPREPLY=( $(compgen -W "bytes" -- $cur) ) From 81bca2b4f468c77fe7c3645f217338363ed33490 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 12:24:20 -0400 Subject: [PATCH 009/174] bash-completion: (cal) add missing long options Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/cal | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bash-completion/cal b/bash-completion/cal index 8791d123a8d..272f6f6c829 100644 --- a/bash-completion/cal +++ b/bash-completion/cal @@ -6,6 +6,9 @@ _cal_module() case $cur in -*) OPTS=" --one + --columns + --iso + --reform --three --months --sunday From 1730170815d5839064e45bf6fe2c5e432ea6d0e4 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 12:26:04 -0400 Subject: [PATCH 010/174] bash-completion: (cfdisk) add missing --sector-size Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/cfdisk | 1 + 1 file changed, 1 insertion(+) diff --git a/bash-completion/cfdisk b/bash-completion/cfdisk index 0a57d68a644..683986d8ed4 100644 --- a/bash-completion/cfdisk +++ b/bash-completion/cfdisk @@ -20,6 +20,7 @@ _cfdisk_module() --lock --help --read-only + --sector-size --version" COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) ) return 0 From d934a6e29420511b77ab18a4133e52ebc7b00724 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 12:27:27 -0400 Subject: [PATCH 011/174] bash-completion: (column) add missing long options Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/column | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bash-completion/column b/bash-completion/column index fb209204d58..08d0772200f 100644 --- a/bash-completion/column +++ b/bash-completion/column @@ -36,6 +36,7 @@ _column_module() --table-colorscheme --table-name --table-order + --table-column --table-columns --table-columns-limit --table-noextreme @@ -54,6 +55,7 @@ _column_module() --output-width --separator --output-separator + --wrap-separator --fillrows --use-spaces --color From cd510de78c710907bf1281f44e040f8b1ab8090a Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 12:32:59 -0400 Subject: [PATCH 012/174] fadvise: add --fd to the help output Signed-off-by: Christian Goeschel Ndjomouo --- misc-utils/fadvise.c | 1 + 1 file changed, 1 insertion(+) diff --git a/misc-utils/fadvise.c b/misc-utils/fadvise.c index da7fc691a0f..6e9ced0083f 100644 --- a/misc-utils/fadvise.c +++ b/misc-utils/fadvise.c @@ -50,6 +50,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(USAGE_OPTIONS, out); fputs(_(" -a, --advice applying advice to the file (default: \"dontneed\")\n"), out); + fputs(_(" -d, --fd applying advice to the file descriptor\n"), out); fputs(_(" -l, --length length for range operations, in bytes\n"), out); fputs(_(" -o, --offset offset for range operations, in bytes\n"), out); From a972e9eb5219e88d2cab0f1a49e0910125c46d6b Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 12:33:57 -0400 Subject: [PATCH 013/174] bash-completion: (fadvise) add missing --fd Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/fadvise | 1 + 1 file changed, 1 insertion(+) diff --git a/bash-completion/fadvise b/bash-completion/fadvise index 9d75ded6a3e..44a87f2fbbe 100644 --- a/bash-completion/fadvise +++ b/bash-completion/fadvise @@ -26,6 +26,7 @@ _fadvise_module() case $cur in -*) OPTS='--advice + --fd --length --offset --help From 88e4b6f8bfd188b210ffcda10ecb4a1034c412c7 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 12:35:05 -0400 Subject: [PATCH 014/174] bash-completion: (fallocate) add missing --write-zeroes Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/fallocate | 1 + 1 file changed, 1 insertion(+) diff --git a/bash-completion/fallocate b/bash-completion/fallocate index 670874c9602..dd0d07d07f5 100644 --- a/bash-completion/fallocate +++ b/bash-completion/fallocate @@ -24,6 +24,7 @@ _fallocate_module() --offset --punch-hole --zero-range + --write-zeroes --posix --verbose --help From 1188191acace5f39be8732164ea01274b2913586 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 12:38:26 -0400 Subject: [PATCH 015/174] bash-completion: (fincore) add missing --total Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/fincore | 1 + 1 file changed, 1 insertion(+) diff --git a/bash-completion/fincore b/bash-completion/fincore index 34007e04d8f..c2341f6dfc3 100644 --- a/bash-completion/fincore +++ b/bash-completion/fincore @@ -31,6 +31,7 @@ _fincore_module() --noheadings --output --output-all + --total --raw --recursive --cachestat From 9eb659f100276f4398d404db4b6a740a24114209 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 12:40:58 -0400 Subject: [PATCH 016/174] bash-completion: (findmnt) add missing long options Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/findmnt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/bash-completion/findmnt b/bash-completion/findmnt index fe04cba5c75..0990eb7e983 100644 --- a/bash-completion/findmnt +++ b/bash-completion/findmnt @@ -136,6 +136,15 @@ _findmnt_module() --real --pseudo --list-columns + --bytes + --filter + --nocanonicalize + --shadowed + --shell + --uniq + --verbose + --verify + --vfs-all --version" COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) ) return 0 From 93d0a87cb93f90c137cfda0242703cd3eba0b692 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 12:41:25 -0400 Subject: [PATCH 017/174] bash-completion: (flock) add missing --verbose Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/flock | 1 + 1 file changed, 1 insertion(+) diff --git a/bash-completion/flock b/bash-completion/flock index a4de186f388..e9f9a851923 100644 --- a/bash-completion/flock +++ b/bash-completion/flock @@ -36,6 +36,7 @@ _flock_module() --fcntl --start --length + --verbose --help --version" COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) ) From ed442ddba1969ba826a4e07ccebac6e797d54d82 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 12:43:29 -0400 Subject: [PATCH 018/174] bash-completion: (fsck) add missing long options Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/fsck | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bash-completion/fsck b/bash-completion/fsck index 8e6942c672e..cf8756c5b74 100644 --- a/bash-completion/fsck +++ b/bash-completion/fsck @@ -27,7 +27,7 @@ _fsck_module() esac case $cur in -*) - OPTS="-p -n -y -c -f -v -b -B -j -l -L" + OPTS="-p -n -y -c -f -v -b -B -j -l -L --help --version" COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) ) return 0 ;; From e84a692a4da69caee88d141b45518cfe36dc7bc6 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 12:44:30 -0400 Subject: [PATCH 019/174] bash-completion: (getopt) add missing --unknown Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/getopt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/bash-completion/getopt b/bash-completion/getopt index 5e3fca61cbc..9cd9b7319a6 100644 --- a/bash-completion/getopt +++ b/bash-completion/getopt @@ -27,7 +27,18 @@ _getopt_module() esac case $cur in -*) - OPTS="--alternative --help --longoptions --name --options --quiet --quiet-output --shell --test --unquoted --version" + OPTS="--alternative + --help + --longoptions + --name + --options + --quiet + --quiet-output + --shell + --test + --unknown + --unquoted + --version" COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) ) return 0 ;; From fec4066b73483523282a283932b4fe17e8aa012d Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 12:48:04 -0400 Subject: [PATCH 020/174] bash-completion: (hardlink) add missing long options Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/hardlink | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/bash-completion/hardlink b/bash-completion/hardlink index 3b0200640cd..4af9e5c56f7 100644 --- a/bash-completion/hardlink +++ b/bash-completion/hardlink @@ -49,18 +49,27 @@ _hardlink_module() -*) OPTS=" --content + --cache-size + --exclude + --exclude-subtree --respect-dir --respect-name --maximize --minimize + --minimum-size + --maximum-size --mount --dry-run + --io-size + --include --ignore-owner --keep-oldest --list-duplicates --ignore-mode --quiet + --prioritize-trees --ignore-time + --reflink --verbose --respect-xattrs --skip-reflinks From 2d5e6592c3de8103e4aa2a6de343a3676b535249 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 13:09:51 -0400 Subject: [PATCH 021/174] bash-completion: (hwclock) add missing long options Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/hwclock | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bash-completion/hwclock b/bash-completion/hwclock index 6240d7d4be6..a82b87f6740 100644 --- a/bash-completion/hwclock +++ b/bash-completion/hwclock @@ -54,6 +54,8 @@ _hwclock_module() --epoch --param-get --param-set + --param-index + --verbose --vl-read --vl-clear --update-drift From 75213a646be5183bcb07558432014211f0b3c0d0 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 13:10:19 -0400 Subject: [PATCH 022/174] bash-completion: (losetup) add missing long options Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/losetup | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bash-completion/losetup b/bash-completion/losetup index 783d966c79c..2d314c111ed 100644 --- a/bash-completion/losetup +++ b/bash-completion/losetup @@ -60,6 +60,9 @@ _losetup_module() --remove --show --verbose + --direct-io + --loop-ref + --sector-size --json --list --noheadings From 735da1b9cd4131d042e593f1c01f45199ef549ee Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 13:10:58 -0400 Subject: [PATCH 023/174] bash-completion: (lsblk) add missing long options Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/lsblk | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bash-completion/lsblk b/bash-completion/lsblk index ff826858137..577dcce13cf 100644 --- a/bash-completion/lsblk +++ b/bash-completion/lsblk @@ -96,6 +96,11 @@ _lsblk_module() --virtio --sort --width + --noempty + --shell + --sysroot + --tree + --zoned --list-columns --help --version" From 43105e32f07b35f53e1615a9627bdf84f7eeed5e Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 13:11:29 -0400 Subject: [PATCH 024/174] bash-completion: (lsclocks) add missing --no-discover-dynamic Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/lsclocks | 1 + 1 file changed, 1 insertion(+) diff --git a/bash-completion/lsclocks b/bash-completion/lsclocks index 7158701ea7c..dda9bba361a 100644 --- a/bash-completion/lsclocks +++ b/bash-completion/lsclocks @@ -53,6 +53,7 @@ _lsclocks_module() --raw --time --dynamic-clock + --no-discover-dynamic --rtc --cpu-clock --help From e31f075b5b63928b7cb33f916e6bb8dcef6affed Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 13:11:59 -0400 Subject: [PATCH 025/174] bash-completion: (lscpu) add missing --hierarchic Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/lscpu | 1 + 1 file changed, 1 insertion(+) diff --git a/bash-completion/lscpu b/bash-completion/lscpu index b26086afb17..950be9bfaa0 100644 --- a/bash-completion/lscpu +++ b/bash-completion/lscpu @@ -38,6 +38,7 @@ _lscpu_module() --parse= --sysroot --hex + --hierarchic --physical --output-all --raw From 8976325fbbb344312cbff09067b651eea6d3e126 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 13:12:32 -0400 Subject: [PATCH 026/174] bash-completion: (lslogins) add missing --shell Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/lslogins | 1 + 1 file changed, 1 insertion(+) diff --git a/bash-completion/lslogins b/bash-completion/lslogins index daf614d313a..cd6364f1f2d 100644 --- a/bash-completion/lslogins +++ b/bash-completion/lslogins @@ -71,6 +71,7 @@ _lslogins_module() --print0 --wtmp-file --btmp-file + --shell --lastlog --help --version" -- $cur) ) From 1c5bdd8638986957bfa35a0c520440e74d4564eb Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 13:12:56 -0400 Subject: [PATCH 027/174] bash-completion: (lsmem) add missing --split Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/lsmem | 1 + 1 file changed, 1 insertion(+) diff --git a/bash-completion/lsmem b/bash-completion/lsmem index 7d6e8424785..216b7aced31 100644 --- a/bash-completion/lsmem +++ b/bash-completion/lsmem @@ -43,6 +43,7 @@ _lsmem_module() --output-all --raw --sysroot + --split --summary --help --version From d7d9a98865023f5ada70f8a4fd876578033c9d69 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 13:13:50 -0400 Subject: [PATCH 028/174] bash-completion: (mkfs.bfs) add missing --lock Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/mkfs.bfs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bash-completion/mkfs.bfs b/bash-completion/mkfs.bfs index b7efc767f4a..3d4b492392b 100644 --- a/bash-completion/mkfs.bfs +++ b/bash-completion/mkfs.bfs @@ -19,7 +19,7 @@ _mkfs.bfs_module() esac case $cur in -*) - OPTS='--inodes --vname --fname --verbose --help --version' + OPTS='--inodes --vname --fname --lock --verbose --help --version' COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) ) return 0 ;; From 72b8c115c7ec716eb7df893bc60845da04c698e4 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 13:14:24 -0400 Subject: [PATCH 029/174] bash-completion: (mkfs.cramfs) add missing long options Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/mkfs.cramfs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bash-completion/mkfs.cramfs b/bash-completion/mkfs.cramfs index b7e92fce74c..61a65b37f5f 100644 --- a/bash-completion/mkfs.cramfs +++ b/bash-completion/mkfs.cramfs @@ -31,7 +31,7 @@ _mkfs.cramfs_module() esac case $cur in -*) - OPTS="-h -v -E -b -e -N -i -n -p -s -z" + OPTS="-h -v -E -b -e -N -i -n -p -s -z --help --version" COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) ) return 0 ;; From fdc77706a249c3247ed91d0469617e2d354e2fd9 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 13:14:53 -0400 Subject: [PATCH 030/174] bash-completion: (mkfs.minix) add missing --lock Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/mkfs.minix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bash-completion/mkfs.minix b/bash-completion/mkfs.minix index e7a26cd0a7a..c43fef82ddb 100644 --- a/bash-completion/mkfs.minix +++ b/bash-completion/mkfs.minix @@ -21,7 +21,7 @@ _mkfs.minix_module() esac case $cur in -*) - OPTS="--namelength --inodes --check --badblocks --help --version -1 -2 -3" + OPTS="--namelength --inodes --check --badblocks --lock --help --version -1 -2 -3" COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) ) return 0 ;; From 908bf9e4caf479ec7855523354ff0ad44cb145a1 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 13:15:58 -0400 Subject: [PATCH 031/174] bash-completion: (mkswap) add missing long options Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/mkswap | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/bash-completion/mkswap b/bash-completion/mkswap index 46939c0102c..693347516d3 100644 --- a/bash-completion/mkswap +++ b/bash-completion/mkswap @@ -35,7 +35,21 @@ _mkswap_module() esac case $cur in -*) - OPTS="--check --force --pagesize --lock --label --swapversion --uuid --offset --verbose --version --help --size --file" + OPTS="--check + --endianness + --quiet + --force + --pagesize + --lock + --label + --swapversion + --uuid + --offset + --verbose + --version + --help + --size + --file" COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) ) return 0 ;; From 3ff74d751992262ac93a07bdc57af757d85b7709 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 13:16:21 -0400 Subject: [PATCH 032/174] bash-completion: (more) add missing --exit-on-eof Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/more | 1 + 1 file changed, 1 insertion(+) diff --git a/bash-completion/more b/bash-completion/more index d93200a454b..e372f0de1b6 100644 --- a/bash-completion/more +++ b/bash-completion/more @@ -16,6 +16,7 @@ _more_module() case $cur in -*) OPTS=" + --exit-on-eof --silent --logical --no-pause From fb2ca61fa6eb029d771dcae80ee9bb765d176f82 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 13:17:05 -0400 Subject: [PATCH 033/174] bash-completion: (renice) add missing --relative Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/renice | 1 + 1 file changed, 1 insertion(+) diff --git a/bash-completion/renice b/bash-completion/renice index 20ddb9d90d9..8af037d2bc9 100644 --- a/bash-completion/renice +++ b/bash-completion/renice @@ -32,6 +32,7 @@ _renice_module() OPTS="--pgrp --priority --pid + --relative --user --help --version" From be76d195af3ea6df20e58a864e20cc457c485278 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 13:18:32 -0400 Subject: [PATCH 034/174] bash-completion: (scriptlive) add missing --echo Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/scriptlive | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/bash-completion/scriptlive b/bash-completion/scriptlive index 56a296f5b57..69f0a3633da 100644 --- a/bash-completion/scriptlive +++ b/bash-completion/scriptlive @@ -14,13 +14,19 @@ _scriptlive_module() COMPREPLY=( $(compgen -W "digit" -- $cur) ) return 0 ;; + '-E'|'--echo') + COMPREPLY=( $(compgen -W "auto always never" -- $cur) ) + return 0 + ;; '-h'|'--help'|'-V'|'--version') return 0 ;; esac case $cur in -*) - OPTS="--timing + OPTS=" + --echo + --timing --log-in --log-io --log-timing From 378c96795598ebda2d28ff4c2725ece1bd7e0ed7 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 13:18:58 -0400 Subject: [PATCH 035/174] bash-completion: (setsid) add missing --fork Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/setsid | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bash-completion/setsid b/bash-completion/setsid index 955ec27c0ee..bf22477cf44 100644 --- a/bash-completion/setsid +++ b/bash-completion/setsid @@ -11,7 +11,7 @@ _setsid_module() esac case $cur in -*) - OPTS="--ctty --wait --help --version" + OPTS="--ctty --wait --fork --help --version" COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) ) return 0 ;; From 154ac6ad9eb4466be9ff81202400db5cab841cad Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 13:20:24 -0400 Subject: [PATCH 036/174] bash-completion: (sfdisk) add missing long options Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/sfdisk | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bash-completion/sfdisk b/bash-completion/sfdisk index 27f64c6021a..290d234fdfb 100644 --- a/bash-completion/sfdisk +++ b/bash-completion/sfdisk @@ -89,6 +89,11 @@ _sfdisk_module() --wipe-partitions --label --label-nested + --Linux + --move-use-fsync + --sector-size + --show-pt-geometry + --unit --help --version " From b0390e6291c021cef7fbb62a4ac458b65b1ee67a Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 13:21:14 -0400 Subject: [PATCH 037/174] bash-completion: (swapon) add missing --options Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/swapon | 1 + 1 file changed, 1 insertion(+) diff --git a/bash-completion/swapon b/bash-completion/swapon index 5906ec8445f..0b09ff88ac4 100644 --- a/bash-completion/swapon +++ b/bash-completion/swapon @@ -65,6 +65,7 @@ _swapon_module() --summary --show --output-all + --options --noheadings --raw --bytes From 49eff4652d4dcb71766727ce9eb0359ba6e8ced5 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 13:22:46 -0400 Subject: [PATCH 038/174] bash-completion: (unshare) add missing long options Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/unshare | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/bash-completion/unshare b/bash-completion/unshare index d421eb1a3b4..219579c56aa 100644 --- a/bash-completion/unshare +++ b/bash-completion/unshare @@ -39,6 +39,13 @@ _unshare_module() --version --root --wd + --load-interp + --map-auto + --map-group + --map-groups + --map-user + --map-users + --mount-binfmt --monotonic --boottime --setuid From 347dbbdc6498d6df8fdeb8aa5d6f967edaa6d833 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 13:24:12 -0400 Subject: [PATCH 039/174] bash-completion: (uuidd) add missing --cont-clock Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/uuidd | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/bash-completion/uuidd b/bash-completion/uuidd index c8f6697c9b8..d827454a022 100644 --- a/bash-completion/uuidd +++ b/bash-completion/uuidd @@ -29,7 +29,21 @@ _uuidd_module() esac case $cur in -*) - OPTS="--pid --socket --timeout --kill --random --time --uuids --no-pid --no-fork --socket-activation --debug --quiet --version --help" + OPTS="--cont-clock + --pid + --socket + --timeout + --kill + --random + --time + --uuids + --no-pid + --no-fork + --socket-activation + --debug + --quiet + --version + --help" COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) ) return 0 ;; From 56344d2c9a97d393ac8f6de366cb5bfac11659f6 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 13:24:54 -0400 Subject: [PATCH 040/174] bash-completion: (wdctl) add missing long options Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/wdctl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bash-completion/wdctl b/bash-completion/wdctl index f1a870ef695..2a4e62eaf88 100644 --- a/bash-completion/wdctl +++ b/bash-completion/wdctl @@ -56,6 +56,8 @@ _wdctl_module() --notimeouts --settimeout --flags-only + --setpregovernor + --setpretimeout --help --version" COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) ) From a8835586c23f8906952481e1b96611e1f9b4c62f Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 31 Oct 2025 13:25:29 -0400 Subject: [PATCH 041/174] bash-completion: (whereis) add missing long options Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/whereis | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bash-completion/whereis b/bash-completion/whereis index 7db67a398c7..55c6d2dfdb2 100644 --- a/bash-completion/whereis +++ b/bash-completion/whereis @@ -17,7 +17,7 @@ _whereis_module() esac case $cur in -*) - OPTS="-b -B -m -M -s -S -f -u -l -g" + OPTS="-b -B -m -M -s -S -f -u -l -g --help --version" COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) ) return 0 ;; From 58684fa95032c37c50129d92f94b2305f540e20f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Nov 2025 18:05:45 +0000 Subject: [PATCH 042/174] build(deps): bump github/codeql-action from 3 to 4 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3 to 4. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/v3...v4) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 223111611cc..8133150be9c 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -35,7 +35,7 @@ jobs: uses: actions/checkout@v5 - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} queries: +security-extended,security-and-quality @@ -54,7 +54,7 @@ jobs: COMPILER: gcc - name: Autobuild - uses: github/codeql-action/autobuild@v3 + uses: github/codeql-action/autobuild@v4 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@v4 From 906f1b7a779b29f7b8b3d1021d8ded8a3c9b493a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Nov 2025 18:05:54 +0000 Subject: [PATCH 043/174] build(deps): bump actions/upload-artifact from 4 to 5 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/cifuzz.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml index e4777eb182c..d2736cd0b28 100644 --- a/.github/workflows/cifuzz.yml +++ b/.github/workflows/cifuzz.yml @@ -52,7 +52,7 @@ jobs: dry-run: false sanitizer: ${{ matrix.sanitizer }} - name: Upload Crash - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 if: failure() && steps.build.outcome == 'success' with: name: ${{ matrix.sanitizer }}-${{ matrix.architecture }}-artifacts From 6cdbe06519ebc235c3d0fbb8e0092ffc8abf0ce6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sat, 1 Nov 2025 14:58:34 +0100 Subject: [PATCH 044/174] fincore: do not fall back to mincore if cachestat fails with EPERM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cachestat() and mincore() both require that the tested file is (potentially) writable by the current user. If this permission check fails, cachestat() will return EPERM while mincore() will simply mark all pages as resident in core, as a proper EPERM would violate its API contract. But when cachestat() fails with EPERM we know that mincore() will not return real data, so instead show an error message. Reported-by: Christian Hesse Signed-off-by: Thomas Weißschuh --- misc-utils/fincore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc-utils/fincore.c b/misc-utils/fincore.c index c297c104573..7ccec2a82ec 100644 --- a/misc-utils/fincore.c +++ b/misc-utils/fincore.c @@ -370,7 +370,7 @@ static int fincore_fd (struct fincore_control *ctl, if (errno != ENOSYS || ctl->cachestat) warn(_("failed to do cachestat: %s"), st->name); - if (ctl->cachestat) + if (errno == EPERM || ctl->cachestat) return -errno; return mincore_fd(ctl, fd, st); From 2ce6bcc507e56b34584960e26af16b48984feb7e Mon Sep 17 00:00:00 2001 From: cgoesche Date: Sat, 1 Nov 2025 19:45:32 -0400 Subject: [PATCH 045/174] bash-completion: (lastlog2) add missing --active Signed-off-by: cgoesche --- bash-completion/lastlog2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bash-completion/lastlog2 b/bash-completion/lastlog2 index 09aa4ed11e4..40d867789bc 100644 --- a/bash-completion/lastlog2 +++ b/bash-completion/lastlog2 @@ -35,7 +35,7 @@ _lastlog2_module() esac case $cur in -*) - OPTS=" + OPTS=" --active --before --clear --database From 3b9f287a8c5b2f561bd6bbc7a4b4fe2a8e797f6b Mon Sep 17 00:00:00 2001 From: cgoesche Date: Sat, 1 Nov 2025 19:46:27 -0400 Subject: [PATCH 046/174] bash-completion: (pg) add missing long options Signed-off-by: cgoesche --- bash-completion/pg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bash-completion/pg b/bash-completion/pg index 8fce1302abe..04b47f340b0 100644 --- a/bash-completion/pg +++ b/bash-completion/pg @@ -15,7 +15,7 @@ _pg_module() esac case $cur in -*) - OPTS="-number -c -e -f -n -p -r -s -h -V" + OPTS="-number -c -e -f -n -p -r -s -h -V --help --version" COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) ) return 0 ;; From 4f65381173406d2d6807bfb328e5cc1efd680359 Mon Sep 17 00:00:00 2001 From: cgoesche Date: Sat, 1 Nov 2025 19:47:03 -0400 Subject: [PATCH 047/174] bash-completion: (setpriv) add missing long options Signed-off-by: cgoesche --- bash-completion/setpriv | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bash-completion/setpriv b/bash-completion/setpriv index d19b275573a..a472943fa51 100644 --- a/bash-completion/setpriv +++ b/bash-completion/setpriv @@ -124,6 +124,9 @@ _setpriv_module() --securebits --pdeathsig --reset-env + --init-groups + --nnp + --ptracer --selinux-label --apparmor-profile --landlock-access From 32a3c16efc9721d575222df783749266c2b1f9c4 Mon Sep 17 00:00:00 2001 From: cgoesche Date: Sat, 1 Nov 2025 19:49:33 -0400 Subject: [PATCH 048/174] bash-completion: (namei) add missing --context Signed-off-by: cgoesche --- bash-completion/namei | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/bash-completion/namei b/bash-completion/namei index 640273500a1..85a3d74c821 100644 --- a/bash-completion/namei +++ b/bash-completion/namei @@ -11,7 +11,15 @@ _namei_module() esac case $cur in -*) - OPTS="--help --version --mountpoints --modes --owners --long --nosymlinks --vertical" + OPTS=" --context + --help + --version + --mountpoints + --modes + --owners + --long + --nosymlinks + --vertical" COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) ) return 0 ;; From f1f7085b8e07729365bf2e82fc9c0d8396f0f42e Mon Sep 17 00:00:00 2001 From: cgoesche Date: Sat, 1 Nov 2025 19:50:17 -0400 Subject: [PATCH 049/174] bash-completion: (nsenter) add missing --follow-context Signed-off-by: cgoesche --- bash-completion/nsenter | 1 + 1 file changed, 1 insertion(+) diff --git a/bash-completion/nsenter b/bash-completion/nsenter index 1acc764ad09..165300a2a8f 100644 --- a/bash-completion/nsenter +++ b/bash-completion/nsenter @@ -34,6 +34,7 @@ _nsenter_module() -*) OPTS=" --all + --follow-context --target --mount= --uts= From 278249ac779d585ba3decd09d89d5489631ffbe8 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Sun, 2 Nov 2025 12:25:26 -0800 Subject: [PATCH 050/174] meson: fix non threaded toolchains threads needs to be set as not required. Cleaned up meson build slightly to use one dependency call. Signed-off-by: Rosen Penev --- libuuid/meson.build | 4 +--- meson.build | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/libuuid/meson.build b/libuuid/meson.build index 5115944adad..17b759a0c05 100644 --- a/libuuid/meson.build +++ b/libuuid/meson.build @@ -31,8 +31,6 @@ if cc.has_link_argument('-Wl,--version-script=@0@'.format(libuuid_sym_path)) libuuid_link_args += ['-Wl,--version-script=@0@'.format(libuuid_sym_path)] endif -thread_dep = dependency('threads') - lib_uuid = library( 'uuid', list_h, @@ -47,7 +45,7 @@ lib_uuid = library( link_depends : libuuid_link_depends, version : libuuid_version, link_args : libuuid_link_args, - dependencies : [socket_libs, thread_dep, + dependencies : [socket_libs, thread_libs, build_libuuid ? [] : disabler()], install : build_libuuid) uuid_dep = declare_dependency(link_with: lib_uuid, include_directories: dir_libuuid) diff --git a/meson.build b/meson.build index 66fcbef543d..7a995d612c2 100644 --- a/meson.build +++ b/meson.build @@ -804,7 +804,7 @@ if not have endif conf.set('HAVE_CLOCK_GETTIME', have ? 1 : false) -thread_libs = dependency('threads') +thread_libs = dependency('threads', required: false) conf.set('HAVE_LIBPTHREAD', thread_libs.found() ? 1 : false) have = cc.has_function('timer_create') @@ -880,7 +880,7 @@ have = cc.has_header_symbol('linux/vm_sockets.h', 'VMADDR_CID_LOCAL', prefix : '#include ') conf.set('HAVE_DECL_VMADDR_CID_LOCAL', have ? 1 : false) -build_plymouth_support = (not build_plymouth_support.disabled() and +build_plymouth_support = (not build_plymouth_support.disabled() and have_tiocglcktrmios and have_sock_cloexec and have_sock_nonblock and From e54b6aa631aced38527fcae41397b5aec8fac87f Mon Sep 17 00:00:00 2001 From: cgoesche Date: Sun, 2 Nov 2025 22:31:40 -0500 Subject: [PATCH 051/174] login: fix minor grammar mistake in the manpage Signed-off-by: cgoesche --- login-utils/login.1.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/login-utils/login.1.adoc b/login-utils/login.1.adoc index 0b380942ac7..f28323ff9c5 100644 --- a/login-utils/login.1.adoc +++ b/login-utils/login.1.adoc @@ -26,7 +26,7 @@ login - begin session on the system The user is then prompted for a password, where appropriate. Echoing is disabled to prevent revealing the password. Only a number of password failures are permitted before *login* exits and the communications link is severed. See *LOGIN_RETRIES* in the *CONFIG FILE ITEMS* section. -If password aging has been enabled for the account, the user may be prompted for a new password before proceeding. In such case old password must be provided and the new password entered before continuing. Please refer to *passwd*(1) for more information. +If password aging has been enabled for the account, the user may be prompted for a new password before proceeding. In such a case, the old password must be provided and the new password entered before continuing. Please refer to *passwd*(1) for more information. The user and group ID will be set according to their values in the _/etc/passwd_ file. There is one exception if the user ID is zero. In this case, only the primary group ID of the account is set. This should allow the system administrator to login even in case of network problems. The environment variable values for *$HOME*, *$USER*, *$SHELL*, *$PATH*, *$LOGNAME*, and *$MAIL* are set according to the appropriate fields in the password entry. *$PATH* defaults to _/usr/local/bin:/bin:/usr/bin_ for normal users, and to _/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin_ for root, if not otherwise configured. From 56e2c86c2c7ea012b63cd896d9ca3daa34f19565 Mon Sep 17 00:00:00 2001 From: Munehisa Kamata Date: Tue, 28 Oct 2025 12:54:17 -0700 Subject: [PATCH 052/174] wdctl: remove -d option leftover -d option was removed in commit f56338b43973 ("wdctl: allow to specify more than one device"), but the optstring wasn't updated at that time and wdctl can still accept the option halfway as below: $ wdctl -d wdctl: option requires an argument -- 'd' whereas it should say: wdctl: invalid option -- 'd' So update the optstring. Fixes: f56338b43973 ("wdctl: allow to specify more than one device") Signed-off-by: Munehisa Kamata --- sys-utils/wdctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys-utils/wdctl.c b/sys-utils/wdctl.c index f3ae0e3f8c6..0cf8ee7a436 100644 --- a/sys-utils/wdctl.c +++ b/sys-utils/wdctl.c @@ -779,7 +779,7 @@ int main(int argc, char *argv[]) close_stdout_atexit(); while ((c = getopt_long(argc, argv, - "d:f:g:hFnITp:o:s:OrVx", long_opts, NULL)) != -1) { + "f:g:hFnITp:o:s:OrVx", long_opts, NULL)) != -1) { err_exclusive_options(c, long_opts, excl, excl_st); From 86f94ecda56a2af176a785fbaa26b4260c6b7b85 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Wed, 29 Oct 2025 12:03:56 +0100 Subject: [PATCH 053/174] losetup: sort 'O' correctly for the mutual-exclusive check to work The options need to be in strict ascending order. Signed-off-by: Benno Schulenberg --- sys-utils/losetup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys-utils/losetup.c b/sys-utils/losetup.c index c2eec5600ba..2a3257473d2 100644 --- a/sys-utils/losetup.c +++ b/sys-utils/losetup.c @@ -739,7 +739,7 @@ int main(int argc, char **argv) static const ul_excl_t excl[] = { /* rows and cols in ASCII order */ { 'D','a','c','d','f','j',OPT_REMOVE }, { 'D','c','d','f','l',OPT_REMOVE }, - { 'D','c','d','f','O',OPT_REMOVE }, + { 'D','O','c','d','f',OPT_REMOVE }, { 'J',OPT_RAW }, { 0 } }; From 7e27c815979986666f78696adcfd5d13eab5df36 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Wed, 29 Oct 2025 12:03:57 +0100 Subject: [PATCH 054/174] losetup: remove the --verbose flag, as it doesn't actually do anything Fourteen years ago, commit c7e0925def rewrote the `losetup` tool, removing all references to the 'verbose' variable. Three years later, commit 60cb2c3720 removed the line 'verbose = 1' because the compiler complained that the variable was set but never used. Signed-off-by: Benno Schulenberg --- sys-utils/losetup.8.adoc | 3 --- sys-utils/losetup.c | 4 ---- 2 files changed, 7 deletions(-) diff --git a/sys-utils/losetup.8.adoc b/sys-utils/losetup.8.adoc index f51710af87b..131ebfa568c 100644 --- a/sys-utils/losetup.8.adoc +++ b/sys-utils/losetup.8.adoc @@ -106,9 +106,6 @@ Set up a read-only loop device. *--direct-io*[**=on**|*off*]:: Enable or disable direct I/O for the backing file. The default is *off*. Specifying either *--direct-io* or *--direct-io=on* will enable it. But, *--direct-io=off* can be provided to explicitly turn it off. -*-v*, *--verbose*:: -Verbose mode. - *-l*, *--list*:: If a loop device or the *-a* option is specified, print the default columns for either the specified loop device or all loop devices; the default is to print info about all devices. See also *--output*, *--noheadings*, *--raw*, and *--json*. diff --git a/sys-utils/losetup.c b/sys-utils/losetup.c index 2a3257473d2..7da0ebbd00a 100644 --- a/sys-utils/losetup.c +++ b/sys-utils/losetup.c @@ -501,7 +501,6 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" --direct-io[=] open backing file with O_DIRECT\n"), out); fputs(_(" --loop-ref loop device reference\n"), out); fputs(_(" --show print device name after setup (with -f)\n"), out); - fputs(_(" -v, --verbose verbose mode\n"), out); /* output options */ fputs(USAGE_SEPARATOR, out); @@ -730,7 +729,6 @@ int main(int argc, char **argv) { "raw", no_argument, NULL, OPT_RAW }, { "loop-ref", required_argument, NULL, OPT_REF, }, { "show", no_argument, NULL, OPT_SHOW }, - { "verbose", no_argument, NULL, 'v' }, { "version", no_argument, NULL, 'V' }, { "remove", no_argument, NULL, OPT_REMOVE }, { NULL, 0, NULL, 0 } @@ -829,8 +827,6 @@ int main(int argc, char **argv) if (use_dio) lo_flags |= LO_FLAGS_DIRECT_IO; break; - case 'v': - break; case OPT_SIZELIMIT: /* --sizelimit */ sizelimit = strtosize_or_err(optarg, _("failed to parse size")); flags |= LOOPDEV_FL_SIZELIMIT; From 3cd29d861d69b70ca5390596425d4906adbf0082 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Wed, 29 Oct 2025 12:03:58 +0100 Subject: [PATCH 055/174] losetup: (man) put the synopses in a better order, the name-giver first Also, condense the synopsis for setting up a loop device to just the essentials -- it had become so long that it was incomprehensible. Signed-off-by: Benno Schulenberg --- sys-utils/losetup.8.adoc | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/sys-utils/losetup.8.adoc b/sys-utils/losetup.8.adoc index 131ebfa568c..cecc09618d5 100644 --- a/sys-utils/losetup.8.adoc +++ b/sys-utils/losetup.8.adoc @@ -12,31 +12,27 @@ losetup - set up and control loop devices == SYNOPSIS -Get info: - -*losetup* [_loopdev_] +Set up a loop device: -*losetup* *-l* [*-a*] +*losetup* [options] *-f*|_loopdev file_ -*losetup* *-j* _file_ [*-o* _offset_] - -Detach a loop device: +Get info: -*losetup* *-d* _loopdev_ ... +*losetup* [*-l*] [*-a*|_loopdev_] -Detach all associated loop devices: +*losetup* *-j* _file_ [*-o* _offset_] -*losetup* *-D* +Recalibrate the size of a loop device: -Set up a loop device: +*losetup* *-c* _loopdev_ -*losetup* [*-o* _offset_] [*--sizelimit* _size_] [*--sector-size* _size_] [*--loop-ref* _name_] [*-Pr*] [*--show*] *-f*|_loopdev file_ +Detach loop devices: -Resize a loop device: +*losetup* *-d* _loopdev_ ... -*losetup* *-c* _loopdev_ +*losetup* *-D* -Remove a loop device: +Prevent loop devices from getting listed: *losetup* *--remove* _loopdev_ ... From ac0147fd14b348097c82c1c89a5417b582e26bad Mon Sep 17 00:00:00 2001 From: cgoesche Date: Sun, 2 Nov 2025 11:55:09 -0500 Subject: [PATCH 056/174] su: pass arguments after to shell The su(1) manpage describes how the arguments after are passed to the invoked shell. However this is empirically wrong, as option flags after are interpreted by su(1) and will eventually never be passed or yield an error that terminates the program due to an unrecognized option flag. To fix this we can change getopt(3)'s scanning mode with a '+' prefixed to 'optstring', this will make it so that getopt(3) stops processing argv elements on the first occurrence of a non-option argument, e.g. '-' or ''. Additionally, if the argument that directly follows '-' is an option flag, su(1) will assume that this argument and the ones that follow, are to be passed to a shell invoked by the root user. Addresses: https://github.com/util-linux/util-linux/pull/1809 Signed-off-by: cgoesche --- login-utils/su-common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/login-utils/su-common.c b/login-utils/su-common.c index 38d476a1a29..4d54eab31b5 100644 --- a/login-utils/su-common.c +++ b/login-utils/su-common.c @@ -1036,7 +1036,7 @@ int su_main(int argc, char **argv, int mode) su->conv.appdata_ptr = (void *) su; while ((optc = - getopt_long(argc, argv, "c:fg:G:lmpPTs:u:hVw:", longopts, + getopt_long(argc, argv, "+c:fg:G:lmpPTs:u:hVw:", longopts, NULL)) != -1) { err_exclusive_options(optc, longopts, excl, excl_st); @@ -1142,7 +1142,7 @@ int su_main(int argc, char **argv, int mode) } FALLTHROUGH; case SU_MODE: - if (optind < argc) + if (optind < argc && *argv[optind] != '-') su->new_user = argv[optind++]; break; } From 28e91d087ed1b9e3851bb16b129a1acda9253986 Mon Sep 17 00:00:00 2001 From: cgoesche Date: Sun, 2 Nov 2025 12:54:02 -0500 Subject: [PATCH 057/174] tests: (su) add more options tests Signed-off-by: cgoesche --- tests/expected/su/group-primary-login | 1 + tests/expected/su/group-primary-no-login | 1 + tests/expected/su/group-supplemental-login | 1 + tests/expected/su/group-supplemental-no-login | 1 + tests/expected/su/shell-additional-args | 1 + tests/expected/su/shell-command-option | 1 + tests/ts/su/group | 78 +++++++++++++++++++ tests/ts/su/shell | 35 +++++++++ 8 files changed, 119 insertions(+) create mode 100644 tests/expected/su/group-primary-login create mode 100644 tests/expected/su/group-primary-no-login create mode 100644 tests/expected/su/group-supplemental-login create mode 100644 tests/expected/su/group-supplemental-no-login create mode 100644 tests/expected/su/shell-additional-args create mode 100644 tests/expected/su/shell-command-option create mode 100755 tests/ts/su/group create mode 100755 tests/ts/su/shell diff --git a/tests/expected/su/group-primary-login b/tests/expected/su/group-primary-login new file mode 100644 index 00000000000..b4b6910249b --- /dev/null +++ b/tests/expected/su/group-primary-login @@ -0,0 +1 @@ +ts_grp diff --git a/tests/expected/su/group-primary-no-login b/tests/expected/su/group-primary-no-login new file mode 100644 index 00000000000..b4b6910249b --- /dev/null +++ b/tests/expected/su/group-primary-no-login @@ -0,0 +1 @@ +ts_grp diff --git a/tests/expected/su/group-supplemental-login b/tests/expected/su/group-supplemental-login new file mode 100644 index 00000000000..b4b6910249b --- /dev/null +++ b/tests/expected/su/group-supplemental-login @@ -0,0 +1 @@ +ts_grp diff --git a/tests/expected/su/group-supplemental-no-login b/tests/expected/su/group-supplemental-no-login new file mode 100644 index 00000000000..b4b6910249b --- /dev/null +++ b/tests/expected/su/group-supplemental-no-login @@ -0,0 +1 @@ +ts_grp diff --git a/tests/expected/su/shell-additional-args b/tests/expected/su/shell-additional-args new file mode 100644 index 00000000000..01dca2d74bb --- /dev/null +++ b/tests/expected/su/shell-additional-args @@ -0,0 +1 @@ +/bin/bash diff --git a/tests/expected/su/shell-command-option b/tests/expected/su/shell-command-option new file mode 100644 index 00000000000..01dca2d74bb --- /dev/null +++ b/tests/expected/su/shell-command-option @@ -0,0 +1 @@ +/bin/bash diff --git a/tests/ts/su/group b/tests/ts/su/group new file mode 100755 index 00000000000..9bb4b14f0a3 --- /dev/null +++ b/tests/ts/su/group @@ -0,0 +1,78 @@ +#!/bin/bash + +# This file is part of util-linux. +# +# This file 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 file is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# Copyright (C) 2025 Christian Goeschel Ndjomouo + +TS_TOPDIR="${0%/*}/../.." +TS_DESC="group" + +. "$TS_TOPDIR/functions.sh" +ts_init "$*" + +ts_skip_nonroot +ts_check_test_command "$TS_CMD_SU" +ts_check_prog "groupadd" +ts_check_prog "groupdel" +ts_check_prog "getent" + +TS_CMD_ID="id" + +username="$(whoami)" +grp_name="ts_grp" + +if ! groupadd --force "$grp_name"; then + ts_skip "could not create group '$grp_name'" +fi + +# Since here '-c' comes after it'll be passed to the actual shell +# instead of being interpreted by su(1). +ts_init_subtest "primary-no-login" + +"$TS_CMD_SU" --group "$grp_name" "$username" \ + -c "$TS_CMD_ID --groups --name" 2>> "$TS_ERRLOG" \ + | grep -o "$grp_name" \ + | uniq >> "$TS_OUTPUT" + +ts_finalize_subtest + +ts_init_subtest "primary-login" +"$TS_CMD_SU" --group "$grp_name" - "$username" \ + -c "$TS_CMD_ID --groups --name" 2>> "$TS_ERRLOG" \ + | grep -o "$grp_name" \ + | uniq >> "$TS_OUTPUT" + +grep -q 'Authentication failure' "$TS_ERRLOG" +[ "$?" -eq 0 ] && ts_skip_subtest "authentication failure" +ts_finalize_subtest + +ts_init_subtest "supplemental-no-login" +"$TS_CMD_SU" --supp-group "$grp_name" "$username" \ + -c "$TS_CMD_ID --groups --name" 2>> "$TS_ERRLOG" \ + | grep -o "$grp_name" \ + | uniq >> "$TS_OUTPUT" +ts_finalize_subtest + +ts_init_subtest "supplemental-login" +"$TS_CMD_SU" --supp-group "$grp_name" - "$username" \ + -c "$TS_CMD_ID --groups --name" 2>> "$TS_ERRLOG" \ + | grep -o "$grp_name" \ + | uniq >> "$TS_OUTPUT" + +grep -q 'Authentication failure' "$TS_ERRLOG" +[ "$?" -eq 0 ] && ts_skip_subtest "authentication failure" +ts_finalize_subtest + +groupdel "$grp_name" + +ts_finalize \ No newline at end of file diff --git a/tests/ts/su/shell b/tests/ts/su/shell new file mode 100755 index 00000000000..dc77b0b4fbf --- /dev/null +++ b/tests/ts/su/shell @@ -0,0 +1,35 @@ +#!/bin/bash + +# This file is part of util-linux. +# +# This file 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 file is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# Copyright (C) 2025 Christian Goeschel Ndjomouo + +TS_TOPDIR="${0%/*}/../.." +TS_DESC="shell" + +. "$TS_TOPDIR/functions.sh" +ts_init "$*" + +ts_skip_nonroot + +username="$(whoami)" + +ts_init_subtest "command-option" +"$TS_CMD_SU" --shell "/bin/bash" --command "echo \$SHELL" "$username" >> "$TS_OUTPUT" 2>> "$TS_ERRLOG" +ts_finalize_subtest + +ts_init_subtest "additional-args" +"$TS_CMD_SU" --shell "/bin/bash" "$username" -c "echo \$SHELL" >> "$TS_OUTPUT" 2>> "$TS_ERRLOG" +ts_finalize_subtest + +ts_finalize \ No newline at end of file From 52491bde50e0afadc6e8d6f840ccd17bf4df62e0 Mon Sep 17 00:00:00 2001 From: Sumanth Korikkar Date: Thu, 16 Oct 2025 17:38:01 +0200 Subject: [PATCH 058/174] lsmem: display global memmap on memory parameter Display the output of global memmap-on-memory parameter for memory hotplug. Retrieve the details via /sys/module/memory_hotplug/parameters/memmap_on_memory. lsmem RANGE SIZE STATE REMOVABLE BLOCK 0x0000000000000000-0x00000001ffffffff 8G online yes 0-63 Memory block size: 128M Total online memory: 8G Total offline memory: 0B Memmap on memory parameter: yes Signed-off-by: Sumanth Korikkar --- sys-utils/lsmem.1.adoc | 2 ++ sys-utils/lsmem.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/sys-utils/lsmem.1.adoc b/sys-utils/lsmem.1.adoc index d588051a816..9c9397631a4 100644 --- a/sys-utils/lsmem.1.adoc +++ b/sys-utils/lsmem.1.adoc @@ -28,6 +28,8 @@ Not all columns are supported on all systems. If an unsupported column is specif Use the *--help* option to see the columns description. +Memmap on memory parameter output displays the globally enabled memmap-on-memory setting for memory_hotplug. This is typically set on the kernel command line via memory_hotplug.memmap_on_memory. + == OPTIONS *-a*, *--all*:: diff --git a/sys-utils/lsmem.c b/sys-utils/lsmem.c index 39967bfc962..6151e269ff7 100644 --- a/sys-utils/lsmem.c +++ b/sys-utils/lsmem.c @@ -32,6 +32,7 @@ #include "optutils.h" #define _PATH_SYS_MEMORY "/sys/devices/system/memory" +#define _PATH_SYS_MEMMAP_PARM "/sys/module/memory_hotplug/parameters/memmap_on_memory" #define MEMORY_STATE_ONLINE 0 #define MEMORY_STATE_OFFLINE 1 @@ -306,8 +307,24 @@ static void fill_scols_table(struct lsmem *lsmem) add_scols_line(lsmem, &lsmem->blocks[i]); } +static int get_memmap_mode(char *res, char *src, int len) +{ + if (!strncmp(src, "Y", 1)) + strncpy(res, N_("yes"), len); + else if (!strncmp(src, "N", 1)) + strncpy(res, N_("no"), len); + else if (!strncmp(src, "force", 5)) + strncpy(res, N_("force"), len); + else + return -1; + return 0; +} + static void print_summary(struct lsmem *lsmem) { + char buf[8], res[8]; + FILE *memmap; + if (lsmem->bytes) { printf("%-32s %15"PRId64"\n",_("Memory block size:"), lsmem->block_size); printf("%-32s %15"PRId64"\n",_("Total online memory:"), lsmem->mem_online); @@ -327,6 +344,18 @@ static void print_summary(struct lsmem *lsmem) printf("%-32s %5s\n",_("Total offline memory:"), p); free(p); } + memmap = fopen(_PATH_SYS_MEMMAP_PARM, "r"); + if (!memmap) + return; + if (fgets(buf, sizeof(buf), memmap)) { + if (!get_memmap_mode(res, buf, sizeof(res))) { + if (lsmem->bytes) + printf("%-32s %15s\n", _("Memmap on memory parameter:"), _(res)); + else + printf("%-32s %5s\n", _("Memmap on memory parameter:"), _(res)); + } + } + fclose(memmap); } static int memory_block_get_node(struct lsmem *lsmem, char *name) From 92d018a105e0b2ee6b7bafe25681de919247373d Mon Sep 17 00:00:00 2001 From: Sumanth Korikkar Date: Thu, 16 Oct 2025 17:38:02 +0200 Subject: [PATCH 059/174] lsmem: add support to display dynamic (de)configuration of memory Extend lsmem to display (de)configured blocks and memmap_on_memory state. With the new s390 kernel interface (linux-next) ff18dcb19aab ("s390/sclp: Add support for dynamic (de)configuration of memory"), standby memory blocks are no longer pre-added at boot, but must be explicitly configured before being eligible for online/offline operations. At configuration time, users can also decide whether to use memmap-on-memory per block. Add CONFIGURED column : indicate if a memory block has been explicitly configured. Add MEMMAP-ON-MEMORY column : indicate if a memory block uses memmap-on-memory. memmap-on-memory reference: https://docs.kernel.org/admin-guide/mm/memory-hotplug.html Users can now inspect memory configuration state and retrieve memmap-on-memory state per block. lsmem -o RANGE,SIZE,STATE,BLOCK,CONFIGURED,MEMMAP-ON-MEMORY RANGE SIZE STATE BLOCK CONFIGURED MEMMAP-ON-MEMORY 0x00000000-0x7fffffff 2G online 0-15 yes no 0x80000000-0xffffffff 2G offline 16-31 no yes Memory block size: 128M Total online memory: 2G Total offline memory: 2G Memmap on memory parameter: yes Signed-off-by: Sumanth Korikkar --- sys-utils/lsmem.c | 107 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 95 insertions(+), 12 deletions(-) diff --git a/sys-utils/lsmem.c b/sys-utils/lsmem.c index 6151e269ff7..648c0bc2741 100644 --- a/sys-utils/lsmem.c +++ b/sys-utils/lsmem.c @@ -33,6 +33,7 @@ #define _PATH_SYS_MEMORY "/sys/devices/system/memory" #define _PATH_SYS_MEMMAP_PARM "/sys/module/memory_hotplug/parameters/memmap_on_memory" +#define _PATH_SYS_MEMCONFIG "/sys/firmware/memory" #define MEMORY_STATE_ONLINE 0 #define MEMORY_STATE_OFFLINE 1 @@ -59,12 +60,17 @@ struct memory_block { int nr_zones; int zones[MAX_NR_ZONES]; bool removable; + bool config; + bool memmap_on_memory; }; struct lsmem { struct path_cxt *sysmem; /* _PATH_SYS_MEMORY directory handler */ + struct path_cxt *sysmemconfig; /* _PATH_SYS_MEMCONFIG directory handler */ struct dirent **dirs; + struct dirent **memconfig_dirs; int ndirs; + int memconfig_ndirs; struct memory_block *blocks; int nblocks; uint64_t block_size; @@ -86,7 +92,10 @@ struct lsmem { split_by_state : 1, split_by_removable : 1, split_by_zones : 1, - have_zones : 1; + split_by_memmap_on_memory : 1, + split_by_config : 1, + have_zones : 1, + have_memconfig : 1; }; @@ -98,6 +107,8 @@ enum { COL_BLOCK, COL_NODE, COL_ZONES, + COL_CONFIG, + COL_MEMMAP, }; static const char *const zone_names[] = { @@ -128,6 +139,10 @@ static struct coldesc coldescs[] = { [COL_BLOCK] = { "BLOCK", 0, SCOLS_FL_RIGHT, N_("memory block number or blocks range")}, [COL_NODE] = { "NODE", 0, SCOLS_FL_RIGHT, N_("numa node of memory")}, [COL_ZONES] = { "ZONES", 0, SCOLS_FL_RIGHT, N_("valid zones for the memory range")}, + [COL_CONFIG] = { "CONFIGURED", 0, SCOLS_FL_RIGHT, + N_("configuration status of the memory range")}, + [COL_MEMMAP] = { "MEMMAP-ON-MEMORY", 0, SCOLS_FL_RIGHT, + N_("memmap-on-memory status of the memory range")}, }; /* columns[] array specifies all currently wanted output column. The columns @@ -197,6 +212,8 @@ static inline void reset_split_policy(struct lsmem *l, int enable) l->split_by_node = enable; l->split_by_removable = enable; l->split_by_zones = enable; + l->split_by_memmap_on_memory = enable; + l->split_by_config = enable; } static void set_split_policy(struct lsmem *l, int cols[], size_t ncols) @@ -219,12 +236,23 @@ static void set_split_policy(struct lsmem *l, int cols[], size_t ncols) case COL_ZONES: l->split_by_zones = 1; break; + case COL_MEMMAP: + l->split_by_memmap_on_memory = 1; + break; + case COL_CONFIG: + l->split_by_config = 1; + break; default: break; } } } +static bool skip_memconfig_column(struct lsmem *lsmem, int id) +{ + return (id == COL_MEMMAP || id == COL_CONFIG) && !lsmem->have_memconfig; +} + static void add_scols_line(struct lsmem *lsmem, struct memory_block *blk) { size_t i; @@ -237,6 +265,8 @@ static void add_scols_line(struct lsmem *lsmem, struct memory_block *blk) for (i = 0; i < ncolumns; i++) { char *str = NULL; + if (skip_memconfig_column(lsmem, get_column_id(i))) + continue; switch (get_column_id(i)) { case COL_RANGE: { @@ -292,6 +322,14 @@ static void add_scols_line(struct lsmem *lsmem, struct memory_block *blk) str = xstrdup(valid_zones); } break; + case COL_CONFIG: + if (lsmem->have_memconfig) + str = xstrdup(blk->config ? _("yes") : _("no")); + break; + case COL_MEMMAP: + if (lsmem->have_memconfig) + str = xstrdup(blk->memmap_on_memory ? _("yes") : _("no")); + break; } if (str && scols_line_refer_data(line, i, str) != 0) @@ -400,6 +438,15 @@ static int memory_block_read_attrs(struct lsmem *lsmem, char *name, if (errno) rc = -errno; + if (lsmem->have_memconfig) { + if (ul_path_readf_s32(lsmem->sysmemconfig, &x, "%s/config", name) == 0) + blk->config = x == 1; + if (ul_path_readf_s32(lsmem->sysmemconfig, &x, "%s/memmap_on_memory", name) == 0) + blk->memmap_on_memory = x == 1; + blk->state = MEMORY_STATE_OFFLINE; + if (!blk->config) + return rc; + } if (ul_path_readf_s32(lsmem->sysmem, &x, "%s/removable", name) == 0) blk->removable = x == 1; @@ -463,6 +510,10 @@ static int is_mergeable(struct lsmem *lsmem, struct memory_block *blk) return 0; } } + if (lsmem->split_by_config && curr->config != blk->config) + return 0; + if (lsmem->split_by_memmap_on_memory && curr->memmap_on_memory != blk->memmap_on_memory) + return 0; return 1; } @@ -478,11 +529,33 @@ static void free_info(struct lsmem *lsmem) free(lsmem->dirs); } +static int memory_block_filter(const struct dirent *de) +{ + if (strncmp("memory", de->d_name, 6) != 0) + return 0; + return isdigit_string(de->d_name + 6); +} + +static void read_memconfig(struct lsmem *lsmem) +{ + char dir[PATH_MAX]; + + if (!lsmem->have_memconfig) { + lsmem->memconfig_ndirs = 0; + return; + } + ul_path_get_abspath(lsmem->sysmemconfig, dir, sizeof(dir), NULL); + lsmem->memconfig_ndirs = scandir(dir, &lsmem->memconfig_dirs, + memory_block_filter, versionsort); + if (lsmem->memconfig_ndirs <= 0) + err(EXIT_FAILURE, _("Failed to read %s"), dir); +} + static void read_info(struct lsmem *lsmem) { struct memory_block blk; - char buf[128]; - int i; + char buf[128], *name; + int i, num_dirs; if (ul_path_read_buffer(lsmem->sysmem, buf, sizeof(buf), "block_size_bytes") <= 0) err(EXIT_FAILURE, _("failed to read memory block size")); @@ -492,8 +565,17 @@ static void read_info(struct lsmem *lsmem) if (errno) err(EXIT_FAILURE, _("failed to read memory block size")); - for (i = 0; i < lsmem->ndirs; i++) { - memory_block_read_attrs(lsmem, lsmem->dirs[i]->d_name, &blk); + read_memconfig(lsmem); + if (lsmem->have_memconfig) + num_dirs = lsmem->memconfig_ndirs; + else + num_dirs = lsmem->ndirs; + for (i = 0; i < num_dirs; i++) { + if (lsmem->have_memconfig) + name = lsmem->memconfig_dirs[i]->d_name; + else + name = lsmem->dirs[i]->d_name; + memory_block_read_attrs(lsmem, name, &blk); if (blk.state == MEMORY_STATE_ONLINE) lsmem->mem_online += lsmem->block_size; else @@ -508,13 +590,6 @@ static void read_info(struct lsmem *lsmem) } } -static int memory_block_filter(const struct dirent *de) -{ - if (strncmp("memory", de->d_name, 6) != 0) - return 0; - return isdigit_string(de->d_name + 6); -} - static void read_basic_info(struct lsmem *lsmem) { char dir[PATH_MAX]; @@ -696,6 +771,12 @@ int main(int argc, char **argv) lsmem->sysmem = ul_new_path(_PATH_SYS_MEMORY); if (!lsmem->sysmem) err(EXIT_FAILURE, _("failed to initialize %s handler"), _PATH_SYS_MEMORY); + lsmem->sysmemconfig = ul_new_path(_PATH_SYS_MEMCONFIG); + /* Always check for the existence of /sys/firmware/memory/memory0 first */ + if (ul_path_access(lsmem->sysmemconfig, F_OK, "memory0") == 0) + lsmem->have_memconfig = 1; + if (!lsmem->sysmemconfig) + err(EXIT_FAILURE, _("failed to initialized %s handler"), _PATH_SYS_MEMCONFIG); if (prefix && ul_path_set_prefix(lsmem->sysmem, prefix) != 0) err(EXIT_FAILURE, _("invalid argument to --sysroot")); if (!ul_path_is_accessible(lsmem->sysmem)) @@ -745,6 +826,8 @@ int main(int argc, char **argv) struct coldesc *ci = get_column_desc(i); struct libscols_column *cl; + if (skip_memconfig_column(lsmem, get_column_id(i))) + continue; cl = scols_table_new_column(lsmem->table, ci->name, ci->whint, ci->flags); if (!cl) err(EXIT_FAILURE, _("failed to initialize output column")); From bc7ff96027dfaa62c18acd4b9e5485bf875cd7ac Mon Sep 17 00:00:00 2001 From: Sumanth Korikkar Date: Thu, 16 Oct 2025 17:38:03 +0200 Subject: [PATCH 060/174] chmem: add support for dynamic (de)configuration of hotplug memory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend chmem to use the new s390 kernel interface for configuring and deconfiguring hotpluggable memory blocks, with memmap-on-memory support. Background: On s390, memmap-on-memory was introduced to ensure that the struct page array (metadata) for hotpluggable standby memory is allocated from the memory block itself. This allowed hot-add operations even under memory pressure, particularly in cases with a strong imbalance between boot-time online memory and standby memory. The original design, however, had few limitations: * All hotpluggable standby memory was added at boot. * The use of memmap-on-memory was global and static, decided at boot time. Either all standby blocks used it, or none of them did. * memmap-on-memory choice could not be changed at runtime, limiting flexibility. For example, when continuous physical memory was required later across memory blocks. The s390 kernel ff18dcb19aab ("s390/sclp: Add support for dynamic (de)configuration of memory") no longer pre-adds all standby memory at boot. Instead, users must explicitly configure a block before it can be used for online/offline actions. At configuration time, users can dynamically decide whether to use optional memmap-on-memory for each memory block, where value of 1 allocates metadata (such as struct pages array) from the hotplug memory itself, enabling hot-add operations even under memory pressure. A value of 0 stores metadata in regular system memory and enables continuous physical memory across memory blocks. s390 kernel sysfs interface to configure/deconfigure memory with memmap-on-memory support looks as shown below: 1. Configure memory echo 1 > /sys/firmware/memory/memoryX/config   2. Deconfigure memory echo 0 > /sys/firmware/memory/memoryX/config 3. Enable memmap-on-memory echo 1 > /sys/firmware/memory/memoryX/memmap_on_memory 4. Disable memmap-on-memory echo 0 > /sys/firmware/memory/memoryX/memmap_on_memory * Initial memory layout: lsmem -o RANGE,SIZE,STATE,BLOCK,CONFIGURED,MEMMAP-ON-MEMORY RANGE SIZE STATE BLOCK CONFIGURED MEMMAP-ON-MEMORY 0x00000000-0x7fffffff 2G online 0-15 yes no 0x80000000-0xffffffff 2G offline 16-31 no yes Memory block size: 128M Total online memory: 2G Total offline memory: 2G Memmap on memory parameter: yes * Configure memory with memmap-on-memory. chmem -c 128M -m 1 lsmem -o RANGE,SIZE,STATE,BLOCK,CONFIGURED,MEMMAP-ON-MEMORY RANGE SIZE STATE BLOCK CONFIGURED MEMMAP-ON-MEMORY 0x00000000-0x7fffffff 2G online 0-15 yes no 0x80000000-0x87ffffff 128M offline 16 yes yes 0x88000000-0xffffffff 1.9G offline 17-31 no yes Memory block size: 128M Total online memory: 2G Total offline memory: 2G Memmap on memory parameter: yes * Deconfigure memory chmem -g 128M lsmem -o RANGE,SIZE,STATE,BLOCK,CONFIGURED,MEMMAP-ON-MEMORY RANGE SIZE STATE BLOCK CONFIGURED MEMMAP-ON-MEMORY 0x00000000-0x7fffffff 2G online 0-15 yes no 0x80000000-0xffffffff 2G offline 16-31 no yes Memory block size: 128M Total online memory: 2G Total offline memory: 2G Memmap on memory parameter: yes * Online memory. If the memory is in deconfigured state, configure and online it. chmem -e 128M -v Memory Block 16 (0x0000000080000000-0x0000000087ffffff) configured Memory Block 16 (0x0000000080000000-0x0000000087ffffff) enabled lsmem -o RANGE,SIZE,STATE,BLOCK,CONFIGURED,MEMMAP-ON-MEMORY RANGE SIZE STATE BLOCK CONFIGURED MEMMAP-ON-MEMORY 0x00000000-0x7fffffff 2G online 0-15 yes no 0x80000000-0x87ffffff 128M online 16 yes yes 0x88000000-0xffffffff 1.9G offline 17-31 no yes Memory block size: 128M Total online memory: 2.1G Total offline memory: 1.9G Memmap on memory parameter: yes * Offline memory If the memory is in online state, then offline it and deconfigure it. chmem -d 128M -v Memory Block 16 (0x0000000080000000-0x0000000087ffffff) disabled Memory Block 16 (0x0000000080000000-0x0000000087ffffff) deconfigured lsmem -o RANGE,SIZE,STATE,BLOCK,CONFIGURED,MEMMAP-ON-MEMORY RANGE SIZE STATE BLOCK CONFIGURED MEMMAP-ON-MEMORY 0x00000000-0x7fffffff 2G online 0-15 yes no 0x80000000-0xffffffff 2G offline 16-31 no yes Memory block size: 128M Total online memory: 2G Total offline memory: 2G Memmap on memory parameter: yes Just like online and offline actions, memory configuration and deconfiguration can be controlled through similar options. Also, memmap-on-memory setting can be changed, only when the memory block is in deconfigured state. This means, it is usable only via --configure option. Signed-off-by: Sumanth Korikkar --- sys-utils/chmem.c | 371 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 342 insertions(+), 29 deletions(-) diff --git a/sys-utils/chmem.c b/sys-utils/chmem.c index bee2a90f8cb..51240bf5aef 100644 --- a/sys-utils/chmem.c +++ b/sys-utils/chmem.c @@ -37,11 +37,16 @@ #define CHMEM_EXIT_SOMEOK 64 #define _PATH_SYS_MEMORY "/sys/devices/system/memory" +#define _PATH_SYS_MEMCONFIG "/sys/firmware/memory" struct chmem_desc { struct path_cxt *sysmem; /* _PATH_SYS_MEMORY handler */ + struct path_cxt *sysmemconfig; /* _PATH_SYS_MEMCONFIG directory handler */ struct dirent **dirs; + struct dirent **memconfig_dirs; int ndirs; + int memconfig_ndirs; + int memmap_on_memory; uint64_t block_size; uint64_t start; uint64_t end; @@ -50,11 +55,14 @@ struct chmem_desc { unsigned int is_size : 1; unsigned int verbose : 1; unsigned int have_zones : 1; + unsigned int have_memconfig : 1; }; enum { CMD_MEMORY_ENABLE = 0, CMD_MEMORY_DISABLE, + CMD_MEMORY_CONFIGURE, + CMD_MEMORY_DECONFIGURE, CMD_NONE }; @@ -101,16 +109,129 @@ static void idxtostr(struct chmem_desc *desc, uint64_t idx, char *buf, size_t bu idx, start, end); } -static int chmem_size(struct chmem_desc *desc, int enable, int zone_id) +static bool chmem_memmap_enabled(struct chmem_desc *desc) +{ + if (desc->memmap_on_memory == 0 || desc->memmap_on_memory == 1) + return true; + else + return false; +} + +static int chmem_set_memmap_on_memory(struct chmem_desc *desc, char *name) +{ + int rc, index; + + index = strtou64_or_err(name + 6, _("Failed to parse index")); + rc = ul_path_writef_u64(desc->sysmemconfig, desc->memmap_on_memory, + "%s/memmap_on_memory", name); + if (rc) { + char str[64]; + idxtostr(desc, index, str, sizeof(str)); + warn(_("%s memmap-on-memory failed"), str); + } + return rc; +} + +static int chmem_config(struct chmem_desc *desc, char *name, int configure) +{ + int mblock_configured, memmap, rc, index; + char str[BUFSIZ], state[BUFSIZ]; + + index = strtou64_or_err(name + 6, _("Failed to parse index")); + idxtostr(desc, index, str, sizeof(str)); + rc = ul_path_readf_s32(desc->sysmemconfig, &mblock_configured, "%s/config", name); + if (rc) + goto out; + rc = ul_path_readf_s32(desc->sysmemconfig, &memmap, "%s/memmap_on_memory", name); + if (rc) + goto out; + if (mblock_configured) { + if (configure) { + if (chmem_memmap_enabled(desc) && + memmap != desc->memmap_on_memory) { + if (!desc->is_size || desc->verbose) + fprintf(stdout, + _("%s must be deconfigured before using -m option\n"), str); + rc = -1; + } else if (desc->is_size) { + /* + * Allow chmem_onoff_size() to proceed with + * configuring different memory blocks when the + * current block is already configured. + */ + rc = -1; + } else if (desc->verbose) { + fprintf(stdout, _("%s already configured\n"), str); + } + goto out; + } else if (ul_path_readf_buffer(desc->sysmem, state, + sizeof(state), "%s/state", name) > 0 && + strncmp("online", state, 6) == 0) { + if (!desc->is_size || desc->verbose) + fprintf(stdout, _("%s must be offline before deconfiguration\n"), str); + rc = -1; + goto out; + } + } else { + /* + * If memory block is currently in deconfigured state, set + * memmap-on-memory if -m option is enabled. + */ + if (chmem_memmap_enabled(desc)) { + rc = chmem_set_memmap_on_memory(desc, name); + if (rc) + goto out; + } else if (!configure) { + /* + * Allow chmem_onoff_size() to proceed with + * deconfiguring different memory blocks when the + * current block is already deconfigured. + */ + if (desc->is_size) + rc = -1; + else if (desc->verbose) + fprintf(stdout, _("%s already deconfigured\n"), str); + goto out; + } + } + rc = ul_path_writef_u64(desc->sysmemconfig, configure ? 1 : 0, "%s/config", name); + if (rc) { + if (!desc->is_size) { + warn(configure ? _("%s configure failed") : + _("%s deconfigure failed"), str); + } else if (desc->verbose) { + if (configure) + fprintf(stdout, _("%s configure failed\n"), str); + else + fprintf(stdout, _("%s deconfigure failed\n"), str); + } + } else if (desc->verbose) { + if (configure) + fprintf(stdout, _("%s configured\n"), str); + else + fprintf(stdout, _("%s deconfigured\n"), str); + } +out: + return rc; +} + +static int chmem_configured(struct chmem_desc *desc, char *name) +{ + int mblock_configured = 0; + + ul_path_readf_s32(desc->sysmemconfig, &mblock_configured, "%s/config", name); + return mblock_configured; +} + +static int chmem_onoff_size(struct chmem_desc *desc, int enable, int zone_id) { char *name, *onoff, line[BUFSIZ], str[BUFSIZ]; uint64_t size, index; + int i, rc = 0, ndirs; const char *zn; - int i, rc; size = desc->size; onoff = enable ? "online" : "offline"; - i = enable ? 0 : desc->ndirs - 1; if (enable && zone_id >= 0) { if (zone_id == ZONE_MOVABLE) @@ -118,15 +239,30 @@ static int chmem_size(struct chmem_desc *desc, int enable, int zone_id) else onoff = "online_kernel"; } - - for (; i >= 0 && i < desc->ndirs && size; i += enable ? 1 : -1) { - name = desc->dirs[i]->d_name; + ndirs = desc->have_memconfig ? desc->memconfig_ndirs : desc->ndirs; + i = enable ? 0 : ndirs - 1; + for (; i >= 0 && i < ndirs && size; i += enable ? 1 : -1) { + if (desc->have_memconfig) + name = desc->memconfig_dirs[i]->d_name; + else + name = desc->dirs[i]->d_name; index = strtou64_or_err(name + 6, _("Failed to parse index")); - - if (ul_path_readf_buffer(desc->sysmem, line, sizeof(line), "%s/state", name) > 0 - && strncmp(onoff, line, 6) == 0) + if (enable && desc->have_memconfig && !chmem_configured(desc, name)) { + /* Configure memory block */ + rc = chmem_config(desc, name, enable); + if (rc) + continue; + } else if (ul_path_readf_buffer(desc->sysmem, line, sizeof(line), "%s/state", name) > 0) { + if (strncmp(onoff, line, 6) == 0) + continue; + } else if (!enable) { + /* + * If /sys/devices/system/memory/memoryX is + * unavailable, memory block is offline and + * deconfigured. + */ continue; - + } if (desc->have_zones) { ul_path_readf_buffer(desc->sysmem, line, sizeof(line), "%s/valid_zones", name); if (zone_id >= 0) { @@ -143,7 +279,6 @@ static int chmem_size(struct chmem_desc *desc, int enable, int zone_id) onoff = "online"; } } - idxtostr(desc, index, str, sizeof(str)); rc = ul_path_writef_string(desc->sysmem, onoff, "%s/state", name); if (rc != 0 && desc->verbose) { @@ -157,6 +292,12 @@ static int chmem_size(struct chmem_desc *desc, int enable, int zone_id) else fprintf(stdout, _("%s disabled\n"), str); } + if (!rc && !enable && desc->have_memconfig) { + /* Deconfigure memory block */ + rc = chmem_config(desc, name, enable); + if (rc) + continue; + } if (rc == 0) size--; } @@ -175,12 +316,80 @@ static int chmem_size(struct chmem_desc *desc, int enable, int zone_id) return size == 0 ? 0 : size == desc->size ? -1 : 1; } -static int chmem_range(struct chmem_desc *desc, int enable, int zone_id) +static int chmem_config_size(struct chmem_desc *desc, int configure) +{ + uint64_t size; + char *name; + int i, rc; + + if (!desc->have_memconfig) { + if (configure) + fprintf(stdout, + _("Skip configuration — use chmem -e instead\n")); + else + fprintf(stdout, + _("Skip deconfiguration - use chmem -d instead\n")); + return -1; + } + size = desc->size; + i = configure ? 0 : desc->memconfig_ndirs - 1; + for (; i >= 0 && i < desc->memconfig_ndirs && size; i += configure ? 1 : -1) { + name = desc->memconfig_dirs[i]->d_name; + rc = chmem_config(desc, name, configure); + if (rc == 0) + size--; + } + if (size) { + uint64_t bytes; + char *sizestr; + + bytes = (desc->size - size) * desc->block_size; + sizestr = size_to_human_string(SIZE_SUFFIX_1LETTER, bytes); + if (configure) + fprintf(stdout, _("Could only configure %s of memory\n"), sizestr); + else + fprintf(stdout, _("Could only deconfigure %s of memory\n"), sizestr); + free(sizestr); + } + return size == 0 ? 0 : size == desc->size ? -1 : 1; +} + +static int chmem_config_range(struct chmem_desc *desc, int configure) +{ + uint64_t index, todo; + char *name; + int rc, i; + + if (!desc->have_memconfig) { + if (configure) + fprintf(stdout, + _("Skip configuration — use chmem -e instead\n")); + else + fprintf(stdout, + _("Skip deconfiguration - use chmem -d instead\n")); + return -1; + } + todo = desc->end - desc->start + 1; + for (i = 0; i < desc->memconfig_ndirs; i++) { + name = desc->memconfig_dirs[i]->d_name; + index = strtou64_or_err(name + 6, _("Failed to parse index")); + if (index < desc->start) + continue; + if (index > desc->end) + break; + rc = chmem_config(desc, name, configure); + if (rc == 0) + todo--; + } + return todo == 0 ? 0 : todo == desc->end - desc->start + 1 ? -1 : 1; +} + +static int chmem_onoff_range(struct chmem_desc *desc, int enable, int zone_id) { char *name, *onoff, line[BUFSIZ], str[BUFSIZ]; uint64_t index, todo; + int i, rc, ndirs; const char *zn; - int i, rc; todo = desc->end - desc->start + 1; onoff = enable ? "online" : "offline"; @@ -192,22 +401,43 @@ static int chmem_range(struct chmem_desc *desc, int enable, int zone_id) onoff = "online_kernel"; } - for (i = 0; i < desc->ndirs; i++) { - name = desc->dirs[i]->d_name; + ndirs = desc->have_memconfig ? desc->memconfig_ndirs : desc->ndirs; + for (i = 0; i < ndirs; i++) { + name = desc->have_memconfig ? desc->memconfig_dirs[i]->d_name : + desc->dirs[i]->d_name; index = strtou64_or_err(name + 6, _("Failed to parse index")); if (index < desc->start) continue; if (index > desc->end) break; + if (enable && desc->have_memconfig && !chmem_configured(desc, name)) { + /* Configure memory block */ + rc = chmem_config(desc, name, enable); + if (rc) + continue; + } idxtostr(desc, index, str, sizeof(str)); - if (ul_path_readf_buffer(desc->sysmem, line, sizeof(line), "%s/state", name) > 0 - && strncmp(onoff, line, 6) == 0) { - if (desc->verbose && enable) - fprintf(stdout, _("%s already enabled\n"), str); - else if (desc->verbose && !enable) - fprintf(stdout, _("%s already disabled\n"), str); - todo--; - continue; + if (ul_path_readf_buffer(desc->sysmem, line, sizeof(line), "%s/state", name) > 0) { + if (strncmp(onoff, line, 6) == 0) { + if (desc->verbose && enable) + fprintf(stdout, _("%s already enabled\n"), str); + else if (desc->verbose && !enable) + fprintf(stdout, _("%s already disabled\n"), str); + todo--; + continue; + } + } else { + /* + * If /sys/devices/system/memory/memoryX is + * unavailable, memory block is offline and + * deconfigured. + */ + if (!enable) { + if (desc->verbose) + fprintf(stdout, _("%s already disabled\n"), str); + todo--; + continue; + } } if (desc->have_zones) { @@ -243,6 +473,12 @@ static int chmem_range(struct chmem_desc *desc, int enable, int zone_id) else fprintf(stdout, _("%s disabled\n"), str); } + if (!rc && !enable && desc->have_memconfig) { + /* Deconfigure memory block */ + rc = chmem_config(desc, name, enable); + if (rc) + continue; + } if (rc == 0) todo--; } @@ -256,6 +492,16 @@ static int filter(const struct dirent *de) return isdigit_string(de->d_name + 6); } +static void read_conf(struct chmem_desc *desc) +{ + if (!desc->have_memconfig) + return; + desc->memconfig_ndirs = scandir(_PATH_SYS_MEMCONFIG, &desc->memconfig_dirs, + filter, versionsort); + if (desc->memconfig_ndirs <= 0) + err(EXIT_FAILURE, _("Failed to read %s"), _PATH_SYS_MEMCONFIG); +} + static void read_info(struct chmem_desc *desc) { char line[128]; @@ -269,6 +515,7 @@ static void read_info(struct chmem_desc *desc) desc->block_size = strtoumax(line, NULL, 16); if (errno) goto fail; + read_conf(desc); return; fail: err(EXIT_FAILURE, _("Failed to read %s"), _PATH_SYS_MEMORY); @@ -347,6 +594,9 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -d, --disable disable memory\n"), out); fputs(_(" -b, --blocks use memory blocks\n"), out); fputs(_(" -z, --zone select memory zone (see below)\n"), out); + fputs(_(" -c, --configure configure range\n"), out); + fputs(_(" -g, --deconfigure deconfigure range\n"), out); + fputs(_(" -m, --memmap-on-memory select memmap-on-memory\n"), out); fputs(_(" -v, --verbose verbose output\n"), out); fprintf(out, USAGE_HELP_OPTIONS(20)); @@ -359,6 +609,52 @@ static void __attribute__((__noreturn__)) usage(void) exit(EXIT_SUCCESS); } +static int chmem_range(struct chmem_desc *desc, int cmd, int zone_id) +{ + int rc = -1; + + switch (cmd) { + case CMD_MEMORY_ENABLE: + rc = chmem_onoff_range(desc, 1, zone_id); + break; + case CMD_MEMORY_DISABLE: + rc = chmem_onoff_range(desc, 0, zone_id); + break; + case CMD_MEMORY_CONFIGURE: + rc = chmem_config_range(desc, 1); + break; + case CMD_MEMORY_DECONFIGURE: + rc = chmem_config_range(desc, 0); + break; + default: + break; + } + return rc; +} + +static int chmem_size(struct chmem_desc *desc, int cmd, int zone_id) +{ + int rc = -1; + + switch (cmd) { + case CMD_MEMORY_ENABLE: + rc = chmem_onoff_size(desc, 1, zone_id); + break; + case CMD_MEMORY_DISABLE: + rc = chmem_onoff_size(desc, 0, zone_id); + break; + case CMD_MEMORY_CONFIGURE: + rc = chmem_config_size(desc, 1); + break; + case CMD_MEMORY_DECONFIGURE: + rc = chmem_config_size(desc, 0); + break; + default: + break; + } + return rc; +} + int main(int argc, char **argv) { struct chmem_desc _desc = { 0 }, *desc = &_desc; @@ -374,11 +670,15 @@ int main(int argc, char **argv) {"verbose", no_argument, NULL, 'v'}, {"version", no_argument, NULL, 'V'}, {"zone", required_argument, NULL, 'z'}, + {"configure", no_argument, NULL, 'c'}, + {"deconfigure", no_argument, NULL, 'g'}, + {"memmap-on-memory", required_argument, NULL, 'm'}, {NULL, 0, NULL, 0} }; static const ul_excl_t excl[] = { /* rows and cols in ASCII order */ - { 'd','e' }, + { 'd', 'e', 'g', 'm' }, + { 'c', 'd', 'e', 'g' }, { 0 } }; int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT; @@ -389,13 +689,18 @@ int main(int argc, char **argv) close_stdout_atexit(); ul_path_init_debug(); + desc->memmap_on_memory = -1; desc->sysmem = ul_new_path(_PATH_SYS_MEMORY); if (!desc->sysmem) err(EXIT_FAILURE, _("failed to initialize %s handler"), _PATH_SYS_MEMORY); - + desc->sysmemconfig = ul_new_path(_PATH_SYS_MEMCONFIG); + if (!desc->sysmemconfig) + err(EXIT_FAILURE, _("failed to initialize %s handler"), _PATH_SYS_MEMCONFIG); + if (ul_path_access(desc->sysmemconfig, F_OK, "memory0") == 0) + desc->have_memconfig = 1; read_info(desc); - while ((c = getopt_long(argc, argv, "bdehvVz:", longopts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "bcdeghm:vVz:", longopts, NULL)) != -1) { err_exclusive_options(c, longopts, excl, excl_st); @@ -415,7 +720,15 @@ int main(int argc, char **argv) case 'z': zone = xstrdup(optarg); break; - + case 'c': + cmd = CMD_MEMORY_CONFIGURE; + break; + case 'g': + cmd = CMD_MEMORY_DECONFIGURE; + break; + case 'm': + desc->memmap_on_memory = atoi(optarg); + break; case 'h': usage(); case 'V': @@ -448,9 +761,9 @@ int main(int argc, char **argv) } if (desc->is_size) - rc = chmem_size(desc, cmd == CMD_MEMORY_ENABLE ? 1 : 0, zone_id); + rc = chmem_size(desc, cmd, zone_id); else - rc = chmem_range(desc, cmd == CMD_MEMORY_ENABLE ? 1 : 0, zone_id); + rc = chmem_range(desc, cmd, zone_id); ul_unref_path(desc->sysmem); From e896d7b8a3ca71e1a565f7f539059fcd8b4a6251 Mon Sep 17 00:00:00 2001 From: Sumanth Korikkar Date: Thu, 16 Oct 2025 17:38:04 +0200 Subject: [PATCH 061/174] chmem: add chmem documentation for dynamic (de)configuration of memory Describe chmem configure, deconfigure and memmap-on-memory options: ff18dcb19aab ("s390/sclp: Add support for dynamic (de)configuration of memory") s390 kernel no longer pre-adds all standby memory at boot. Instead, users must explicitly configure a block before it can be used for online/offline actions. At configuration time, users can dynamically decide whether to use optional memmap-on-memory for each memory block, where value of 1 allocates metadata (such as struct pages array) from the hotplug memory itself, enabling hot-add operations even under memory pressure. A value of 0 stores metadata in regular system memory, which may require additional free memory, but enables continuous physical memory across memory blocks. Add documentation to reflect the following options: * chmem --configure 128M --memmap-on-memory 1 * chmem --deconfigure 128M * chmem --enable 128M # implicitly configure memory if supported by architecture and online it * chmem --disable 128M # offline memory and implicitly deconfigure if supported by the architecture. Just like online and offline actions, memory configuration and deconfiguration can be controlled through similar options. Also, memmap-on-memory setting can be changed, only when the memory block is in deconfigured state. This means, it is usable only via --configure option. Reviewed-by: Maria Eisenhaendler Signed-off-by: Sumanth Korikkar --- sys-utils/chmem.8.adoc | 47 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/sys-utils/chmem.8.adoc b/sys-utils/chmem.8.adoc index 5067a98b87d..537beec63a2 100644 --- a/sys-utils/chmem.8.adoc +++ b/sys-utils/chmem.8.adoc @@ -12,7 +12,7 @@ chmem - configure memory == SYNOPSIS -*chmem* [*-h*] [*-V*] [*-v*] [*-e*|*-d*] [_SIZE_|_RANGE_|*-b* _BLOCKRANGE_] [*-z* _ZONE_] +*chmem* [*-h*] [*-V*] [*-v*] [*-c*|*-e*|*-d*|*-g*] [_SIZE_|_RANGE_|*-b* _BLOCKRANGE_] [*-z* _ZONE_] [*-m* _MEMMAP-ON-MEMORY_] == DESCRIPTION @@ -26,23 +26,48 @@ The *chmem* command sets a particular size or range of memory online or offline. * Specify _ZONE_ as the name of a memory zone, as shown in the output of the *lsmem -o +ZONES* command. The output shows one or more valid memory zones for each memory range. If multiple zones are shown, then the memory range currently belongs to the first zone. By default, *chmem* will set memory online to the zone Movable, if this is among the valid zones. This default can be changed by specifying the *--zone* option with another valid zone. For memory ballooning, it is recommended to select the zone Movable for memory online and offline, if possible. Memory in this zone is much more likely to be able to be offlined again, but it cannot be used for arbitrary kernel allocations, only for migratable pages (e.g., anonymous and page cache pages). Use the *--help* option to see all available zones. +* Specify _MEMMAP-ON-MEMORY_ as 1 or 0. A value of 1 allocates hotplug metadata (such as the struct pages array) from the hotplug memory itself, enabling hot-add operations even under memory pressure and without requiring additional system memory to do so. A value of 0 stores hotplugged memory metadata in regular system memory, which helps avoid issues related to fragmentation of continuous physical memory across memory blocks. The value can only be set when the memory block is in a deconfigured state, and *--memmap-on-memory* is valid only with *--configure*. If not specified, and if supported, *chmem* uses the default value shown in *lsmem* output. + +The *--enable* option configures the memory, if this is supported by the architecture. If configuring memory is not supported by the architecture, *--enable* still brings the memory online. + +The *--disable* option brings the memory offline and performs an optional deconfigure step if this is supported by the architecture. + +The *--configure* option requests memory from the hypervisor without bringing it online, when supported by the architecture, allowing explicit control and use of *--memmap-on-memory*. + +The *--deconfigure* option returns memory resources to the hypervisor if supported by the architecture. + _SIZE_ and _RANGE_ must be aligned to the Linux memory block size, as shown in the output of the *lsmem*(1) command. Setting memory online can fail for various reasons. On virtualized systems it can fail if the hypervisor does not have enough memory left, for example because memory was overcommitted. Setting memory offline can fail if Linux cannot free the memory. If only part of the requested memory can be set online or offline, a message tells you how much memory was set online or offline instead of the requested amount. -When setting memory online *chmem* starts with the lowest memory block numbers. When setting memory offline *chmem* starts with the highest memory block numbers. +When setting memory online or when configuring memory, *chmem* starts with the lowest memory block numbers. When setting memory offline or deconfiguring memory, *chmem* starts with the highest memory block numbers. + +== ARCHITECTURE + +* s390 architecture: + +_MEMMAP-ON-MEMORY_: For memory blocks configured online at boot, the default value is 0 because they are added without memmap-on-memory support. Memory added dynamically at runtime uses the default value displayed in *lsmem* output. == OPTIONS *-b*, *--blocks*:: Use a _BLOCKRANGE_ parameter instead of _RANGE_ or _SIZE_ for the *--enable* and *--disable* options. +*-c*, *--configure*:: +Set the specified _RANGE_, _SIZE_, or _BLOCKRANGE_ of memory to be configured. + *-d*, *--disable*:: Set the specified _RANGE_, _SIZE_, or _BLOCKRANGE_ of memory offline. *-e*, *--enable*:: Set the specified _RANGE_, _SIZE_, or _BLOCKRANGE_ of memory online. +*-g*, *--deconfigure*:: +Set the specified _RANGE_, _SIZE_, or _BLOCKRANGE_ of memory to be deconfigured. + +*-m*, *--memmap-on-memory*:: +Select memmap-on-memory for the specified _RANGE_, _SIZE_, or _BLOCKRANGE_ of memory. This option is valid only with *--configure*. + *-z*, *--zone*:: Select the memory _ZONE_ where to set the specified _RANGE_, _SIZE_, or _BLOCKRANGE_ of memory online or offline. By default, memory will be set online to the zone Movable, if possible. @@ -70,13 +95,25 @@ partial success This command requests 1024 MiB of memory to be set online. *chmem -e 2g*:: -This command requests 2 GiB of memory to be set online. +This command requests 2 GB of memory to be brought online and, if supported by the architecture, configures the memory beforehand. *chmem --disable 0x00000000e4000000-0x00000000f3ffffff*:: -This command requests the memory range starting with 0x00000000e4000000 and ending with 0x00000000f3ffffff to be set offline. +This command takes the memory range from 0x00000000e4000000 to 0x00000000f3ffffff offline and deconfigures it if supported by the architecture. *chmem -b -d 10*:: -This command requests the memory block number 10 to be set offline. +This command takes memory block number 10 offline. + +*chmem -b -c 10 -m 1*:: +This command configures memory block 10 with  _MEMMAP-ON-MEMORY_ set. The block must be in a deconfigured state. + +*chmem -b -c 10*:: +This command configures memory block 10 with the default _MEMMAP-ON-MEMORY_ setting. The default value is displayed in *lsmem --output-all*. The block must be in a deconfigured state. + +*chmem -b -g 10*:: +This command deconfigures memory block 10. The block must be offline. + +*chmem -d 5g*:: +This command takes 5 GB of memory offline and deconfigures it if supported by the architecture. Blocks that are already offline but still configured are skipped and must be explicitly deconfigured with *--deconfigure*. == SEE ALSO From 6f1e4ff0545d5ee3a3b4a8358fd28e49721861fa Mon Sep 17 00:00:00 2001 From: Sumanth Korikkar Date: Thu, 16 Oct 2025 17:38:05 +0200 Subject: [PATCH 062/174] lsmem: add doc for dynamic (de)configuration and memmap-on-memory support lsmem --output-all now displays two new columns: CONFIGURED : yes/no indicating if a memory block has been explicitly configured. MEMMAP-ON-MEMORY : yes/no indicating whether the block uses memmap-on-memory. lsmem -o RANGE,SIZE,STATE,BLOCK,CONFIGURED,MEMMAP-ON-MEMORY RANGE SIZE STATE BLOCK CONFIGURED MEMMAP-ON-MEMORY 0x00000000-0x7fffffff 2G online 0-15 yes no 0x80000000-0xffffffff 2G offline 16-31 no yes Memory block size: 128M Total online memory: 2G Total offline memory: 2G Memmap on memory parameter: yes Add documentation for new fields. Reviewed-by: Maria Eisenhaendler Signed-off-by: Sumanth Korikkar --- sys-utils/lsmem.1.adoc | 44 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/sys-utils/lsmem.1.adoc b/sys-utils/lsmem.1.adoc index 9c9397631a4..e7226725a3b 100644 --- a/sys-utils/lsmem.1.adoc +++ b/sys-utils/lsmem.1.adoc @@ -24,7 +24,45 @@ The *lsmem* command lists a new memory range always when the current memory bloc Note that some output columns may provide inaccurate information if a split policy forces *lsmem* to ignore differences in some attributes. For example if you merge removable and non-removable memory blocks to the one range than all the range will be marked as non-removable on *lsmem* output. -Not all columns are supported on all systems. If an unsupported column is specified, *lsmem* prints the column but does not provide any data for it. +The supported columns are RANGE, SIZE, STATE, REMOVABLE, BLOCK, NODE, ZONES, CONFIGURED, MEMMAP-ON-MEMORY. +RANGE +The start and end physical address of the memory range. + +SIZE +The size of the memory range, representing the total amount of memory in that range. + +STATE +The current online status of the memory range. Common states include online, offline or transitional states. + +BLOCK +The specific memory block number. + +NODE +The NUMA (Non-Uniform Memory Access) node to which the memory block belongs. + +ZONES +The memory zones to which the blocks belongs, such as DMA, Normal, Movable. + +CONFIGURED +The configuration state of a memory block. Refer to *chmem* for details on configuring or deconfiguring memory blocks. + +MEMMAP-ON-MEMORY +The memmap-on-memory state of the memory block at configuration time. This setting indicates where memory hotplug stores its internal metadata (the struct pages array or memmap). If MEMMAP-ON-MEMORY is set to 1, the metadata is allocated directly from the newly added hotplugged memory, enabling hot-add operations even when the system is under high memory pressure. If set to 0, the memmap metadata is allocated from existing system memory. + +Possible BLOCK, CONFIGURED, STATE, MEMMAP-ON-MEMORY states:: + +[cols="10,10,10,15,60", options="header"] +|=== +| BLOCK | STATE | CONFIGURED | MEMMAP-ON-MEMORY | Description + +| 0 | online | yes | yes/no | The memory is configured with memmap-on-memory set to (1 or 0) and memory is currently online. + +| 1 | offline | yes | yes/no | The memory is configured, but memory is offline. + +| 2 | offline | no | yes/no | The memory is offline and deconfigured. +|=== + +Not all columns are supported on all systems. If an unsupported column is specified, *lsmem* prints the column but does not provide any data for it. Additionally, *lsmem* may skip columns like CONFIGURED or MEMMAP-ON-MEMORY if these states are not relevant to the system's architecture. Use the *--help* option to see the columns description. @@ -45,7 +83,7 @@ Use JSON output format. Do not print a header line. *-o*, *--output* _list_:: -Specify which output columns to print. Use *--help* to get a list of all supported columns. The default list of columns may be extended if _list_ is specified in the format **+**__list__ (e.g., *lsmem -o +NODE*). +Specify which output columns to print. Use *--help* to obtain a list of all supported columns. To extend the default list of columns specify _list_ in the format **+**__list__. For example, *lsmem -o +NODE*. *--output-all*:: Output all available columns. @@ -57,7 +95,7 @@ Produce output in the form of key="value" pairs. All potentially unsafe value ch Produce output in raw format. All potentially unsafe characters are hex-escaped (\x). *-S*, *--split* _list_:: -Specify which columns (attributes) use to split memory blocks to ranges. The supported columns are STATE, REMOVABLE, NODE and ZONES, or "none". The other columns are silently ignored. For more details see *DESCRIPTION* above. +Specify which columns are used to split memory blocks to ranges. The supported columns are STATE, REMOVABLE, NODE, ZONES, CONFIGURED, MEMMAP-ON-MEMORY or "none". The other columns are silently ignored. For more details see *DESCRIPTION* above. *-s*, *--sysroot* _directory_:: Gather memory data for a Linux instance other than the instance from which the *lsmem* command is issued. The specified _directory_ is the system root of the Linux instance to be inspected. From 3b9ec52f3b89ffe8f93e3b3699375a38c194023f Mon Sep 17 00:00:00 2001 From: Sumanth Korikkar Date: Thu, 16 Oct 2025 17:38:06 +0200 Subject: [PATCH 063/174] lsmem,chmem: add configure/deconfigure bash completion options Add bash completion for configure/deconfigure options in chmem and lsmem. Signed-off-by: Sumanth Korikkar --- bash-completion/chmem | 3 +++ bash-completion/lsmem | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/bash-completion/chmem b/bash-completion/chmem index 3e3af87acaa..f10646677e1 100644 --- a/bash-completion/chmem +++ b/bash-completion/chmem @@ -14,6 +14,9 @@ _chmem_module() OPTS=" --enable --disable + --configure + --deconfigure + --memmap-on-memory --blocks --verbose --zone diff --git a/bash-completion/lsmem b/bash-completion/lsmem index 7d6e8424785..185a15fd2fb 100644 --- a/bash-completion/lsmem +++ b/bash-completion/lsmem @@ -9,7 +9,7 @@ _lsmem_module() local prefix realcur OUTPUT_ALL OUTPUT realcur="${cur##*,}" prefix="${cur%$realcur}" - OUTPUT_ALL='RANGE SIZE STATE REMOVABLE BLOCK NODE ZONES' + OUTPUT_ALL='RANGE SIZE STATE REMOVABLE BLOCK NODE ZONES CONFIGURED MEMMAP-ON-MEMORY' for WORD in $OUTPUT_ALL; do if ! [[ $prefix == *"$WORD"* ]]; then OUTPUT="$WORD ${OUTPUT:-""}" From 21cdb170b850be964ceb7a02f96efb6a035b8be1 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Fri, 7 Nov 2025 10:28:14 +0100 Subject: [PATCH 064/174] lsmem: use xstrncpy() Signed-off-by: Karel Zak --- sys-utils/lsmem.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sys-utils/lsmem.c b/sys-utils/lsmem.c index 648c0bc2741..79d90ff5572 100644 --- a/sys-utils/lsmem.c +++ b/sys-utils/lsmem.c @@ -348,11 +348,11 @@ static void fill_scols_table(struct lsmem *lsmem) static int get_memmap_mode(char *res, char *src, int len) { if (!strncmp(src, "Y", 1)) - strncpy(res, N_("yes"), len); + xstrncpy(res, N_("yes"), len); else if (!strncmp(src, "N", 1)) - strncpy(res, N_("no"), len); + xstrncpy(res, N_("no"), len); else if (!strncmp(src, "force", 5)) - strncpy(res, N_("force"), len); + xstrncpy(res, N_("force"), len); else return -1; return 0; From abfce923bb66aa2a95264867e34ca5051031452b Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Mon, 3 Nov 2025 13:41:31 +0100 Subject: [PATCH 065/174] include/optutils: improve err_exclusive_options() output OLD: $ losetup --remove --detach loop0 losetup: mutually exclusive arguments: --detach-all --all --set-capacity --detach --find --associated --remove NEW: $ losetup --remove --detach loop0 losetup: options --detach and --remove cannot be combined. Suggested-by: Benno Schulenberg Signed-off-by: Karel Zak --- include/optutils.h | 45 +++++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/include/optutils.h b/include/optutils.h index 6fe4aeb7a51..87d20d0d533 100644 --- a/include/optutils.h +++ b/include/optutils.h @@ -11,7 +11,11 @@ #include "nls.h" #include "cctype.h" -static inline const char *option_to_longopt(int c, const struct option *opts) +/* + * Converts the short option @c to the corresponding long option from @opts, or + * returns NULL. + */ +static inline const char *ul_get_longopt(const struct option *opts, int c) { const struct option *o; @@ -22,6 +26,19 @@ static inline const char *option_to_longopt(int c, const struct option *opts) return NULL; } +/* + * Converts the short options @c to "%c" or "0x" if not printable. + */ +static inline const char *ul_get_shortopt(char *buf, size_t bufsz, int c) +{ + if (c_isgraph(c)) + snprintf(buf, bufsz, "%c", c); + else + snprintf(buf, bufsz, "<0x%02x>", c); /* should not happen */ + + return buf; +} + #ifndef OPTUTILS_EXIT_CODE # define OPTUTILS_EXIT_CODE EXIT_FAILURE #endif @@ -84,23 +101,16 @@ static inline void err_exclusive_options( if (status[e] == 0) status[e] = c; else if (status[e] != c) { - size_t ct = 0; + const char *a = ul_get_longopt(opts, status[e]); + const char *b = ul_get_longopt(opts, c); + char buf[16]; /* short option in hex */ - fprintf(stderr, _("%s: mutually exclusive " - "arguments:"), - program_invocation_short_name); - - for (op = excl[e]; - ct + 1 < ARRAY_SIZE(excl[0]) && *op; - op++, ct++) { - const char *n = option_to_longopt(*op, opts); - if (n) - fprintf(stderr, " --%s", n); - else if (c_isgraph(*op)) - fprintf(stderr, " -%c", *op); - } - fputc('\n', stderr); - exit(OPTUTILS_EXIT_CODE); + errx(OPTUTILS_EXIT_CODE, + _("options %s%s and %s%s cannot be combined"), + a ? "--" : "-", + a ? a : ul_get_shortopt(buf, sizeof(buf), status[e]), + b ? "--" : "-", + b ? b : ul_get_shortopt(buf, sizeof(buf), c)); } break; } @@ -108,4 +118,3 @@ static inline void err_exclusive_options( } #endif - From 255a2d71d54f9e293a562e07ada3e32703196a6a Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Fri, 7 Nov 2025 11:35:12 +0100 Subject: [PATCH 066/174] cal: improve header color printing It's more robust to avoid using line breaks within the colored area. Fixes: https://github.com/util-linux/util-linux/issues/3844 Signed-off-by: Karel Zak --- misc-utils/cal.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/misc-utils/cal.c b/misc-utils/cal.c index 09622165a4d..c264610671f 100644 --- a/misc-utils/cal.c +++ b/misc-utils/cal.c @@ -778,27 +778,35 @@ static void cal_output_header(struct cal_month *month, const struct cal_control char out[FMT_ST_CHARS]; struct cal_month *i; - cal_enable_color(CAL_COLOR_HEADER); if (ctl->header_hint || ctl->header_year) { + cal_enable_color(CAL_COLOR_HEADER); for (i = month; i; i = i->next) { snprintf(out, sizeof(out), "%s", ctl->full_month[i->month - 1]); center(out, ctl->week_width, i->next == NULL ? 0 : ctl->gutter_width); } + cal_disable_color(CAL_COLOR_HEADER); + if (!ctl->header_year) { fputc('\n', stdout); + cal_enable_color(CAL_COLOR_HEADER); for (i = month; i; i = i->next) { snprintf(out, sizeof(out), "%04d", i->year); center(out, ctl->week_width, i->next == NULL ? 0 : ctl->gutter_width); } + cal_disable_color(CAL_COLOR_HEADER); } } else { + cal_enable_color(CAL_COLOR_HEADER); for (i = month; i; i = i->next) { snprintf(out, sizeof(out), "%s %04d", ctl->full_month[i->month - 1], i->year); center(out, ctl->week_width, i->next == NULL ? 0 : ctl->gutter_width); } + cal_disable_color(CAL_COLOR_HEADER); } fputc('\n', stdout); + + cal_enable_color(CAL_COLOR_HEADER); for (i = month; i; i = i->next) { if (ctl->weektype) { if (ctl->julian) @@ -821,20 +829,25 @@ static void cal_vert_output_header(struct cal_month *month, struct cal_month *m; int month_width; - cal_enable_color(CAL_COLOR_HEADER); month_width = ctl->day_width * (MAXDAYS / DAYS_IN_WEEK); /* Padding for the weekdays */ + cal_enable_color(CAL_COLOR_HEADER); printf("%*s", (int)ctl->day_width + 1, ""); + cal_disable_color(CAL_COLOR_HEADER); if (ctl->header_hint || ctl->header_year) { + cal_enable_color(CAL_COLOR_HEADER); for (m = month; m; m = m->next) { snprintf(out, sizeof(out), "%s", ctl->full_month[m->month - 1]); left(out, month_width, ctl->gutter_width); } + cal_disable_color(CAL_COLOR_HEADER); + if (!ctl->header_year) { fputc('\n', stdout); + cal_enable_color(CAL_COLOR_HEADER); /* Padding for the weekdays */ printf("%*s", (int)ctl->day_width + 1, ""); @@ -842,15 +855,17 @@ static void cal_vert_output_header(struct cal_month *month, snprintf(out, sizeof(out), "%04d", m->year); left(out, month_width, ctl->gutter_width); } + cal_disable_color(CAL_COLOR_HEADER); } } else { + cal_enable_color(CAL_COLOR_HEADER); for (m = month; m; m = m->next) { snprintf(out, sizeof(out), "%s %04d", ctl->full_month[m->month - 1], m->year); left(out, month_width, ctl->gutter_width); } + cal_disable_color(CAL_COLOR_HEADER); } - cal_disable_color(CAL_COLOR_HEADER); fputc('\n', stdout); } From c4d255b8ba067cdcd504f85dfac2e1c454c5e6b1 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Fri, 7 Nov 2025 11:41:21 +0100 Subject: [PATCH 067/174] tests: update lsmem outputs Signed-off-by: Karel Zak --- tests/expected/lsmem/lsmem-s390-zvm-6g | 6 ++++++ tests/expected/lsmem/lsmem-x86_64-16g | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/tests/expected/lsmem/lsmem-s390-zvm-6g b/tests/expected/lsmem/lsmem-s390-zvm-6g index ac576e1ab5b..4fcdc718cb0 100644 --- a/tests/expected/lsmem/lsmem-s390-zvm-6g +++ b/tests/expected/lsmem/lsmem-s390-zvm-6g @@ -17,6 +17,7 @@ RANGE SIZE STATE REMOVABLE BLOCK Memory block size: 256M Total online memory: 4.8G Total offline memory: 1.3G +Memmap on memory parameter: no --- @@ -27,6 +28,7 @@ RANGE SIZE Memory block size: 256M Total online memory: 4.8G Total offline memory: 1.3G +Memmap on memory parameter: no --- @@ -40,6 +42,7 @@ RANGE SIZE STATE Memory block size: 256M Total online memory: 4.8G Total offline memory: 1.3G +Memmap on memory parameter: no --- @@ -73,6 +76,7 @@ RANGE SIZE STATE REMOVABLE BLOCK NODE Memory block size: 256M Total online memory: 4.8G Total offline memory: 1.3G +Memmap on memory parameter: no --- @@ -216,6 +220,7 @@ RANGE SIZE STATE REMOVABLE BLOCK ZON Memory block size: 256M Total online memory: 4.8G Total offline memory: 1.3G +Memmap on memory parameter: no --- @@ -235,3 +240,4 @@ RANGE SIZE STATE REMOVABLE BLOCK Memory block size: 256M Total online memory: 4.8G Total offline memory: 1.3G +Memmap on memory parameter: no diff --git a/tests/expected/lsmem/lsmem-x86_64-16g b/tests/expected/lsmem/lsmem-x86_64-16g index 663a8fe1dae..955ad958128 100644 --- a/tests/expected/lsmem/lsmem-x86_64-16g +++ b/tests/expected/lsmem/lsmem-x86_64-16g @@ -37,6 +37,7 @@ RANGE SIZE STATE REMOVABLE BLOCK Memory block size: 128M Total online memory: 16G Total offline memory: 0B +Memmap on memory parameter: no --- @@ -48,6 +49,7 @@ RANGE SIZE Memory block size: 128M Total online memory: 16G Total offline memory: 0B +Memmap on memory parameter: no --- @@ -59,6 +61,7 @@ RANGE SIZE STATE Memory block size: 128M Total online memory: 16G Total offline memory: 0B +Memmap on memory parameter: no --- @@ -196,6 +199,7 @@ RANGE SIZE STATE REMOVABLE BLOCK NODE ZONES Memory block size: 128M Total online memory: 16G Total offline memory: 0B +Memmap on memory parameter: no --- @@ -519,6 +523,7 @@ RANGE SIZE STATE REMOVABLE BLOCK ZONES Memory block size: 128M Total online memory: 16G Total offline memory: 0B +Memmap on memory parameter: no --- @@ -558,3 +563,4 @@ RANGE SIZE STATE REMOVABLE BLOCK Memory block size: 128M Total online memory: 16G Total offline memory: 0B +Memmap on memory parameter: no From 3636e6de6e1e3c8e6d7c51808bcecc8549665c8e Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Fri, 7 Nov 2025 11:57:58 +0100 Subject: [PATCH 068/174] login: add line break after timeout message Just to make login(1) more user-friendly for those who do crazy things. Based on https://github.com/util-linux/util-linux/pull/3842 Signed-off-by: Karel Zak --- login-utils/login.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/login-utils/login.c b/login-utils/login.c index ee42d081cbf..402e178201e 100644 --- a/login-utils/login.c +++ b/login-utils/login.c @@ -1340,7 +1340,7 @@ static void initialize(int argc, char **argv, struct login_context *cxt) timeout = (unsigned int)getlogindefs_num("LOGIN_TIMEOUT", LOGIN_TIMEOUT); /* TRANSLATORS: The standard value for %u is 60. */ - xasprintf(&timeout_msg, _("%s: timed out after %u seconds"), + xasprintf(&timeout_msg, _("%s: timed out after %u seconds\n"), program_invocation_short_name, timeout); signal(SIGALRM, timedout); From 8653af2499e47c03ec29f622f840b01e823a1ac1 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Fri, 7 Nov 2025 12:15:51 +0100 Subject: [PATCH 069/174] tests: update cal color outputs Signed-off-by: Karel Zak --- tests/expected/cal/color-first-day | 4 ++-- tests/expected/cal/color-last-day | 4 ++-- tests/expected/cal/color-reformation-corner-cases-1 | 4 ++-- tests/expected/cal/color-reformation-corner-cases-2 | 4 ++-- tests/expected/cal/color-reformation-corner-cases-3 | 4 ++-- tests/expected/cal/color-reformation-corner-cases-4 | 4 ++-- tests/expected/cal/color-vertical | 2 +- tests/expected/cal/color-vertical-week | 2 +- tests/expected/cal/colorw-first-day-week-numbers | 4 ++-- tests/expected/cal/colorw-last-day-week-numbers | 4 ++-- .../cal/colorw-reformation-corner-cases-1-week-numbers | 4 ++-- .../cal/colorw-reformation-corner-cases-2-week-numbers | 4 ++-- .../cal/colorw-reformation-corner-cases-3-week-numbers | 4 ++-- .../cal/colorw-reformation-corner-cases-4-week-numbers | 4 ++-- 14 files changed, 26 insertions(+), 26 deletions(-) diff --git a/tests/expected/cal/color-first-day b/tests/expected/cal/color-first-day index 229681d6aab..f0a836dc1b1 100644 --- a/tests/expected/cal/color-first-day +++ b/tests/expected/cal/color-first-day @@ -1,5 +1,5 @@ - January 0001 -Su Mo Tu We Th Fr Sa + January 0001  +Su Mo Tu We Th Fr Sa  [ 1  2 3 4 5 6 7 8  9 10 11 12 13 14 15 diff --git a/tests/expected/cal/color-last-day b/tests/expected/cal/color-last-day index b7020ab3ffd..622839167d9 100644 --- a/tests/expected/cal/color-last-day +++ b/tests/expected/cal/color-last-day @@ -1,5 +1,5 @@ - November 9999 December 9999 January 10000 -Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa + November 9999 December 9999 January 10000  +Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa  1 2 3 4 5 6  1 2 3 4  1  7 8 9 10 11 12 13  5 6 7 8 9 10 11  2 3 4 5 6 7 8 14 15 16 17 18 19 20 12 13 14 15 16 17 18  9 10 11 12 13 14 15 diff --git a/tests/expected/cal/color-reformation-corner-cases-1 b/tests/expected/cal/color-reformation-corner-cases-1 index af9e2bd81a5..56448187e5f 100644 --- a/tests/expected/cal/color-reformation-corner-cases-1 +++ b/tests/expected/cal/color-reformation-corner-cases-1 @@ -1,5 +1,5 @@ - September 1752 -Su Mo Tu We Th Fr Sa + September 1752  +Su Mo Tu We Th Fr Sa  1 [ 2 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 diff --git a/tests/expected/cal/color-reformation-corner-cases-2 b/tests/expected/cal/color-reformation-corner-cases-2 index 75402e99a92..afe0f864a55 100644 --- a/tests/expected/cal/color-reformation-corner-cases-2 +++ b/tests/expected/cal/color-reformation-corner-cases-2 @@ -1,5 +1,5 @@ - September 1752 -Su Mo Tu We Th Fr Sa + September 1752  +Su Mo Tu We Th Fr Sa  1 2 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 diff --git a/tests/expected/cal/color-reformation-corner-cases-3 b/tests/expected/cal/color-reformation-corner-cases-3 index 75402e99a92..afe0f864a55 100644 --- a/tests/expected/cal/color-reformation-corner-cases-3 +++ b/tests/expected/cal/color-reformation-corner-cases-3 @@ -1,5 +1,5 @@ - September 1752 -Su Mo Tu We Th Fr Sa + September 1752  +Su Mo Tu We Th Fr Sa  1 2 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 diff --git a/tests/expected/cal/color-reformation-corner-cases-4 b/tests/expected/cal/color-reformation-corner-cases-4 index dbf47a90858..52dd9ce97ef 100644 --- a/tests/expected/cal/color-reformation-corner-cases-4 +++ b/tests/expected/cal/color-reformation-corner-cases-4 @@ -1,5 +1,5 @@ - September 1752 -Su Mo Tu We Th Fr Sa + September 1752  +Su Mo Tu We Th Fr Sa  1 2 [14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 diff --git a/tests/expected/cal/color-vertical b/tests/expected/cal/color-vertical index f4ffac6a5d4..0d7e2596b28 100644 --- a/tests/expected/cal/color-vertical +++ b/tests/expected/cal/color-vertical @@ -1,4 +1,4 @@ - February 2023  + February 2023  Su  5 12 19 26 Mo  6 13 20 27 Tu  7 14 21 28 diff --git a/tests/expected/cal/color-vertical-week b/tests/expected/cal/color-vertical-week index 70603618538..dfaad2b7710 100644 --- a/tests/expected/cal/color-vertical-week +++ b/tests/expected/cal/color-vertical-week @@ -1,4 +1,4 @@ - February 2023  + February 2023  Su  5 12 19 26 Mo  6 13 20 27 Tu  7 14 21 28 diff --git a/tests/expected/cal/colorw-first-day-week-numbers b/tests/expected/cal/colorw-first-day-week-numbers index f3117d89b26..f1fb66f9a9b 100644 --- a/tests/expected/cal/colorw-first-day-week-numbers +++ b/tests/expected/cal/colorw-first-day-week-numbers @@ -1,5 +1,5 @@ - January 0001 - Su Mo Tu We Th Fr Sa + January 0001  + Su Mo Tu We Th Fr Sa  1  [ 1  2 2 3 4 5 6 7 8  3 9 10 11 12 13 14 15 diff --git a/tests/expected/cal/colorw-last-day-week-numbers b/tests/expected/cal/colorw-last-day-week-numbers index dd081fdfc65..ddf8f54b22a 100644 --- a/tests/expected/cal/colorw-last-day-week-numbers +++ b/tests/expected/cal/colorw-last-day-week-numbers @@ -1,5 +1,5 @@ - November 9999 December 9999 January 10000 - Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa + November 9999 December 9999 January 10000  + Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa 45  1 2 3 4 5 6 49  1 2 3 4  1  1 46 7 8 9 10 11 12 13 50 5 6 7 8 9 10 11  2 2 3 4 5 6 7 8 47 14 15 16 17 18 19 20 51 12 13 14 15 16 17 18  3 9 10 11 12 13 14 15 diff --git a/tests/expected/cal/colorw-reformation-corner-cases-1-week-numbers b/tests/expected/cal/colorw-reformation-corner-cases-1-week-numbers index a94a28e549e..9144c72db97 100644 --- a/tests/expected/cal/colorw-reformation-corner-cases-1-week-numbers +++ b/tests/expected/cal/colorw-reformation-corner-cases-1-week-numbers @@ -1,5 +1,5 @@ - September 1752 - Su Mo Tu We Th Fr Sa + September 1752  + Su Mo Tu We Th Fr Sa 36  1 [ 2 14 15 16 37 17 18 19 20 21 22 23 38 24 25 26 27 28 29 30 diff --git a/tests/expected/cal/colorw-reformation-corner-cases-2-week-numbers b/tests/expected/cal/colorw-reformation-corner-cases-2-week-numbers index 701eb91fe83..88955a4935a 100644 --- a/tests/expected/cal/colorw-reformation-corner-cases-2-week-numbers +++ b/tests/expected/cal/colorw-reformation-corner-cases-2-week-numbers @@ -1,5 +1,5 @@ - September 1752 - Su Mo Tu We Th Fr Sa + September 1752  + Su Mo Tu We Th Fr Sa 36  1 2 14 15 16 37 17 18 19 20 21 22 23 38 24 25 26 27 28 29 30 diff --git a/tests/expected/cal/colorw-reformation-corner-cases-3-week-numbers b/tests/expected/cal/colorw-reformation-corner-cases-3-week-numbers index 701eb91fe83..88955a4935a 100644 --- a/tests/expected/cal/colorw-reformation-corner-cases-3-week-numbers +++ b/tests/expected/cal/colorw-reformation-corner-cases-3-week-numbers @@ -1,5 +1,5 @@ - September 1752 - Su Mo Tu We Th Fr Sa + September 1752  + Su Mo Tu We Th Fr Sa 36  1 2 14 15 16 37 17 18 19 20 21 22 23 38 24 25 26 27 28 29 30 diff --git a/tests/expected/cal/colorw-reformation-corner-cases-4-week-numbers b/tests/expected/cal/colorw-reformation-corner-cases-4-week-numbers index e35901a0f3c..fc4fb46946c 100644 --- a/tests/expected/cal/colorw-reformation-corner-cases-4-week-numbers +++ b/tests/expected/cal/colorw-reformation-corner-cases-4-week-numbers @@ -1,5 +1,5 @@ - September 1752 - Su Mo Tu We Th Fr Sa + September 1752  + Su Mo Tu We Th Fr Sa 36  1 2 [14 15 16 37 17 18 19 20 21 22 23 38 24 25 26 27 28 29 30 From 6ed7ac3ca5fdef498a3317f65ee1c5625b1ba4c2 Mon Sep 17 00:00:00 2001 From: Jesse Gilles Date: Fri, 7 Nov 2025 13:27:49 -0600 Subject: [PATCH 070/174] hwclock-rtc: fix verbose output when --param-set value is unchanged RTC_PARAM_SET operation is skipped rather than GET --- sys-utils/hwclock-rtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys-utils/hwclock-rtc.c b/sys-utils/hwclock-rtc.c index 318e692e97c..a210eac941a 100644 --- a/sys-utils/hwclock-rtc.c +++ b/sys-utils/hwclock-rtc.c @@ -533,7 +533,7 @@ int set_param_rtc(const struct hwclock_control *ctl, const char *opt0) && current_param.uvalue == param.uvalue) { /* value to be written matches current value, skip write */ if (ctl->verbose) - printf(_("skipping ioctl(%d, RTC_PARAM_GET, param) to %s: value unchanged\n"), + printf(_("skipping ioctl(%d, RTC_PARAM_SET, param) to %s: value unchanged\n"), rtc_fd, rtc_dev_name); rc = 0; goto done; From 5bbe47432f98a7e391da04157af9906832058ef7 Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Sat, 8 Nov 2025 11:42:31 +0900 Subject: [PATCH 071/174] lsfd: (bugfix) use PRIu32 for prining lport of netlink socket Fixes #3849 Signed-off-by: Masatake YAMATO --- lsfd-cmd/sock-xinfo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lsfd-cmd/sock-xinfo.c b/lsfd-cmd/sock-xinfo.c index 6803300cb88..78986eb4679 100644 --- a/lsfd-cmd/sock-xinfo.c +++ b/lsfd-cmd/sock-xinfo.c @@ -2127,11 +2127,11 @@ static char *netlink_get_name(struct sock_xinfo *sock_xinfo, const char *protocol = netlink_decode_protocol(nl->protocol); if (nl->groups) - xasprintf(&str, "protocol=%s lport=%"PRIu16 " groups=%"PRIu32, + xasprintf(&str, "protocol=%s lport=%"PRIu32 " groups=%"PRIu32, protocol, nl->lportid, nl->groups); else - xasprintf(&str, "protocol=%s lport=%"PRIu16, + xasprintf(&str, "protocol=%s lport=%"PRIu32, protocol, nl->lportid); return str; From 6fb7ee330af7acbbcd93d559761229329b4d0bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 7 Nov 2025 12:47:20 +0100 Subject: [PATCH 072/174] build: simplify checks for fallocate() and posix_fallocate() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bespoke test logic for those two functions was only necessary for old glibc versions which have long gone out of support. Align the checks with all other ones. Signed-off-by: Thomas Weißschuh --- configure.ac | 63 ++-------------------------------------------------- meson.build | 34 ++-------------------------- 2 files changed, 4 insertions(+), 93 deletions(-) diff --git a/configure.ac b/configure.ac index 6836f0564aa..297b9fb3fea 100644 --- a/configure.ac +++ b/configure.ac @@ -614,6 +614,7 @@ AC_CHECK_FUNCS([ \ explicit_bzero \ __fpending \ __fpurge \ + fallocate \ fpurge \ fnmatch \ fsconfig \ @@ -652,6 +653,7 @@ AC_CHECK_FUNCS([ \ pidfd_open \ pidfd_send_signal \ posix_fadvise \ + posix_fallocate \ prctl \ qsort_r \ reallocarray \ @@ -1590,67 +1592,6 @@ UL_REQUIRES_LINUX([fallocate]) UL_REQUIRES_SYSCALL_CHECK([fallocate], [UL_CHECK_SYSCALL([fallocate])]) AM_CONDITIONAL([BUILD_FALLOCATE], [test "x$build_fallocate" = xyes]) -AS_IF([test "x$build_fallocate" = xyes], [ - dnl check for valid fallocate() function - dnl with 32 bits glibc 2.10, fallocate() exists but not fallocate64() - dnl when _FILE_OFFSET_BITS==64, fallocate() is redirect to fallocate64() - dnl and program can't be linked. - dnl AC_CHECK_FUNC can't catch such errors since it's redefining - dnl function prototype. - AC_MSG_CHECKING([for valid fallocate() function]) - AC_LINK_IFELSE([AC_LANG_PROGRAM([[ -#ifdef HAVE_UNISTD_H -# include -#endif -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_LINUX_FALLOC_H -# include -#endif -#ifdef HAVE_FCNTL_H -# include -#endif -]],[[ - long ret; - ret = fallocate(0, FALLOC_FL_KEEP_SIZE, 0xfffffffful, 0xfffffffful); - if (ret != 0) { - return 1; - } - ]])],[ - AC_MSG_RESULT([yes]) - AC_DEFINE([HAVE_FALLOCATE], [1], [Have valid fallocate() function])],[ - AC_MSG_RESULT([no])]) -]) - -AS_IF([test "x$build_fallocate" = xyes], [ - dnl check for valid posix_fallocate() function - AC_MSG_CHECKING([for valid posix_fallocate() function]) - AC_LINK_IFELSE([AC_LANG_PROGRAM([[ -#ifdef HAVE_UNISTD_H -# include -#endif -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_LINUX_FALLOC_H -# include -#endif -#ifdef HAVE_FCNTL_H -# include -#endif -]],[[ - long ret; - ret = posix_fallocate(0, 0xfffffffful, 0xfffffffful); - if (ret != 0) { - return 1; - } - ]])],[ - AC_MSG_RESULT([yes]) - AC_DEFINE([HAVE_POSIX_FALLOCATE], [1], [Have valid posix_fallocate() function])],[ - AC_MSG_RESULT([no])]) -]) - AC_ARG_ENABLE([unshare], AS_HELP_STRING([--disable-unshare], [do not build unshare]), diff --git a/meson.build b/meson.build index 7a995d612c2..00c24c751ec 100644 --- a/meson.build +++ b/meson.build @@ -606,6 +606,7 @@ funcs = ''' err errx explicit_bzero + fallocate fnmatch fseeko fsconfig @@ -644,6 +645,7 @@ funcs = ''' pidfd_open pidfd_send_signal posix_fadvise + posix_fallocate prctl qsort_r reallocarray @@ -890,38 +892,6 @@ summary('plymouth support', build_plymouth_support ? 'enabled' : 'disabled', section : 'components') -# check for valid fallocate() function -# with 32 bits glibc 2.10, fallocate() exists but not fallocate64() -# when _FILE_OFFSET_BITS==64, fallocate() is redirect to fallocate64() -# and program can't be linked. -code = ''' -#define _GNU_SOURCE -#include -#include - -int main(void) { - long ret; - ret = fallocate(0, FALLOC_FL_KEEP_SIZE, 0xfffffffful, 0xfffffffful); - return ret == 0 ? 0 : 1; -} -''' -have = cc.links(code, name : 'fallocate() function') -conf.set('HAVE_FALLOCATE', have ? 1 : false) - -code = ''' -#define _POSIX_C_SOURCE 200112L -#include -#include - -int main(void) { - long ret; - ret = posix_fallocate(0, 0xfffffffful, 0xfffffffful); - return ret == 0 ? 0 : 1; -} -''' -have = cc.links(code, name : 'posix_fallocate() function') -conf.set('HAVE_POSIX_FALLOCATE', have ? 1 : false) - use_hwclock_cmos = host_machine.cpu_family() in ['x86', 'x86_64'] message('Use CMOS clock: @0@'.format(use_hwclock_cmos)) conf.set('USE_HWCLOCK_CMOS', use_hwclock_cmos ? 1 : false) From 941265121258160db37ac4778f19b19baf7a5951 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sat, 1 Nov 2025 21:49:58 +0100 Subject: [PATCH 073/174] fallocate: drop syscall() fallback for fallocate() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ABI of the fallocate() syscall is complicated and not properly handled by the open-coded fallback logic. As all recent libcs implement fallocate() properly, drop the open-coded systemcall fallback and depend on the libc implementation. Signed-off-by: Thomas Weißschuh --- configure.ac | 4 ++-- meson.build | 5 ++++- sys-utils/fallocate.c | 9 +-------- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/configure.ac b/configure.ac index 297b9fb3fea..fc66f214952 100644 --- a/configure.ac +++ b/configure.ac @@ -614,7 +614,6 @@ AC_CHECK_FUNCS([ \ explicit_bzero \ __fpending \ __fpurge \ - fallocate \ fpurge \ fnmatch \ fsconfig \ @@ -687,6 +686,7 @@ AC_CHECK_FUNCS([ \ ]) AC_FUNC_FSEEKO +AC_CHECK_FUNCS([fallocate], [have_fallocate=yes], [have_fallocate=no]) AC_CHECK_FUNCS([futimens], [have_futimens=yes]) AC_CHECK_FUNCS([getusershell], [have_getusershell=yes],[have_getusershell=no]) AC_CHECK_FUNCS([inotify_init1], [have_inotify_init1=yes]) @@ -1589,7 +1589,7 @@ AC_ARG_ENABLE([fallocate], ) UL_BUILD_INIT([fallocate]) UL_REQUIRES_LINUX([fallocate]) -UL_REQUIRES_SYSCALL_CHECK([fallocate], [UL_CHECK_SYSCALL([fallocate])]) +UL_REQUIRES_HAVE([fallocate], [fallocate], [fallocate functions]) AM_CONDITIONAL([BUILD_FALLOCATE], [test "x$build_fallocate" = xyes]) diff --git a/meson.build b/meson.build index 00c24c751ec..9d520615459 100644 --- a/meson.build +++ b/meson.build @@ -2041,7 +2041,10 @@ if opt and not is_disabler(exe) bashcompletions += ['mountpoint'] endif -opt = not get_option('build-fallocate').disabled() +opt = get_option('build-fallocate') \ + .require(LINUX) \ + .require(conf.get('HAVE_FALLOCATE').to_string() == '1') \ + .allowed() exe = executable( 'fallocate', fallocate_sources, diff --git a/sys-utils/fallocate.c b/sys-utils/fallocate.c index 686e4925e24..244c1dfa4da 100644 --- a/sys-utils/fallocate.c +++ b/sys-utils/fallocate.c @@ -33,10 +33,6 @@ #include #include -#ifndef HAVE_FALLOCATE -# include -#endif - #if defined(HAVE_LINUX_FALLOC_H) && \ (!defined(FALLOC_FL_KEEP_SIZE) || !defined(FALLOC_FL_PUNCH_HOLE) || \ !defined(FALLOC_FL_COLLAPSE_RANGE) || !defined(FALLOC_FL_ZERO_RANGE) || \ @@ -129,11 +125,8 @@ static void xfallocate(int fd, int mode, off_t offset, off_t length) { int error; -#ifdef HAVE_FALLOCATE error = fallocate(fd, mode, offset, length); -#else - error = syscall(SYS_fallocate, fd, mode, offset, length); -#endif + /* * EOPNOTSUPP: The FALLOC_FL_KEEP_SIZE is unsupported * ENOSYS: The filesystem does not support sys_fallocate From 13b4a466cef2ff9176cb40eaaf0a82f42c1f0f71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sat, 1 Nov 2025 16:55:49 +0100 Subject: [PATCH 074/174] fallocate: require posix_fallocate() from libc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recent libcs implement posix_fallocate() properly. The fallback logic should never be used. Furthermore unconditional support for posix_fallocate() will enable some further cleanup and fixes. Signed-off-by: Thomas Weißschuh --- configure.ac | 3 ++- meson.build | 1 + sys-utils/fallocate.c | 12 ------------ 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/configure.ac b/configure.ac index fc66f214952..cf415f5ed46 100644 --- a/configure.ac +++ b/configure.ac @@ -652,7 +652,6 @@ AC_CHECK_FUNCS([ \ pidfd_open \ pidfd_send_signal \ posix_fadvise \ - posix_fallocate \ prctl \ qsort_r \ reallocarray \ @@ -693,6 +692,7 @@ AC_CHECK_FUNCS([inotify_init1], [have_inotify_init1=yes]) AC_CHECK_FUNCS([ioperm iopl], [have_io=yes]) AC_CHECK_FUNCS([openat fstatat unlinkat], [have_openat=yes], [have_openat=no]) AC_CHECK_FUNCS([open_memstream], [have_open_memstream=yes],[have_open_memstream=no]) +AC_CHECK_FUNCS([posix_fallocate], [have_posix_fallocate=yes], [have_posix_fallocate=no]) AC_CHECK_FUNCS([reboot], [have_reboot=yes],[have_reboot=no]) AC_CHECK_FUNCS([updwtmpx updwtmpx], [have_gnu_utmpx=yes], [have_gnu_utmpx=no]) @@ -1590,6 +1590,7 @@ AC_ARG_ENABLE([fallocate], UL_BUILD_INIT([fallocate]) UL_REQUIRES_LINUX([fallocate]) UL_REQUIRES_HAVE([fallocate], [fallocate], [fallocate functions]) +UL_REQUIRES_HAVE([fallocate], [posix_fallocate], [posix_fallocate functions]) AM_CONDITIONAL([BUILD_FALLOCATE], [test "x$build_fallocate" = xyes]) diff --git a/meson.build b/meson.build index 9d520615459..cac8bb57869 100644 --- a/meson.build +++ b/meson.build @@ -2044,6 +2044,7 @@ endif opt = get_option('build-fallocate') \ .require(LINUX) \ .require(conf.get('HAVE_FALLOCATE').to_string() == '1') \ + .require(conf.get('HAVE_POSIX_FALLOCATE').to_string() == '1') \ .allowed() exe = executable( 'fallocate', diff --git a/sys-utils/fallocate.c b/sys-utils/fallocate.c index 244c1dfa4da..aedb091cfbd 100644 --- a/sys-utils/fallocate.c +++ b/sys-utils/fallocate.c @@ -95,9 +95,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -p, --punch-hole replace a range with a hole (implies -n)\n"), out); fputs(_(" -v, --verbose verbose mode\n"), out); fputs(_(" -w, --write-zeroes write zeroes and ensure allocation of a range\n"), out); -#ifdef HAVE_POSIX_FALLOCATE fputs(_(" -x, --posix use posix_fallocate(3) instead of fallocate(2)\n"), out); -#endif fputs(_(" -z, --zero-range zero and ensure allocation of a range\n"), out); fputs(USAGE_SEPARATOR, out); @@ -138,7 +136,6 @@ static void xfallocate(int fd, int mode, off_t offset, off_t length) } } -#ifdef HAVE_POSIX_FALLOCATE static void xposix_fallocate(int fd, off_t offset, off_t length) { errno = posix_fallocate(fd, offset, length); @@ -146,7 +143,6 @@ static void xposix_fallocate(int fd, off_t offset, off_t length) err(EXIT_FAILURE, _("fallocate failed")); } } -#endif /* The real buffer size has to be bufsize + sizeof(uintptr_t) */ static int is_nul(void *buf, size_t bufsize) @@ -287,9 +283,7 @@ int main(int argc, char **argv) int fd; int mode = 0; int dig = 0; -#ifdef HAVE_POSIX_FALLOCATE int posix = 0; -#endif loff_t length = -2LL; loff_t offset = 0; @@ -356,12 +350,8 @@ int main(int argc, char **argv) mode |= FALLOC_FL_WRITE_ZEROES; break; case 'x': -#ifdef HAVE_POSIX_FALLOCATE posix = 1; break; -#else - errx(EXIT_FAILURE, _("posix_fallocate support is not compiled")); -#endif case 'v': verbose++; break; @@ -409,11 +399,9 @@ int main(int argc, char **argv) if (dig) dig_holes(fd, offset, length); else { -#ifdef HAVE_POSIX_FALLOCATE if (posix) xposix_fallocate(fd, offset, length); else -#endif xfallocate(fd, mode, offset, length); if (verbose) { From ccb00ea5efe064b265104fbd19b36883172d9700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sat, 1 Nov 2025 16:50:49 +0100 Subject: [PATCH 075/174] tests: (swaplabel) don't create test image with truncate(1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit truncate(1) can create holes in the file. These will trigger a warning in mkswap(1), failing the testsuite. Given that fallocate(1) now alway supports posix_fallocate() which works on all filesystems, truncate(1) is unnecessary anyways. Reported-by: Christian Hesse Signed-off-by: Thomas Weißschuh --- tests/ts/misc/swaplabel | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/tests/ts/misc/swaplabel b/tests/ts/misc/swaplabel index 9db7d2b80f2..6e777ac2a97 100755 --- a/tests/ts/misc/swaplabel +++ b/tests/ts/misc/swaplabel @@ -21,14 +21,7 @@ ts_init "$*" ts_check_test_command "$TS_CMD_MKSWAP" ts_check_test_command "$TS_CMD_SWAPLABEL" ts_check_test_command "$TS_HELPER_SYSINFO" - -# fallocate does not work on most file systems -function fallocate_or_skip() -{ - $TS_CMD_FALLOCATE -x -l $1 $2 2>/dev/null || \ - truncate -s $1 $2 || \ - ts_skip "no way to create test image" -} +ts_check_test_command "$TS_CMD_FALLOCATE" IMAGE=${TS_OUTDIR}/${TS_TESTNAME}.file @@ -38,7 +31,7 @@ MIN_SWAP_SIZE=$(( 10 * $PAGE_SIZE )) MIN_SWAP_SIZE_KB=$(( MIN_SWAP_SIZE / 1024 )) rm -f $IMAGE -fallocate_or_skip $(( $MIN_SWAP_SIZE - 1 )) $IMAGE +$TS_CMD_FALLOCATE -x -l $(( $MIN_SWAP_SIZE - 1 )) $IMAGE 2> /dev/null $TS_CMD_MKSWAP \ --label 1234567890abcdef \ --uuid 12345678-abcd-abcd-abcd-1234567890ab \ @@ -50,7 +43,7 @@ sed -i -e "s/ $MIN_SWAP_SIZE_KB KiB/ 10 pages/" \ $TS_OUTPUT $TS_ERRLOG rm -f $IMAGE -fallocate_or_skip $MIN_SWAP_SIZE $IMAGE +$TS_CMD_FALLOCATE -x -l $MIN_SWAP_SIZE $IMAGE 2> /dev/null $TS_CMD_MKSWAP \ --label 1234567890abcdef \ --uuid 12345678-abcd-abcd-abcd-1234567890ab \ From c305d73eebc11279e8e85454b58a3f4d7c36874d Mon Sep 17 00:00:00 2001 From: Leefancy Date: Mon, 10 Nov 2025 17:14:18 +0800 Subject: [PATCH 076/174] Fix the issue of fd resource leakage Signed-off-by: Leefancy --- misc-utils/kill.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/misc-utils/kill.c b/misc-utils/kill.c index b522bcb2088..df83548f61c 100644 --- a/misc-utils/kill.c +++ b/misc-utils/kill.c @@ -612,6 +612,8 @@ static int kill_verbose(const struct kill_control *ctl) rc = pidfd_send_signal(pfd, ctl->numsig, 0, 0); if (rc < 0) err(EXIT_FAILURE, _("pidfd_send_signal() failed")); + + close(pfd); } else #endif rc = kill(ctl->pid, ctl->numsig); From 0a031019cffb125d570c7730c843a9cd8b8282a8 Mon Sep 17 00:00:00 2001 From: syokensyo Date: Wed, 12 Nov 2025 14:57:57 +0800 Subject: [PATCH 077/174] fincore: close the ftsp to prevent fd leak --- misc-utils/fincore.c | 1 + 1 file changed, 1 insertion(+) diff --git a/misc-utils/fincore.c b/misc-utils/fincore.c index c297c104573..bfe4cd03df4 100644 --- a/misc-utils/fincore.c +++ b/misc-utils/fincore.c @@ -610,6 +610,7 @@ int main(int argc, char ** argv) rc |= fincore_name(&ctl, ent->fts_accpath, ent->fts_path, ent->fts_statp); } } + fts_close(fts); } #endif } else { From ab2e709600f3dc456b882628c1d490e7a3e7fa8f Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Wed, 12 Nov 2025 12:18:10 +0100 Subject: [PATCH 078/174] chmem: improve messages Suggested-by: Sumanth Korikkar Signed-off-by: Karel Zak --- sys-utils/chmem.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sys-utils/chmem.c b/sys-utils/chmem.c index 51240bf5aef..6ec66bb6b34 100644 --- a/sys-utils/chmem.c +++ b/sys-utils/chmem.c @@ -325,10 +325,10 @@ static int chmem_config_size(struct chmem_desc *desc, int configure) if (!desc->have_memconfig) { if (configure) fprintf(stdout, - _("Skip configuration — use chmem -e instead\n")); + _("Skip configuration. Use chmem -e instead.\n")); else fprintf(stdout, - _("Skip deconfiguration - use chmem -d instead\n")); + _("Skip deconfiguration. Use chmem -d instead\n")); return -1; } size = desc->size; @@ -363,10 +363,10 @@ static int chmem_config_range(struct chmem_desc *desc, int configure) if (!desc->have_memconfig) { if (configure) fprintf(stdout, - _("Skip configuration — use chmem -e instead\n")); + _("Skip configuration. Use chmem -e instead.\n")); else fprintf(stdout, - _("Skip deconfiguration - use chmem -d instead\n")); + _("Skip deconfiguration. Use chmem -d instead\n")); return -1; } todo = desc->end - desc->start + 1; From 4aec9df42a7c2ff09bbcc7a45afbb69a64bda437 Mon Sep 17 00:00:00 2001 From: Louis Sautier Date: Sun, 16 Nov 2025 22:44:02 +0100 Subject: [PATCH 079/174] Fix typos when "set up" is used as a verb The noun is "setup" while the verb is "set up". --- disk-utils/fsck.c | 2 +- libmount/src/context_mount.c | 2 +- libmount/src/hook_idmap.c | 2 +- libmount/src/hook_loopdev.c | 4 ++-- sys-utils/losetup.8.adoc | 2 +- sys-utils/rtcwake.8.adoc | 2 +- tests/expected/libmount/loop-o-loop-val-conflict | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/disk-utils/fsck.c b/disk-utils/fsck.c index beccb17508f..02ddaedae94 100644 --- a/disk-utils/fsck.c +++ b/disk-utils/fsck.c @@ -442,7 +442,7 @@ static struct libmnt_fs *add_dummy_fs(const char *device) } mnt_unref_fs(fs); - err(FSCK_EX_ERROR, _("failed to setup description for %s"), device); + err(FSCK_EX_ERROR, _("failed to set up description for %s"), device); } static void fs_interpret_type(struct libmnt_fs *fs) diff --git a/libmount/src/context_mount.c b/libmount/src/context_mount.c index c6d854f7a63..2de6766cda5 100644 --- a/libmount/src/context_mount.c +++ b/libmount/src/context_mount.c @@ -1584,7 +1584,7 @@ int mnt_context_get_mount_excode( return MNT_EX_USAGE; case -MNT_ERR_LOOPDEV: if (buf) - snprintf(buf, bufsz, _("failed to setup loop device for %s"), src); + snprintf(buf, bufsz, _("failed to set up loop device for %s"), src); return MNT_EX_FAIL; case -MNT_ERR_LOOPOVERLAP: if (buf) diff --git a/libmount/src/hook_idmap.c b/libmount/src/hook_idmap.c index 5095de1f6ac..821269f1e91 100644 --- a/libmount/src/hook_idmap.c +++ b/libmount/src/hook_idmap.c @@ -492,7 +492,7 @@ static int hook_prepare_options( return 0; err: - DBG(HOOK, ul_debugobj(hs, " failed to setup idmap")); + DBG(HOOK, ul_debugobj(hs, " failed to set up idmap")); free_hook_data(hd); free(buf); return -MNT_ERR_MOUNTOPT; diff --git a/libmount/src/hook_loopdev.c b/libmount/src/hook_loopdev.c index b72164535c5..0bb97e59b4e 100644 --- a/libmount/src/hook_loopdev.c +++ b/libmount/src/hook_loopdev.c @@ -138,7 +138,7 @@ static int setup_loopdev(struct libmnt_context *cxt, if (!backing_file) return -EINVAL; - DBG(LOOP, ul_debugobj(cxt, "trying to setup device for %s", backing_file)); + DBG(LOOP, ul_debugobj(cxt, "trying to set up device for %s", backing_file)); if (mnt_optlist_is_rdonly(ol)) { DBG(LOOP, ul_debugobj(cxt, "enabling READ-ONLY flag")); @@ -332,7 +332,7 @@ static int setup_loopdev(struct libmnt_context *cxt, break; /* success */ if (loopdev || rc != -EBUSY) { - DBG(LOOP, ul_debugobj(cxt, "failed to setup device")); + DBG(LOOP, ul_debugobj(cxt, "failed to set up device")); rc = -MNT_ERR_LOOPDEV; goto done; } diff --git a/sys-utils/losetup.8.adoc b/sys-utils/losetup.8.adoc index cecc09618d5..54a825c63ea 100644 --- a/sys-utils/losetup.8.adoc +++ b/sys-utils/losetup.8.adoc @@ -148,7 +148,7 @@ The *--remove* option completely removes the loop device node from the system us == NOTES -Since version 2.37 *losetup* uses *LOOP_CONFIGURE* ioctl to setup a new loop device by one ioctl call. The old versions use *LOOP_SET_FD* and *LOOP_SET_STATUS64* ioctls to do the same. +Since version 2.37 *losetup* uses *LOOP_CONFIGURE* ioctl to set up a new loop device by one ioctl call. The old versions use *LOOP_SET_FD* and *LOOP_SET_STATUS64* ioctls to do the same. == ENVIRONMENT diff --git a/sys-utils/rtcwake.8.adoc b/sys-utils/rtcwake.8.adoc index b118534c836..5164a23a378 100644 --- a/sys-utils/rtcwake.8.adoc +++ b/sys-utils/rtcwake.8.adoc @@ -24,7 +24,7 @@ This is normally used like the old *apmsleep* utility, to wake from a suspend st On some systems, this can also be used like *nvram-wakeup*, waking from states like ACPI S4 (suspend to disk). Not all systems have persistent media that are appropriate for such suspend modes. -Note that alarm functionality depends on hardware; not every RTC is able to setup an alarm up to 24 hours in the future. +Note that alarm functionality depends on hardware; not every RTC is able to set up an alarm up to 24 hours in the future. The suspend setup may be interrupted by active hardware; for example wireless USB input devices that continue to send events for some fraction of a second after the return key is pressed. *rtcwake* tries to avoid this problem and it waits to the terminal to settle down before entering a system sleep. diff --git a/tests/expected/libmount/loop-o-loop-val-conflict b/tests/expected/libmount/loop-o-loop-val-conflict index 0eb73221454..faedb3b9bc1 100644 --- a/tests/expected/libmount/loop-o-loop-val-conflict +++ b/tests/expected/libmount/loop-o-loop-val-conflict @@ -1,2 +1,2 @@ -mount: failed to setup loop device for +mount: failed to set up loop device for Success From b2f9be52153e16ad8a9704dc3781ae6408b3566f Mon Sep 17 00:00:00 2001 From: fortunate-lee Date: Tue, 18 Nov 2025 10:37:58 +0800 Subject: [PATCH 080/174] fincore: The previous exit did not call munmap, resulting in a memory mapping leak. Signed-off-by: fortunate-lee --- misc-utils/fincore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc-utils/fincore.c b/misc-utils/fincore.c index cbf3c9bab13..eba23445543 100644 --- a/misc-utils/fincore.c +++ b/misc-utils/fincore.c @@ -333,10 +333,10 @@ static int mincore_fd (struct fincore_control *ctl, } rc = do_mincore(ctl, window, len, st); + munmap (window, len); if (rc) break; - munmap (window, len); } return rc; From c62bb65ad321eebea18f32f5529f8f0a085e57e2 Mon Sep 17 00:00:00 2001 From: fortunate-lee Date: Wed, 19 Nov 2025 09:59:18 +0800 Subject: [PATCH 081/174] kill: the situation where fd is opened but not closed Signed-off-by: fortunate-lee --- misc-utils/kill.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/misc-utils/kill.c b/misc-utils/kill.c index df83548f61c..245c3b6b7a3 100644 --- a/misc-utils/kill.c +++ b/misc-utils/kill.c @@ -557,6 +557,9 @@ static int kill_with_timeout(const struct kill_control *ctl) err(EXIT_FAILURE, _("pidfd_send_signal() failed")); } } + + close(pfd); + return 0; } #endif From 5fc8401d09d791d132badd3029426407a8733dea Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Wed, 19 Nov 2025 13:01:02 +0100 Subject: [PATCH 082/174] mountpoint: use statmount() syscall on modern kernels Improve mountpoint(1) to use the modern statmount() system call (available since Linux 6.8) instead of parsing /proc/self/mountinfo. - Works without /proc mounted on modern kernels - More efficient than parsing /proc/self/mountinfo - Better detection of bind mounts via statmount() - Graceful fallback maintains compatibility Addresses: https://github.com/util-linux/util-linux/issues/3806 Signed-off-by: Karel Zak --- sys-utils/mountpoint.1.adoc | 2 +- sys-utils/mountpoint.c | 108 ++++++++++++++++++++++++++++++++---- 2 files changed, 98 insertions(+), 12 deletions(-) diff --git a/sys-utils/mountpoint.1.adoc b/sys-utils/mountpoint.1.adoc index bc8a2e9ed69..0e1252c72c9 100644 --- a/sys-utils/mountpoint.1.adoc +++ b/sys-utils/mountpoint.1.adoc @@ -18,7 +18,7 @@ mountpoint - see if a directory or file is a mountpoint == DESCRIPTION -*mountpoint* checks whether the given _directory_ or _file_ is mentioned in the _/proc/self/mountinfo_ file. +*mountpoint* checks whether the given _directory_ or _file_ is a mountpoint. On kernels that support the *statmount*(2) system call (Linux 6.8 and newer), it uses that interface. On older kernels, it falls back to reading _/proc/self/mountinfo_. == OPTIONS diff --git a/sys-utils/mountpoint.c b/sys-utils/mountpoint.c index 6294a4c07a8..8a114b5bb06 100644 --- a/sys-utils/mountpoint.c +++ b/sys-utils/mountpoint.c @@ -31,6 +31,7 @@ #include "c.h" #include "closestream.h" #include "pathnames.h" +#include "mount-api-utils.h" #define MOUNTPOINT_EXIT_NOMNT 32 @@ -44,13 +45,80 @@ struct mountpoint_control { quiet; }; +#ifdef HAVE_STATMOUNT_API +/* + * dir_to_device_statmount - check if path is a mountpoint using statmount() + * @ctl: mountpoint control structure + * + * Returns: <0 on error, 0 if mountpoint, 1 if not a mountpoint + */ +static int dir_to_device_statmount(struct mountpoint_control *ctl) +{ + struct libmnt_fs *fs = NULL; + const char *mnt_target; + char *cn = NULL; + uint64_t id = 0; + int rc; + + cn = mnt_resolve_path(ctl->path, NULL); + + rc = mnt_id_from_path(cn ? cn : ctl->path, &id, NULL); + if (rc) + goto done; + + fs = mnt_new_fs(); + if (!fs) { + rc = -ENOMEM; + goto done; + } + + mnt_fs_set_uniq_id(fs, id); + + rc = mnt_fs_fetch_statmount(fs, STATMOUNT_MNT_POINT | STATMOUNT_SB_BASIC); + if (rc) + goto done; + + mnt_target = mnt_fs_get_target(fs); + if (!mnt_target) { + rc = -EINVAL; + goto done; + } + + if (strcmp(mnt_target, cn ? cn : ctl->path) != 0) + rc = 1; /* not a mountpoint */ + else { + ctl->dev = mnt_fs_get_devno(fs); + rc = 0; /* is a mountpoint */ + } +done: + free(cn); + mnt_unref_fs(fs); + return rc; +} +#endif /* STATMOUNT_MNT_POINT */ + +/* + * dir_to_device - check if path is a mountpoint + * @ctl: mountpoint control structure + * + * Returns: <0 on error, 0 if mountpoint, 1 if not a mountpoint + */ static int dir_to_device(struct mountpoint_control *ctl) { - struct libmnt_table *tb = mnt_new_table_from_file(_PATH_PROC_MOUNTINFO); + struct libmnt_table *tb; struct libmnt_fs *fs; struct libmnt_cache *cache; - int rc = -1; + int rc; +#ifdef HAVE_STATMOUNT_API + rc = dir_to_device_statmount(ctl); + if (rc >= 0) + return rc; +#endif + /* + * Fallback for older kernels without statmount() support + */ + tb = mnt_new_table_from_file(_PATH_PROC_MOUNTINFO); if (!tb) { /* * Fallback. Traditional way to detect mountpoints. This way @@ -66,16 +134,18 @@ static int dir_to_device(struct mountpoint_control *ctl) free(cn); if (len < 0 || (size_t) len >= sizeof(buf)) - return -1; - if (stat(buf, &pst) !=0) - return -1; + return -EINVAL; + + rc = stat(buf, &pst); + if (rc) + return -errno; if (ctl->st.st_dev != pst.st_dev || ctl->st.st_ino == pst.st_ino) { ctl->dev = ctl->st.st_dev; - return 0; + return 0; /* is a mountpoint */ } - return -1; + return 1; /* not a mountpoint */ } /* to canonicalize all necessary paths */ @@ -86,8 +156,9 @@ static int dir_to_device(struct mountpoint_control *ctl) fs = mnt_table_find_target(tb, ctl->path, MNT_ITER_BACKWARD); if (fs && mnt_fs_get_target(fs)) { ctl->dev = mnt_fs_get_devno(fs); - rc = 0; - } + rc = 0; /* is a mountpoint */ + } else + rc = 1; /* not a mountpoint */ mnt_unref_table(tb); return rc; @@ -129,7 +200,7 @@ static void __attribute__((__noreturn__)) usage(void) int main(int argc, char **argv) { - int c; + int c, rc; struct mountpoint_control ctl = { NULL }; enum { @@ -196,11 +267,26 @@ int main(int argc, char **argv) if (ctl.dev_devno) return print_devno(&ctl) ? MOUNTPOINT_EXIT_NOMNT : EXIT_SUCCESS; - if ((ctl.nofollow && S_ISLNK(ctl.st.st_mode)) || dir_to_device(&ctl)) { + if (ctl.nofollow && S_ISLNK(ctl.st.st_mode)) { + if (!ctl.quiet) + printf(_("%s is not a mountpoint\n"), ctl.path); + return MOUNTPOINT_EXIT_NOMNT; + } + + rc = dir_to_device(&ctl); + if (rc < 0) { + if (!ctl.quiet) { + errno = -rc; + warn("%s", ctl.path); + } + return EXIT_FAILURE; + } + if (rc == 1) { if (!ctl.quiet) printf(_("%s is not a mountpoint\n"), ctl.path); return MOUNTPOINT_EXIT_NOMNT; } + if (ctl.fs_devno) printf("%u:%u\n", major(ctl.dev), minor(ctl.dev)); else if (!ctl.quiet) From f7facbb928a908ff4453891e45f124669f8318f1 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Wed, 19 Nov 2025 13:32:25 +0100 Subject: [PATCH 083/174] mountpoint: add --show option to print mountpoint path Add a new --show option that prints the actual mountpoint path for a given directory or file. This is useful for: - Resolving any path to its containing mountpoint - Finding the canonical mountpoint path when symlinks are involved - Determining the mountpoint from paths within filesystems The option requires kernel support for statmount(2) (Linux 6.8+). On older kernels without statmount support, the option fails with an error message, as the /proc/self/mountinfo fallback cannot resolve arbitrary paths to their containing mountpoint. Example usage: $ mountpoint --show / / $ mountpoint --show /home/user/file.txt /home The --show option always returns EXIT_SUCCESS (0) when it successfully finds the mountpoint, regardless of whether the given path itself is a mountpoint or not. Addresses: https://github.com/util-linux/util-linux/issues/3806 Signed-off-by: Karel Zak --- sys-utils/mountpoint.1.adoc | 3 +++ sys-utils/mountpoint.c | 27 ++++++++++++++++++++++++--- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/sys-utils/mountpoint.1.adoc b/sys-utils/mountpoint.1.adoc index 0e1252c72c9..250f6d1a954 100644 --- a/sys-utils/mountpoint.1.adoc +++ b/sys-utils/mountpoint.1.adoc @@ -34,6 +34,9 @@ Do not follow symbolic link if it the last element of the _directory_ path. *-x*, *--devno*:: Show the major/minor numbers of the given blockdevice on standard output. +*--show*:: +Print the mountpoint path for the given path. This resolves the given directory or file to its actual mountpoint, which is useful with bind mounts, symlinks, or paths within filesystems. This option requires kernel support for the *statmount*(2) system call (Linux 6.8 and newer). On older kernels, this option will fail with an error message. + include::man-common/help-version.adoc[] == EXIT STATUS diff --git a/sys-utils/mountpoint.c b/sys-utils/mountpoint.c index 8a114b5bb06..aed1f0fef69 100644 --- a/sys-utils/mountpoint.c +++ b/sys-utils/mountpoint.c @@ -37,12 +37,14 @@ struct mountpoint_control { char *path; + char *mnt_target; dev_t dev; struct stat st; bool dev_devno, fs_devno, nofollow, - quiet; + quiet, + show; }; #ifdef HAVE_STATMOUNT_API @@ -84,6 +86,9 @@ static int dir_to_device_statmount(struct mountpoint_control *ctl) goto done; } + if (ctl->show) + ctl->mnt_target = xstrdup(mnt_target); + if (strcmp(mnt_target, cn ? cn : ctl->path) != 0) rc = 1; /* not a mountpoint */ else { @@ -118,6 +123,9 @@ static int dir_to_device(struct mountpoint_control *ctl) /* * Fallback for older kernels without statmount() support */ + if (ctl->show) + errx(EXIT_FAILURE, _("--show is not supported on this system")); + tb = mnt_new_table_from_file(_PATH_PROC_MOUNTINFO); if (!tb) { /* @@ -190,7 +198,8 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -q, --quiet quiet mode - don't print anything\n" " --nofollow do not follow symlink\n" " -d, --fs-devno print maj:min device number of the filesystem\n" - " -x, --devno print maj:min device number of the block device\n"), out); + " -x, --devno print maj:min device number of the block device\n" + " --show print mountpoint for given path\n"), out); fputs(USAGE_SEPARATOR, out); fprintf(out, USAGE_HELP_OPTIONS(20)); fprintf(out, USAGE_MAN_TAIL("mountpoint(1)")); @@ -204,7 +213,8 @@ int main(int argc, char **argv) struct mountpoint_control ctl = { NULL }; enum { - OPT_NOFOLLOW = CHAR_MAX + 1 + OPT_NOFOLLOW = CHAR_MAX + 1, + OPT_SHOW }; static const struct option longopts[] = { @@ -212,6 +222,7 @@ int main(int argc, char **argv) { "nofollow", no_argument, NULL, OPT_NOFOLLOW }, { "fs-devno", no_argument, NULL, 'd' }, { "devno", no_argument, NULL, 'x' }, + { "show", no_argument, NULL, OPT_SHOW }, { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } @@ -239,6 +250,9 @@ int main(int argc, char **argv) case 'x': ctl.dev_devno = 1; break; + case OPT_SHOW: + ctl.show = 1; + break; case 'h': usage(); @@ -281,6 +295,13 @@ int main(int argc, char **argv) } return EXIT_FAILURE; } + + if (ctl.show) { + printf("%s\n", ctl.mnt_target); + free(ctl.mnt_target); + return EXIT_SUCCESS; + } + if (rc == 1) { if (!ctl.quiet) printf(_("%s is not a mountpoint\n"), ctl.path); From da5b727cd9a64d9992155f7ec60819a301c7354d Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Wed, 19 Nov 2025 13:46:40 +0100 Subject: [PATCH 084/174] mountpoint: use single libmount cache for all path resolutions Move libmount cache initialization to main() and pass it through the control structure. This allows the cache to be reused across all mnt_resolve_path() calls, reducing allocations. Also add cleanup section in main() with goto labels for proper resource deallocation in a single location. Signed-off-by: Karel Zak --- sys-utils/mountpoint.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/sys-utils/mountpoint.c b/sys-utils/mountpoint.c index aed1f0fef69..688ee67c650 100644 --- a/sys-utils/mountpoint.c +++ b/sys-utils/mountpoint.c @@ -40,6 +40,7 @@ struct mountpoint_control { char *mnt_target; dev_t dev; struct stat st; + struct libmnt_cache *cache; bool dev_devno, fs_devno, nofollow, @@ -62,7 +63,7 @@ static int dir_to_device_statmount(struct mountpoint_control *ctl) uint64_t id = 0; int rc; - cn = mnt_resolve_path(ctl->path, NULL); + cn = mnt_resolve_path(ctl->path, ctl->cache); rc = mnt_id_from_path(cn ? cn : ctl->path, &id, NULL); if (rc) @@ -96,7 +97,6 @@ static int dir_to_device_statmount(struct mountpoint_control *ctl) rc = 0; /* is a mountpoint */ } done: - free(cn); mnt_unref_fs(fs); return rc; } @@ -112,7 +112,6 @@ static int dir_to_device(struct mountpoint_control *ctl) { struct libmnt_table *tb; struct libmnt_fs *fs; - struct libmnt_cache *cache; int rc; #ifdef HAVE_STATMOUNT_API @@ -133,13 +132,13 @@ static int dir_to_device(struct mountpoint_control *ctl) * is independent on /proc, but not able to detect bind mounts. */ struct stat pst; - char buf[PATH_MAX], *cn; + char buf[PATH_MAX]; + const char *cn; int len; - cn = mnt_resolve_path(ctl->path, NULL); /* canonicalize */ + cn = mnt_resolve_path(ctl->path, ctl->cache); /* canonicalize */ len = snprintf(buf, sizeof(buf), "%s/..", cn ? cn : ctl->path); - free(cn); if (len < 0 || (size_t) len >= sizeof(buf)) return -EINVAL; @@ -157,9 +156,7 @@ static int dir_to_device(struct mountpoint_control *ctl) } /* to canonicalize all necessary paths */ - cache = mnt_new_cache(); - mnt_table_set_cache(tb, cache); - mnt_unref_cache(cache); + mnt_table_set_cache(tb, ctl->cache); fs = mnt_table_find_target(tb, ctl->path, MNT_ITER_BACKWARD); if (fs && mnt_fs_get_target(fs)) { @@ -287,25 +284,31 @@ int main(int argc, char **argv) return MOUNTPOINT_EXIT_NOMNT; } + ctl.cache = mnt_new_cache(); + if (!ctl.cache) + err(EXIT_FAILURE, _("failed to initialize libmount cache")); + rc = dir_to_device(&ctl); if (rc < 0) { if (!ctl.quiet) { errno = -rc; warn("%s", ctl.path); } - return EXIT_FAILURE; + rc = EXIT_FAILURE; + goto done; } if (ctl.show) { printf("%s\n", ctl.mnt_target); - free(ctl.mnt_target); - return EXIT_SUCCESS; + rc = EXIT_SUCCESS; + goto done; } if (rc == 1) { if (!ctl.quiet) printf(_("%s is not a mountpoint\n"), ctl.path); - return MOUNTPOINT_EXIT_NOMNT; + rc = MOUNTPOINT_EXIT_NOMNT; + goto done; } if (ctl.fs_devno) @@ -313,5 +316,10 @@ int main(int argc, char **argv) else if (!ctl.quiet) printf(_("%s is a mountpoint\n"), ctl.path); - return EXIT_SUCCESS; + rc = EXIT_SUCCESS; + +done: + free(ctl.mnt_target); + mnt_unref_cache(ctl.cache); + return rc; } From bffe45293fd20260ffae387c488b480a8899d360 Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Sun, 23 Nov 2025 06:35:14 +0900 Subject: [PATCH 085/174] lsfd: (refactor) introduce tundata struct Signed-off-by: Masatake YAMATO --- lsfd-cmd/cdev.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/lsfd-cmd/cdev.c b/lsfd-cmd/cdev.c index 1405f4c65cd..c70cc7ebabd 100644 --- a/lsfd-cmd/cdev.c +++ b/lsfd-cmd/cdev.c @@ -369,6 +369,10 @@ static struct cdev_ops cdev_misc_ops = { /* * tun device driver */ +struct tundata { + const char *iff; +}; + static bool cdev_tun_probe(struct cdev *cdev) { const char *miscdev; @@ -377,25 +381,32 @@ static bool cdev_tun_probe(struct cdev *cdev) return false; miscdev = get_miscdev(minor(cdev->file.stat.st_rdev)); - if (miscdev && strcmp(miscdev, "tun") == 0) + if (miscdev && strcmp(miscdev, "tun") == 0) { + struct tundata *tundata = xcalloc(1, sizeof *tundata); + cdev->cdev_data = tundata; return true; + } return false; } static void cdev_tun_free(const struct cdev *cdev) { - if (cdev->cdev_data) - free(cdev->cdev_data); + if (cdev->cdev_data) { + struct tundata *tundata = cdev->cdev_data; + free((void *)tundata->iff); + free(tundata); + } } static char * cdev_tun_get_name(struct cdev *cdev) { char *str = NULL; + struct tundata *tundata = cdev->cdev_data; - if (cdev->cdev_data == NULL) + if (tundata == NULL || tundata->iff == NULL) return NULL; - xasprintf(&str, "iface=%s", (const char *)cdev->cdev_data); + xasprintf(&str, "iface=%s", tundata->iff); return str; } @@ -406,6 +417,8 @@ static bool cdev_tun_fill_column(struct proc *proc __attribute__((__unused__)), size_t column_index __attribute__((__unused__)), char **str) { + struct tundata *tundata = cdev->cdev_data; + switch(column_id) { case COL_MISCDEV: *str = xstrdup("tun"); @@ -414,8 +427,8 @@ static bool cdev_tun_fill_column(struct proc *proc __attribute__((__unused__)), *str = xstrdup("misc:tun"); return true; case COL_TUN_IFACE: - if (cdev->cdev_data) { - *str = xstrdup(cdev->cdev_data); + if (tundata && tundata->iff) { + *str = xstrdup(tundata->iff); return true; } } @@ -424,8 +437,10 @@ static bool cdev_tun_fill_column(struct proc *proc __attribute__((__unused__)), static int cdev_tun_handle_fdinfo(struct cdev *cdev, const char *key, const char *val) { - if (strcmp(key, "iff") == 0 && cdev->cdev_data == NULL) { - cdev->cdev_data = xstrdup(val); + struct tundata *tundata = cdev->cdev_data; + + if (strcmp(key, "iff") == 0 && tundata->iff == NULL) { + tundata->iff = xstrdup(val); return 1; } return false; From 87ebe6b37d781fa0232dbe6f5a1c131586e29e6f Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Sun, 23 Nov 2025 08:14:42 +0900 Subject: [PATCH 086/174] lsfd: (cleanup) return 0 instead of false Signed-off-by: Masatake YAMATO --- lsfd-cmd/cdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lsfd-cmd/cdev.c b/lsfd-cmd/cdev.c index c70cc7ebabd..9cf5b6b5a6e 100644 --- a/lsfd-cmd/cdev.c +++ b/lsfd-cmd/cdev.c @@ -443,7 +443,7 @@ static int cdev_tun_handle_fdinfo(struct cdev *cdev, const char *key, const char tundata->iff = xstrdup(val); return 1; } - return false; + return 0; } static struct cdev_ops cdev_tun_ops = { From 4db0abf8df020551c10bb3dda651c5eebdb2725f Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Sun, 23 Nov 2025 08:15:38 +0900 Subject: [PATCH 087/174] lsfd: (cleanup) add missing "break" in a case statement Signed-off-by: Masatake YAMATO --- lsfd-cmd/cdev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lsfd-cmd/cdev.c b/lsfd-cmd/cdev.c index 9cf5b6b5a6e..fd20e38d17e 100644 --- a/lsfd-cmd/cdev.c +++ b/lsfd-cmd/cdev.c @@ -431,6 +431,7 @@ static bool cdev_tun_fill_column(struct proc *proc __attribute__((__unused__)), *str = xstrdup(tundata->iff); return true; } + break; } return false; } From 171a6410c43993cf7d06f8aa0d2b715952570d4b Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Sun, 23 Nov 2025 17:43:40 +0900 Subject: [PATCH 088/174] lsfd: (doc) fix English in SOCK.NETNS description Signed-off-by: Masatake YAMATO --- lsfd-cmd/lsfd.1.adoc | 2 +- lsfd-cmd/lsfd.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lsfd-cmd/lsfd.1.adoc b/lsfd-cmd/lsfd.1.adoc index ab30b231d73..7c20c00de75 100644 --- a/lsfd-cmd/lsfd.1.adoc +++ b/lsfd-cmd/lsfd.1.adoc @@ -457,7 +457,7 @@ SOCK.LISTENING <``boolean``>:: Listening socket. SOCK.NETS <``number``>:: -Inode identifying network namespace where the socket belongs to. +Inode identifying network namespace where the socket belongs. SOCK.PROTONAME <``string``>:: Protocol name. diff --git a/lsfd-cmd/lsfd.c b/lsfd-cmd/lsfd.c index 335594144dc..64b9a27b3f4 100644 --- a/lsfd-cmd/lsfd.c +++ b/lsfd-cmd/lsfd.c @@ -363,7 +363,7 @@ static const struct colinfo infos[] = { N_("listening socket") }, [COL_SOCK_NETNS] = { "SOCK.NETNS", 0, SCOLS_FL_RIGHT, SCOLS_JSON_NUMBER, - N_("inode identifying network namespace where the socket belongs to") }, + N_("inode identifying network namespace where the socket belongs") }, [COL_SOCK_PROTONAME] = { "SOCK.PROTONAME", 0, SCOLS_FL_RIGHT, SCOLS_JSON_STRING, N_("protocol name") }, From aed371507cc18cd613449396aa35b3303484e2c8 Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Sun, 23 Nov 2025 16:00:24 +0900 Subject: [PATCH 089/174] tests: (lsfd::mkfds-cdev-tun,refactor) make the case extensible Signed-off-by: Masatake YAMATO --- tests/ts/lsfd/mkfds-cdev-tun | 55 ++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/tests/ts/lsfd/mkfds-cdev-tun b/tests/ts/lsfd/mkfds-cdev-tun index 7354509c4dd..028b420013d 100755 --- a/tests/ts/lsfd/mkfds-cdev-tun +++ b/tests/ts/lsfd/mkfds-cdev-tun @@ -32,34 +32,47 @@ PID= FD=3 IFNAME= +cdev_tun_test() { - coproc MKFDS { "$TS_HELPER_MKFDS" cdev-tun $FD ; } - if read -u ${MKFDS[0]} PID IFNAME; then - EXPR='(FD == '"$FD"')' - ${TS_CMD_LSFD} -p "${PID}" -n -o ASSOC,MODE,TYPE,SOURCE -Q "${EXPR}" - echo 'ASSOC,MODE,TYPE,SOURCE': $? + local tname=domestic - output=$(${TS_CMD_LSFD} -p "${PID}" -n --raw -o NAME -Q "${EXPR}") - if [[ "$output" == "iface=$IFNAME" ]]; then - echo 'NAME': $? - else - echo 'NAME': $? - echo "expected NAME: iface=$IFNAME" - echo "output NAME: $output" - fi + ts_init_subtest "$tname" + { + coproc MKFDS { "$TS_HELPER_MKFDS" cdev-tun $FD ; } + + if read -u ${MKFDS[0]} PID IFNAME; then + EXPR='(FD == '"$FD"')' + ${TS_CMD_LSFD} -p "${PID}" -n -o ASSOC,MODE,TYPE,SOURCE -Q "${EXPR}" + echo 'ASSOC,MODE,TYPE,SOURCE': $? + + output=$(${TS_CMD_LSFD} -p "${PID}" -n --raw -o NAME -Q "${EXPR}") + if [[ "$output" == "iface=$IFNAME" ]]; then + echo 'NAME': $? + else + echo 'NAME': $? + echo "expected NAME: iface=$IFNAME" + echo "output NAME: $output" + fi - output=$(${TS_CMD_LSFD} -p "${PID}" -n --raw -o TUN.IFACE -Q "${EXPR}") - if [[ "$output" == "$IFNAME" ]]; then - echo 'TUN.IFACE': $? - else - echo 'TUN.IFAEC': $? - echo "expected TUN.IFACE: $IFNAME" - echo "output TUN.IFACE: $output" + output=$(${TS_CMD_LSFD} -p "${PID}" -n --raw -o TUN.IFACE -Q "${EXPR}") + if [[ "$output" == "$IFNAME" ]]; then + echo 'TUN.IFACE': $? + else + echo 'TUN.IFAEC': $? + echo "expected TUN.IFACE: $IFNAME" + echo "output TUN.IFACE: $output" + fi fi + } > $TS_OUTPUT 2>&1 + ts_finalize_subtest + if [[ -n "$PID" ]]; then echo DONE >&"${MKFDS[1]}" fi + wait ${MKFDS_PID} -} > $TS_OUTPUT 2>&1 +} + +cdev_tun_test ts_finalize From 711bda1441561bfd2eb6d45fe0bc789535c1f1a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20Rodr=C3=ADguez?= Date: Sat, 22 Nov 2025 10:41:08 -0300 Subject: [PATCH 090/174] lsfd: fix bsearch macro usage with glibc C23 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit C23 requires bsearch to be a const preserving macro, build now fails with ../lsfd-cmd/lsfd.c:1879:75: error: macro ‘bsearch’ passed 6 arguments, but takes just 5 1879 | nfds, sizeof(struct pollfd), pollfdcmp)) | ^ In file included from ../include/c.h:17, from ../lsfd-cmd/lsfd.c:48: /usr/include/stdlib.h:987:10: note: macro ‘bsearch’ defined here 987 | # define bsearch(KEY, BASE, NMEMB, SIZE, COMPAR) \ add parenthesis around expression to fix it. --- lsfd-cmd/lsfd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lsfd-cmd/lsfd.c b/lsfd-cmd/lsfd.c index 335594144dc..4da86c602e7 100644 --- a/lsfd-cmd/lsfd.c +++ b/lsfd-cmd/lsfd.c @@ -1875,7 +1875,7 @@ static void mark_poll_fds_as_multiplexed(char *buf, struct file *file = list_entry(f, struct file, files); if (is_opened_file(file) && !file->multiplexed) { int fd = file->association; - if (bsearch(&(struct pollfd){.fd = fd,}, local.iov_base, + if (bsearch((&(struct pollfd){.fd = fd,}), local.iov_base, nfds, sizeof(struct pollfd), pollfdcmp)) file->multiplexed = 1; } From ff2650962f09b9abef33116b9b4ecd1da2feacae Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Sun, 23 Nov 2025 16:18:48 +0900 Subject: [PATCH 091/174] lsfd: add TUN.DEVNETNS column lsfd can show the name of the network device behind a file descriptor pointing to a tun/tap device. # lsfd -Q 'SOURCE == "misc:tun"' COMMAND PID USER ASSOC XMODE TYPE SOURCE MNTID INODE NAME qemu-system-x86 846384 qemu 35 rw---- CHR misc:tun 36 1145 iface=vnet21 pasta.avx2 1837933 yamato 8 rw---m CHR misc:tun 2143 1145 iface=ens8191 ... This feature helps users inspect target processes, containers, and/or VMs with tools such as tcpdump, wireshark, or ip-link. However, I found a case where the device name was not sufficient. pasta (https://passt.top/) provides networking for rootless containers. It creates a tap device whose name matches the name of a network device on the host: $ ip link show ens8191 5: ens8191: mtu 1500 ... $ ethtool -i ens8191 | head -1 driver: atlantic $ podman exec 9fbbed215871 ip link show ens8191 2: ens8191: mtu 65520 ... $ podman exec 9fbbed215871 ethtool -i ens8191 | head -1 driver: tun A name alone is not enough to identify a network device on the system. With this change, lsfd reports the network namespace to which the tun/tap device belongs: # lsfd -Q 'SOURCE == "misc:tun"' -oCOMMAND,PID,SOURCE,TUN.DEVNETNS,NAME COMMAND PID SOURCE TUN.DEVNETNS NAME qemu-system-x86 846384 misc:tun 4026531840 iface=vnet21 devnetns=4026531840 pasta.avx2 1837933 misc:tun 4026536354 iface=ens8191 devnetns=4026536354 ... This change relies on the TUNGETDEVNETNS ioctl added in: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=0c3e0e3bb623c3735b8c9ab8aa8332f944f83a9f Signed-off-by: Masatake YAMATO --- lsfd-cmd/cdev.c | 77 ++++++++++++++++++- lsfd-cmd/lsfd.1.adoc | 5 +- lsfd-cmd/lsfd.c | 3 + lsfd-cmd/lsfd.h | 1 + ...mkfds-cdev-tun => mkfds-cdev-tun-domestic} | 0 .../lsfd/mkfds-cdev-tun-domestic-devnetns | 1 + tests/expected/lsfd/mkfds-cdev-tun-foreign | 4 + .../lsfd/mkfds-cdev-tun-foreign-devnetns | 1 + tests/ts/lsfd/mkfds-cdev-tun | 52 ++++++++++++- 9 files changed, 138 insertions(+), 6 deletions(-) rename tests/expected/lsfd/{mkfds-cdev-tun => mkfds-cdev-tun-domestic} (100%) create mode 100644 tests/expected/lsfd/mkfds-cdev-tun-domestic-devnetns create mode 100644 tests/expected/lsfd/mkfds-cdev-tun-foreign create mode 100644 tests/expected/lsfd/mkfds-cdev-tun-foreign-devnetns diff --git a/lsfd-cmd/cdev.c b/lsfd-cmd/cdev.c index fd20e38d17e..f047ef1b47c 100644 --- a/lsfd-cmd/cdev.c +++ b/lsfd-cmd/cdev.c @@ -20,6 +20,10 @@ */ #include "lsfd.h" +#include "pidfd-utils.h" + +#include /* ioctl */ +#include /* TUNGETDEVNETNS */ static struct list_head miscdevs; static struct list_head ttydrvs; @@ -371,6 +375,7 @@ static struct cdev_ops cdev_misc_ops = { */ struct tundata { const char *iff; + ino_t devnetns; /* 0 implies no value given. */ }; static bool cdev_tun_probe(struct cdev *cdev) @@ -406,7 +411,12 @@ static char * cdev_tun_get_name(struct cdev *cdev) if (tundata == NULL || tundata->iff == NULL) return NULL; - xasprintf(&str, "iface=%s", tundata->iff); + if (tundata->devnetns) + xasprintf(&str, "iface=%s devnetns=%llu", + tundata->iff, (unsigned long long)tundata->devnetns); + else + xasprintf(&str, "iface=%s", tundata->iff); + return str; } @@ -426,6 +436,12 @@ static bool cdev_tun_fill_column(struct proc *proc __attribute__((__unused__)), case COL_SOURCE: *str = xstrdup("misc:tun"); return true; + case COL_TUN_DEVNETNS: + if (tundata && tundata->devnetns) { + xasprintf(str, "%llu", (unsigned long long)tundata->devnetns); + return true; + } + break; case COL_TUN_IFACE: if (tundata && tundata->iff) { *str = xstrdup(tundata->iff); @@ -447,6 +463,64 @@ static int cdev_tun_handle_fdinfo(struct cdev *cdev, const char *key, const char return 0; } +#ifdef TUNGETDEVNETNS +static int call_with_foreign_fd(pid_t target_pid, int target_fd, + int (*fn)(int, void*), void *data) +{ + int pidfd, tfd, r; + + pidfd = pidfd_open(target_pid, 0); + if (pidfd < 0) + return pidfd; + + tfd = pidfd_getfd(pidfd, target_fd, 0); + if (tfd < 0) { + close(pidfd); + return tfd; + } + + r = fn(tfd, data); + + close(tfd); + close(pidfd); + return r; +} + +static int cdev_tun_get_devnetns(int tfd, void *data) +{ + + struct tundata *tundata = data; + int nsfd = ioctl(tfd, TUNGETDEVNETNS); + struct stat sb; + + if (nsfd < 0) + return -1; + + if (fstat(nsfd, &sb) == 0) + tundata->devnetns = sb.st_ino; + + close(nsfd); + + return 0; +} +#endif + +static void cdev_tun_attach_xinfo(struct cdev *cdev) +{ + struct tundata *tundata = cdev->cdev_data; + + if (tundata->iff == NULL) + return; + +#ifdef TUNGETDEVNETNS + { + struct file *file = &cdev->file; + call_with_foreign_fd(file->proc->pid, file->association, + cdev_tun_get_devnetns, tundata); + } +#endif +} + static struct cdev_ops cdev_tun_ops = { .parent = &cdev_misc_ops, .probe = cdev_tun_probe, @@ -454,6 +528,7 @@ static struct cdev_ops cdev_tun_ops = { .get_name = cdev_tun_get_name, .fill_column = cdev_tun_fill_column, .handle_fdinfo = cdev_tun_handle_fdinfo, + .attach_xinfo = cdev_tun_attach_xinfo, }; /* diff --git a/lsfd-cmd/lsfd.1.adoc b/lsfd-cmd/lsfd.1.adoc index 7c20c00de75..195e54d7eb9 100644 --- a/lsfd-cmd/lsfd.1.adoc +++ b/lsfd-cmd/lsfd.1.adoc @@ -307,7 +307,7 @@ inotify::: inodes=_INOTIFY.INODES_ + misc:tun::: -iface=_TUN.IFACE_ +iface=_TUN.IFACE_[ devnetns=_TUN.DEVNETNS_] + NETLINK::: protocol=_NETLINK.PROTOCOL_[ lport=_NETLINK.LPORT_[ group=_NETLINK.GROUPS_]] @@ -525,6 +525,9 @@ Remaining time. PTMX.TTY-INDEX <``number``>:: TTY index of the counterpart. +TUN.DEVNETNS <``number``>:: +Inode identifying network namespace where the device belongs. + TUN.IFACE <``string``>:: Network interface behind the tun device. diff --git a/lsfd-cmd/lsfd.c b/lsfd-cmd/lsfd.c index 64b9a27b3f4..18d1c12a3e1 100644 --- a/lsfd-cmd/lsfd.c +++ b/lsfd-cmd/lsfd.c @@ -406,6 +406,9 @@ static const struct colinfo infos[] = { [COL_TIMERFD_REMAINING]= { "TIMERFD.REMAINING", 0, SCOLS_FL_RIGHT, SCOLS_JSON_FLOAT, N_("remaining time") }, + [COL_TUN_DEVNETNS] = { "TUN.DEVNETNS", + 0, SCOLS_FL_RIGHT, SCOLS_JSON_NUMBER, + N_("inode identifying network namespace where the device belongs") }, [COL_TUN_IFACE] = { "TUN.IFACE", 0, SCOLS_FL_RIGHT, SCOLS_JSON_STRING, N_("network interface behind the tun device") }, diff --git a/lsfd-cmd/lsfd.h b/lsfd-cmd/lsfd.h index 916ad2d7652..ea9bf5e70fc 100644 --- a/lsfd-cmd/lsfd.h +++ b/lsfd-cmd/lsfd.h @@ -131,6 +131,7 @@ enum { COL_TIMERFD_CLOCKID, COL_TIMERFD_INTERVAL, COL_TIMERFD_REMAINING, + COL_TUN_DEVNETNS, COL_TUN_IFACE, COL_TYPE, COL_UDP_LADDR, diff --git a/tests/expected/lsfd/mkfds-cdev-tun b/tests/expected/lsfd/mkfds-cdev-tun-domestic similarity index 100% rename from tests/expected/lsfd/mkfds-cdev-tun rename to tests/expected/lsfd/mkfds-cdev-tun-domestic diff --git a/tests/expected/lsfd/mkfds-cdev-tun-domestic-devnetns b/tests/expected/lsfd/mkfds-cdev-tun-domestic-devnetns new file mode 100644 index 00000000000..291bc7d5315 --- /dev/null +++ b/tests/expected/lsfd/mkfds-cdev-tun-domestic-devnetns @@ -0,0 +1 @@ +TUN.DEVNETNS: 0 diff --git a/tests/expected/lsfd/mkfds-cdev-tun-foreign b/tests/expected/lsfd/mkfds-cdev-tun-foreign new file mode 100644 index 00000000000..5217d7939a3 --- /dev/null +++ b/tests/expected/lsfd/mkfds-cdev-tun-foreign @@ -0,0 +1,4 @@ +3 rw- CHR misc:tun +ASSOC,MODE,TYPE,SOURCE: 0 +NAME: 0 +TUN.IFACE: 0 diff --git a/tests/expected/lsfd/mkfds-cdev-tun-foreign-devnetns b/tests/expected/lsfd/mkfds-cdev-tun-foreign-devnetns new file mode 100644 index 00000000000..291bc7d5315 --- /dev/null +++ b/tests/expected/lsfd/mkfds-cdev-tun-foreign-devnetns @@ -0,0 +1 @@ +TUN.DEVNETNS: 0 diff --git a/tests/ts/lsfd/mkfds-cdev-tun b/tests/ts/lsfd/mkfds-cdev-tun index 028b420013d..1079167fb14 100755 --- a/tests/ts/lsfd/mkfds-cdev-tun +++ b/tests/ts/lsfd/mkfds-cdev-tun @@ -25,40 +25,65 @@ ts_skip_nonroot ts_check_test_command "$TS_CMD_LSFD" ts_check_test_command "$TS_HELPER_MKFDS" +ts_check_test_command "$TS_CMD_UNSHARE" +ts_check_test_command "$TS_CMD_LSNS" ts_cd "$TS_OUTDIR" PID= FD=3 IFNAME= +readonly MYNETNS=$($TS_CMD_LSNS -n -t net -p $$ -oNS) + +if [[ -z "$MYNETNS" ]]; then + ts_skip "the current netns is unknown" +fi cdev_tun_test() { - local tname=domestic + local unshare=$1 + local tname + local devnetns_available + local netns + + if [[ -z "$unshare" ]]; then + tname=domestic + netns=$MYNETNS + else + tname=foreign + fi ts_init_subtest "$tname" { - coproc MKFDS { "$TS_HELPER_MKFDS" cdev-tun $FD ; } + coproc MKFDS { $unshare "$TS_HELPER_MKFDS" cdev-tun $FD ; } if read -u ${MKFDS[0]} PID IFNAME; then EXPR='(FD == '"$FD"')' ${TS_CMD_LSFD} -p "${PID}" -n -o ASSOC,MODE,TYPE,SOURCE -Q "${EXPR}" echo 'ASSOC,MODE,TYPE,SOURCE': $? + if [[ -z "$netns" ]]; then + netns=$($TS_CMD_LSNS -n -t net -p $PID -oNS) + fi + output=$(${TS_CMD_LSFD} -p "${PID}" -n --raw -o NAME -Q "${EXPR}") - if [[ "$output" == "iface=$IFNAME" ]]; then + if [[ "$output" =~ "iface=$IFNAME"(\\x20devnetns=$netns)? ]]; then echo 'NAME': $? + if [[ -n "${BASH_REMATCH[1]}" ]]; then + devnetns_available=yes + fi else echo 'NAME': $? echo "expected NAME: iface=$IFNAME" echo "output NAME: $output" + echo "netns: $netns" fi output=$(${TS_CMD_LSFD} -p "${PID}" -n --raw -o TUN.IFACE -Q "${EXPR}") if [[ "$output" == "$IFNAME" ]]; then echo 'TUN.IFACE': $? else - echo 'TUN.IFAEC': $? + echo 'TUN.IFACE': $? echo "expected TUN.IFACE: $IFNAME" echo "output TUN.IFACE: $output" fi @@ -66,6 +91,24 @@ cdev_tun_test() } > $TS_OUTPUT 2>&1 ts_finalize_subtest + ts_init_subtest "$tname"-devnetns + if [[ -z "${devnetns_available}" ]]; then + ts_skip_subtest "no method to access devnetns on this platform" + else + { + output=$(${TS_CMD_LSFD} -p "${PID}" -n --raw -o TUN.DEVNETNS -Q "${EXPR}") + if [[ "$output" == "$netns" ]]; then + echo 'TUN.DEVNETNS': $? + else + echo 'TUN.DEVNETNS': $? + echo "expected TUN.DEVNETNS: $netns" + echo "output TUN.DEVNETNS: $output" + fi + } > $TS_OUTPUT 2>&1 + fi + ts_finalize_subtest + + if [[ -n "$PID" ]]; then echo DONE >&"${MKFDS[1]}" fi @@ -74,5 +117,6 @@ cdev_tun_test() } cdev_tun_test +cdev_tun_test "$TS_CMD_UNSHARE" --net ts_finalize From 14c1a16a1d85ec925e80970f7114d63b5fe0f1a9 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Sun, 23 Nov 2025 22:29:01 -0500 Subject: [PATCH 092/174] flock: fix incomplete -n option info in usage message Signed-off-by: Christian Goeschel Ndjomouo --- sys-utils/flock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys-utils/flock.c b/sys-utils/flock.c index fe1a71f7282..4cc0610e501 100644 --- a/sys-utils/flock.c +++ b/sys-utils/flock.c @@ -75,7 +75,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_( " -s, --shared get a shared lock\n"), stdout); fputs(_( " -x, --exclusive get an exclusive lock (default)\n"), stdout); fputs(_( " -u, --unlock remove a lock\n"), stdout); - fputs(_( " -n, --nonblock fail rather than wait\n"), stdout); + fputs(_( " -n, --nb, --nonblocking fail rather than wait\n"), stdout); fputs(_( " -w, --timeout wait for a limited amount of time\n"), stdout); fputs(_( " -E, --conflict-exit-code exit code after conflict or timeout\n"), stdout); fputs(_( " -o, --close close file descriptor before running command\n"), stdout); From 1a005e379d31eb36654bf23784f94e872fdb5b44 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Sun, 23 Nov 2025 22:31:00 -0500 Subject: [PATCH 093/174] bash-completion: (flock) add missing long options Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/flock | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bash-completion/flock b/bash-completion/flock index e9f9a851923..ce5049b7bca 100644 --- a/bash-completion/flock +++ b/bash-completion/flock @@ -27,7 +27,8 @@ _flock_module() OPTS="--shared --exclusive --unlock - --nonblock + --nb + --nonblocking --timeout --conflict-exit-code --close @@ -36,6 +37,7 @@ _flock_module() --fcntl --start --length + --wait --verbose --help --version" From 2470180bd9ff9cd0e7f18a39a9f1a8fb60e46fde Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Sun, 23 Nov 2025 22:35:09 -0500 Subject: [PATCH 094/174] bash-completion: (hwclock) add missing --ul-debug option Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/hwclock | 1 + 1 file changed, 1 insertion(+) diff --git a/bash-completion/hwclock b/bash-completion/hwclock index a82b87f6740..39232041624 100644 --- a/bash-completion/hwclock +++ b/bash-completion/hwclock @@ -59,6 +59,7 @@ _hwclock_module() --vl-read --vl-clear --update-drift + --ul-debug --noadjfile --adjfile --test From 0592699282f9f73cae07d4fe34f9ad653ad1cd5c Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Sun, 23 Nov 2025 22:40:26 -0500 Subject: [PATCH 095/174] bash-completion: (lsclocks) add missing --no-discover-rtc option Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/lsclocks | 1 + 1 file changed, 1 insertion(+) diff --git a/bash-completion/lsclocks b/bash-completion/lsclocks index dda9bba361a..175b3f05bf7 100644 --- a/bash-completion/lsclocks +++ b/bash-completion/lsclocks @@ -54,6 +54,7 @@ _lsclocks_module() --time --dynamic-clock --no-discover-dynamic + --no-discover-rtc --rtc --cpu-clock --help From f648be022a4c4e851235542419ce5d54a63dc0b8 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Sun, 23 Nov 2025 22:41:07 -0500 Subject: [PATCH 096/174] lsclocks: add missing --no-discover-rtc option info in usage message Signed-off-by: Christian Goeschel Ndjomouo --- misc-utils/lsclocks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/misc-utils/lsclocks.c b/misc-utils/lsclocks.c index 1d4f567bb33..5d22285b527 100644 --- a/misc-utils/lsclocks.c +++ b/misc-utils/lsclocks.c @@ -225,6 +225,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -r, --raw use raw output format\n"), out); fputs(_(" -t, --time show current time of single clock\n"), out); fputs(_(" --no-discover-dynamic do not try to discover dynamic clocks\n"), out); + fputs(_(" --no-discover-rtc do not try to discover RTCs"), out); fputs(_(" -d, --dynamic-clock also display specified dynamic clock\n"), out); fputs(_(" -c, --cpu-clock also display CPU clock of specified process\n"), out); From 09330dfe53260b89293ed9f9ed86db6efbb3f932 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Sun, 23 Nov 2025 22:51:34 -0500 Subject: [PATCH 097/174] lslogins: fix incomplete option info in usage message Signed-off-by: Christian Goeschel Ndjomouo --- login-utils/lslogins.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/login-utils/lslogins.c b/login-utils/lslogins.c index 90db60cbc89..2134d957d89 100644 --- a/login-utils/lslogins.c +++ b/login-utils/lslogins.c @@ -1582,9 +1582,11 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -z, --print0 delimit user entries with a nul character\n"), out); fputs(_(" --wtmp-file set an alternate path for wtmp\n"), out); fputs(_(" --btmp-file set an alternate path for btmp\n"), out); - fputs(_(" --lastlog set an alternate path for lastlog\n"), out); + fputs(_(" --lastlog-file \n" + " set an alternate path for lastlog\n"), out); #ifdef HAVE_LIBLASTLOG2 - fputs(_(" --lastlog2 set an alternate path for lastlog2\n"), out); + fputs(_(" --lastlog2-file \n" + " set an alternate path for lastlog2\n"), out); #endif fputs(USAGE_SEPARATOR, out); /* FIXME: Replace with USAGE_LIST_COLUMNS_OPTION() macro from include/c.h */ From 19d10eda1fc43f9d45429485ca28092e3d2e8bc9 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Sun, 23 Nov 2025 22:53:31 -0500 Subject: [PATCH 098/174] bash-completion: (lslogins) add missing long options Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/lslogins | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bash-completion/lslogins b/bash-completion/lslogins index cd6364f1f2d..efad4bc0b4b 100644 --- a/bash-completion/lslogins +++ b/bash-completion/lslogins @@ -72,7 +72,8 @@ _lslogins_module() --wtmp-file --btmp-file --shell - --lastlog + --lastlog-file + --lastlog-file2 --help --version" -- $cur) ) return 0 From 947a19355cab82236c632bea24d08e187bfaf45c Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Sun, 23 Nov 2025 22:57:35 -0500 Subject: [PATCH 099/174] mount: add missing --ro option info in usage message Signed-off-by: Christian Goeschel Ndjomouo --- sys-utils/mount.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys-utils/mount.c b/sys-utils/mount.c index 2450228d04d..377cafcf849 100644 --- a/sys-utils/mount.c +++ b/sys-utils/mount.c @@ -583,7 +583,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" --onlyonce check if filesystem is already mounted on target\n"), out); fputs(_(" -o, --options comma-separated list of mount options\n"), out); fputs(_(" -O, --test-opts limit the set of filesystems (use with -a)\n"), out); - fputs(_(" -r, --read-only mount the filesystem read-only (same as -o ro)\n"), out); + fputs(_(" -r, --ro, --read-only mount the filesystem read-only (same as -o ro)\n"), out); fputs(_(" -t, --types limit the set of filesystem types\n"), out); fputs(_(" --source explicitly specifies source (path, label, uuid)\n"), out); fputs(_(" --target explicitly specifies mountpoint\n"), out); From 22de06af301327e810d05a3a3aba5c653976a3d0 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Sun, 23 Nov 2025 22:58:35 -0500 Subject: [PATCH 100/174] mount: document --ro option on the man page Signed-off-by: Christian Goeschel Ndjomouo --- sys-utils/mount.8.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys-utils/mount.8.adoc b/sys-utils/mount.8.adoc index 9a5479fe54e..28978eda6c1 100644 --- a/sys-utils/mount.8.adoc +++ b/sys-utils/mount.8.adoc @@ -437,7 +437,7 @@ Use options from _fstab_/_mtab_ even if both _device_ and _dir_ are specified. *-R*, *--rbind*:: Remount a subtree and all possible submounts somewhere else (so that its contents are available in both places). See above, the subsection *Bind mount operation*. -*-r*, *--read-only*:: +*-r*, *--ro*, *--read-only*:: Mount the filesystem read-only. A synonym is *-o ro*. + Note that, depending on the filesystem type, state and kernel behavior, the system may still write to the device. For example, ext3 and ext4 will replay the journal if the filesystem is dirty. To prevent this kind of write access, you may want to mount an ext3 or ext4 filesystem with the *ro,noload* mount options or set the block device itself to read-only mode, see the *blockdev*(8) command. From 754d18b7029fadd2adad1ed2168fd4a2b5270133 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Sun, 23 Nov 2025 22:59:31 -0500 Subject: [PATCH 101/174] bash-completion: (mount) add missing --ro option Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/mount | 1 + 1 file changed, 1 insertion(+) diff --git a/bash-completion/mount b/bash-completion/mount index 3e208282847..616fb0b50dd 100644 --- a/bash-completion/mount +++ b/bash-completion/mount @@ -72,6 +72,7 @@ _mount_module() --options-source-force --test-opts --read-only + --ro --types --source --target From 661798cf3170d6c74fce5511194470d37876f7c2 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Sun, 23 Nov 2025 23:01:30 -0500 Subject: [PATCH 102/174] bash-completion: (mountpoint) add missing --show option Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/mountpoint | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bash-completion/mountpoint b/bash-completion/mountpoint index 15c6d2314aa..cca764517fe 100644 --- a/bash-completion/mountpoint +++ b/bash-completion/mountpoint @@ -11,7 +11,7 @@ _mountpoint_module() esac case $cur in -*) - OPTS="--quiet --nofollow --fs-devno --devno --help --version" + OPTS="--quiet --nofollow --fs-devno --devno --show --help --version" COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) ) return 0 ;; From dbd18d20e543d1c453235a3dec64edadc00642e3 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Sun, 23 Nov 2025 23:04:55 -0500 Subject: [PATCH 103/174] namei: reestablish --nosymlinks option's functionality Signed-off-by: Christian Goeschel Ndjomouo --- misc-utils/namei.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc-utils/namei.c b/misc-utils/namei.c index 0a9ed8df80e..3bfe216e39a 100644 --- a/misc-utils/namei.c +++ b/misc-utils/namei.c @@ -387,7 +387,7 @@ static const struct option longopts[] = { "modes", no_argument, NULL, 'm' }, { "owners", no_argument, NULL, 'o' }, { "long", no_argument, NULL, 'l' }, - { "nolinks", no_argument, NULL, 'n' }, + { "nosymlinks", no_argument, NULL, 'n' }, { "vertical", no_argument, NULL, 'v' }, #ifdef HAVE_LIBSELINUX { "context", no_argument, NULL, 'Z' }, From f485a07b4197c4216b8767bfa0e1bfd81c4175a1 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Sun, 23 Nov 2025 23:19:56 -0500 Subject: [PATCH 104/174] partx: mark the --list option as deprecated Signed-off-by: Christian Goeschel Ndjomouo --- disk-utils/partx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/disk-utils/partx.c b/disk-utils/partx.c index 68d29f62f41..f4affe9728e 100644 --- a/disk-utils/partx.c +++ b/disk-utils/partx.c @@ -813,7 +813,7 @@ int main(int argc, char **argv) { "bytes", no_argument, NULL, 'b' }, { "noheadings", no_argument, NULL, 'g' }, { "raw", no_argument, NULL, 'r' }, - { "list", no_argument, NULL, 'l' }, + { "list", no_argument, NULL, 'l' }, /* deprecated */ { "show", no_argument, NULL, 's' }, { "add", no_argument, NULL, 'a' }, { "delete", no_argument, NULL, 'd' }, From 647541d06ff7e23766aa45c006779fabbd6f61dc Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Sun, 23 Nov 2025 23:30:15 -0500 Subject: [PATCH 105/174] tunelp: remove extraneous -T option Signed-off-by: Christian Goeschel Ndjomouo --- sys-utils/tunelp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sys-utils/tunelp.c b/sys-utils/tunelp.c index 2201f81ce36..68b795d3b96 100644 --- a/sys-utils/tunelp.c +++ b/sys-utils/tunelp.c @@ -133,7 +133,6 @@ int main(int argc, char **argv) {"check-status", required_argument, NULL, 'o'}, {"careful", required_argument, NULL, 'C'}, {"status", no_argument, NULL, 's'}, - {"trust-irq", required_argument, NULL, 'T'}, {"reset", no_argument, NULL, 'r'}, {"print-irq", required_argument, NULL, 'q'}, {"version", no_argument, NULL, 'V'}, From a2a6b7d61eda1e16a7af3bdc16eccd16667c2e2b Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Sun, 23 Nov 2025 23:32:11 -0500 Subject: [PATCH 106/174] bash-completion: (unshare) add missing --map-subids option Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/unshare | 1 + 1 file changed, 1 insertion(+) diff --git a/bash-completion/unshare b/bash-completion/unshare index 219579c56aa..2d887bd5ce7 100644 --- a/bash-completion/unshare +++ b/bash-completion/unshare @@ -45,6 +45,7 @@ _unshare_module() --map-groups --map-user --map-users + --map-subids --mount-binfmt --monotonic --boottime From 6cc285a9d07d53099ce2e318466a56bb6b1e0606 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20Rodr=C3=ADguez?= Date: Mon, 24 Nov 2025 17:04:08 -0300 Subject: [PATCH 107/174] include: implement ARRAY_SIZE with compiler _Countof if supported C2Y has _Countof operator for this. GCC has an stdcountof.h hedaer and a countof definition Clang implements _Countof and needs __has_extension check --- include/c.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/c.h b/include/c.h index f7cd08fd8bb..0126591f2b6 100644 --- a/include/c.h +++ b/include/c.h @@ -133,6 +133,10 @@ C23 : https://en.cppreference.com/w/c/language/attributes/fallthrough #define __has_feature(x) 0 #endif +#ifndef __has_extension + #define __has_extension __has_feature +#endif + /* * Function attributes */ @@ -173,6 +177,15 @@ C23 : https://en.cppreference.com/w/c/language/attributes/fallthrough #define UL_BUILD_BUG_ON_ZERO(e) __extension__ (sizeof(struct { int:-!!(e); })) #define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); })) +#if __has_include() +#include +#define ARRAY_SIZE(arr) countof(arr) +#endif + +#if !defined(ARRAY_SIZE) && __has_extension(c_countof) +#define ARRAY_SIZE(arr) _Countof(arr) +#endif + #ifndef ARRAY_SIZE # define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr)) #endif From d9836753d1d8ac22701bc12817a9cf5ae6de52c4 Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Wed, 26 Nov 2025 17:36:53 +0900 Subject: [PATCH 108/174] docs: write about EditorConfig Signed-off-by: Masatake YAMATO --- Documentation/howto-contribute.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/howto-contribute.txt b/Documentation/howto-contribute.txt index 97f3ce1e160..80c2e9f0a1b 100644 --- a/Documentation/howto-contribute.txt +++ b/Documentation/howto-contribute.txt @@ -188,6 +188,9 @@ Coding Style multiple lines. In case the shorthand does not look good on one line use the normal "if () else" syntax. + * To avoid whitespace errors, consider installing an EditorConfig plugin + (https://editorconfig.org/) into your favorite editor or IDE. + Options * The rule of thumb for options is that once they exist, you may not From b243de928aab8565e264f4af1d776cc860689f64 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Wed, 26 Nov 2025 15:08:25 +0100 Subject: [PATCH 109/174] blkid: Drop const from blkid_partitions_get_name() const for idx is useless as the value is copied anyway, so drop the const. AFAIK this doesn't change ABI. --- libblkid/src/blkid.h.in | 2 +- libblkid/src/partitions/partitions.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libblkid/src/blkid.h.in b/libblkid/src/blkid.h.in index db70d9e5ad2..a0b381ccbaf 100644 --- a/libblkid/src/blkid.h.in +++ b/libblkid/src/blkid.h.in @@ -339,7 +339,7 @@ extern uint64_t blkid_topology_get_diskseq(blkid_topology tp) * partitions probing */ extern int blkid_known_pttype(const char *pttype); -extern int blkid_partitions_get_name(const size_t idx, const char **name); +extern int blkid_partitions_get_name(size_t idx, const char **name); extern int blkid_probe_enable_partitions(blkid_probe pr, int enable) __ul_attribute__((nonnull)); diff --git a/libblkid/src/partitions/partitions.c b/libblkid/src/partitions/partitions.c index 9df813c9214..e838b3db1f7 100644 --- a/libblkid/src/partitions/partitions.c +++ b/libblkid/src/partitions/partitions.c @@ -907,7 +907,7 @@ int blkid_known_pttype(const char *pttype) * * Returns: -1 if @idx is out of range, or 0 on success. */ -int blkid_partitions_get_name(const size_t idx, const char **name) +int blkid_partitions_get_name(size_t idx, const char **name) { if (idx < ARRAY_SIZE(idinfos)) { *name = idinfos[idx]->name; From 0cef3e4f5aac19bc3623883ca64c66538aa9b442 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Thu, 27 Nov 2025 10:27:07 +0100 Subject: [PATCH 110/174] lib, lscpu: fix const qualifier discarded warnings in bsearch Fix compilation warnings from newer compilers with stricter const-correctness checks. When bsearch() searches in const arrays, the result pointer must also be const to avoid discarding the const qualifier. Fixed in: - lib/color-names.c: searching in static const basic_schemes[] - sys-utils/lscpu-cputype.c: searching in const pattern arrays The warnings were: lib/color-names.c:62:13: error: assignment discards 'const' qualifier from pointer target type [-Werror=discarded-qualifiers] Signed-off-by: Karel Zak --- lib/color-names.c | 3 ++- sys-utils/lscpu-cputype.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/color-names.c b/lib/color-names.c index 88c4ef95774..daebcedaef5 100644 --- a/lib/color-names.c +++ b/lib/color-names.c @@ -54,7 +54,8 @@ const char *color_sequence_from_colorname(const char *str) { "white", UL_COLOR_WHITE }, { "yellow", UL_COLOR_BOLD_YELLOW } }; - struct ul_color_name key = { .name = str }, *res; + struct ul_color_name key = { .name = str }; + const struct ul_color_name *res; if (!str) return NULL; diff --git a/sys-utils/lscpu-cputype.c b/sys-utils/lscpu-cputype.c index eda6bd1004b..958cbe7b67c 100644 --- a/sys-utils/lscpu-cputype.c +++ b/sys-utils/lscpu-cputype.c @@ -450,7 +450,8 @@ static char *key_cleanup(char *str, int *keynum) static const struct cpuinfo_pattern *cpuinfo_parse_line(char *str, char **value, int *keynum) { - struct cpuinfo_pattern key = { .id = 0 }, *pat; + struct cpuinfo_pattern key = { .id = 0 }; + const struct cpuinfo_pattern *pat; char *p, *v; char buf[CPUTYPE_PATTERN_BUFSZ] = { 0 }; From dbe4c16973d5d0f69ba3bf1bd8942a51de9a0933 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Thu, 27 Nov 2025 15:41:21 +0100 Subject: [PATCH 111/174] lsns: fix const qualifier warnings for C23 Fix const qualifier discarded warnings in read_persistent_namespaces() and is_path_included() functions. These warnings are reported by gcc 15 which defaults to the C23 standard. The strchr() and strstr() functions return pointers into const strings, so the receiving variables must be declared as const char *. Signed-off-by: Karel Zak --- sys-utils/lsns.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sys-utils/lsns.c b/sys-utils/lsns.c index 2e887e80253..2b73377775c 100644 --- a/sys-utils/lsns.c +++ b/sys-utils/lsns.c @@ -1030,8 +1030,8 @@ static int read_persistent_namespaces(struct lsns *ls) struct libmnt_fs *fs = NULL; while (mnt_table_next_fs(ls->tab, itr, &fs) == 0) { - const char *root; - char *p, *end = NULL; + const char *root, *p; + char *end = NULL; ino_t ino; int fd; @@ -1126,7 +1126,7 @@ static int is_path_included(const char *path_set, const char *elt, { size_t elt_len; size_t path_set_len; - char *tmp; + const char *tmp; tmp = strstr(path_set, elt); From c0c79c41527365ca7de30c75daaa018ea01fff97 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Thu, 27 Nov 2025 15:45:55 +0100 Subject: [PATCH 112/174] libmount: fix const qualifier warnings for C23 Fix const qualifier discarded warnings in optlist_add_flags(), mnt_opt_value_with(), and mnt_optstr_apply_flags() functions. These warnings are reported by gcc 15 which defaults to the C23 standard. The strchr() and strstr() functions return pointers into const strings, so the receiving variables must be declared as const char *. Signed-off-by: Karel Zak --- libmount/src/optlist.c | 7 +++---- libmount/src/optstr.c | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/libmount/src/optlist.c b/libmount/src/optlist.c index 256c592fdec..1d32c2dd6ea 100644 --- a/libmount/src/optlist.c +++ b/libmount/src/optlist.c @@ -601,7 +601,7 @@ static int optlist_add_flags(struct libmnt_optlist *ls, unsigned long flags, for (ent = map; ent && ent->name; ent++) { - char *p; + const char *p; size_t sz; struct libmnt_opt *opt; @@ -621,7 +621,7 @@ static int optlist_add_flags(struct libmnt_optlist *ls, unsigned long flags, sz = p - ent->name; p -= sz; } else { - p = (char *) ent->name; + p = ent->name; sz = strlen(ent->name); /* alone "name" */ } @@ -1162,8 +1162,7 @@ const char *mnt_opt_get_value(struct libmnt_opt *opt) /* check if option value is @str or comma separated @str */ int mnt_opt_value_with(struct libmnt_opt *opt, const char *str) { - char *p; - const char *start = opt->value; + const char *p, *start = opt->value; size_t len; if (!str || !opt->value || !*opt->value) diff --git a/libmount/src/optstr.c b/libmount/src/optstr.c index ac20d875571..51526973dfa 100644 --- a/libmount/src/optstr.c +++ b/libmount/src/optstr.c @@ -807,7 +807,7 @@ int mnt_optstr_apply_flags(char **optstr, unsigned long flags, const struct libmnt_optmap *ent; struct ul_buffer buf = UL_INIT_BUFFER; size_t sz; - char *p; + const char *p; ul_buffer_refer_string(&buf, *optstr); From 530bf5c5b071753e149699c638ad1820daf5c205 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Thu, 27 Nov 2025 16:24:11 +0100 Subject: [PATCH 113/174] libmount: fix const qualifier warning in mnt_parse_mountinfo_line Fix const qualifier discarded warning in mnt_parse_mountinfo_line(). This warning is reported by gcc 15 which defaults to the C23 standard. The strstr() function returns a pointer into a const string, so introduce a separate 'sep' variable to hold this const pointer, keeping 'p' for non-const unmangle() results that need to be freed. Signed-off-by: Karel Zak --- libmount/src/tab_parse.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/libmount/src/tab_parse.c b/libmount/src/tab_parse.c index bd15ad90985..7ec4c401635 100644 --- a/libmount/src/tab_parse.c +++ b/libmount/src/tab_parse.c @@ -186,6 +186,7 @@ static int mnt_parse_mountinfo_line(struct libmnt_fs *fs, const char *s) int rc = 0; unsigned int maj, min; char *p; + const char *sep; fs->flags |= MNT_FS_KERNEL; mnt_fs_mark_attached(fs); @@ -243,15 +244,15 @@ static int mnt_parse_mountinfo_line(struct libmnt_fs *fs, const char *s) } /* (7) optional fields, terminated by " - " */ - p = strstr(s, " - "); - if (!p) { + sep = strstr(s, " - "); + if (!sep) { DBG(TAB, ul_debug("mountinfo parse error: separator not found")); return -EINVAL; } - if (p > s + 1) - fs->opt_fields = strndup(s + 1, p - s - 1); + if (sep > s + 1) + fs->opt_fields = strndup(s + 1, sep - s - 1); - s = skip_separator(p + 3); + s = skip_separator(sep + 3); /* (8) FS type */ p = unmangle(s, &s); From c45442ef125270d0ab2cb539747ccaf737d60d37 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Thu, 27 Nov 2025 16:28:41 +0100 Subject: [PATCH 114/174] libblkid: fix const qualifier warning in blkid_parse_tag_string Fix const qualifier discarded warning in blkid_parse_tag_string(). This warning is reported by gcc 15 which defaults to the C23 standard. The strchr() function returns a pointer into a const string, so introduce a separate 'eq' variable to hold this const pointer for finding the '=' separator. Also move the 'cp' variable declaration into the block where it's actually used for quote handling. Signed-off-by: Karel Zak --- libblkid/src/tag.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libblkid/src/tag.c b/libblkid/src/tag.c index 178336505fd..f195c0625cf 100644 --- a/libblkid/src/tag.c +++ b/libblkid/src/tag.c @@ -202,21 +202,23 @@ int blkid_set_tag(blkid_dev dev, const char *name, */ int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val) { - char *name, *value, *cp; + char *name, *value; + const char *eq; DBG(TAG, ul_debug("trying to parse '%s' as a tag", token)); - if (!token || !(cp = strchr(token, '='))) + if (!token || !(eq = strchr(token, '='))) return -1; name = strdup(token); if (!name) return -1; - value = name + (cp - token); + value = name + (eq - token); *value++ = '\0'; if (*value == '"' || *value == '\'') { char c = *value++; - if (!(cp = strrchr(value, c))) + char *cp = strrchr(value, c); + if (!cp) goto errout; /* missing closing quote */ *cp = '\0'; } From 40e6850d2b2ba2492d5f3e75656cb9bcce2806bb Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Thu, 27 Nov 2025 16:33:04 +0100 Subject: [PATCH 115/174] dmesg: fix const qualifier warnings in parse_callerid Fix const qualifier discarded warnings in parse_callerid(). These warnings are reported by gcc 15 which defaults to the C23 standard. The strchr() and strstr() functions return pointers into const strings, so the receiving variables must be declared as const char *. Signed-off-by: Karel Zak --- sys-utils/dmesg.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sys-utils/dmesg.c b/sys-utils/dmesg.c index f4b04840025..402323247d6 100644 --- a/sys-utils/dmesg.c +++ b/sys-utils/dmesg.c @@ -844,8 +844,7 @@ static const char *parse_callerid(const char *p_str, const char *end, const char *p_after; const char *p_next; size_t cid_size; - char *p_scn; - char *p_cid; + const char *p_scn, *p_cid; /* Check for PRINTK_CALLER prefix, must be before msg text */ p_cid = strstr(p_str, DMESG_CALLER_PREFIX); From 014d2779afb4118d7117442eeed562e2c7b7594f Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Thu, 27 Nov 2025 16:35:56 +0100 Subject: [PATCH 116/174] lsfd: fix const qualifier warning in new_counter_spec Fix const qualifier discarded warning in new_counter_spec(). This warning is reported by gcc 15 which defaults to the C23 standard. The function modifies the input string by inserting a null terminator to split it into name and expression parts, so the parameter should be char * rather than const char *. Signed-off-by: Karel Zak --- lsfd-cmd/lsfd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lsfd-cmd/lsfd.c b/lsfd-cmd/lsfd.c index b7d996f6e81..26d0bd54a61 100644 --- a/lsfd-cmd/lsfd.c +++ b/lsfd-cmd/lsfd.c @@ -2320,7 +2320,7 @@ static struct libscols_filter *new_filter(const char *expr, bool debug, struct l return f; } -static struct counter_spec *new_counter_spec(const char *spec_str) +static struct counter_spec *new_counter_spec(char *spec_str) { char *sep; struct counter_spec *spec; From 935f2ab21add95059a92208f69ef578708307481 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Thu, 27 Nov 2025 16:38:18 +0100 Subject: [PATCH 117/174] lsfd: fix const qualifier warning in strnrstr Fix const qualifier discarded warning in strnrstr(). This warning is reported by gcc 15 which defaults to the C23 standard. The function returns a non-const pointer into the haystack parameter, and callers modify the string through that pointer. Therefore, the haystack parameter should be char * rather than const char *. Signed-off-by: Karel Zak --- lsfd-cmd/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lsfd-cmd/file.c b/lsfd-cmd/file.c index 2857c941039..0df0554f578 100644 --- a/lsfd-cmd/file.c +++ b/lsfd-cmd/file.c @@ -384,7 +384,7 @@ void decode_source(char *buf, size_t bufsize, dev_minor); } -static char *strnrstr(const char *haystack, const char *needle, size_t needle_len) +static char *strnrstr(char *haystack, const char *needle, size_t needle_len) { char *last = strstr(haystack, needle); if (last == NULL) From 22c3b959ef381b35a55ed00cf6acd2507b461d4b Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Thu, 27 Nov 2025 16:43:38 +0100 Subject: [PATCH 118/174] logger: fix const qualifier warnings for C23 Fix const qualifier discarded warnings in valid_structured_data_param() and valid_structured_data_id() functions. These warnings are reported by gcc 15 which defaults to the C23 standard. The strchr() and strstr() functions return pointers into const strings, so the receiving variables must be declared as const char *. Signed-off-by: Karel Zak --- misc-utils/logger.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/misc-utils/logger.c b/misc-utils/logger.c index d27c8064f32..89fa4e8a314 100644 --- a/misc-utils/logger.c +++ b/misc-utils/logger.c @@ -699,10 +699,10 @@ static char *get_structured_data_string(struct logger_ctl *ctl) static int valid_structured_data_param(const char *str) { - char *s; - char *eq = strchr(str, '='), - *qm1 = strchr(str, '"'), - *qm2 = qm1 ? ul_strchr_escaped(qm1 + 1, '"') : NULL; + const char *s; + const char *eq = strchr(str, '='), + *qm1 = strchr(str, '"'), + *qm2 = qm1 ? ul_strchr_escaped(qm1 + 1, '"') : NULL; /* something is missing */ if (!eq || !qm1 || !qm2) @@ -710,7 +710,7 @@ static int valid_structured_data_param(const char *str) /* ']' need to be escaped */ for (s = qm1 + 1; s && *s; ) { - char *p = strchr(s, ']'); + const char *p = strchr(s, ']'); if (!p) break; if (p > qm2 || p == ul_strchr_escaped(s, ']')) @@ -720,7 +720,7 @@ static int valid_structured_data_param(const char *str) /* '\' is allowed only before '[]"\' chars */ for (s = qm1 + 1; s && *s; ) { - char *p = strchr(s, '\\'); + const char *p = strchr(s, '\\'); if (!p) break; if (!strchr("[]\"\\", *(p + 1))) @@ -739,7 +739,7 @@ static int valid_structured_data_param(const char *str) */ static int valid_structured_data_id(const char *str) { - char *at = strchr(str, '@'); + const char *at = strchr(str, '@'); const char *p; /* standardized IDs without @ */ From e318417f00982bf496fd2359853b07ada3e3c544 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Thu, 27 Nov 2025 16:44:47 +0100 Subject: [PATCH 119/174] namei: fix const qualifier warning in readlink_to_namei Fix const qualifier discarded warning in readlink_to_namei(). This warning is reported by gcc 15 which defaults to the C23 standard. The strrchr() function returns a pointer into a const string, so the receiving variable must be declared as const char *. Signed-off-by: Karel Zak --- misc-utils/namei.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc-utils/namei.c b/misc-utils/namei.c index 3bfe216e39a..768ae00d7ab 100644 --- a/misc-utils/namei.c +++ b/misc-utils/namei.c @@ -100,7 +100,7 @@ readlink_to_namei(struct namei *nm, const char *path) if (sz < 1) err(EXIT_FAILURE, _("failed to read symlink: %s"), path); if (*sym != '/') { - char *p = strrchr(path, '/'); + const char *p = strrchr(path, '/'); if (p) { isrel = 1; From 01018b74163f9122c75179a7c991b0aa0f8c603c Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Thu, 27 Nov 2025 16:46:22 +0100 Subject: [PATCH 120/174] whereis: fix const qualifier warnings for C23 Fix const qualifier discarded warnings in dirlist_add_subdir() and lookup() functions. These warnings are reported by gcc 15 which defaults to the C23 standard. The strchr() and strrchr() functions return pointers into const strings, so the receiving variables must be declared as const char *. Signed-off-by: Karel Zak --- misc-utils/whereis.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/misc-utils/whereis.c b/misc-utils/whereis.c index f705ac278ef..2e2ecda9e98 100644 --- a/misc-utils/whereis.c +++ b/misc-utils/whereis.c @@ -270,7 +270,7 @@ static void dirlist_add_subdir(struct wh_dirlist **ls, int type, const char *dir char buf[PATH_MAX], *d; DIR *dirp; struct dirent *dp; - char *postfix; + const char *postfix; size_t len; postfix = strchr(dir, '*'); @@ -474,11 +474,12 @@ static void lookup(const char *pattern, struct wh_dirlist *ls, int want) { char patbuf[PATH_MAX] = { 0 }; int count = 0; - char *wait = NULL, *p; + char *wait = NULL; + const char *p; /* canonicalize pattern -- remove path suffix etc. */ p = strrchr(pattern, '/'); - p = p ? p + 1 : (char *) pattern; + p = p ? p + 1 : pattern; xstrncpy(patbuf, p, PATH_MAX); DBG(SEARCH, ul_debug("lookup dirs for '%s' (%s), want: %s %s %s", From 70379d240dcf975d140160bb4c14cf1b3fe70bcc Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Thu, 27 Nov 2025 16:47:46 +0100 Subject: [PATCH 121/174] enosys: fix const qualifier warning in parse_block Fix const qualifier discarded warning in parse_block(). This warning is reported by gcc 15 which defaults to the C23 standard. The strchr() function returns a pointer into a const string, so the receiving variable must be declared as const char *. Signed-off-by: Karel Zak --- misc-utils/enosys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc-utils/enosys.c b/misc-utils/enosys.c index 68e426c9ddc..f1438b8e83e 100644 --- a/misc-utils/enosys.c +++ b/misc-utils/enosys.c @@ -108,7 +108,7 @@ static struct blocked_number *parse_block(const char *s, int ret, const struct s struct blocked_number *blocked; const char *name, *error_name; long blocked_number; - char *colon; + const char *colon; bool found; size_t i; From 4c94ce5d05d97420df7a512bbbaee8c4017414ae Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Thu, 27 Nov 2025 16:48:53 +0100 Subject: [PATCH 122/174] partx: fix const qualifier warning in get_max_partno Fix const qualifier discarded warning in get_max_partno(). This warning is reported by gcc 15 which defaults to the C23 standard. The strrchr() function returns a pointer into a const string, so the receiving variable must be declared as const char *. Signed-off-by: Karel Zak --- disk-utils/partx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/disk-utils/partx.c b/disk-utils/partx.c index f4affe9728e..bb1bdc26895 100644 --- a/disk-utils/partx.c +++ b/disk-utils/partx.c @@ -219,7 +219,8 @@ static int get_partno_from_device(char *partition, dev_t devno) static int get_max_partno(const char *disk, dev_t devno) { - char path[PATH_MAX], *parent, *dirname = NULL; + char path[PATH_MAX], *dirname = NULL; + const char *parent; struct stat st; DIR *dir; struct dirent *d; From cc1f2ac99b99eede36a58cf115a56bdfbc977e52 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Thu, 27 Nov 2025 16:50:19 +0100 Subject: [PATCH 123/174] eject: fix const qualifier warning in read_speed Fix const qualifier discarded warning in read_speed(). This warning is reported by gcc 15 which defaults to the C23 standard. The strrchr() function returns a pointer into a const string, so the receiving variable must be declared as const char *. Signed-off-by: Karel Zak --- sys-utils/eject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys-utils/eject.c b/sys-utils/eject.c index f5d48badb38..0debd0df334 100644 --- a/sys-utils/eject.c +++ b/sys-utils/eject.c @@ -492,7 +492,7 @@ static void select_speed(const struct eject_control *ctl) static int read_speed(const char *devname) { int drive_number = -1; - char *name; + const char *name; FILE *f; f = fopen(_PATH_PROC_CDROMINFO, "r"); From c608d7f851b6306ae4cb2faf2e00cf29e83d498b Mon Sep 17 00:00:00 2001 From: cgoesche Date: Fri, 31 Oct 2025 01:58:11 -0400 Subject: [PATCH 124/174] tools: new helper for extraction of program long options from source files Signed-off-by: Christian Goeschel Ndjomouo --- tools/checkcompletion.sh | 35 +++++++++++++++ tools/get-options.sh | 96 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100755 tools/get-options.sh diff --git a/tools/checkcompletion.sh b/tools/checkcompletion.sh index 58e1f7a08c7..c815c1c43e8 100755 --- a/tools/checkcompletion.sh +++ b/tools/checkcompletion.sh @@ -97,6 +97,35 @@ extract_meson_registered() { fi } +# Check for the bash-completion file integrity, i.e. all long options are completed +# Argument(s): program_name +check_completion_file_integrity() { + local prog="$1" + + if "./$prog" --version &>/dev/null; then + prog_long_opts="$( "./$prog" --help \ + | grep -o -P '[[:space:]]*--(?![^[:alpha:]])[A-Za-z-]*' \ + | sed -e 's/^ *//' \ + -e 's/ *$//' \ + | sort \ + | uniq )" + + comp_opts="$( cat "${completion_dir}/${prog}" \ + | grep -o -P '[[:space:]]*--(?![^[:alpha:]])[A-Za-z-]*' \ + | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' \ + | sort \ + | uniq )" + + res="$( comm -23 <(echo "${prog_long_opts}") <(echo "${comp_opts}") )" + if [ -n "$res" ]; then + printf "%s\n%s\n" "${prog}:" "$res" + return 1 + fi + fi + + return 0 +} + # Get programs that should have completions programs=$(extract_programs | grep -v -w -E "(${exclude_programs}|${special_handling})") @@ -148,6 +177,12 @@ if [ -n "$meson_unregistered" ]; then errors=$((errors + 1)) fi +if [ $errors -eq 0 ]; then + for f in $files; do + check_completion_file_integrity "$f" || errors=$((errors + 1)) + done +fi + if [ $errors -eq 0 ]; then echo "All bash-completion files are consistent." exit 0 diff --git a/tools/get-options.sh b/tools/get-options.sh new file mode 100755 index 00000000000..49d798ce7ba --- /dev/null +++ b/tools/get-options.sh @@ -0,0 +1,96 @@ +#!/bin/bash + +# This file is part of util-linux. +# +# This file 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 file is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# Copyright (C) 2025 Christian Goeschel Ndjomouo +TOP_SRCDIR=${TOP_SRCDIR:-../} + +# Directories that contain relevant source files for util-linux programs. +src_file_paths="$(grep -rE --include="*.c" --exclude="*test_*" \ + --exclude-dir="lib*" \ + --exclude-dir="po*" \ + --exclude-dir="tests" \ + --exclude-dir="tools" \ + --exclude-dir="bash-completion" \ + --exclude-dir=".[a-z]*" \ + --exclude-dir="man-common" \ + --exclude-dir="Documentation" \ + --exclude-dir="build*" \ + -l "getopt_long(_only)?\s*\(" \ + )" + +# We skip these programs because they do not make use of 'struct option longopts[]' +# which is passed to getopt(3) for command line argument parsing. +unsupported_programs='blockdev|fsck|mkfs\.cramfs|pg|renice|whereis' + +# In general a program's source file name will be '.c', however +# some tools have differing file names. To handle these special cases we build +# a hash table with the program name as the key and the actual source file name +# as the value, the latter will ultimately be passed to find_prog_src(). +typeset -A canonical_src_prefix +canonical_src_prefix=( \ + [su]="su-common" +) + +function find_prog_src() { + local prog + prog="$1" + + for p in ${src_file_paths}; do + if [[ "${p##*/}" =~ ^"${prog}".c$ ]]; then + echo "${TOP_SRCDIR}/${p}" + break + fi + done +} + +function extract_long_opts() { + local src_path + src_path="$1" + + awk -F ',' 'BEGIN { x = 0 }; \ + /struct[[:space:]]*option[[:space:]]*.*[[:space:]]*\[\][[:space:]]*=[[:space:]]*(\{)?/ { x = 1 } \ + x && ! /.*\/\*.*(deprecated|COMPLETION:no).*\*\/.*/ { print $1 } \ + /\};/ { x = 0 }' "${src_path}" \ + | grep -Eo '".*"' \ + | tr -d '"' \ + | sort \ + | awk '{ printf "--%s\n", $0 }' \ + | grep -v '^--_.*$' +} + +function main() { + local progname + progname="$1" + + if [[ "$progname" =~ $unsupported_programs ]]; then + echo "ENOTSUP" + return 0 + fi + + # Handle special programs that have unusual source file names + if [ -n "${canonical_src_prefix[$progname]+exists}" ]; then + progname="${canonical_src_prefix[$progname]}" + fi + + src_path="$(find_prog_src "$progname")" + if [ -z "$src_path" ]; then + return 1 + fi + + extract_long_opts "$src_path" + + return 0 +} + +main "$@" From 0166a0de4ca6b2b019236a987979d0bd2fc1e41c Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Sun, 23 Nov 2025 22:07:56 -0500 Subject: [PATCH 125/174] tools: (checkcompletion.sh) test the integrity of long options completion Signed-off-by: Christian Goeschel Ndjomouo --- tools/checkcompletion.sh | 58 +++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/tools/checkcompletion.sh b/tools/checkcompletion.sh index c815c1c43e8..c92354a2c46 100755 --- a/tools/checkcompletion.sh +++ b/tools/checkcompletion.sh @@ -6,8 +6,10 @@ # 2. All bash-completion files are registered in bash-completion/Makemodule.am # 3. All bash-completion files are registered in meson.build # 4. All bash-completion files correspond to actual programs +# 5. All bash-completion files handle all available long options in each program # # Copyright (C) 2025 Karel Zak +# Copyright (C) 2025 Christian Goeschel Ndjomouo # set -e @@ -43,7 +45,11 @@ exclude_programs="nologin|agetty|login|sulogin|switch_root|vipw|line|kill" # These are handled via install-data-hook-bashcomp-* rules # - runuser: symlinked to su completion # - lastb: symlinked to last completion -special_handling="runuser|lastb" +special_handling="runuser|lastb" + +# Certain completions have an unusual algorithm that is distinct from the pattern used +# in the majority of completion files, we skip these for now. +unusual_completions="pipesz" top_srcdir=${1:-.} [ -d "${top_srcdir}" ] || die "directory '${top_srcdir}' not found" @@ -102,25 +108,34 @@ extract_meson_registered() { check_completion_file_integrity() { local prog="$1" - if "./$prog" --version &>/dev/null; then - prog_long_opts="$( "./$prog" --help \ - | grep -o -P '[[:space:]]*--(?![^[:alpha:]])[A-Za-z-]*' \ - | sed -e 's/^ *//' \ - -e 's/ *$//' \ + prog_long_opts="$( TOP_SRCDIR="${top_srcdir}" "${top_srcdir}"/tools/get-options.sh "$prog" \ + | sed -e 's/^$//' -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + + if [[ "$?" != "0" || -z "$prog_long_opts" ]]; then + echo "Failed to get long options for $prog" + return 1 + fi + + # tools/get-options.sh prints 'ENOTSUP' when it receives the name of an + # unsupported program. See comments for the 'unsupported_programs' variable + # in tools/get-options.sh for more details. + # + # We do not treat this case as an error, thereby we simply return 0 to the + # caller and skip the comparison. + if [ "$prog_long_opts" == "ENOTSUP" ]; then + return 0 + fi + + comp_opts="$( cat "${completion_dir}/${prog}" \ + | grep -o -P '[[:space:]]*--(?![^[:alnum:]])[A-Za-z-.0-9_]*' \ + | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' \ | sort \ | uniq )" - comp_opts="$( cat "${completion_dir}/${prog}" \ - | grep -o -P '[[:space:]]*--(?![^[:alpha:]])[A-Za-z-]*' \ - | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' \ - | sort \ - | uniq )" - - res="$( comm -23 <(echo "${prog_long_opts}") <(echo "${comp_opts}") )" - if [ -n "$res" ]; then - printf "%s\n%s\n" "${prog}:" "$res" - return 1 - fi + res="$( comm -23 <(echo "${prog_long_opts}") <(echo "${comp_opts}") )" + if [ -n "$res" ]; then + printf "%s\n%s\n" "${prog}:" "$res" + return 1 fi return 0 @@ -177,11 +192,10 @@ if [ -n "$meson_unregistered" ]; then errors=$((errors + 1)) fi -if [ $errors -eq 0 ]; then - for f in $files; do - check_completion_file_integrity "$f" || errors=$((errors + 1)) - done -fi +for f in $files; do + [[ "$f" =~ $unusual_completions ]] && continue + check_completion_file_integrity "$f" || errors=$((errors + 1)) +done if [ $errors -eq 0 ]; then echo "All bash-completion files are consistent." From c5c8326a8a19b7560b23fea386804c9f1325295b Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Thu, 27 Nov 2025 00:40:54 -0500 Subject: [PATCH 126/174] bash-completion: (lslogins) fix typo in long option Signed-off-by: Christian Goeschel Ndjomouo --- bash-completion/lslogins | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bash-completion/lslogins b/bash-completion/lslogins index efad4bc0b4b..dd1770855d5 100644 --- a/bash-completion/lslogins +++ b/bash-completion/lslogins @@ -73,7 +73,7 @@ _lslogins_module() --btmp-file --shell --lastlog-file - --lastlog-file2 + --lastlog2-file --help --version" -- $cur) ) return 0 From ab9f074397eee7c9db308dad1b40125f1e1c9f2c Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Fri, 28 Nov 2025 01:17:03 -0500 Subject: [PATCH 127/174] lslogins: remove duplicate errno initialization Signed-off-by: Christian Goeschel Ndjomouo --- login-utils/lslogins.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/login-utils/lslogins.c b/login-utils/lslogins.c index 2134d957d89..96d0299c638 100644 --- a/login-utils/lslogins.c +++ b/login-utils/lslogins.c @@ -800,7 +800,6 @@ static struct lslogins_user *get_user_info(struct lslogins_control *ctl, const c size_t n = 0; time_t time; uid_t uid; - errno = 0; errno = 0; pwd = username ? getpwnam(username) : getpwent(); @@ -1183,7 +1182,7 @@ static int create_usertree(struct lslogins_control *ctl) int rc = get_user(ctl, &user, ctl->ulist[n]); if (ctl->fail_on_unknown && !user) { - warnx(_("cannot found '%s'"), ctl->ulist[n]); + warnx(_("cannot find '%s'"), ctl->ulist[n]); return -1; } if (rc || !user) From 4a1d1e33b56beccfb70d4f10e4ea1a5b91a5af2f Mon Sep 17 00:00:00 2001 From: Jonathan Thackray Date: Thu, 27 Nov 2025 16:54:40 +0000 Subject: [PATCH 128/174] lscpu: Add a few missing Arm CPU identifiers --- sys-utils/lscpu-arm.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sys-utils/lscpu-arm.c b/sys-utils/lscpu-arm.c index b5cdd69a28a..563ececfd83 100644 --- a/sys-utils/lscpu-arm.c +++ b/sys-utils/lscpu-arm.c @@ -23,6 +23,9 @@ struct id_part { }; static const struct id_part arm_part[] = { + { 0xb36, "ARM1136j-s" }, + { 0xb56, "ARM1156t2-s" }, + { 0xb76, "ARM1176jz-s" }, { 0x810, "ARM810" }, { 0x920, "ARM920" }, { 0x922, "ARM922" }, @@ -69,10 +72,12 @@ static const struct id_part arm_part[] = { { 0xd0d, "Cortex-A77" }, { 0xd0e, "Cortex-A76AE" }, { 0xd13, "Cortex-R52" }, + { 0xd14, "Cortex-R82AE" }, { 0xd15, "Cortex-R82" }, { 0xd16, "Cortex-R52+" }, { 0xd20, "Cortex-M23" }, { 0xd21, "Cortex-M33" }, + { 0xd24, "Cortex-M52" }, { 0xd22, "Cortex-M55" }, { 0xd23, "Cortex-M85" }, { 0xd40, "Neoverse-V1" }, From 3ce751c0347de472ac1dcdd58e06a21759f1ad78 Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Sun, 30 Nov 2025 04:10:46 +0900 Subject: [PATCH 129/174] lsfd: fix memory leak related to stat_error_class Memory objects pointed by the name member of a file object allocate as an instance of stat_error_class are leaked. I intrdouced this bug in a125e2eea7cea4d0bac1404c2e1b1d65d11cc10c. In the commit, I arranged the class hierarchy. Signed-off-by: Masatake YAMATO --- lsfd-cmd/file.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lsfd-cmd/file.c b/lsfd-cmd/file.c index 0df0554f578..d52f3a31946 100644 --- a/lsfd-cmd/file.c +++ b/lsfd-cmd/file.c @@ -319,10 +319,16 @@ const struct file_class readlink_error_class = { .fill_column = readlink_error_fill_column, }; +static void stat_error_file_free_content(struct file *file) +{ + free(file->name); +} + const struct file_class stat_error_class = { .super = &error_class, .size = sizeof(struct file), .initialize_content = init_error_content, + .free_content = stat_error_file_free_content, }; /* From 0c841ec5eb35400abf2a65c58a799d4045942a8d Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Sun, 30 Nov 2025 20:14:30 -0500 Subject: [PATCH 130/174] include/c.h: add MAX_OF_UINT_TYPE macro to get max num of an uint type Signed-off-by: Christian Goeschel Ndjomouo --- include/c.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/c.h b/include/c.h index 0126591f2b6..e74a4486bf9 100644 --- a/include/c.h +++ b/include/c.h @@ -652,6 +652,7 @@ static inline int fputsln(const char *s, FILE *stream) { #endif #define SINT_MAX(t) (((t)1 << (sizeof(t) * 8 - 2)) - (t)1 + ((t)1 << (sizeof(t) * 8 - 2))) +#define MAX_OF_UINT_TYPE(t) ~((t)0) #ifndef HAVE_REALLOCARRAY static inline void *reallocarray(void *ptr, size_t nmemb, size_t size) From 563ce081db1fdc11ae290e15f430193e1dcef85a Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Tue, 25 Nov 2025 21:36:23 -0500 Subject: [PATCH 131/174] lib: (pwdutils.c) new library routines to get a group/passwd struct by name or GID/UID In some tools users can specify groups/users by their name but not the GID or UID. To enable this in a trivial manner util-linux tools can now call the ul_getgrp_str(), ul_getuserpw_str(), xgetgroup() and xgetuserpw() routines to achieve this. Signed-off-by: Christian Goeschel Ndjomouo --- include/pwdutils.h | 6 +- lib/Makemodule.am | 1 + lib/pwdutils.c | 138 ++++++++++++++++++++++++++++++++++----------- 3 files changed, 110 insertions(+), 35 deletions(-) diff --git a/include/pwdutils.h b/include/pwdutils.h index 1d44242746e..321b2ac5966 100644 --- a/include/pwdutils.h +++ b/include/pwdutils.h @@ -9,10 +9,12 @@ #include #include -extern struct passwd *xgetpwnam(const char *username, char **pwdbuf); -extern struct group *xgetgrnam(const char *groupname, char **grpbuf); extern struct passwd *xgetpwuid(uid_t uid, char **pwdbuf); +extern struct passwd *xgetuserpw(const char *str, char **pwdbuf); +extern struct group *xgetgroup(const char *str, char **pwdbuf); extern char *xgetlogin(void); +extern struct group *ul_getgrp_str(const char *str); +extern struct passwd *ul_getuserpw_str(const char *str); #endif /* UTIL_LINUX_PWDUTILS_H */ diff --git a/lib/Makemodule.am b/lib/Makemodule.am index a9da577348b..e824593d6cc 100644 --- a/lib/Makemodule.am +++ b/lib/Makemodule.am @@ -231,6 +231,7 @@ test_timeutils_LDADD = $(LDADD) libcommon.la test_pwdutils_SOURCES = lib/pwdutils.c test_pwdutils_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM +test_pwdutils_LDADD = $(LDADD) libcommon.la test_remove_env_SOURCES = lib/env.c test_remove_env_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM_ENV diff --git a/lib/pwdutils.c b/lib/pwdutils.c index 1c1f13e9293..35f1f7866cc 100644 --- a/lib/pwdutils.c +++ b/lib/pwdutils.c @@ -1,31 +1,28 @@ /* - * No copyright is claimed. This code is in the public domain; do with + * No copyright is claimed. This code is in the public domain; do with * it what you wish. */ #include #include +#include #include "c.h" #include "pwdutils.h" #include "xalloc.h" +#include "strutils.h" -/* Returns allocated passwd and allocated pwdbuf to store passwd strings - * fields. In case of error returns NULL and set errno, for unknown user set - * errno to EINVAL - */ -struct passwd *xgetpwnam(const char *username, char **pwdbuf) +struct passwd *xgetpwuid(uid_t uid, char **pwdbuf) { struct passwd *pwd = NULL, *res = NULL; int rc; assert(pwdbuf); - assert(username); *pwdbuf = xmalloc(UL_GETPW_BUFSIZ); pwd = xcalloc(1, sizeof(struct passwd)); errno = 0; - rc = getpwnam_r(username, pwd, *pwdbuf, UL_GETPW_BUFSIZ, &res); + rc = getpwuid_r(uid, pwd, *pwdbuf, UL_GETPW_BUFSIZ, &res); if (rc != 0) { errno = rc; goto failed; @@ -41,23 +38,39 @@ struct passwd *xgetpwnam(const char *username, char **pwdbuf) return NULL; } -/* Returns allocated group and allocated grpbuf to store group strings - * fields. In case of error returns NULL and set errno, for unknown group set - * errno to EINVAL +/* Returns allocated passwd and allocated pwdbuf for the username or UID passed + * as @str. In case of error returns NULL and set errno, for unknown user it + * sets errno to EINVAL. */ -struct group *xgetgrnam(const char *groupname, char **grpbuf) +struct passwd *xgetuserpw(const char *str ,char **pwdbuf) { - struct group *grp = NULL, *res = NULL; + struct passwd *pwd = NULL, *res = NULL; int rc; + uint64_t uid; - assert(grpbuf); - assert(groupname); + assert(pwdbuf); + assert(str); - *grpbuf = xmalloc(UL_GETPW_BUFSIZ); - grp = xcalloc(1, sizeof(struct group)); + *pwdbuf = xmalloc(UL_GETPW_BUFSIZ); + pwd = xcalloc(1, sizeof(struct passwd)); + + /* is @str a UID ? */ + rc = ul_strtou64(str, &uid, 10); + if (rc == -ERANGE) { + errno = ERANGE; + goto failed; + } + /* @str is an invalid number, let's assume it is the username */ + if (rc == -EINVAL) { + rc = getpwnam_r(str, pwd, *pwdbuf, UL_GETPW_BUFSIZ, &res); + } else { + if (uid > MAX_OF_UINT_TYPE(uid_t)) { + errno = ERANGE; + goto failed; + } + rc = getpwuid_r((uid_t)uid, pwd, *pwdbuf, UL_GETPW_BUFSIZ, &res); + } - errno = 0; - rc = getgrnam_r(groupname, grp, *grpbuf, UL_GETPW_BUFSIZ, &res); if (rc != 0) { errno = rc; goto failed; @@ -66,25 +79,46 @@ struct group *xgetgrnam(const char *groupname, char **grpbuf) errno = EINVAL; goto failed; } - return grp; + return pwd; failed: - free(grp); - free(*grpbuf); + free(pwd); + free(*pwdbuf); return NULL; } -struct passwd *xgetpwuid(uid_t uid, char **pwdbuf) +/* Returns allocated group and allocated grpbuf for the group name or GID passed + * as @str. In case of error returns NULL and set errno, for unknown group it + * sets errno to EINVAL. + */ +struct group *xgetgroup(const char *str, char **grpbuf) { - struct passwd *pwd = NULL, *res = NULL; + struct group *grp = NULL, *res = NULL; int rc; + uint64_t gid; - assert(pwdbuf); + assert(grpbuf); + assert(str); - *pwdbuf = xmalloc(UL_GETPW_BUFSIZ); - pwd = xcalloc(1, sizeof(struct passwd)); + *grpbuf = xmalloc(UL_GETPW_BUFSIZ); + grp = xcalloc(1, sizeof(struct group)); + + /* is @str a GID ? */ + rc = ul_strtou64(str, &gid, 10); + if (rc == -ERANGE) { + errno = ERANGE; + goto failed; + } + /* @str is an invalid number, let's assume it is the group name */ + if (rc == -EINVAL) { + rc = getgrnam_r(str, grp, *grpbuf, UL_GETPW_BUFSIZ, &res); + } else { + if (gid > MAX_OF_UINT_TYPE(gid_t)) { + errno = ERANGE; + goto failed; + } + rc = getgrgid_r((gid_t)gid, grp, *grpbuf, UL_GETPW_BUFSIZ, &res); + } - errno = 0; - rc = getpwuid_r(uid, pwd, *pwdbuf, UL_GETPW_BUFSIZ, &res); if (rc != 0) { errno = rc; goto failed; @@ -93,10 +127,10 @@ struct passwd *xgetpwuid(uid_t uid, char **pwdbuf) errno = EINVAL; goto failed; } - return pwd; + return grp; failed: - free(pwd); - free(*pwdbuf); + free(grp); + free(*grpbuf); return NULL; } @@ -127,6 +161,44 @@ char *xgetlogin(void) return NULL; } +/* + * Return a pointer to a `struct group` for a matching group name or GID. + */ +struct group *ul_getgrp_str(const char *str) +{ + int rc; + uint64_t gid; + + rc = ul_strtou64(str, &gid, 10); + if (rc == -ERANGE) + return NULL; + if (rc == -EINVAL) + return getgrnam(str); + if (gid > MAX_OF_UINT_TYPE(gid_t)) + return NULL; + + return getgrgid((gid_t)gid); +} + +/* + * Return a pointer to a `struct passwd` for a matching username or UID. + */ +struct passwd *ul_getuserpw_str(const char *str) +{ + int rc; + uint64_t uid; + + rc = ul_strtou64(str, &uid, 10); + if (rc == -ERANGE) + return NULL; + if (rc == -EINVAL) + return getpwnam(str); + if (uid > MAX_OF_UINT_TYPE(uid_t)) + return NULL; + + return getpwuid((uid_t)uid); +} + #ifdef TEST_PROGRAM int main(int argc, char *argv[]) { @@ -138,7 +210,7 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } - pwd = xgetpwnam(argv[1], &buf); + pwd = xgetuserpw(argv[1], &buf); if (!pwd) err(EXIT_FAILURE, "failed to get %s pwd entry", argv[1]); From 51b488d48a4d707384d7bb51c0742525bff0aafb Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Tue, 25 Nov 2025 22:29:03 -0500 Subject: [PATCH 132/174] tests: (su) test GID argument in --group option Signed-off-by: Christian Goeschel Ndjomouo --- tests/expected/su/group-group-id | 1 + tests/ts/su/group | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 tests/expected/su/group-group-id diff --git a/tests/expected/su/group-group-id b/tests/expected/su/group-group-id new file mode 100644 index 00000000000..b4b6910249b --- /dev/null +++ b/tests/expected/su/group-group-id @@ -0,0 +1 @@ +ts_grp diff --git a/tests/ts/su/group b/tests/ts/su/group index 9bb4b14f0a3..d3294fd7293 100755 --- a/tests/ts/su/group +++ b/tests/ts/su/group @@ -73,6 +73,16 @@ grep -q 'Authentication failure' "$TS_ERRLOG" [ "$?" -eq 0 ] && ts_skip_subtest "authentication failure" ts_finalize_subtest +ts_init_subtest "group-id" + +grp_id="$(cat /etc/group | grep -E "^$grp_name" | cut -d: -f 3)" +"$TS_CMD_SU" --group "$grp_id" "$username" \ + -c "$TS_CMD_ID --groups --name" 2>> "$TS_ERRLOG" \ + | grep -o "$grp_name" \ + | uniq >> "$TS_OUTPUT" + +ts_finalize_subtest + groupdel "$grp_name" ts_finalize \ No newline at end of file From 1a5773de844015a6413535b0672856653c15ba8d Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Tue, 25 Nov 2025 22:19:12 -0500 Subject: [PATCH 133/174] su: accept group name and GID in -g and -G options Signed-off-by: Christian Goeschel Ndjomouo --- login-utils/su-common.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/login-utils/su-common.c b/login-utils/su-common.c index 4d54eab31b5..81ea262875a 100644 --- a/login-utils/su-common.c +++ b/login-utils/su-common.c @@ -267,7 +267,7 @@ static void chownmod_pty(struct su_context *su) const char *grname = getlogindefs_str("TTYGROUP", TTYGRPNAME); if (grname && *grname) { - struct group *gr = getgrnam(grname); + struct group *gr = ul_getgrp_str(grname); if (gr) /* group by name */ gid = gr->gr_gid; else /* group by ID */ @@ -970,7 +970,7 @@ static gid_t add_supp_group(const char *name, gid_t **groups, size_t *ngroups) "specifying more than %d supplemental groups is not possible", NGROUPS_MAX - 1), NGROUPS_MAX - 1); - gr = getgrnam(name); + gr = ul_getgrp_str(name); if (!gr) errx(EXIT_FAILURE, _("group %s does not exist"), name); @@ -1154,7 +1154,7 @@ int su_main(int argc, char **argv, int mode) logindefs_set_loader(load_config, (void *) su); init_tty(su); - su->pwd = xgetpwnam(su->new_user, &su->pwdbuf); + su->pwd = xgetuserpw(su->new_user, &su->pwdbuf); if (!su->pwd || !su->pwd->pw_passwd || !su->pwd->pw_name || !*su->pwd->pw_name From fb8d31db2c1655d564c7cfaaf97fa490c1e1706e Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Thu, 27 Nov 2025 20:04:58 -0500 Subject: [PATCH 134/174] chsh: use new xgetuserpw() instead of xgetpwnam() Signed-off-by: Christian Goeschel Ndjomouo --- login-utils/chsh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/login-utils/chsh.c b/login-utils/chsh.c index 3850bb843ad..0723367389c 100644 --- a/login-utils/chsh.c +++ b/login-utils/chsh.c @@ -207,7 +207,7 @@ int main(int argc, char **argv) errx(EXIT_FAILURE, _("you (user %d) don't exist."), uid); } else { - pw = xgetpwnam(info.username, &pwbuf); + pw = xgetuserpw(info.username, &pwbuf); if (!pw) errx(EXIT_FAILURE, _("user \"%s\" does not exist."), info.username); From 5a65afff1dfbd33ccf3304d6ed0dedce0a2bd6aa Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Thu, 27 Nov 2025 20:05:38 -0500 Subject: [PATCH 135/174] login: use new xgetuserpw() instead of xgetpwnam() Signed-off-by: Christian Goeschel Ndjomouo --- login-utils/login.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/login-utils/login.c b/login-utils/login.c index 402e178201e..4f4cc90551c 100644 --- a/login-utils/login.c +++ b/login-utils/login.c @@ -478,11 +478,9 @@ static void chown_tty(struct login_context *cxt) grname = getlogindefs_str("TTYGROUP", TTYGRPNAME); if (grname && *grname) { - struct group *gr = getgrnam(grname); - if (gr) /* group by name */ + struct group *gr = ul_getgrp_str(grname); + if (gr) gid = gr->gr_gid; - else /* group by ID */ - gid = (gid_t) getlogindefs_num("TTYGROUP", gid); } if (fchown(0, uid, gid)) /* tty */ chown_err(cxt->tty_name, uid, gid); @@ -643,13 +641,13 @@ static void log_audit(struct login_context *cxt, int status) if (audit_fd == -1) return; if (!pwd && cxt->username) - pwd = getpwnam(cxt->username); + pwd = ul_getuserpw_str(cxt->username); ignore_result( audit_log_acct_message(audit_fd, AUDIT_USER_LOGIN, NULL, "login", - cxt->username ? cxt->username : "(unknown)", + pwd ? pwd->pw_name : "(unknown)", pwd ? pwd->pw_uid : (unsigned int)-1, cxt->hostname, NULL, @@ -1521,7 +1519,7 @@ int main(int argc, char **argv) */ loginpam_acct(&cxt); - cxt.pwd = xgetpwnam(cxt.username, &cxt.pwdbuf); + cxt.pwd = xgetuserpw(cxt.username, &cxt.pwdbuf); if (!cxt.pwd) { warnx(_("\nSession setup problem, abort.")); syslog(LOG_ERR, _("Invalid user name \"%s\". Abort."), From bd89462910f32042dbe1882044a5c076638a89b9 Mon Sep 17 00:00:00 2001 From: Alessandro Ratti Date: Sun, 23 Nov 2025 16:20:57 +0100 Subject: [PATCH 136/174] lib: introduce ul_default_shell() for consistent shell resolution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new ul_default_shell() function to provide consistent shell resolution across util-linux tools. The function follows a priority order: $SHELL environment variable, user's shell from passwd database, and finally _PATH_BSHELL as fallback. The function supports flags to control its behavior: - UL_SHELL_NOENV: skip $SHELL environment variable check - UL_SHELL_NOPWD: skip passwd database lookup This addresses the issue where tools like script(1) would default to /bin/sh without respecting the user's configured shell, potentially causing data loss. Addresses: https://github.com/util-linux/util-linux/issues/3865 Suggested-by: Karel Zak Suggested-by: Thomas Weißschuh Signed-off-by: Alessandro Ratti --- include/shells.h | 7 +++++++ lib/Makemodule.am | 1 + lib/meson.build | 1 + lib/shells.c | 26 ++++++++++++++++++++++++++ 4 files changed, 35 insertions(+) diff --git a/include/shells.h b/include/shells.h index c770a13ba98..7f2d2469c27 100644 --- a/include/shells.h +++ b/include/shells.h @@ -4,7 +4,14 @@ #ifndef UTIL_LINUX_SHELLS_H #define UTIL_LINUX_SHELLS_H +#include + +#define UL_SHELL_NOENV (1 << 0) +#define UL_SHELL_NOPWD (1 << 1) + extern void print_shells(FILE *out, const char *format); extern int is_known_shell(const char *shell_name); +const char *ul_default_shell(int flags, const struct passwd *pw); + #endif /* UTIL_LINUX_SHELLS_H */ diff --git a/lib/Makemodule.am b/lib/Makemodule.am index a9da577348b..1d598faa284 100644 --- a/lib/Makemodule.am +++ b/lib/Makemodule.am @@ -49,6 +49,7 @@ libcommon_la_SOURCES = \ if LINUX libcommon_la_SOURCES += \ lib/linux_version.c \ + lib/shells.c \ lib/loopdev.c endif diff --git a/lib/meson.build b/lib/meson.build index 0f94a9b99b3..cb35ecbd60f 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -25,6 +25,7 @@ lib_common_sources = ''' randutils.c sha1.c sha256.c + shells.c signames.c strutils.c strv.c diff --git a/lib/shells.c b/lib/shells.c index 13f293c5e0c..ef2aecd0f5e 100644 --- a/lib/shells.c +++ b/lib/shells.c @@ -1,6 +1,11 @@ /* * SPDX-License-Identifier: GPL-2.0-or-later */ +#include +#include +#include +#include +#include #include #if defined (HAVE_LIBECONF) && defined (USE_VENDORDIR) #include @@ -116,3 +121,24 @@ extern int is_known_shell(const char *shell_name) #endif return ret; } + +const char *ul_default_shell(int flags, const struct passwd *pw) +{ + const char *shell = NULL; + + if (!(flags & UL_SHELL_NOENV)) { + shell = getenv("SHELL"); + if (shell && *shell) + return shell; + } + if (!(flags & UL_SHELL_NOPWD)) { + if (!pw) + pw = getpwuid(getuid()); + if (pw) + shell = pw->pw_shell; + if (shell && *shell) + return shell; + } + + return _PATH_BSHELL; +} From 6651ae5822610789d9ca620c4e0e65c3bd4e12af Mon Sep 17 00:00:00 2001 From: Alessandro Ratti Date: Sun, 23 Nov 2025 16:24:52 +0100 Subject: [PATCH 137/174] *: use ul_default_shell() for interactive shell spawning Update tools that spawn interactive shells to use ul_default_shell() for consistent shell resolution. This ensures these tools respect both $SHELL and the user's configured shell from the passwd database before falling back to _PATH_BSHELL. Affected tools: - script(1): fixes history truncation when invoked without $SHELL - scriptlive(1): consistent with script(1) behavior - flock(1): for -c command execution - more(1): for shell escape feature - exec_shell (used by unshare(1) and nsenter(1)) This change addresses user reports of data loss due to tools defaulting to /bin/sh instead of the user's configured shell, particularly affecting command history with different HISTSIZE configurations. Addresses: https://github.com/util-linux/util-linux/issues/3865 Signed-off-by: Alessandro Ratti --- lib/exec_shell.c | 8 ++------ sys-utils/flock.c | 6 +++--- term-utils/script.c | 5 ++--- term-utils/scriptlive.c | 5 ++--- text-utils/more.c | 6 +++--- 5 files changed, 12 insertions(+), 18 deletions(-) diff --git a/lib/exec_shell.c b/lib/exec_shell.c index ffe65f006e8..8f10ea4df49 100644 --- a/lib/exec_shell.c +++ b/lib/exec_shell.c @@ -26,19 +26,15 @@ #include "xalloc.h" #include "exec_shell.h" - -#define DEFAULT_SHELL "/bin/sh" +#include "shells.h" void __attribute__((__noreturn__)) exec_shell(void) { - const char *shell = getenv("SHELL"); + const char *shell = ul_default_shell(0, NULL); char *shellc; const char *shell_basename; char *arg0; - if (!shell) - shell = DEFAULT_SHELL; - shellc = xstrdup(shell); shell_basename = basename(shellc); xasprintf(&arg0, "-%s", shell_basename); diff --git a/sys-utils/flock.c b/sys-utils/flock.c index 4cc0610e501..642e026c855 100644 --- a/sys-utils/flock.c +++ b/sys-utils/flock.c @@ -47,6 +47,7 @@ #include "closestream.h" #include "monotonic.h" #include "timer.h" +#include "shells.h" #ifndef F_OFD_GETLK #define F_OFD_GETLK 36 @@ -207,6 +208,7 @@ int main(int argc, char *argv[]) int conflict_exit_code = 1; char **cmd_argv = NULL, *sh_c_argv[4]; const char *filename = NULL; + enum { OPT_VERBOSE = CHAR_MAX + 1, OPT_FCNTL, @@ -327,9 +329,7 @@ int main(int argc, char *argv[]) _("%s requires exactly one command argument"), argv[optind + 1]); cmd_argv = sh_c_argv; - cmd_argv[0] = getenv("SHELL"); - if (!cmd_argv[0] || !*cmd_argv[0]) - cmd_argv[0] = _PATH_BSHELL; + cmd_argv[0] = (char *)ul_default_shell(0, NULL); cmd_argv[1] = "-c"; cmd_argv[2] = argv[optind + 2]; cmd_argv[3] = NULL; diff --git a/term-utils/script.c b/term-utils/script.c index ff7f4409f61..4e302347f22 100644 --- a/term-utils/script.c +++ b/term-utils/script.c @@ -70,6 +70,7 @@ #include "signames.h" #include "pty-session.h" #include "debug.h" +#include "shells.h" static UL_DEBUG_DEFINE_MASK(script); UL_DEBUG_DEFINE_MASKNAMES(script) = UL_DEBUG_EMPTY_MASKNAMES; @@ -966,9 +967,7 @@ int main(int argc, char **argv) log_associate(&ctl, &ctl.in, timingfile, format); } - shell = getenv("SHELL"); - if (!shell) - shell = _PATH_BSHELL; + shell = ul_default_shell(0, NULL); ctl.pty = ul_new_pty(ctl.isterm); if (!ctl.pty) diff --git a/term-utils/scriptlive.c b/term-utils/scriptlive.c index e4a3434ed5b..6ac685506f2 100644 --- a/term-utils/scriptlive.c +++ b/term-utils/scriptlive.c @@ -38,6 +38,7 @@ #include "pty-session.h" #include "script-playutils.h" #include "monotonic.h" +#include "shells.h" #define SCRIPT_MIN_DELAY 0.0001 /* from original scriptreplay.pl */ @@ -281,9 +282,7 @@ main(int argc, char *argv[]) replay_set_delay_max(ss.setup, &maxdelay); replay_set_delay_min(ss.setup, &mindelay); - shell = getenv("SHELL"); - if (shell == NULL) - shell = _PATH_BSHELL; + shell = ul_default_shell(0, NULL); fprintf(stdout, _(">>> scriptlive: Starting your typescript execution by %s.\n"), command ? command : shell); diff --git a/text-utils/more.c b/text-utils/more.c index 4980aef4cac..bc04064cf15 100644 --- a/text-utils/more.c +++ b/text-utils/more.c @@ -89,6 +89,7 @@ #include "widechar.h" #include "closestream.h" #include "env.h" +#include "shells.h" #ifdef TEST_PROGRAM # define NON_INTERACTIVE_MORE 1 @@ -174,7 +175,7 @@ struct more_control { int next_jump; /* number of lines to skip ahead */ char **file_names; /* The list of file names */ int num_files; /* Number of files left to process */ - char *shell; /* name of the shell to use */ + const char *shell; /* name of the shell to use */ int sigfd; /* signalfd() file descriptor */ sigset_t sigset; /* signal operations */ char *line_buf; /* line buffer */ @@ -2110,8 +2111,7 @@ static void initterm(struct more_control *ctl) if ((ctl->backspace_ch = tigetstr(TERM_BACKSPACE)) == NULL) ctl->backspace_ch = BACKSPACE; - if ((ctl->shell = getenv("SHELL")) == NULL) - ctl->shell = _PATH_BSHELL; + ctl->shell = ul_default_shell(0, NULL); } int main(int argc, char **argv) From 54023fdf092ca479e1ccd5e6a7aa69cef68f840a Mon Sep 17 00:00:00 2001 From: Alessandro Ratti Date: Sun, 23 Nov 2025 16:26:37 +0100 Subject: [PATCH 138/174] login-utils, sys-utils: use _PATH_BSHELL consistently Remove local DEFAULT_SHELL definitions and hardcoded "/bin/sh" strings in favor of the standard _PATH_BSHELL macro from . This provides consistency across the codebase while following libc conventions. These tools already perform their own passwd lookups and only need a fallback value, so they don't require the full ul_default_shell() resolution logic. Affected tools: - su(1): already checks pw_shell validity - sulogin(8): emergency login with explicit shell handling - setpriv(1): already has passwd entry for environment setup Signed-off-by: Alessandro Ratti --- login-utils/su-common.c | 5 +---- login-utils/sulogin.c | 9 +++++---- sys-utils/setpriv.c | 6 ++---- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/login-utils/su-common.c b/login-utils/su-common.c index 4d54eab31b5..c6232ce7acb 100644 --- a/login-utils/su-common.c +++ b/login-utils/su-common.c @@ -105,9 +105,6 @@ UL_DEBUG_DEFINE_MASKNAMES(su) = UL_DEBUG_EMPTY_MASKNAMES; #define is_pam_failure(_rc) ((_rc) != PAM_SUCCESS) -/* The shell to run if none is given in the user's passwd entry. */ -#define DEFAULT_SHELL "/bin/sh" - /* The user to become if none is specified. */ #define DEFAULT_USER "root" @@ -1167,7 +1164,7 @@ int su_main(int argc, char **argv, int mode) su->old_user = xgetlogin(); if (!su->pwd->pw_shell || !*su->pwd->pw_shell) - su->pwd->pw_shell = DEFAULT_SHELL; + su->pwd->pw_shell = _PATH_BSHELL; if (use_supp && !use_gid) su->pwd->pw_gid = groups[0]; diff --git a/login-utils/sulogin.c b/login-utils/sulogin.c index eb4609db656..c546cc7c163 100644 --- a/login-utils/sulogin.c +++ b/login-utils/sulogin.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -892,7 +893,7 @@ static void sushell(struct passwd *pwd, struct console *con) if (pwd->pw_shell[0]) su_shell = pwd->pw_shell; else - su_shell = "/bin/sh"; + su_shell = _PATH_BSHELL; } if ((p = strrchr(su_shell, '/')) == NULL) p = su_shell; @@ -941,9 +942,9 @@ static void sushell(struct passwd *pwd, struct console *con) execl(su_shell, shell, (char *)NULL); warn(_("failed to execute %s"), su_shell); - xsetenv("SHELL", "/bin/sh", 1); - execl("/bin/sh", profile ? "-sh" : "sh", (char *)NULL); - warn(_("failed to execute %s"), "/bin/sh"); + xsetenv("SHELL", _PATH_BSHELL, 1); + execl(_PATH_BSHELL, profile ? "-sh" : "sh", (char *)NULL); + warn(_("failed to execute %s"), _PATH_BSHELL); } #ifdef HAVE_LIBSELINUX diff --git a/sys-utils/setpriv.c b/sys-utils/setpriv.c index c218be8e5e3..505d1ee5b4e 100644 --- a/sys-utils/setpriv.c +++ b/sys-utils/setpriv.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "all-io.h" #include "c.h" @@ -56,9 +57,6 @@ #define SETPRIV_EXIT_PRIVERR 127 /* how we exit when we fail to set privs */ -/* The shell to set SHELL env.variable if none is given in the user's passwd entry. */ -#define DEFAULT_SHELL "/bin/sh" - static gid_t get_group(const char *s, const char *err); enum cap_type { @@ -741,7 +739,7 @@ static void do_reset_environ(struct passwd *pw) if (pw->pw_shell && *pw->pw_shell) xsetenv("SHELL", pw->pw_shell, 1); else - xsetenv("SHELL", DEFAULT_SHELL, 1); + xsetenv("SHELL", _PATH_BSHELL, 1); xsetenv("HOME", pw->pw_dir, 1); xsetenv("USER", pw->pw_name, 1); From 561f0bb21d2e88b5feca2fdf56b283a6f48befc5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Dec 2025 21:01:27 +0000 Subject: [PATCH 139/174] build(deps): bump actions/checkout from 1 to 6 Bumps [actions/checkout](https://github.com/actions/checkout) from 1 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v1...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/cibuild.yml | 14 +++++++------- .github/workflows/codeql.yml | 2 +- .github/workflows/coverity.yml | 2 +- .github/workflows/differential-shellcheck.yml | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/cibuild.yml b/.github/workflows/cibuild.yml index 44985d9a162..38dfb266e7d 100644 --- a/.github/workflows/cibuild.yml +++ b/.github/workflows/cibuild.yml @@ -34,7 +34,7 @@ jobs: env: ${{ matrix.env }} steps: - name: Repository checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Ubuntu setup run: sudo -E .github/workflows/cibuild-setup-ubuntu.sh - name: Configure @@ -64,7 +64,7 @@ jobs: COVERAGE: yes steps: - name: Repository checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Ubuntu setup run: sudo -E .github/workflows/cibuild-setup-ubuntu.sh - name: Configure & Make @@ -89,7 +89,7 @@ jobs: SANITIZE: no steps: - name: Repository checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Ubuntu setup run: sudo -E .github/workflows/cibuild-setup-ubuntu.sh - name: Meson configure @@ -110,7 +110,7 @@ jobs: TRANSLATE_MANPAGES: yes steps: - name: Repository checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Ubuntu setup run: sudo -E .github/workflows/cibuild-setup-ubuntu.sh - name: Configure @@ -135,7 +135,7 @@ jobs: image: ${{ matrix.image }} steps: - name: Repository checkout - uses: actions/checkout@v1 + uses: actions/checkout@v6 - name: Ubuntu setup run: .github/workflows/cibuild-setup-ubuntu.sh - name: Configure @@ -162,7 +162,7 @@ jobs: - arch: armv7 steps: - name: Repository checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - uses: uraimo/run-on-arch-action@v3 with: arch: ${{ matrix.arch }} @@ -217,7 +217,7 @@ jobs: COMPILER: none steps: - name: Repository checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Ubuntu setup run: sudo -E .github/workflows/cibuild-setup-ubuntu.sh - name: OpenWrt environment diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 223111611cc..93143ad6799 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -32,7 +32,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Initialize CodeQL uses: github/codeql-action/init@v3 diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml index c4593ad061a..702697a32a8 100644 --- a/.github/workflows/coverity.yml +++ b/.github/workflows/coverity.yml @@ -18,7 +18,7 @@ jobs: COVERITY_SCAN_TOKEN: "${{ secrets.COVERITY_SCAN_TOKEN }}" steps: - name: Repository checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Ubuntu setup run: sudo -E .github/workflows/cibuild-setup-ubuntu.sh - name: Configure diff --git a/.github/workflows/differential-shellcheck.yml b/.github/workflows/differential-shellcheck.yml index e524a11734b..cd6b7ebb18c 100644 --- a/.github/workflows/differential-shellcheck.yml +++ b/.github/workflows/differential-shellcheck.yml @@ -16,7 +16,7 @@ jobs: steps: - name: Repository checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 0 From 0a7fb806118bc4418e231081bd13c69bbc31b988 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Thu, 27 Nov 2025 21:32:41 -0500 Subject: [PATCH 140/174] unshare: use the new ul_get{grp,userpw}_str() routines This change refactors get_group() and get_user(), so that it uses the new routines ul_getgrp_str() and ul_getuserpw_str(), to simplify the code and remove the overkill mem allocations. Signed-off-by: Christian Goeschel Ndjomouo --- sys-utils/unshare.c | 40 ++++++++++++---------------------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/sys-utils/unshare.c b/sys-utils/unshare.c index 11aeae48ed5..0671ed3e1a8 100644 --- a/sys-utils/unshare.c +++ b/sys-utils/unshare.c @@ -322,40 +322,24 @@ static pid_t bind_ns_files_from_child(int *fd) exit(EXIT_SUCCESS); } -static uid_t get_user(const char *s, const char *err) +static uid_t get_user(const char *s) { struct passwd *pw; - char *buf = NULL; - uid_t ret; - pw = xgetpwnam(s, &buf); - if (pw) { - ret = pw->pw_uid; - free(pw); - free(buf); - } else { - ret = strtoul_or_err(s, err); - } - - return ret; + pw = ul_getuserpw_str(s); + if (!pw) + errx(EXIT_FAILURE, _("failed to parse uid '%s'"), s); + return pw->pw_uid; } -static gid_t get_group(const char *s, const char *err) +static gid_t get_group(const char *s) { struct group *gr; - char *buf = NULL; - gid_t ret; - - gr = xgetgrnam(s, &buf); - if (gr) { - ret = gr->gr_gid; - free(gr); - free(buf); - } else { - ret = strtoul_or_err(s, err); - } - return ret; + gr = ul_getgrp_str(s); + if (!gr) + errx(EXIT_FAILURE, _("failed to parse gid '%s'"), s); + return gr->gr_gid; } /** @@ -970,11 +954,11 @@ int main(int argc, char *argv[]) break; case OPT_MAPUSER: unshare_flags |= CLONE_NEWUSER; - mapuser = get_user(optarg, _("failed to parse uid")); + mapuser = get_user(optarg); break; case OPT_MAPGROUP: unshare_flags |= CLONE_NEWUSER; - mapgroup = get_group(optarg, _("failed to parse gid")); + mapgroup = get_group(optarg); break; case 'r': unshare_flags |= CLONE_NEWUSER; From 384840b432cde849cbdb3d5c0e88ca5959a4ca96 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Thu, 27 Nov 2025 21:56:05 -0500 Subject: [PATCH 141/174] chfn: enable the use of the username or UID Signed-off-by: Christian Goeschel Ndjomouo --- login-utils/chfn.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/login-utils/chfn.c b/login-utils/chfn.c index 059432b3d28..8577916a286 100644 --- a/login-utils/chfn.c +++ b/login-utils/chfn.c @@ -44,6 +44,7 @@ #include "logindefs.h" #include "ch-common.h" +#include "pwdutils.h" #ifdef HAVE_LIBSELINUX # include @@ -88,7 +89,7 @@ static void __attribute__((__noreturn__)) usage(void) { FILE *fp = stdout; fputs(USAGE_HEADER, fp); - fprintf(fp, _(" %s [options] []\n"), program_invocation_short_name); + fprintf(fp, _(" %s [options] [|]\n"), program_invocation_short_name); fputs(USAGE_SEPARATOR, fp); fputs(_("Change your finger information.\n"), fp); @@ -186,7 +187,7 @@ static void parse_argv(struct chfn_control *ctl, int argc, char **argv) /* done parsing arguments. check for a username. */ if (optind < argc) { if (optind + 1 < argc) { - warnx(_("cannot handle multiple usernames")); + warnx(_("cannot handle multiple usernames or UIDs")); errtryhelp(EXIT_FAILURE); } ctl->username = argv[optind]; @@ -417,13 +418,13 @@ int main(int argc, char **argv) if (!ctl.pw) errx(EXIT_FAILURE, _("you (user %d) don't exist."), uid); - ctl.username = ctl.pw->pw_name; } else { - ctl.pw = getpwnam(ctl.username); + ctl.pw = ul_getuserpw_str(ctl.username); if (!ctl.pw) errx(EXIT_FAILURE, _("user \"%s\" does not exist."), ctl.username); } + ctl.username = ctl.pw->pw_name; parse_passwd(&ctl); #ifndef HAVE_LIBUSER if (!(is_local(ctl.username))) From a8a75b667520c72c45b032bf42b8905cb276ee3c Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Tue, 2 Dec 2025 00:50:28 -0500 Subject: [PATCH 142/174] unshare: use MAX_OF_UINT_TYPE instead of (type)-1 Signed-off-by: Christian Goeschel Ndjomouo --- sys-utils/unshare.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys-utils/unshare.c b/sys-utils/unshare.c index 0671ed3e1a8..3cec3be82ac 100644 --- a/sys-utils/unshare.c +++ b/sys-utils/unshare.c @@ -1190,14 +1190,14 @@ int main(int argc, char *argv[]) #endif } - if (mapuser != (uid_t) -1 && !usermap) + if (mapuser != MAX_OF_UINT_TYPE(uid_t) && !usermap) map_id(_PATH_PROC_UIDMAP, mapuser, real_euid); /* Since Linux 3.19 unprivileged writing of /proc/self/gid_map * has been disabled unless /proc/self/setgroups is written * first to permanently disable the ability to call setgroups * in that user namespace. */ - if (mapgroup != (gid_t) -1 && !groupmap) { + if (mapgroup != MAX_OF_UINT_TYPE(gid_t) && !groupmap) { if (setgrpcmd == SETGROUPS_ALLOW) errx(EXIT_FAILURE, _("options --setgroups=allow and " "--map-group are mutually exclusive")); From 764c97800eadd1a49225c566771fec6905115acb Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Tue, 2 Dec 2025 16:08:38 +0100 Subject: [PATCH 143/174] cal: add note about today highlight on -w Signed-off-by: Karel Zak --- misc-utils/cal.1.adoc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/misc-utils/cal.1.adoc b/misc-utils/cal.1.adoc index b4096ed15fb..a464d56b4df 100644 --- a/misc-utils/cal.1.adoc +++ b/misc-utils/cal.1.adoc @@ -120,6 +120,9 @@ If a _number_ is specified, the requested week in the desired or current year will be printed and its number highlighted. The _number_ may be ignored if _month_ is also specified. + +If the _number_ is specified but the current day is unspecified on the command +line, then the current day is not highlighted. ++ See the *NOTES* section for more details. *--color*[**=**_when_]:: From 11a38ec82c4db476c47be9e5dc19fc4d6d159cce Mon Sep 17 00:00:00 2001 From: Martin Minkus Date: Tue, 2 Dec 2025 19:51:05 -0800 Subject: [PATCH 144/174] libfdisk: modernize ZFS GPT type description MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The GPT type GUID 6A898CC3-1DD2-11B2-99A6-080020736631 is currently described as "Solaris /usr & Apple ZFS". This reflects early Solaris and Apple experiments with ZFS, but today the same GUID is widely used by OpenZFS implementations on Linux, illumos, FreeBSD, and other platforms to mark ZFS pool member partitions. Apple's ZFS work was discontinued long ago, while OpenZFS has become the actively maintained and de facto standard implementation. Update the human-readable description to the simpler and more accurate: "ZFS pool member" A short comment is added to note the GUID’s historical Solaris /usr origin and its brief use by Apple. Only the description string is changed; the GUID itself and its semantics remain unchanged. --- include/pt-gpt-partnames.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/pt-gpt-partnames.h b/include/pt-gpt-partnames.h index b17a636299f..cf12d2baa46 100644 --- a/include/pt-gpt-partnames.h +++ b/include/pt-gpt-partnames.h @@ -202,8 +202,8 @@ DEF_GUID("52637672-7900-11AA-AA11-00306543ECAC", N_("Apple Silicon recovery")), /* Solaris */ DEF_GUID("6A82CB45-1DD2-11B2-99A6-080020736631", N_("Solaris boot")), DEF_GUID("6A85CF4D-1DD2-11B2-99A6-080020736631", N_("Solaris root")), -/* same as Apple ZFS */ -DEF_GUID("6A898CC3-1DD2-11B2-99A6-080020736631", N_("Solaris /usr & Apple ZFS")), +/* ZFS pool member; originally Solaris /usr and briefly Apple ZFS */ +DEF_GUID("6A898CC3-1DD2-11B2-99A6-080020736631", N_("ZFS pool member")), DEF_GUID("6A87C46F-1DD2-11B2-99A6-080020736631", N_("Solaris swap")), DEF_GUID("6A8B642B-1DD2-11B2-99A6-080020736631", N_("Solaris backup")), DEF_GUID("6A8EF2E9-1DD2-11B2-99A6-080020736631", N_("Solaris /var")), From bc577050f952b3ea0603c6ca8a4354950b330402 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Wed, 3 Dec 2025 11:11:59 +0100 Subject: [PATCH 145/174] column: add --input-separator as an alias for --separator This change adds --input-separator as an alias for the existing --separator option, providing symmetry with --output-separator. The new alias is documented in: - command-line help text - man page - bash completion Fixes: https://github.com/util-linux/util-linux/issues/3889 Signed-off-by: Karel Zak --- bash-completion/column | 3 ++- text-utils/column.1.adoc | 2 +- text-utils/column.c | 4 +++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/bash-completion/column b/bash-completion/column index 08d0772200f..eea03f35d4a 100644 --- a/bash-completion/column +++ b/bash-completion/column @@ -13,7 +13,7 @@ _column_module() COMPREPLY=( $(compgen -W "auto never always" -- $cur) ) return 0 ;; - '-s'|'--separator'|'-o'|'--output-separator'|'-n'|'--table-name'|'-O') + '-s'|'--separator'|'--input-separator'|'-o'|'--output-separator'|'-n'|'--table-name'|'-O') COMPREPLY=( $(compgen -W "string" -- $cur) ) return 0 ;; @@ -54,6 +54,7 @@ _column_module() --tree-parent --output-width --separator + --input-separator --output-separator --wrap-separator --fillrows diff --git a/text-utils/column.1.adoc b/text-utils/column.1.adoc index 69f2f794ffc..e1e5a1c6f44 100644 --- a/text-utils/column.1.adoc +++ b/text-utils/column.1.adoc @@ -99,7 +99,7 @@ Omit printing the header. This option allows having user-supplied column names o *-o, --output-separator* _string_:: Column delimiter for table output (default is two spaces). -*-s, --separator* _separators_:: +*-s, --input-separator, --separator* _separators_:: Possible input-item delimiters (default is whitespace). *-S, --use-spaces* _number_:: diff --git a/text-utils/column.c b/text-utils/column.c index 7a37cb886c7..5a9e9a03b65 100644 --- a/text-utils/column.c +++ b/text-utils/column.c @@ -1021,7 +1021,8 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -c, --output-width width of output in number of characters\n"), out); fputs(_(" -o, --output-separator columns separator for table output\n" " (default is two spaces)\n"), out); - fputs(_(" -s, --separator possible table delimiters\n"), out); + fputs(_(" -s, --input-separator, --separator \n" + " possible table delimiters\n"), out); fputs(_(" -x, --fillrows fill rows before columns\n"), out); fputs(_(" -S, --use-spaces minimal whitespaces between columns (no tabs)\n"), out); @@ -1059,6 +1060,7 @@ int main(int argc, char **argv) { "color", optional_argument, NULL, OPT_COLOR }, { "fillrows", no_argument, NULL, 'x' }, { "help", no_argument, NULL, 'h' }, + { "input-separator", required_argument, NULL, 's' }, /* alias for --separator */ { "json", no_argument, NULL, 'J' }, { "keep-empty-lines", no_argument, NULL, 'L' }, { "output-separator", required_argument, NULL, 'o' }, From e6a17012e42a1dd61cfe74f8c0b6e8804beb7c56 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Wed, 26 Nov 2025 22:52:21 -0500 Subject: [PATCH 146/174] login: define shell to log in to with -s or --shell The -s and --shell options allow a user to define a shell to log in to other than the one defined it the passwd entry or _PATH_BSHELL. Addresses: #3855 Signed-off-by: Christian Goeschel Ndjomouo --- login-utils/login.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/login-utils/login.c b/login-utils/login.c index 402e178201e..3cd1d528bed 100644 --- a/login-utils/login.c +++ b/login-utils/login.c @@ -111,6 +111,8 @@ struct login_context { const char *tty_number; /* end of the tty_path */ mode_t tty_mode; /* chmod() mode */ + char *shell_arg; /* command line argument defining the login shell */ + const char *username; /* points to PAM, pwd or cmd_username */ char *cmd_username; /* username specified on command line */ @@ -1282,17 +1284,18 @@ static void init_remote_info(struct login_context *cxt, char *remotehost) static void __attribute__((__noreturn__)) usage(void) { fputs(USAGE_HEADER, stdout); - printf(_(" %s [-p] [-h ] [-H] [[-f] ]\n"), program_invocation_short_name); + printf(_(" %s [-p] [-s ] [-h ] [-H] [[-f] ]\n"), program_invocation_short_name); fputs(USAGE_SEPARATOR, stdout); fputs(_("Begin a session on the system.\n"), stdout); fputs(USAGE_OPTIONS, stdout); - puts(_(" -p do not destroy the environment")); - puts(_(" -f skip a login authentication")); - puts(_(" -h hostname to be used for utmp logging")); - puts(_(" -H suppress hostname in the login prompt")); - printf(" --help %s\n", USAGE_OPTSTR_HELP); - printf(" -V, --version %s\n", USAGE_OPTSTR_VERSION); + puts(_(" -p do not destroy the environment")); + puts(_(" -f skip a login authentication")); + puts(_(" -h hostname to be used for utmp logging")); + puts(_(" -H suppress hostname in the login prompt")); + puts(_(" -s, --shell define the shell to log in to")); + printf(" --help %s\n", USAGE_OPTSTR_HELP); + printf(" -V, --version %s\n", USAGE_OPTSTR_VERSION); printf(USAGE_MAN_TAIL("login(1)")); exit(EXIT_SUCCESS); } @@ -1328,6 +1331,7 @@ static void initialize(int argc, char **argv, struct login_context *cxt) /* the only two longopts to satisfy UL standards */ enum { HELP_OPTION = CHAR_MAX + 1 }; const struct option longopts[] = { + {"shell", required_argument, NULL, 's'}, {"help", no_argument, NULL, HELP_OPTION}, {"version", no_argument, NULL, 'V'}, {NULL, 0, NULL, 0} @@ -1356,7 +1360,7 @@ static void initialize(int argc, char **argv, struct login_context *cxt) load_credentials(cxt); - while ((c = getopt_long(argc, argv, "fHh:pV", longopts, NULL)) != -1) + while ((c = getopt_long(argc, argv, "fHh:ps:V", longopts, NULL)) != -1) switch (c) { case 'f': cxt->noauth = 1; @@ -1379,6 +1383,10 @@ static void initialize(int argc, char **argv, struct login_context *cxt) cxt->keep_env = 1; break; + case 's': + cxt->shell_arg = optarg; + break; + case 'V': print_version(EXIT_SUCCESS); case HELP_OPTION: @@ -1580,8 +1588,11 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } - if (pwd->pw_shell == NULL || *pwd->pw_shell == '\0') + if (cxt.shell_arg && *cxt.shell_arg != '\0') { + pwd->pw_shell = cxt.shell_arg; + } else if (pwd->pw_shell == NULL || *pwd->pw_shell == '\0') { pwd->pw_shell = _PATH_BSHELL; + } init_environ(&cxt); /* init $HOME, $TERM ... */ From 61fe4126eaff3e8f7b52d57d63a4c7b8d2685f17 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Wed, 26 Nov 2025 23:07:14 -0500 Subject: [PATCH 147/174] login: document -s and --shell on the man page Signed-off-by: Christian Goeschel Ndjomouo --- login-utils/login.1.adoc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/login-utils/login.1.adoc b/login-utils/login.1.adoc index f28323ff9c5..de89b03c6ff 100644 --- a/login-utils/login.1.adoc +++ b/login-utils/login.1.adoc @@ -18,7 +18,7 @@ login - begin session on the system == SYNOPSIS -*login* [*-p*] [*-h* _host_] [*-H*] [*-f* _username_|_username_] +*login* [*-p*] [*-s* _shell_] [*-h* _host_] [*-H*] [*-f* _username_|_username_] == DESCRIPTION @@ -36,7 +36,7 @@ Other environment variables are preserved if the *-p* option is given or if *LOG The environment variables defined by PAM are always preserved. -Then the user's shell is started. If no shell is specified for the user in _/etc/passwd_, then _/bin/sh_ is used. If the specified shell contains a space, it is treated as a shell script. If there is no home directory specified in _/etc/passwd_, then _/_ is used, followed by _.hushlogin_ check as described below. +Then the user's shell is started. If no shell is specified for the user with *-s* or in _/etc/passwd_, then _/bin/sh_ is used. If the specified shell contains a space, it is treated as a shell script. If there is no home directory specified in _/etc/passwd_, then _/_ is used, followed by _.hushlogin_ check as described below. If the file _.hushlogin_ exists, then a "quiet" login is performed. This disables the checking of mail and the printing of the last login time and message of the day. Otherwise, if _/var/log/lastlog_ exists, the last login time is printed, and the current login is recorded. @@ -56,6 +56,9 @@ Note that the *-h* option has an impact on the *PAM service* *name*. The standar *-H*:: Used by other servers (for example, *telnetd*(8)) to tell *login* that printing the hostname should be suppressed in the login: prompt. See also *LOGIN_PLAIN_PROMPT* below. +*-s*, *--shell* _shell_:: +Specify a _shell_, other than the one defined in _/etc/passwd_, to log in to. + include::man-common/help-version.adoc[] == CONFIG FILE ITEMS From 5756e7ba8aba220177099188c3d120e111199fa9 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Thu, 4 Dec 2025 16:58:28 +0100 Subject: [PATCH 148/174] github: revert actions/checkout for ubuntu 18.04 Signed-off-by: Karel Zak --- .github/workflows/cibuild.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cibuild.yml b/.github/workflows/cibuild.yml index 38dfb266e7d..9eeaba04951 100644 --- a/.github/workflows/cibuild.yml +++ b/.github/workflows/cibuild.yml @@ -135,7 +135,7 @@ jobs: image: ${{ matrix.image }} steps: - name: Repository checkout - uses: actions/checkout@v6 + uses: actions/checkout@v1 - name: Ubuntu setup run: .github/workflows/cibuild-setup-ubuntu.sh - name: Configure From 8fb291f942382a460b514abd891871e657d94cfb Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Thu, 4 Dec 2025 12:02:30 -0500 Subject: [PATCH 149/174] login: duplicate --shell argument to avoid nulling through explicit_bzero() Addresses: #3855 Signed-off-by: Christian Goeschel Ndjomouo --- login-utils/login.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/login-utils/login.c b/login-utils/login.c index 3cd1d528bed..604d63c235b 100644 --- a/login-utils/login.c +++ b/login-utils/login.c @@ -1384,7 +1384,7 @@ static void initialize(int argc, char **argv, struct login_context *cxt) break; case 's': - cxt->shell_arg = optarg; + cxt->shell_arg = xstrdup(optarg); break; case 'V': From bf7166be215a473852204f74f62d3862b66d9b52 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Mon, 24 Nov 2025 23:26:48 -0500 Subject: [PATCH 150/174] include: add helper routines for opening and validating pidfds With the new ul_get_valid_pidfd_or_err() routine util-linux tools can now simply validate pidfd inode numbers before opening a file descriptor for a given PID. Signed-off-by: Christian Goeschel Ndjomouo --- include/pidfd-utils.h | 2 ++ lib/Makemodule.am | 1 + lib/meson.build | 1 + lib/pidfd-utils.c | 54 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+) create mode 100644 lib/pidfd-utils.c diff --git a/include/pidfd-utils.h b/include/pidfd-utils.h index 08627ca8d28..1b9f4dc4fdd 100644 --- a/include/pidfd-utils.h +++ b/include/pidfd-utils.h @@ -94,4 +94,6 @@ static inline int pidfd_getfd(int pidfd __attribute__((unused)), } #endif +int ul_get_valid_pidfd_or_err(pid_t pid, ino_t pfd_ino); + #endif /* UTIL_LINUX_PIDFD_UTILS */ diff --git a/lib/Makemodule.am b/lib/Makemodule.am index 1d598faa284..aeab09f76c3 100644 --- a/lib/Makemodule.am +++ b/lib/Makemodule.am @@ -34,6 +34,7 @@ libcommon_la_SOURCES = \ lib/netaddrq.c \ lib/netlink.c \ lib/pidutils.c \ + lib/pidfd-utils.c \ lib/pwdutils.c \ lib/randutils.c \ lib/sha1.c \ diff --git a/lib/meson.build b/lib/meson.build index cb35ecbd60f..db871913d29 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -20,6 +20,7 @@ lib_common_sources = ''' netaddrq.c netlink.c pidutils.c + pidfd-utils.c procfs.c pwdutils.c randutils.c diff --git a/lib/pidfd-utils.c b/lib/pidfd-utils.c new file mode 100644 index 00000000000..a0cc16953ff --- /dev/null +++ b/lib/pidfd-utils.c @@ -0,0 +1,54 @@ +/* + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. + * + * Authors: Christian Goeschel Ndjomouo [2025] + */ +#include +#include +#include +#include +#include + +#include "c.h" +#include "nls.h" +#include "strutils.h" +#include "pidfd-utils.h" + +/* + * ul_get_valid_pidfd_or_err() - Return a valid file descriptor for a PID + * or exit the process with an error message. + * + * @pid: PID number for which to get a file descriptor + * @pfd_ino: A pidfd inode number that is expected to be the + * same as for the new file descriptor. + * + * Pass @pfd_ino as NULL, if the pidfd should not be validated. + * + * Return: On success, a file descriptor is returned. + * On failure, err() or errx() is called to + * print an error message and kill the program. + * + */ +int ul_get_valid_pidfd_or_err(pid_t pid, ino_t pfd_ino) +{ + int pfd, rc; + struct stat f; + + pfd = pidfd_open(pid, 0); + if (pfd < 0) + err(EXIT_FAILURE, _("pidfd_open() failed")); + + if (pfd_ino) { + rc = fstat(pfd, &f); + if (rc < 0) + err(EXIT_FAILURE, _("failed to fstat() pidfd")); + + if (f.st_ino != pfd_ino) { + close(pfd); + errx(EXIT_FAILURE, _("pidfd inode %"PRIu64" not found for pid %d"), + pfd_ino, pid); + } + } + return pfd; +} \ No newline at end of file From 15225d77b822d05da2561ee874d5927f9d4eeb0b Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Mon, 24 Nov 2025 23:54:39 -0500 Subject: [PATCH 151/174] kill: use ul_get_valid_pidfd_or_err() to validate user provided pidfd inodes Signed-off-by: Christian Goeschel Ndjomouo --- misc-utils/kill.c | 29 ++--------------------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/misc-utils/kill.c b/misc-utils/kill.c index 245c3b6b7a3..ff0dcae52eb 100644 --- a/misc-utils/kill.c +++ b/misc-utils/kill.c @@ -534,8 +534,7 @@ static int kill_with_timeout(const struct kill_control *ctl) info.si_value.sival_int = ctl->use_sigval != 0 ? ctl->use_sigval : ctl->numsig; - if ((pfd = pidfd_open(ctl->pid, 0)) < 0) - err(EXIT_FAILURE, _("pidfd_open() failed: %d"), ctl->pid); + pfd = ul_get_valid_pidfd_or_err(ctl->pid, ctl->pidfd_ino); p.fd = pfd; p.events = POLLIN; @@ -564,22 +563,6 @@ static int kill_with_timeout(const struct kill_control *ctl) } #endif -#ifdef USE_KILL_WITH_PIDFDINO -static int validate_pfd_ino(int pfd, ino_t pfd_ino) -{ - int rc; - struct stat f; - - rc = fstat(pfd, &f); - if (rc != 0) - return -EINVAL; - - if (f.st_ino != pfd_ino) - return -EINVAL; - return 0; -} -#endif - static int kill_verbose(const struct kill_control *ctl) { int rc = 0; @@ -603,15 +586,7 @@ static int kill_verbose(const struct kill_control *ctl) #ifdef USE_KILL_WITH_PIDFDINO if ((ctl->pidfd_ino > 0)) { int pfd; - pfd = pidfd_open(ctl->pid, 0); - if (pfd < 0) - err(EXIT_FAILURE, _("pidfd_open() failed: %d"), ctl->pid); - - rc = validate_pfd_ino(pfd, ctl->pidfd_ino); - if (rc < 0) - errx(EXIT_FAILURE, _("pidfd inode %"PRIu64" not found for pid %d: %s"), - ctl->pidfd_ino, ctl->pid, strerror(-rc)); - + pfd = ul_get_valid_pidfd_or_err(ctl->pid, ctl->pidfd_ino); rc = pidfd_send_signal(pfd, ctl->numsig, 0, 0); if (rc < 0) err(EXIT_FAILURE, _("pidfd_send_signal() failed")); From ed991af658ec776d83c65937e7aa6ec3bc4c77ab Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Wed, 3 Dec 2025 20:27:22 -0500 Subject: [PATCH 152/174] include: (statfs_magic.h) add pidfs magic number Signed-off-by: Christian Goeschel Ndjomouo --- include/statfs_magic.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/statfs_magic.h b/include/statfs_magic.h index 857058a7314..6921abaa4dc 100644 --- a/include/statfs_magic.h +++ b/include/statfs_magic.h @@ -77,6 +77,7 @@ #define STATFS_OCFS2_MAGIC 0x7461636f #define STATFS_OMFS_MAGIC 0xC2993D87 #define STATFS_OPENPROMFS_MAGIC 0x9fa1 +#define STATFS_PIDFS_MAGIC 0x50494446 #define STATFS_PIPEFS_MAGIC 0x50495045 #define STATFS_PROC_MAGIC 0x9fa0 #define STATFS_PSTOREFS_MAGIC 0x6165676C From 6da67c93fd944d00c3c0f70397f7283568816030 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Wed, 3 Dec 2025 20:31:37 -0500 Subject: [PATCH 153/174] libmount: add pidfs magic number for fstype check Signed-off-by: Christian Goeschel Ndjomouo --- libmount/src/utils.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libmount/src/utils.c b/libmount/src/utils.c index 7626b6f91ee..b9980c88e8e 100644 --- a/libmount/src/utils.c +++ b/libmount/src/utils.c @@ -510,6 +510,7 @@ const char *mnt_statfs_get_fstype(struct statfs *vfs) case STATFS_OCFS2_MAGIC: return "ocfs2"; case STATFS_OMFS_MAGIC: return "omfs"; case STATFS_OPENPROMFS_MAGIC: return "openpromfs"; + case STATFS_PIDFS_MAGIC: return "pidfs"; case STATFS_PIPEFS_MAGIC: return "pipefs"; case STATFS_PROC_MAGIC: return "proc"; case STATFS_PSTOREFS_MAGIC: return "pstore"; From 967fb9cbc2837263f7a44449c3f8e1a89251844a Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Wed, 3 Dec 2025 20:38:11 -0500 Subject: [PATCH 154/174] include: (pidfd-utils.h) conditionally define pidfd inode support Signed-off-by: Christian Goeschel Ndjomouo --- include/pidfd-utils.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/pidfd-utils.h b/include/pidfd-utils.h index 1b9f4dc4fdd..cfa1d862c51 100644 --- a/include/pidfd-utils.h +++ b/include/pidfd-utils.h @@ -31,6 +31,9 @@ # define PIDFD_GET_UTS_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 10) #endif +#if (defined(HAVE_PIDFD_OPEN) || defined(SYS_pidfd_open)) && defined(HAVE_STATX) +#define USE_PIDFD_INO_SUPPORT 1 +#endif #ifdef HAVE_SYS_SYSCALL_H # include From 086ec5cd4d784eb799d7c67349d9a442207f0cec Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Wed, 3 Dec 2025 20:45:05 -0500 Subject: [PATCH 155/174] kill: replace USE_KILL_WITH_PIDFD_INO ifdef with USE_PIDFD_INO_SUPPORT Signed-off-by: Christian Goeschel Ndjomouo --- misc-utils/kill.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/misc-utils/kill.c b/misc-utils/kill.c index ff0dcae52eb..877a1c2a109 100644 --- a/misc-utils/kill.c +++ b/misc-utils/kill.c @@ -72,7 +72,6 @@ #if defined(HAVE_PIDFD_OPEN) && defined(HAVE_PIDFD_SEND_SIGNAL) # define USE_KILL_WITH_TIMEOUT 1 -# define USE_KILL_WITH_PIDFDINO 1 #endif enum { @@ -330,7 +329,7 @@ static void __attribute__((__noreturn__)) print_kill_version(void) #ifdef USE_KILL_WITH_TIMEOUT "pidfd", #endif -#ifdef USE_KILL_WITH_PIDFDINO +#ifdef USE_PIDFD_INO_SUPPORT "pidfdino", #endif }; @@ -583,7 +582,7 @@ static int kill_verbose(const struct kill_control *ctl) rc = sigqueue(ctl->pid, ctl->numsig, ctl->sigdata); else #endif -#ifdef USE_KILL_WITH_PIDFDINO +#ifdef USE_PIDFD_INO_SUPPORT if ((ctl->pidfd_ino > 0)) { int pfd; pfd = ul_get_valid_pidfd_or_err(ctl->pid, ctl->pidfd_ino); From f90de571343efdd108047ec94b4cfd277accf126 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Wed, 3 Dec 2025 22:59:54 -0500 Subject: [PATCH 156/174] lib: (pidfd-utils.c) add a helper routine to check the pidfd fs type Signed-off-by: Christian Goeschel Ndjomouo --- include/pidfd-utils.h | 1 + lib/pidfd-utils.c | 41 ++++++++++++++++++++++++++++++++++------- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/include/pidfd-utils.h b/include/pidfd-utils.h index cfa1d862c51..bd83f790d4d 100644 --- a/include/pidfd-utils.h +++ b/include/pidfd-utils.h @@ -97,6 +97,7 @@ static inline int pidfd_getfd(int pidfd __attribute__((unused)), } #endif +int pfd_is_pidfs(int pfd); int ul_get_valid_pidfd_or_err(pid_t pid, ino_t pfd_ino); #endif /* UTIL_LINUX_PIDFD_UTILS */ diff --git a/lib/pidfd-utils.c b/lib/pidfd-utils.c index a0cc16953ff..cf8286928d4 100644 --- a/lib/pidfd-utils.c +++ b/lib/pidfd-utils.c @@ -4,8 +4,11 @@ * * Authors: Christian Goeschel Ndjomouo [2025] */ +#define _GNU_SOURCE 1 + #include #include +#include #include #include #include @@ -14,6 +17,22 @@ #include "nls.h" #include "strutils.h" #include "pidfd-utils.h" +#include "statfs_magic.h" + +/* + * Returns 1, if the pidfd has the pidfs file system type, otherwise 0. + */ +int pfd_is_pidfs(int pfd) +{ + struct statfs stfs; + int rc; + + rc = fstatfs(pfd, &stfs); + if (rc < 0) + return 0; + + return F_TYPE_EQUAL(stfs.f_type, STATFS_PIDFS_MAGIC); +} /* * ul_get_valid_pidfd_or_err() - Return a valid file descriptor for a PID @@ -33,22 +52,30 @@ int ul_get_valid_pidfd_or_err(pid_t pid, ino_t pfd_ino) { int pfd, rc; - struct stat f; + struct statx stx; pfd = pidfd_open(pid, 0); if (pfd < 0) - err(EXIT_FAILURE, _("pidfd_open() failed")); + err(EXIT_FAILURE, N_("pidfd_open() failed")); + + /* the file descriptor has to have the pidfs file system type + * otherwise the inode assigned to it will not be useful. + */ + if (!pfd_is_pidfs(pfd)) { + close(pfd); + errx(EXIT_FAILURE, N_("pidfd needs to have the pidfs file system type")); + } if (pfd_ino) { - rc = fstat(pfd, &f); + rc = statx(pfd, NULL, AT_EMPTY_PATH, STATX_INO, &stx); if (rc < 0) - err(EXIT_FAILURE, _("failed to fstat() pidfd")); + err(EXIT_FAILURE, N_("failed to statx() pidfd")); - if (f.st_ino != pfd_ino) { + if (stx.stx_ino != pfd_ino) { close(pfd); - errx(EXIT_FAILURE, _("pidfd inode %"PRIu64" not found for pid %d"), + errx(EXIT_FAILURE, N_("pidfd inode %"PRIu64" not found for pid %d"), pfd_ino, pid); } } return pfd; -} \ No newline at end of file +} From d6997b698f35034d5dae80eec0e5f6d5bf2a0d1e Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Wed, 3 Dec 2025 23:47:16 -0500 Subject: [PATCH 157/174] lib: (pidfd-utils) new helper function to retrieve pidfd inode number Signed-off-by: Christian Goeschel Ndjomouo --- include/pidfd-utils.h | 8 ++++--- lib/pidfd-utils.c | 54 +++++++++++++++++++++++++++---------------- 2 files changed, 39 insertions(+), 23 deletions(-) diff --git a/include/pidfd-utils.h b/include/pidfd-utils.h index bd83f790d4d..af67b865b0a 100644 --- a/include/pidfd-utils.h +++ b/include/pidfd-utils.h @@ -31,7 +31,8 @@ # define PIDFD_GET_UTS_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 10) #endif -#if (defined(HAVE_PIDFD_OPEN) || defined(SYS_pidfd_open)) && defined(HAVE_STATX) +#if (defined(HAVE_PIDFD_OPEN) || defined(SYS_pidfd_open)) && defined(HAVE_STATX) \ + && defined(HAVE_STRUCT_STATX) #define USE_PIDFD_INO_SUPPORT 1 #endif @@ -97,7 +98,8 @@ static inline int pidfd_getfd(int pidfd __attribute__((unused)), } #endif -int pfd_is_pidfs(int pfd); -int ul_get_valid_pidfd_or_err(pid_t pid, ino_t pfd_ino); +int pfd_is_pidfs(int pidfd); +ino_t pidfd_get_inode(int pidfd); +int ul_get_valid_pidfd_or_err(pid_t pid, uint64_t pidfd_ino __attribute__((__unused__))); #endif /* UTIL_LINUX_PIDFD_UTILS */ diff --git a/lib/pidfd-utils.c b/lib/pidfd-utils.c index cf8286928d4..55f05a437f1 100644 --- a/lib/pidfd-utils.c +++ b/lib/pidfd-utils.c @@ -22,18 +22,33 @@ /* * Returns 1, if the pidfd has the pidfs file system type, otherwise 0. */ -int pfd_is_pidfs(int pfd) +int pfd_is_pidfs(int pidfd) { struct statfs stfs; int rc; - rc = fstatfs(pfd, &stfs); + rc = fstatfs(pidfd, &stfs); if (rc < 0) return 0; return F_TYPE_EQUAL(stfs.f_type, STATFS_PIDFS_MAGIC); } +#ifdef USE_PIDFD_INO_SUPPORT +uint64_t pidfd_get_inode(int pidfd) +{ + struct statx stx; + int rc; + + rc = statx(pidfd, "", AT_EMPTY_PATH, STATX_INO, &stx); + if (rc < 0) { + close(pidfd); + err(EXIT_FAILURE, N_("failed to statx() pidfd")); + } + return stx.stx_ino; +} +#endif + /* * ul_get_valid_pidfd_or_err() - Return a valid file descriptor for a PID * or exit the process with an error message. @@ -49,14 +64,13 @@ int pfd_is_pidfs(int pfd) * print an error message and kill the program. * */ -int ul_get_valid_pidfd_or_err(pid_t pid, ino_t pfd_ino) +int ul_get_valid_pidfd_or_err(pid_t pid, uint64_t pidfd_ino __attribute__((__unused__))) { - int pfd, rc; - struct statx stx; + int pfd; - pfd = pidfd_open(pid, 0); - if (pfd < 0) - err(EXIT_FAILURE, N_("pidfd_open() failed")); + pfd = pidfd_open(pid, 0); + if (pfd < 0) + err(EXIT_FAILURE, N_("pidfd_open() failed")); /* the file descriptor has to have the pidfs file system type * otherwise the inode assigned to it will not be useful. @@ -66,16 +80,16 @@ int ul_get_valid_pidfd_or_err(pid_t pid, ino_t pfd_ino) errx(EXIT_FAILURE, N_("pidfd needs to have the pidfs file system type")); } - if (pfd_ino) { - rc = statx(pfd, NULL, AT_EMPTY_PATH, STATX_INO, &stx); - if (rc < 0) - err(EXIT_FAILURE, N_("failed to statx() pidfd")); - - if (stx.stx_ino != pfd_ino) { - close(pfd); - errx(EXIT_FAILURE, N_("pidfd inode %"PRIu64" not found for pid %d"), - pfd_ino, pid); - } - } - return pfd; +#ifdef USE_PIDFD_INO_SUPPORT + uint64_t real_pidfd_ino; + if (pidfd_ino) { + real_pidfd_ino = pidfd_get_inode(pfd); + if (real_pidfd_ino != pidfd_ino) { + close(pfd); + errx(EXIT_FAILURE, N_("pidfd inode %"PRIu64" not found for pid %d"), + pidfd_ino, pid); + } + } +#endif + return pfd; } From 3d81cdd5881b248fdece446cf4f45a1e0d35ffdd Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Thu, 4 Dec 2025 10:16:25 -0500 Subject: [PATCH 158/174] lib: (pidfd-utils.c) remove extraneous _GNU_SOURCE feature test macro Signed-off-by: Christian Goeschel Ndjomouo --- lib/pidfd-utils.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/pidfd-utils.c b/lib/pidfd-utils.c index 55f05a437f1..879f964c458 100644 --- a/lib/pidfd-utils.c +++ b/lib/pidfd-utils.c @@ -4,8 +4,6 @@ * * Authors: Christian Goeschel Ndjomouo [2025] */ -#define _GNU_SOURCE 1 - #include #include #include From d75ba99153d02f0b821a4b2e98a6827c2bc98cc8 Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Thu, 4 Dec 2025 13:35:21 -0500 Subject: [PATCH 159/174] kill: use uint64_t as type for kill_control->pidfd_ino Signed-off-by: Christian Goeschel Ndjomouo --- misc-utils/kill.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/misc-utils/kill.c b/misc-utils/kill.c index 877a1c2a109..4fe11d02bdf 100644 --- a/misc-utils/kill.c +++ b/misc-utils/kill.c @@ -90,10 +90,10 @@ struct timeouts { #endif struct kill_control { - char *arg; - pid_t pid; - ino_t pidfd_ino; - int numsig; + char *arg; + pid_t pid; + uint64_t pidfd_ino; + int numsig; #ifdef HAVE_SIGQUEUE union sigval sigdata; #endif From ce809d79cc88cd1facda872fd8031b2a5c897e0d Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Thu, 4 Dec 2025 13:37:57 -0500 Subject: [PATCH 160/174] lib: (pidutils.c) use uint64_t instead of ino_t for seamless cross-compatibility Signed-off-by: Christian Goeschel Ndjomouo --- include/pidutils.h | 4 ++-- lib/pidutils.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/pidutils.h b/include/pidutils.h index 9d3257dfdf3..b2c575c190b 100644 --- a/include/pidutils.h +++ b/include/pidutils.h @@ -9,6 +9,6 @@ #include -extern int ul_parse_pid_str(char *pidstr, pid_t *pid_num, ino_t *pfd_ino); +extern int ul_parse_pid_str(char *pidstr, pid_t *pid_num, uint64_t *pfd_ino); -#endif /* UTIL_LINUX_PIDUTILS_H */ \ No newline at end of file +#endif /* UTIL_LINUX_PIDUTILS_H */ diff --git a/lib/pidutils.c b/lib/pidutils.c index 56f3b857889..a7567eb3fd4 100644 --- a/lib/pidutils.c +++ b/lib/pidutils.c @@ -23,7 +23,7 @@ * Return: On success, 0 is returned. * On failure, a negative errno number will be returned. */ -int ul_parse_pid_str(char *pidstr, pid_t *pid_num, ino_t *pfd_ino) +int ul_parse_pid_str(char *pidstr, pid_t *pid_num, uint64_t *pfd_ino) { int rc; char *end = NULL; @@ -40,7 +40,7 @@ int ul_parse_pid_str(char *pidstr, pid_t *pid_num, ino_t *pfd_ino) if (*end == ':' && pfd_ino) { rc = ul_strtou64(++end, pfd_ino, 10); if (rc != 0) - return -ERANGE; + return -ERANGE; *end = '\0'; } if (errno != 0 || ((end && *end != '\0') || pidstr >= end)) From 50218435dbeaa3574afa8d0acc76bcacf5488ecf Mon Sep 17 00:00:00 2001 From: Christian Goeschel Ndjomouo Date: Thu, 4 Dec 2025 14:00:32 -0500 Subject: [PATCH 161/174] lib: (procfs.c) remove extraneous return statement Signed-off-by: Christian Goeschel Ndjomouo --- lib/procfs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/procfs.c b/lib/procfs.c index 47cc8eea2c7..ca34e54b066 100644 --- a/lib/procfs.c +++ b/lib/procfs.c @@ -414,7 +414,6 @@ int fd_is_procfs(int fd) } while (ret != 0); return F_TYPE_EQUAL(st.f_type, STATFS_PROC_MAGIC); - return 0; } #else int fd_is_procfs(int fd __attribute__((__unused__))) From 08a0f0ae66e799d8f0f19fb8f5bbd73691af6880 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Mon, 24 Nov 2025 09:42:09 +0100 Subject: [PATCH 162/174] libmount: refactor mnt_get_fstype() Move the current code into two small functions to improve readability and facilitate future extensions. Signed-off-by: Karel Zak --- libmount/src/cache.c | 59 ++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/libmount/src/cache.c b/libmount/src/cache.c index 29426544915..a03d6d6d618 100644 --- a/libmount/src/cache.c +++ b/libmount/src/cache.c @@ -446,7 +446,7 @@ static int __mnt_cache_find_tag_value(struct libmnt_cache *cache, * mnt_cache_find_tag_value: * @cache: cache for results * @devname: device name - * @token: tag name ("LABEL" or "UUID") + * @token: tag name ("LABEL", "UUID", ...) * * Returns: LABEL or UUID for the @devname or NULL in case of error. */ @@ -460,35 +460,24 @@ char *mnt_cache_find_tag_value(struct libmnt_cache *cache, return NULL; } -/** - * mnt_get_fstype: - * @devname: device name - * @ambi: returns TRUE if probing result is ambivalent (optional argument) - * @cache: cache for results or NULL - * - * Returns: filesystem type or NULL in case of error. The result has to be - * deallocated by free() if @cache is NULL. - */ -char *mnt_get_fstype(const char *devname, int *ambi, struct libmnt_cache *cache) +static char *fstype_from_cache(const char *devname, struct libmnt_cache *cache) +{ + char *val = NULL; + + assert(cache); + + if (__mnt_cache_find_tag_value(cache, devname, "TYPE", &val) != 0) + return NULL; + return val; +} + +static char *fstype_from_blkid(const char *devname, int *ambi) { blkid_probe pr; const char *data; char *type = NULL; int rc; - DBG(CACHE, ul_debugobj(cache, "get %s FS type", devname)); - - if (cache) { - char *val = NULL; - rc = __mnt_cache_find_tag_value(cache, devname, "TYPE", &val); - if (ambi) - *ambi = rc == -2 ? TRUE : FALSE; - return rc ? NULL : val; - } - - /* - * no cache, probe directly - */ pr = blkid_new_probe_from_filename(devname); if (!pr) return NULL; @@ -498,11 +487,8 @@ char *mnt_get_fstype(const char *devname, int *ambi, struct libmnt_cache *cache) rc = blkid_do_safeprobe(pr); - DBG(CACHE, ul_debugobj(cache, "libblkid rc=%d", rc)); - if (!rc && !blkid_probe_lookup_value(pr, "TYPE", &data, NULL)) type = strdup(data); - if (ambi) *ambi = rc == -2 ? TRUE : FALSE; @@ -510,6 +496,25 @@ char *mnt_get_fstype(const char *devname, int *ambi, struct libmnt_cache *cache) return type; } +/** + * mnt_get_fstype: + * @devname: device name + * @ambi: returns TRUE if probing result is ambivalent (optional argument) + * @cache: cache for results or NULL + * + * Returns: filesystem type or NULL in case of error. The result has to be + * deallocated by free() if @cache is NULL. + */ +char *mnt_get_fstype(const char *devname, int *ambi, struct libmnt_cache *cache) +{ + DBG(CACHE, ul_debugobj(cache, "get %s FS type", devname)); + + if (cache) + return fstype_from_cache(devname, cache); + + return fstype_from_blkid(devname, ambi); +} + static char *canonicalize_path_and_cache(const char *path, struct libmnt_cache *cache) { From 800292e940b40d13ef9f5698a6d9a46599110a36 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Mon, 24 Nov 2025 09:54:20 +0100 Subject: [PATCH 163/174] libmount: refactor mnt_cache_read_tags() Split the function into smaller functions to make it easier to read and extend in the future. Introduce a struct to hold all variants of tag names, including udev names in the future. Signed-off-by: Karel Zak --- libmount/src/cache.c | 97 ++++++++++++++++++++++++++++++-------------- 1 file changed, 66 insertions(+), 31 deletions(-) diff --git a/libmount/src/cache.c b/libmount/src/cache.c index a03d6d6d618..29f08674fd9 100644 --- a/libmount/src/cache.c +++ b/libmount/src/cache.c @@ -72,6 +72,24 @@ struct libmnt_cache { struct libmnt_table *mountinfo; }; + +struct libmnt_cachetag { + const char *mnt_name; /* tag name used by libmount */ + const char *blk_name; /* tag name used by libblkid */ +}; + +static const struct libmnt_cachetag mnttags[] = +{ + /* mount blkid */ + { "LABEL", "LABEL" }, + { "UUID", "UUID" }, + { "TYPE", "TYPE" }, + { "PARTUUID", "PART_ENTRY_UUID" }, + { "PARTLABEL", "PART_ENTRY_NAME" }, + + { NULL, NULL } +}; + /** * mnt_new_cache: * @@ -324,39 +342,34 @@ static char *cache_find_tag_value(struct libmnt_cache *cache, return NULL; } -/** - * mnt_cache_read_tags - * @cache: pointer to struct libmnt_cache instance - * @devname: path device - * - * Reads @devname LABEL and UUID to the @cache. - * - * Returns: 0 if at least one tag was added, 1 if no tag was added or - * negative number in case of error. - */ -int mnt_cache_read_tags(struct libmnt_cache *cache, const char *devname) +static bool is_device_cached(struct libmnt_cache *cache, const char *devname) { - blkid_probe pr; - size_t i, ntags = 0; - int rc; - const char *tags[] = { "LABEL", "UUID", "TYPE", "PARTUUID", "PARTLABEL" }; - const char *blktags[] = { "LABEL", "UUID", "TYPE", "PART_ENTRY_UUID", "PART_ENTRY_NAME" }; - - if (!cache || !devname) - return -EINVAL; - - DBG(CACHE, ul_debugobj(cache, "tags for %s requested", devname)); + size_t i; - /* check if device is already cached */ for (i = 0; i < cache->nents; i++) { struct mnt_cache_entry *e = &cache->ents[i]; if (!(e->flag & MNT_CACHE_TAGREAD)) continue; if (strcmp(e->value, devname) == 0) - /* tags have already been read */ - return 0; + return 1; /* already in cache */ } + return 0; +} + +/* read data from libblkid into local cache */ +static int read_from_blkid(struct libmnt_cache *cache, const char *devname) +{ + blkid_probe pr; + const struct libmnt_cachetag *t; + size_t ntags = 0; + int rc; + + assert(cache); + assert(devname); + + DBG(CACHE, ul_debugobj(cache, "%s: reading from blkid", devname)); + pr = blkid_new_probe_from_filename(devname); if (!pr) return -1; @@ -373,23 +386,21 @@ int mnt_cache_read_tags(struct libmnt_cache *cache, const char *devname) if (rc) goto error; - DBG(CACHE, ul_debugobj(cache, "reading tags for: %s", devname)); - - for (i = 0; i < ARRAY_SIZE(tags); i++) { + for (t = mnttags; t && t->mnt_name; t++) { const char *data; char *dev; - if (cache_find_tag_value(cache, devname, tags[i])) { + if (cache_find_tag_value(cache, devname, t->mnt_name)) { DBG(CACHE, ul_debugobj(cache, - "\ntag %s already cached", tags[i])); + "\ntag %s already cached", t->mnt_name)); continue; } - if (blkid_probe_lookup_value(pr, blktags[i], &data, NULL)) + if (blkid_probe_lookup_value(pr, t->blk_name, &data, NULL)) continue; dev = strdup(devname); if (!dev) goto error; - if (cache_add_tag(cache, tags[i], data, dev, + if (cache_add_tag(cache, t->mnt_name, data, dev, MNT_CACHE_TAGREAD)) { free(dev); goto error; @@ -403,6 +414,30 @@ int mnt_cache_read_tags(struct libmnt_cache *cache, const char *devname) error: blkid_free_probe(pr); return rc < 0 ? rc : -1; + +} + +/** + * mnt_cache_read_tags + * @cache: pointer to struct libmnt_cache instance + * @devname: path device + * + * Reads @devname LABEL and UUID to the @cache. + * + * Returns: 0 if at least one tag was added, 1 if no tag was added or + * negative number in case of error. + */ +int mnt_cache_read_tags(struct libmnt_cache *cache, const char *devname) +{ + if (!cache || !devname) + return -EINVAL; + + DBG(CACHE, ul_debugobj(cache, "tags for %s requested", devname)); + + if (is_device_cached(cache, devname)) + return 0; + + return read_from_blkid(cache, devname); } /** From 41521056a67bcd5c179b15df9e09265aba8ec732 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Mon, 24 Nov 2025 16:57:50 +0100 Subject: [PATCH 164/174] libmount: enhance readability of read_from_blkid() Signed-off-by: Karel Zak --- libmount/src/cache.c | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/libmount/src/cache.c b/libmount/src/cache.c index 29f08674fd9..ebba427e43b 100644 --- a/libmount/src/cache.c +++ b/libmount/src/cache.c @@ -364,6 +364,7 @@ static int read_from_blkid(struct libmnt_cache *cache, const char *devname) const struct libmnt_cachetag *t; size_t ntags = 0; int rc; + char *cacheval = NULL; assert(cache); assert(devname); @@ -384,37 +385,31 @@ static int read_from_blkid(struct libmnt_cache *cache, const char *devname) rc = blkid_do_safeprobe(pr); if (rc) - goto error; + goto done; for (t = mnttags; t && t->mnt_name; t++) { const char *data; - char *dev; - if (cache_find_tag_value(cache, devname, t->mnt_name)) { - DBG(CACHE, ul_debugobj(cache, - "\ntag %s already cached", t->mnt_name)); + if (cache_find_tag_value(cache, devname, t->mnt_name)) continue; - } if (blkid_probe_lookup_value(pr, t->blk_name, &data, NULL)) continue; - dev = strdup(devname); - if (!dev) - goto error; - if (cache_add_tag(cache, t->mnt_name, data, dev, - MNT_CACHE_TAGREAD)) { - free(dev); - goto error; - } + + cacheval = strdup(devname); + rc = !cacheval ? -ENOMEM : + cache_add_tag(cache, t->mnt_name, data, cacheval, MNT_CACHE_TAGREAD); + if (rc) + break; ntags++; + cacheval = NULL; /* stored into cache */ } - DBG(CACHE, ul_debugobj(cache, "\tread %zd tags", ntags)); - blkid_free_probe(pr); - return ntags ? 0 : 1; -error: +done: + DBG(CACHE, ul_debugobj(cache, "\tread %zd tags [rc=%d]", ntags, rc)); blkid_free_probe(pr); - return rc < 0 ? rc : -1; + free(cacheval); + return rc ? rc : ntags ? 0 : 1; } /** From 8bdc2546d38979ca65fa9bfd1bbd6e7b985c69db Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Tue, 25 Nov 2025 12:56:07 +0100 Subject: [PATCH 165/174] libmount: read from udev, add --disable-libmount-udev-support The library traditionally uses libblkid to obtain device properties (such as FS-type if not specified). This can be a relatively costly operation to scan the device and requires read access to the device. All relevant libblkid information is usually cached by the udev DB. This commit adds the possibility to reuse the information from udev, with a fallback to libblkid if udev is not available. The commit also adds $ ./configure --disable-libmount-udev-support $ meson setup build -Dbuild-libmount-udev-support=disabled to completely disable this feature and avoid libmount's dependence on libsystemd. Signed-off-by: Karel Zak --- configure.ac | 18 ++++++++ libmount/meson.build | 5 +++ libmount/src/Makemodule.am | 4 ++ libmount/src/cache.c | 91 ++++++++++++++++++++++++++++++++++---- libmount/src/version.c | 3 ++ meson.build | 6 +++ meson_options.txt | 5 +++ 7 files changed, 123 insertions(+), 9 deletions(-) diff --git a/configure.ac b/configure.ac index cf415f5ed46..93ad3a38b12 100644 --- a/configure.ac +++ b/configure.ac @@ -1390,6 +1390,10 @@ AC_ARG_ENABLE([libmount-mountfd-support], AS_HELP_STRING([--disable-libmount-mountfd-support], [do not use new mount API based on FDs]), [], [enable_libmount_mountfd_support=check] ) +AC_ARG_ENABLE([libmount-udev-support], + AS_HELP_STRING([--disable-libmount-udev-support], [do not read from udev in libmount]), + [], [enable_libmount_udev_support=check] +) UL_BUILD_INIT([libmount_mountfd_support]) UL_REQUIRES_BUILD([libmount_mountfd_support], [libmount]) UL_REQUIRES_LINUX([libmount_mountfd_support]) @@ -2701,6 +2705,20 @@ AS_IF([test "x$with_systemd" != xno], [ ]) AM_CONDITIONAL([HAVE_SYSTEMD], [test "x$have_systemd" = xyes]) +libmount_udev_support=no +AS_IF([test "x$enable_libmount_udev_support" != xno && test "x$build_libmount" = xyes], [ + AS_CASE([$enable_libmount_udev_support:$have_systemd], + [yes:no], + [AC_MSG_ERROR([libmount udev support expected but libsystemd not found])], + [*:yes], [ + AC_CHECK_DECLS([sd_device_new_from_devname], [ + AC_DEFINE([USE_LIBMOUNT_UDEV_SUPPORT], [1], [Define if use udev support in libmount]) + libmount_udev_support=yes], + [], [#include ]) + ] + ) +]) +AM_CONDITIONAL([USE_LIBMOUNT_UDEV_SUPPORT], [test "x$libmount_udev_support" = xyes]) AC_ARG_WITH([systemdsystemunitdir], AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [directory for systemd unit files (requires systemd support)]), diff --git a/libmount/meson.build b/libmount/meson.build index 28feadf4845..558f30468aa 100644 --- a/libmount/meson.build +++ b/libmount/meson.build @@ -98,6 +98,11 @@ lib__mount_deps = [ cryptsetup_dlopen ? lib_dl : lib_cryptsetup, realtime_libs ] + +if conf.get('USE_LIBMOUNT_UDEV_SUPPORT').to_string() == '1' + lib__mount_deps += [lib_systemd] +endif + lib_mount = library( 'mount', link_whole : lib__mount, diff --git a/libmount/src/Makemodule.am b/libmount/src/Makemodule.am index 28dbc581130..bbd83b8bcd4 100644 --- a/libmount/src/Makemodule.am +++ b/libmount/src/Makemodule.am @@ -69,6 +69,10 @@ libmount_la_LIBADD += $(CRYPTSETUP_LIBS) endif endif +if USE_LIBMOUNT_UDEV_SUPPORT +libmount_la_LIBADD += $(SYSTEMD_LIBS) +endif + libmount_la_CFLAGS = \ $(AM_CFLAGS) \ $(SOLIB_CFLAGS) \ diff --git a/libmount/src/cache.c b/libmount/src/cache.c index ebba427e43b..4d2a20f235f 100644 --- a/libmount/src/cache.c +++ b/libmount/src/cache.c @@ -30,10 +30,16 @@ #include #include +/* sd-device is a replacement for libudev */ +#ifdef USE_LIBMOUNT_UDEV_SUPPORT +# include +#endif + #include "canonicalize.h" #include "mountP.h" #include "loopdev.h" #include "strutils.h" +#include "mangle.h" /* * Canonicalized (resolved) paths & tags cache @@ -76,16 +82,17 @@ struct libmnt_cache { struct libmnt_cachetag { const char *mnt_name; /* tag name used by libmount */ const char *blk_name; /* tag name used by libblkid */ + const char *udev_name; /* tag name used by udev db */ }; static const struct libmnt_cachetag mnttags[] = { - /* mount blkid */ - { "LABEL", "LABEL" }, - { "UUID", "UUID" }, - { "TYPE", "TYPE" }, - { "PARTUUID", "PART_ENTRY_UUID" }, - { "PARTLABEL", "PART_ENTRY_NAME" }, + /* mount blkid udev */ + { "LABEL", "LABEL", "ID_FS_LABEL_ENC" }, + { "UUID", "UUID", "ID_FS_UUID_ENC" }, + { "TYPE", "TYPE", "ID_FS_TYPE" }, + { "PARTUUID", "PART_ENTRY_UUID", "ID_PART_ENTRY_UUID" }, + { "PARTLABEL", "PART_ENTRY_NAME", "ID_PART_ENTRY_NAME" }, { NULL, NULL } }; @@ -357,7 +364,10 @@ static bool is_device_cached(struct libmnt_cache *cache, const char *devname) return 0; } -/* read data from libblkid into local cache */ +/* + * read data from libblkid into local cache + * returns: <0 on error; 0 success; 1 nothing +*/ static int read_from_blkid(struct libmnt_cache *cache, const char *devname) { blkid_probe pr; @@ -373,7 +383,7 @@ static int read_from_blkid(struct libmnt_cache *cache, const char *devname) pr = blkid_new_probe_from_filename(devname); if (!pr) - return -1; + return -EINVAL; blkid_probe_enable_superblocks(pr, 1); blkid_probe_set_superblocks_flags(pr, @@ -412,12 +422,68 @@ static int read_from_blkid(struct libmnt_cache *cache, const char *devname) return rc ? rc : ntags ? 0 : 1; } +#ifdef USE_LIBMOUNT_UDEV_SUPPORT +/* + * read data from udev into local cache + * returns: <0 on error; 0 success; 1 nothing + */ +static int read_from_udev(struct libmnt_cache *cache, const char *devname) +{ + sd_device *sd = NULL; + const struct libmnt_cachetag *t; + size_t ntags = 0; + char *tagval = NULL, *cacheval = NULL; + int rc; + + assert(cache); + assert(devname); + + rc = sd_device_new_from_devname(&sd, devname); + if (rc < 0) + return rc; + + DBG(CACHE, ul_debugobj(cache, "%s: reading from udev", devname)); + + for (t = mnttags; t && t->mnt_name; t++) { + const char *data; + + if (cache_find_tag_value(cache, devname, t->mnt_name)) + continue; + if (sd_device_get_property_value(sd, t->udev_name, &data) < 0) + continue; + + tagval = strdup(data); /* temporary for unhexmangle() */ + cacheval = strdup(devname); + + if (tagval && cacheval) { + unhexmangle_string(tagval); + rc = cache_add_tag(cache, t->mnt_name, + tagval, cacheval, MNT_CACHE_TAGREAD); + } else + rc = -ENOMEM; + if (rc) + break; + ntags++; + cacheval = NULL; /* stored into cache */ + free(tagval), tagval = NULL; + } + + DBG(CACHE, ul_debugobj(cache, "\tread %zd tags [rc=%d]", ntags, rc)); + sd_device_unref(sd); + free(cacheval); + free(tagval); + + return rc ? rc : ntags ? 0 : 1; +} +#endif /* USE_LIBMOUNT_UDEV_SUPPORT */ + + /** * mnt_cache_read_tags * @cache: pointer to struct libmnt_cache instance * @devname: path device * - * Reads @devname LABEL and UUID to the @cache. + * Reads @devname information into the @cache. * * Returns: 0 if at least one tag was added, 1 if no tag was added or * negative number in case of error. @@ -432,6 +498,10 @@ int mnt_cache_read_tags(struct libmnt_cache *cache, const char *devname) if (is_device_cached(cache, devname)) return 0; +#ifdef USE_LIBMOUNT_UDEV_SUPPORT + if (read_from_udev(cache, devname) == 0) + return 0; +#endif return read_from_blkid(cache, devname); } @@ -532,6 +602,9 @@ static char *fstype_from_blkid(const char *devname, int *ambi) * @ambi: returns TRUE if probing result is ambivalent (optional argument) * @cache: cache for results or NULL * + * Note: If the cache is not specified, it reads the file system type from the + * device, and in this case, there is no optimization like udev db, etc. * + * * Returns: filesystem type or NULL in case of error. The result has to be * deallocated by free() if @cache is NULL. */ diff --git a/libmount/src/version.c b/libmount/src/version.c index 19326d280cb..5ec0d490cde 100644 --- a/libmount/src/version.c +++ b/libmount/src/version.c @@ -52,6 +52,9 @@ static const char *lib_features[] = { #ifdef HAVE_STRUCT_FANOTIFY_EVENT_INFO_HEADER "fanotify", #endif +#ifdef USE_LIBMOUNT_UDEV_SUPPORT + "udev", +#endif #if !defined(NDEBUG) "assert", /* libc assert.h stuff */ #endif diff --git a/meson.build b/meson.build index cac8bb57869..2f4e66feff0 100644 --- a/meson.build +++ b/meson.build @@ -396,6 +396,12 @@ have = cc.has_function( dependencies : lib_systemd) conf.set('HAVE_DECL_SD_SESSION_GET_USERNAME', have ? 1 : false) +have = cc.has_function( + 'sd_device_new_from_devname', + dependencies : lib_systemd) +conf.set('USE_LIBMOUNT_UDEV_SUPPORT', + not get_option('build-libmount-udev-support').disabled() and have ? 1 : false) + lib_udev = dependency( 'libudev', required : get_option('systemd')) diff --git a/meson_options.txt b/meson_options.txt index 1ec904668be..c03de17ff9c 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -303,6 +303,11 @@ option('fs-search-path', option('fs-search-path-extra', type : 'string', description : 'additional search path for fs helpers') + +option('build-libmount-udev-support', + type : 'feature', + description : 'support reading from udev in libmount') + option('vendordir', type: 'string', description : 'directory for distribution provided econf files') From fdac580358e7a1f7ab9fa2b0e330247872fa6979 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Tue, 9 Dec 2025 13:02:11 +0100 Subject: [PATCH 166/174] libmount: add option to override fs-type with mount-type This patch introduces an internal libmount method to convert fs-type (as provided by libblkid or udevd) to mount-type to specify a different mount driver. Currently, the mapping from fs-type to mount-type is hardcoded in libmount as a temporary solution. The final implementation should provide configuration files (e.g., /etc/mount/fs.d/) for these mappings. The current default mapping is implemented only for NTFS. It can be modified during compilation with: ./configure --with-ntfs-mounttype=TYPE or meson setup build -D ntfs-mounttype=TYPE The default is "ntfs3". Addresses: https://github.com/util-linux/util-linux/pull/3618 Addresses: https://github.com/systemd/systemd/pull/39982 Signed-off-by: Karel Zak --- configure.ac | 10 ++++++++++ libmount/src/context.c | 11 +++++++++++ libmount/src/context_umount.c | 4 +++- libmount/src/mountP.h | 1 + libmount/src/utils.c | 27 ++++++++++++++++++++++++++- meson.build | 5 +++++ meson_options.txt | 4 ++++ 7 files changed, 60 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 93ad3a38b12..a424e09476b 100644 --- a/configure.ac +++ b/configure.ac @@ -2760,6 +2760,16 @@ AS_IF([test "x$with_sysusersdir" != "xno"], [ AC_SUBST([sysusersdir], [$with_sysusersdir]) ]) + +AC_ARG_WITH([ntfs-mounttype], + AS_HELP_STRING([--with-ntfs-mounttype=TYPE], [overwrite default ntfs3 mount type for NTFS]), + [], [with_ntfs_mounttype=no] +) +AS_IF([test "x$with_ntfs_mounttype" != "xno"], [ + AC_DEFINE_UNQUOTED([CONFIG_UL_NTFS_MOUNTTYPE], ["$with_ntfs_mounttype"], [NTFS mounttype]) +]) + + AC_ARG_WITH([smack], AS_HELP_STRING([--with-smack], [build with SMACK support]), [], [with_smack=no] diff --git a/libmount/src/context.c b/libmount/src/context.c index 66b5c2d8f1b..6dfc5913dfd 100644 --- a/libmount/src/context.c +++ b/libmount/src/context.c @@ -2090,6 +2090,17 @@ int mnt_context_guess_srcpath_fstype(struct libmnt_context *cxt, char **type) } } + if (rc == 0 && *type) { + const char *x = mnt_fstype_to_mounttype(*type); + + if (x) { + free(*type); + *type = strdup(x); + if (!*type) + rc = -ENOMEM; + } + } + return rc; } diff --git a/libmount/src/context_umount.c b/libmount/src/context_umount.c index 8fbd662ab48..854b704b05a 100644 --- a/libmount/src/context_umount.c +++ b/libmount/src/context_umount.c @@ -298,7 +298,9 @@ static int lookup_umount_fs_by_statfs(struct libmnt_context *cxt, const char *tg close(fd); } if (type) { - int rc = mnt_fs_set_fstype(cxt->fs, type); + const char *x = mnt_fstype_to_mounttype(type); + int rc = mnt_fs_set_fstype(cxt->fs, x ? x : type); + if (rc) return rc; } diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h index fb01041f6b1..02b86585cd6 100644 --- a/libmount/src/mountP.h +++ b/libmount/src/mountP.h @@ -109,6 +109,7 @@ struct libmnt_listmnt; extern int mnt_valid_tagname(const char *tagname); extern const char *mnt_statfs_get_fstype(struct statfs *vfs); +extern const char *mnt_fstype_to_mounttype(const char *fstype); extern int is_file_empty(const char *name); extern int mnt_is_readonly(const char *path) diff --git a/libmount/src/utils.c b/libmount/src/utils.c index 7626b6f91ee..16c5e8a9853 100644 --- a/libmount/src/utils.c +++ b/libmount/src/utils.c @@ -506,7 +506,7 @@ const char *mnt_statfs_get_fstype(struct statfs *vfs) case STATFS_NCP_MAGIC: return "ncp"; case STATFS_NFS_MAGIC: return "nfs"; case STATFS_NILFS_MAGIC: return "nilfs2"; - case STATFS_NTFS_MAGIC: return "ntfs3"; + case STATFS_NTFS_MAGIC: return "ntfs"; case STATFS_OCFS2_MAGIC: return "ocfs2"; case STATFS_OMFS_MAGIC: return "omfs"; case STATFS_OPENPROMFS_MAGIC: return "openpromfs"; @@ -541,6 +541,31 @@ const char *mnt_statfs_get_fstype(struct statfs *vfs) return NULL; } +/* + * Default NTFS mount type (used by libmount and libblkid) + */ +#ifndef CONFIG_UL_NTFS_MOUNTTYPE +# define CONFIG_UL_NTFS_MOUNTTYPE "ntfs3" +#endif + +/* + * Convert FS-type (as provided by libblkid or udev) to the preferred + * kernel FS driver (type used to mount the FS). + * + * This is a temporary solution; the final solution should be + * based on config files like /etc/mount/fs.d/ (from lib/configs.c). + */ +const char *mnt_fstype_to_mounttype(const char *fstype) +{ + if (!fstype) + return NULL; + + if (strcmp(fstype, "ntfs") == 0) + return CONFIG_UL_NTFS_MOUNTTYPE; + + return NULL; +} + /** * mnt_match_fstype: * @type: filesystem type diff --git a/meson.build b/meson.build index 2f4e66feff0..8b7880e465d 100644 --- a/meson.build +++ b/meson.build @@ -918,6 +918,11 @@ if fs_search_path_extra != '' endif conf.set_quoted('FS_SEARCH_PATH', fs_search_path) +ntfs_mounttype = get_option('ntfs-mounttype') +if ntfs_mounttype != '' + conf.set_quoted('CONFIG_UL_NTFS_MOUNTTYPE', ntfs_mounttype) +endif + systemdsystemunitdir = '' if systemd.found() systemdsystemunitdir = systemd.get_variable(pkgconfig : 'systemdsystemunitdir') diff --git a/meson_options.txt b/meson_options.txt index c03de17ff9c..b764b56fbb2 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -308,6 +308,10 @@ option('build-libmount-udev-support', type : 'feature', description : 'support reading from udev in libmount') +option('ntfs-mounttype', + type : 'string', + description : 'overwrite default ntfs3 mount type for NTFS') + option('vendordir', type: 'string', description : 'directory for distribution provided econf files') From efd1d9a607ba6e66464a5894544318c44f74172d Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Tue, 9 Dec 2025 13:12:41 +0100 Subject: [PATCH 167/174] libblkid: Keep NTFS name unmodified and mount driver independent We need stable filesystem names (types) even though there are multiple filesystem drivers. libmount now provides a way to map the stable fs-types to various mount-types. References: 4cd429fdcd3e7db1d031494987d5cf7411689d79 Signed-off-by: Karel Zak --- libblkid/src/superblocks/ntfs.c | 2 +- tests/expected/blkid/low-probe-ntfs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libblkid/src/superblocks/ntfs.c b/libblkid/src/superblocks/ntfs.c index 42c8565df4e..8ce557a113c 100644 --- a/libblkid/src/superblocks/ntfs.c +++ b/libblkid/src/superblocks/ntfs.c @@ -248,7 +248,7 @@ int blkid_probe_is_ntfs(blkid_probe pr) const struct blkid_idinfo ntfs_idinfo = { - .name = "ntfs3", + .name = "ntfs", .usage = BLKID_USAGE_FILESYSTEM, .probefunc = probe_ntfs, .magics = diff --git a/tests/expected/blkid/low-probe-ntfs b/tests/expected/blkid/low-probe-ntfs index 3c364bca022..d18e929a892 100644 --- a/tests/expected/blkid/low-probe-ntfs +++ b/tests/expected/blkid/low-probe-ntfs @@ -3,7 +3,7 @@ ID_FS_FSBLOCKSIZE=4096 ID_FS_FSSIZE=10485248 ID_FS_LABEL=Новый_том ID_FS_LABEL_ENC=Новый\x20том -ID_FS_TYPE=ntfs3 +ID_FS_TYPE=ntfs ID_FS_USAGE=filesystem ID_FS_UUID=09CBB6DE30C87310 ID_FS_UUID_ENC=09CBB6DE30C87310 From e0d602bab9354e8225f2b0ca063dd449caa64e1c Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Wed, 10 Dec 2025 12:09:44 +0100 Subject: [PATCH 168/174] lib: (pidfd-utils.c) set __unused__ in right way Signed-off-by: Karel Zak --- lib/pidfd-utils.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/pidfd-utils.c b/lib/pidfd-utils.c index 879f964c458..32b67a3b197 100644 --- a/lib/pidfd-utils.c +++ b/lib/pidfd-utils.c @@ -62,7 +62,11 @@ uint64_t pidfd_get_inode(int pidfd) * print an error message and kill the program. * */ +#ifdef USE_PIDFD_INO_SUPPORT +int ul_get_valid_pidfd_or_err(pid_t pid, uint64_t pidfd_ino) +#else int ul_get_valid_pidfd_or_err(pid_t pid, uint64_t pidfd_ino __attribute__((__unused__))) +#endif { int pfd; From dd679c971455a46778b1336de90bfc4b98bace62 Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Thu, 11 Dec 2025 07:51:25 +0900 Subject: [PATCH 169/174] docs: lsns(8): add missing a comma in SEE ALSO section --- sys-utils/lsns.8.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys-utils/lsns.8.adoc b/sys-utils/lsns.8.adoc index 49f0d5b950f..d9ab587feff 100644 --- a/sys-utils/lsns.8.adoc +++ b/sys-utils/lsns.8.adoc @@ -115,7 +115,7 @@ mailto:kzak@redhat.com[Karel Zak] *clone*(2), *namespaces*(7), *ioctl_ns*(2), -*ip-netns*(8) +*ip-netns*(8), *scols-filter*(5) include::man-common/bugreports.adoc[] From 9ac5db2c5b7b8bde467448968c77a289b4ed1465 Mon Sep 17 00:00:00 2001 From: yao zhang <294772273@qq.com> Date: Thu, 11 Dec 2025 19:20:58 +0800 Subject: [PATCH 170/174] Fix memory leak in setpwnam() Add memeory release for tmpname upon successful return. --- login-utils/setpwnam.c | 1 + 1 file changed, 1 insertion(+) diff --git a/login-utils/setpwnam.c b/login-utils/setpwnam.c index 7778e98f7cc..e55fbb2346d 100644 --- a/login-utils/setpwnam.c +++ b/login-utils/setpwnam.c @@ -168,6 +168,7 @@ int setpwnam(struct passwd *pwd, const char *prefix) /* finally: success */ ulckpwdf(); free(linebuf); + free(tmpname); return 0; fail: From 926b207cae709b05ba53acf0ee4b88e529d51729 Mon Sep 17 00:00:00 2001 From: Chris Webb Date: Sun, 14 Dec 2025 23:18:33 +0000 Subject: [PATCH 171/174] unshare: add --owner to set user namespace owner uid and gid As well as the mappings between lower and upper ids, a user namespace is associated with an owner user and group in its parent. These are set from the uid and gid when the unshare() call is made, and determine which user in the parent namespace has CAP_SYS_ADMIN in the child and can setns() into it. Add an --owner=: option which allows a privileged user to create a user namespace on behalf of another user, mapping parent ids and/or bind-mounting the namespace with privileges that the new owner would not have. Simplify the control flow around map_ids_from_child() vs mapping them inline to avoid too many special cases. We reset mapuser and mapgroup to -1 to signal that the mapping has been delegated to the child helper. For completeness, we maintain the semantics of --map-root-user and --map-current-user, binding the invoking user to root or itself in the new namespace. However, when --owner is used, these must be handled by a forked child as with --map-users and --map-groups. Signed-off-by: Chris Webb --- bash-completion/unshare | 1 + sys-utils/unshare.1.adoc | 3 +++ sys-utils/unshare.c | 45 ++++++++++++++++++++++++++++------------ 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/bash-completion/unshare b/bash-completion/unshare index 2d887bd5ce7..19eeb8f08f2 100644 --- a/bash-completion/unshare +++ b/bash-completion/unshare @@ -33,6 +33,7 @@ _unshare_module() --mount-proc --map-current-user --map-root-user + --owner --propagation --setgroups --help diff --git a/sys-utils/unshare.1.adoc b/sys-utils/unshare.1.adoc index 1f259962c0e..85d00af3c9e 100644 --- a/sys-utils/unshare.1.adoc +++ b/sys-utils/unshare.1.adoc @@ -121,6 +121,9 @@ Run the program only after the current effective user and group IDs have been ma *-c*, *--map-current-user*:: Run the program only after the current effective user and group IDs have been mapped to the same UID and GID in the newly created user namespace. This option implies *--setgroups=deny* and *--user*. This option is equivalent to *--map-user=$(id -ru) --map-group=$(id -rg)*. +*--owner* __uid__**:**__gid__:: +Set the owner user and group when creating a user namespace. These determine which user in the parent namespace has CAP_SYS_ADMIN in the new child namespace and can *setns*(2) into it. This option allows a privileged user to create a namespace on behalf of an unprivileged one, using its privileges to map ids and/or bind mount the namespace into the filesystem. It implies *--user*. + *--propagation* **private**|**shared**|**slave**|**unchanged**:: Recursively set the mount propagation flag in the new mount namespace. The default is to set the propagation to _private_. It is possible to disable this feature with the argument *unchanged*. The option is silently ignored when the mount namespace (*--mount*) is not requested. diff --git a/sys-utils/unshare.c b/sys-utils/unshare.c index 11aeae48ed5..ebc59887580 100644 --- a/sys-utils/unshare.c +++ b/sys-utils/unshare.c @@ -691,8 +691,7 @@ static void map_ids_internal(const char *type, int ppid, struct map_range *chain * * Return: The pid of the child. */ -static pid_t map_ids_from_child(int *fd, uid_t mapuser, - struct map_range *usermap, gid_t mapgroup, +static pid_t map_ids_from_child(int *fd, struct map_range *usermap, struct map_range *groupmap) { pid_t child, pid = 0; @@ -702,11 +701,6 @@ static pid_t map_ids_from_child(int *fd, uid_t mapuser, if (child) return child; - if (usermap) - add_single_map_range(&usermap, geteuid(), mapuser); - if (groupmap) - add_single_map_range(&groupmap, getegid(), mapgroup); - if (geteuid() == 0) { if (usermap) map_ids_internal("uid_map", ppid, usermap); @@ -800,6 +794,7 @@ static void __attribute__((__noreturn__)) usage(void) " map count users from outeruid to inneruid (implies --user)\n"), out); fputs(_(" --map-groups ::\n" " map count groups from outergid to innergid (implies --user)\n"), out); + fputs(_(" --owner : set the user namespace owner (implies --user)\n"), out); fputs(USAGE_SEPARATOR, out); fputs(_(" -f, --fork fork before launching \n"), out); fputs(_(" --kill-child[=] when dying, kill the forked child (implies --fork)\n" @@ -835,6 +830,7 @@ int main(int argc, char *argv[]) OPT_MAPGROUPS, OPT_MAPAUTO, OPT_MAPSUBIDS, + OPT_OWNER, }; static const struct option longopts[] = { { "help", no_argument, NULL, 'h' }, @@ -861,6 +857,7 @@ int main(int argc, char *argv[]) { "map-current-user", no_argument, NULL, 'c' }, { "map-auto", no_argument, NULL, OPT_MAPAUTO }, { "map-subids", no_argument, NULL, OPT_MAPSUBIDS }, + { "owner", required_argument, NULL, OPT_OWNER }, { "propagation", required_argument, NULL, OPT_PROPAGATION }, { "setgroups", required_argument, NULL, OPT_SETGROUPS }, { "keep-caps", no_argument, NULL, OPT_KEEPCAPS }, @@ -877,8 +874,8 @@ int main(int argc, char *argv[]) int setgrpcmd = SETGROUPS_NONE; int unshare_flags = 0; int c, forkit = 0; - uid_t mapuser = -1; - gid_t mapgroup = -1; + uid_t mapuser = -1, owneruser = -1; + gid_t mapgroup = -1, ownergroup = -1; struct map_range *usermap = NULL; struct map_range *groupmap = NULL; int kill_child_signo = 0; /* 0 means --kill-child was not used */ @@ -1022,6 +1019,12 @@ int main(int argc, char *argv[]) insert_map_range(&usermap, read_subid_range(_PATH_SUBUID, real_euid, 1)); insert_map_range(&groupmap, read_subid_range(_PATH_SUBGID, real_euid, 1)); break; + case OPT_OWNER: + unshare_flags |= CLONE_NEWUSER; + if (sscanf(optarg, "%u:%u%n", &owneruser, &ownergroup, + &c) < 2 || optarg[c]) + errx(EXIT_FAILURE, _("failed to parse owner")); + break; case OPT_SETGROUPS: setgrpcmd = setgroups_str2id(optarg); break; @@ -1093,9 +1096,25 @@ int main(int argc, char *argv[]) if (npersists && (unshare_flags & CLONE_NEWNS)) pid_bind = bind_ns_files_from_child(&fd_bind); + if (usermap || (mapuser != (uid_t) -1 && owneruser != (uid_t) -1)) { + add_single_map_range(&usermap, real_euid, mapuser); + mapuser = -1; + } + + if (groupmap || (mapgroup != (uid_t) -1 && ownergroup != (uid_t) -1)) { + add_single_map_range(&groupmap, real_egid, mapgroup); + mapgroup = -1; + } + if (usermap || groupmap) - pid_idmap = map_ids_from_child(&fd_idmap, mapuser, usermap, - mapgroup, groupmap); + pid_idmap = map_ids_from_child(&fd_idmap, usermap, groupmap); + + if (ownergroup != (gid_t) -1 && setgroups(0, NULL) != 0) + err(EXIT_FAILURE, _("setgroups failed")); + if (ownergroup != (gid_t) -1 && setgid(ownergroup) != 0) + err(EXIT_FAILURE, _("setgid() failed")); + if (owneruser != (uid_t) -1 && setuid(owneruser) != 0) + err(EXIT_FAILURE, _("setuid() failed")); if (-1 == unshare(unshare_flags)) err(EXIT_FAILURE, _("unshare failed")); @@ -1206,14 +1225,14 @@ int main(int argc, char *argv[]) #endif } - if (mapuser != (uid_t) -1 && !usermap) + if (mapuser != (uid_t) -1) map_id(_PATH_PROC_UIDMAP, mapuser, real_euid); /* Since Linux 3.19 unprivileged writing of /proc/self/gid_map * has been disabled unless /proc/self/setgroups is written * first to permanently disable the ability to call setgroups * in that user namespace. */ - if (mapgroup != (gid_t) -1 && !groupmap) { + if (mapgroup != (gid_t) -1) { if (setgrpcmd == SETGROUPS_ALLOW) errx(EXIT_FAILURE, _("options --setgroups=allow and " "--map-group are mutually exclusive")); From 35f142d33fbb758da7787f8040258b45f324b35e Mon Sep 17 00:00:00 2001 From: Chris Webb Date: Mon, 15 Dec 2025 18:41:08 +0000 Subject: [PATCH 172/174] unshare: remove get_mnt_ino() check in bind_ns_files_from_child() get_mnt_ino() was originally introduced in c84f2590 where it was used in a loop to wait for the parent process to unshare the mount namespace before binding the namespace in its child. The parent and child processes are now synchronised with eventfd, so remove this vestigial check and the now-unused get_mnt_ino() function. This allows bind_ns_files_from_child() to be used even when the mount namespace isn't amongst the namespaces being unshared. Signed-off-by: Chris Webb --- sys-utils/unshare.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/sys-utils/unshare.c b/sys-utils/unshare.c index 11aeae48ed5..d9c4d403f77 100644 --- a/sys-utils/unshare.c +++ b/sys-utils/unshare.c @@ -199,18 +199,6 @@ static int bind_ns_files(pid_t pid) return 0; } -static ino_t get_mnt_ino(pid_t pid) -{ - struct stat st; - char path[PATH_MAX]; - - snprintf(path, sizeof(path), "/proc/%u/ns/mnt", (unsigned) pid); - - if (stat(path, &st) != 0) - err(EXIT_FAILURE, _("stat of %s failed"), path); - return st.st_ino; -} - static void settime(int64_t offset, clockid_t clk_id) { char buf[sizeof(stringify_value(ULONG_MAX)) * 3]; @@ -310,14 +298,11 @@ static pid_t fork_and_wait(int *fd) static pid_t bind_ns_files_from_child(int *fd) { pid_t child, ppid = getpid(); - ino_t ino = get_mnt_ino(ppid); child = fork_and_wait(fd); if (child) return child; - if (get_mnt_ino(ppid) == ino) - exit(EXIT_FAILURE); bind_ns_files(ppid); exit(EXIT_SUCCESS); } From 8f84322ecf618b9c84040e08e346341f2853a139 Mon Sep 17 00:00:00 2001 From: Chris Webb Date: Mon, 15 Dec 2025 18:48:29 +0000 Subject: [PATCH 173/174] unshare: fix user namespace bind mounts unshare --user= always fails because we no longer have CAP_SYS_ADMIN in the parent user namespace after unsharing to create the new one. As with unshare --mount=, fork a child to make the bind mount instead. Signed-off-by: Chris Webb --- sys-utils/unshare.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys-utils/unshare.c b/sys-utils/unshare.c index d9c4d403f77..aeb8bf9745a 100644 --- a/sys-utils/unshare.c +++ b/sys-utils/unshare.c @@ -1075,7 +1075,7 @@ int main(int argc, char *argv[]) /* clear any inherited settings */ signal(SIGCHLD, SIG_DFL); - if (npersists && (unshare_flags & CLONE_NEWNS)) + if (npersists && (unshare_flags & (CLONE_NEWNS | CLONE_NEWUSER))) pid_bind = bind_ns_files_from_child(&fd_bind); if (usermap || groupmap) @@ -1130,7 +1130,7 @@ int main(int argc, char *argv[]) if (npersists && (pid || !forkit)) { /* run in parent */ - if (pid_bind && (unshare_flags & CLONE_NEWNS)) + if (pid_bind && (unshare_flags & (CLONE_NEWNS | CLONE_NEWUSER))) sync_with_child(pid_bind, fd_bind); else /* simple way, just bind */ From e4656fa9765f55eb4dcd45ca63b5eea43e59551b Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Wed, 17 Dec 2025 13:10:13 +0100 Subject: [PATCH 174/174] zramctl: Add note about column descriptions Addresses: https://github.com/util-linux/util-linux/issues/3903 Signed-off-by: Karel Zak --- sys-utils/zramctl.8.adoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sys-utils/zramctl.8.adoc b/sys-utils/zramctl.8.adoc index c08f1e00503..7bccc3909d3 100644 --- a/sys-utils/zramctl.8.adoc +++ b/sys-utils/zramctl.8.adoc @@ -34,6 +34,8 @@ Set up a zram device: :: If no option is given, all non-zero size zram devices are shown. +Use *--help* to get an overview of the supported output columns and their descriptions. + Note that _zramdev_ node specified on command line has to already exist. The command *zramctl* creates a new _/dev/zram_ nodes only when *--find* option specified. It's possible (and common) that after system boot _/dev/zram_ nodes are not created yet. == OPTIONS