Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package util-linux for openSUSE:Factory checked in at 2026-05-09 12:59:43 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/util-linux (Old) and /work/SRC/openSUSE:Factory/.util-linux.new.1966 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "util-linux" Sat May 9 12:59:43 2026 rev:309 rq:1352185 version:2.41.3 Changes: -------- --- /work/SRC/openSUSE:Factory/util-linux/util-linux.changes 2026-05-08 16:41:59.596759043 +0200 +++ /work/SRC/openSUSE:Factory/.util-linux.new.1966/util-linux.changes 2026-05-09 12:59:49.945132968 +0200 @@ -2,107 +1,0 @@ -Wed May 6 22:52:28 UTC 2026 - Stanislav Brabec <[email protected]> - -- Temporarily disable following test that do not work properly - in pre-16.1 IBS: - * lsfd/option-hyperlink - * lsfd/option-inet - * lsfd/mkfds_udp - * lsfd/mkfds_udp6 - -------------------------------------------------------------------- -Tue May 5 10:04:33 UTC 2026 - Stanislav Brabec <[email protected]> - -- Fix su passing argument regression - (util-linux-su-revert-su-pass-arguments.patch). - -------------------------------------------------------------------- -Mon Apr 27 09:33:08 UTC 2026 - Stanislav Brabec <[email protected]> - -- Update to version 2.42 (jsc#PED-16188): - * Security fixes: - * CVE-2026-27456: mount(8) TOCTOU symlink attack via loop - device (bsc1261606). - * CWE-190 - Integer overflow in libblkid parse_dos_extended() - (boo#1222465, obsoletes - util-linux-bsc-1222465.patch). - * login(1): now uses the original FQDN (as specified by - "-h <host>") to configure the PAM RHOST item (bsc#1258859, - CVE-2026-3184, obsoletes util-linux-CVE-2026-3184.patch). - * login(1), if configured with LOGIN_SHELL_FALLBACK in - login.defs, can fall back to another valid shell from - /etc/shells if the user's configured shell is inaccessible due - to administrative errors - (refreshed util-linux-login_defs-check.sh). - * agetty reads issue file(s) in a way compatible with libeconf - and systemd, hermetic-usr and drop-ins are now supported. For - more details see - https://uapi-group.org/specifications/specs/configuration_files_specification/ - (obsoletes util-linux-agetty-configs.patch, - util-linux-lib-configs-fix1.patch, - util-linux-lib-configs-fix2.patch - util-linux-lib-configs-fix3.patch - util-linux-lib-configs-fix4.patch - util-linux-lib-configs-fix5.patch - util-linux-lib-configs-fix6.patch - util-linux-lib-configs.patch). - * agetty uses netlink to get network interface information for - issue file output (obsoletes - util-linux-agetty-netlink-fix4.patch, - util-linux-agetty-netlink.patch, - util-linux-lib-netlink-fix1.patch, - util-linux-lib-netlink-fix2.patch, - util-linux-lib-netlink-fix3.patch, - util-linux-lib-netlink-fix5.patch, - util-linux-lib-netlink.patch, - util-linux-man-generated.patch). - * The libsmartcols-based tools with JSON support can now produce - additional JSON formats. The output format may be changed by - LIBSMARTCOLS_JSON={lines,compact} environment variable. - * column(1) now supports colors. - * New command copyfilerange(1) to copy file ranges using the - copy_file_range() syscall. - * New command getino(1) to print the unique inode number - associated with a process file descriptor or namespace for a - given PID. - * fadvise(1) now supports --fd to address a file by file - descriptor rather than by path. - * fallocate(1) now supports --report-holes to scan the file and - report the distribution of holes. - * A significant performance regression has been fixed in - hardlink(1). - * hardlink(1) now supports FIEMAP-based sparse file optimization. - * kill(1), waitpid(1) and nsenter(1) now support the PID:INO - convention to precisely address processes. - * mount(8) now supports --beneath to atomically replace a - filesystem at a mountpoint. - * mount(8) now supports --exclusive to ensure that the filesystem - is mounted as a unique instance and that the superblock is not - reused by the kernel. - * libmount now reads filesystem information from udevd (with - fallback to classic libblkid-based detection). This feature can - be disabled by --disable-libmount-udev-support. - * setarch(8) now supports --pid to show the personality of a - specified process. - * The pager support for tools like "dmesg -H" has been improved - to work better with signals. - * losetup(8) now supports --remove to remove a loop device node - from the system. - * lsblk(8), lslocks(8), lsmem(1) and lsclocks(1) support - <NAME>_COLUMNS environment variable to specify output columns - as an alternative to --output. - * lsfd(1) now supports new UNIX.IPEER, PACKET.PROTOCOL.RAW and - TUN.DEVNETNS columns. - * setpriv(1) now supports landlock via --landlock-access and - --landlock-rule options. - * Many other new features and fixes. For complete list see - https://kernel.org/pub/linux/utils/util-linux/v2.42/v2.42-ReleaseNotes -- Refreshed patch: util-linux-bash-completion-su-chsh-l.patch. -- Dropped upstream patch: util-linux-agetty-escape-erase.patch. -- Fix build wih libeconf - (util-linux-fix-build-with-libeconf.patch). - -------------------------------------------------------------------- -Mon Apr 27 02:30:07 UTC 2026 - Stanislav Brabec <[email protected]> - -- Make uuidd compatible with immutable mode (jsc#PED-16165). - -------------------------------------------------------------------- Old: ---- util-linux-2.42.tar.sign util-linux-2.42.tar.xz util-linux-fix-build-with-libeconf.patch util-linux-su-revert-su-pass-arguments.patch util-linux-uuidd.tmpfiles.in New: ---- util-linux-2.41.3.tar.sign util-linux-2.41.3.tar.xz util-linux-CVE-2026-3184.patch util-linux-agetty-configs.patch util-linux-agetty-escape-erase.patch util-linux-agetty-netlink-fix4.patch util-linux-agetty-netlink.patch util-linux-bsc-1222465.patch util-linux-lib-configs-fix1.patch util-linux-lib-configs-fix2.patch util-linux-lib-configs-fix3.patch util-linux-lib-configs-fix4.patch util-linux-lib-configs-fix5.patch util-linux-lib-configs-fix6.patch util-linux-lib-configs.patch util-linux-lib-netlink-fix1.patch util-linux-lib-netlink-fix2.patch util-linux-lib-netlink-fix3.patch util-linux-lib-netlink-fix5.patch util-linux-lib-netlink.patch util-linux-man-generated.patch ----------(Old B)---------- Old: WARN: util-linux-fix-build-with-libeconf.patch not found in changes Old: WARN: util-linux-su-revert-su-pass-arguments.patch not found in changes ----------(Old E)---------- ----------(New B)---------- New: "login -h" (bsc#1258859, CVE-2026-3184, util-linux-CVE-2026-3184.patch). New: (gh#util-linux/util-linux#3752, util-linux-lib-configs.patch, util-linux-agetty-configs.patch). New:- Fix agetty erase of escape characters (relevant to bsc#1194818, util-linux-agetty-escape-erase.patch). - Own /usr/lib/issue.d directory. New: util-linux-lib-netlink-fix3.patch and util-linux-agetty-netlink-fix4.patch). - Fix configs library use in agetty (replace New: (jsc#PED-8734, util-linux-lib-netlink.patch and util-linux-agetty-netlink.patch) and upstream fixes (util-linux-lib-netlink-fix1.patch, New:- Add patch: * util-linux-bsc-1222465.patch - Patch has already been merged upstream, New: util-linux-issuedir-usr-lib.patch by upstream util-linux-lib-configs-fix1.patch, add util-linux-lib-configs-fix2.patch, New: util-linux-lib-configs-fix1.patch, add util-linux-lib-configs-fix2.patch, util-linux-lib-configs-fix3.patch, New: add util-linux-lib-configs-fix2.patch, util-linux-lib-configs-fix3.patch, util-linux-lib-configs-fix4.patch, New: util-linux-lib-configs-fix3.patch, util-linux-lib-configs-fix4.patch, util-linux-lib-configs-fix5.patch and New: util-linux-lib-configs-fix4.patch, util-linux-lib-configs-fix5.patch and util-linux-lib-configs-fix6.patch). New: util-linux-lib-configs-fix5.patch and util-linux-lib-configs-fix6.patch). - Fix agetty erase of escape characters (relevant to bsc#1194818, New: (gh#util-linux/util-linux#3752, util-linux-lib-configs.patch, util-linux-agetty-configs.patch). New: util-linux-agetty-netlink.patch) and upstream fixes (util-linux-lib-netlink-fix1.patch, util-linux-lib-netlink-fix2.patch, New: (util-linux-lib-netlink-fix1.patch, util-linux-lib-netlink-fix2.patch, util-linux-lib-netlink-fix3.patch and New: util-linux-lib-netlink-fix2.patch, util-linux-lib-netlink-fix3.patch and util-linux-agetty-netlink-fix4.patch). New: SELinux AVC denial (gh#util-linux/util-linux#4032, util-linux-lib-netlink-fix5.patch). New:- Include agetty netlink fixes from the final upstream commits (jsc#PED-8734, util-linux-lib-netlink.patch and util-linux-agetty-netlink.patch) and upstream fixes New: util-linux-lib-netlink.patch). - Update generated man pages (util-linux-man-generated.patch). ----------(New E)---------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ util-linux.spec ++++++ --- /var/tmp/diff_new_pack.pMyfFQ/_old 2026-05-09 12:59:50.981175479 +0200 +++ /var/tmp/diff_new_pack.pMyfFQ/_new 2026-05-09 12:59:50.985175644 +0200 @@ -85,20 +85,19 @@ %endif # ulbuild == python -Version: 2.42 +Version: 2.41.3 Release: 0 License: GPL-2.0-or-later #Git-Clone: https://github.com/util-linux/util-linux URL: https://www.kernel.org/pub/linux/utils/util-linux/ -Source: https://www.kernel.org/pub/linux/utils/util-linux/v2.42/util-linux-%{version}.tar.xz +Source: https://www.kernel.org/pub/linux/utils/util-linux/v2.41/util-linux-%{version}.tar.xz Source2: util-linux-login_defs-check.sh -Source3: util-linux-uuidd.tmpfiles.in Source7: baselibs.conf Source8: login.pamd Source9: remote.pamd Source10: su.pamd Source11: su.default -Source12: https://www.kernel.org/pub/linux/utils/util-linux/v2.42/util-linux-%{version}.tar.sign +Source12: https://www.kernel.org/pub/linux/utils/util-linux/v2.41/util-linux-%{version}.tar.sign Source13: %{_name}.keyring Source14: runuser.pamd Source15: runuser-l.pamd @@ -109,14 +108,47 @@ Patch0: make-sure-sbin-resp-usr-sbin-are-in-PATH.diff Patch1: libmount-print-a-blacklist-hint-for-unknown-filesyst.patch Patch2: Add-documentation-on-blacklisted-modules-to-mount-8-.patch -# PATCH-FIX-SUSE util-linux-bash-completion-su-chsh-l.patch bsc1172427 -- Fix "su -s" bash completion, as SUSE uses chsh from shadow, not util-linux. +# PATCH-FIX-SUSE util-linux-bash-completion-su-chsh-l.patch bsc1172427 -- Fix "su -s" bash completion. Patch3: util-linux-bash-completion-su-chsh-l.patch -# PATCH-FIX-UPSTREAM util-linux-fix-build-with-libeconf.patch -- Fix build with libeconf. -Patch4: util-linux-fix-build-with-libeconf.patch -# PATCH-FIX-SUSE static_lib.patch [email protected] -- Fix build with libeconf. Not upstreamable in this form. Needs work! Patch5: static_lib.patch -# PATCH-FIX-UPSTREAM util-linux-su-revert-su-pass-arguments.patch -- Fix su passing argument regression. -Patch6: util-linux-su-revert-su-pass-arguments.patch +# PATCH-FEATURE-UPSTREAM util-linux-lib-netlink.patch boo1139983 jsc#PED-8734 [email protected] -- Implement netlink based IP address detection and issue reload. +Patch6: util-linux-lib-netlink.patch +# PATCH-FEATURE-UPSTREAM util-linux-agetty-netlink.patch boo1139983 jsc#PED-8734 [email protected] -- Implement netlink based IP address detection and issue reload. +Patch7: util-linux-agetty-netlink.patch +# PATCH-FIX-UPSTREAM util-linux-lib-netlink-fix1.patch jsc#PED-8734 [email protected] -- Implement netlink based IP address detection and issue reload. +Patch8: util-linux-lib-netlink-fix1.patch +# PATCH-FIX-UPSTREAM util-linux-lib-netlink-fix2.patch jsc#PED-8734 [email protected] -- Implement netlink based IP address detection and issue reload. +Patch9: util-linux-lib-netlink-fix2.patch +# PATCH-FIX-UPSTREAM util-linux-lib-netlink-fix3.patch jsc#PED-8734 [email protected] -- Implement netlink based IP address detection and issue reload. +Patch10: util-linux-lib-netlink-fix3.patch +# PATCH-FIX-UPSTREAM util-linux-agetty-netlink-fix4.patch jsc#PED-8734 [email protected] -- Implement netlink based IP address detection and issue reload. +Patch11: util-linux-agetty-netlink-fix4.patch +# PATCH-FIX-UPSTREAM util-linux-lib-netlink-fix5.patch gh#util-linux/util-linux#4032 [email protected] -- Fix NETLINK_ROUTE socket leak. +Patch12: util-linux-lib-netlink-fix5.patch +# PATCH-FEATURE-UPSTREAM util-linux-lib-configs.patch gh#util-linux/util-linux#3752 [email protected] -- Added lib "configs" for parsing configuration. +Patch13: util-linux-lib-configs.patch +# PATCH-FEATURE-UPSTREAM util-linux-agetty-configs.patch gh#util-linux/util-linux#3752 [email protected] -- agetty: using configs lib for parsing issue files. +Patch14: util-linux-agetty-configs.patch +# PATCH-FIX-UPSTREAM util-linux-lib-configs-fix1.patch [email protected] -- Fix agetty: using configs lib. +Patch15: util-linux-lib-configs-fix1.patch +# PATCH-FIX-UPSTREAM util-linux-lib-configs-fix2.patch [email protected] -- Fix agetty: using configs lib. +Patch16: util-linux-lib-configs-fix2.patch +# PATCH-FIX-UPSTREAM util-linux-lib-configs-fix3.patch [email protected] -- Fix agetty: using configs lib. +Patch17: util-linux-lib-configs-fix3.patch +# PATCH-FIX-UPSTREAM util-linux-lib-configs-fix4.patch [email protected] -- Fix agetty: using configs lib. +Patch18: util-linux-lib-configs-fix4.patch +# PATCH-FIX-UPSTREAM util-linux-lib-configs-fix5.patch [email protected] -- Fix agetty: using configs lib. +Patch19: util-linux-lib-configs-fix5.patch +# PATCH-FIX-UPSTREAM util-linux-lib-configs-fix6.patch [email protected] -- Fix agetty: using configs lib. +Patch20: util-linux-lib-configs-fix6.patch +# PATCH-FIX-UPSTREAM util-linux-agetty-escape-erase.patch bsc#1194818 [email protected] -- Fix agetty erase of escape characters. +Patch21: util-linux-agetty-escape-erase.patch +# PATCH-FIX-BUILD util-linux-man-generated.patch [email protected] -- Update generated man pages modified by patches. +Patch22: util-linux-man-generated.patch +# PATCH-FIX-OPENSUSE bsc#1222465: fdisk creates broken partition table +Patch23: util-linux-bsc-1222465.patch +# PATCH-FIX-SECURITY util-linux-CVE-2026-3184.patch bsc1258859 CVE-2026-3184 -- Use full hostname for PAM to ensure correct access control for "login -h". +Patch24: util-linux-CVE-2026-3184.patch BuildRequires: audit-devel BuildRequires: bc BuildRequires: binutils-devel @@ -188,7 +220,7 @@ # Upgrade this symbol version only if new variables appear! # Verify by shadow-login_defs-check.sh from shadow source package. # Use downstream version. Upstream may accept the patch later. -Recommends: login_defs-support-for-util-linux >= 4.19.4 +Recommends: login_defs-support-for-util-linux >= 4.17.4 Requires(post): coreutils %endif # ulsubset == core @@ -474,13 +506,9 @@ %prep %setup -q -n %{_name}-%{version} cp -a %{S:2} . -cp -a %{S:3} uuidd.tmpfiles.in %autopatch -p1 # This test randomly fails or keeps hanging task inside build chroot (tested on 2.38). rm tests/ts/lsns/ioctl_ns -# Sometimes lefts running tasks and hangs forever in pre-16.1 IBS. Remove these checks (tested on 2.42). -rm tests/ts/lsfd/option-hyperlink -rm tests/ts/lsfd/option-inet %build AUTOPOINT=true GTKDOCIZE=true autoreconf -vfi @@ -590,7 +618,6 @@ ############## %if "%ulbuild" == "base" configure_and_build -sed "s:@sharedstatedir@:%{_sharedstatedir}:" uuidd.tmpfiles.in >uuidd.tmpfiles %endif # ulbuild == base @@ -621,7 +648,7 @@ ################ %if "%ulbuild" == "base" %make_install -mkdir -p "%{buildroot}%{_distconfdir}/default" "%{buildroot}%{_pam_vendordir}" "%{buildroot}%{_sysconfdir}/issue.d" "%{buildroot}/usr/lib/issue.d" "%{buildroot}%{_datadir}/user-tmpfiles.d" +mkdir -p "%{buildroot}%{_distconfdir}/default" "%{buildroot}%{_pam_vendordir}" "%{buildroot}%{_sysconfdir}/issue.d" "%{buildroot}/usr/lib/issue.d" install -m 644 %{SOURCE51} %{buildroot}%{_distconfdir}/blkid.conf touch %{buildroot}%{_sysconfdir}/blkid.conf mkdir %{buildroot}%{_sysconfdir}/blkid.conf.d %{buildroot}%{_distconfdir}/blkid.conf.d @@ -644,7 +671,6 @@ "%{buildroot}/%{_mandir}/man8/raw.8"* echo -e "#!/bin/sh\n/sbin/blockdev --flushbufs \$1" > %{buildroot}%{_sbindir}/flushb chmod 755 %{buildroot}%{_sbindir}/flushb -install -m0644 uuidd.tmpfiles %{buildroot}%{_datadir}/user-tmpfiles.d/uuidd.conf # arch dependent @@ -779,11 +805,6 @@ export TS_OPT_lslocks_lslocks_known_fail=yes # FIXME: script/options sometimes fails on aarch64, arm7l and s390x export TS_OPT_script_options_known_fail=yes -# Fails in chroot -export TS_OPT_lsfd_column_mntid_nonroot_known_fail=yes -# Fails in pre-16.1 IBS. Temporarily disable these checks. -export TS_OPT_lsfd_mkfds_udp_known_fail=yes -export TS_OPT_lsfd_mkfds_udp6_known_fail=yes # # hacks export PATH="$PATH:/sbin:/usr/sbin" @@ -949,7 +970,6 @@ # Useful for Tumbleweed or zypper dup only. mv /run/run/uuidd /run/uuidd >/dev/null 2>&1 || : rmdir --ignore-fail-on-non-empty /run/run >/dev/null 2>&1 || : -%tmpfiles_create uuidd.conf %{service_add_post uuidd.socket uuidd.service} %preun -n uuidd @@ -1060,15 +1080,14 @@ %core %{_bindir}/colcrt %core %{_bindir}/colrm %core %{_bindir}/column -%core %{_bindir}/copyfilerange %core %{_bindir}/dmesg %core %{_bindir}/enosys %core %{_bindir}/exch %core %{_bindir}/fadvise %core %{_bindir}/fallocate %core %{_bindir}/fincore + %core %{_bindir}/flock -%core %{_bindir}/getino %core %{_bindir}/getopt %core %{_bindir}/hardlink %core %{_bindir}/hexdump @@ -1273,7 +1292,6 @@ %core %{_mandir}/man1/colcrt.1.gz %core %{_mandir}/man1/colrm.1.gz %core %{_mandir}/man1/column.1.gz -%core %{_mandir}/man1/copyfilerange.1.gz %core %{_mandir}/man1/coresched.1.gz %core %{_mandir}/man1/dmesg.1.gz %core %{_mandir}/man1/enosys.1.gz @@ -1283,7 +1301,6 @@ %core %{_mandir}/man1/fallocate.1.gz %core %{_mandir}/man1/fincore.1.gz %core %{_mandir}/man1/flock.1.gz -%core %{_mandir}/man1/getino.1.gz %core %{_mandir}/man1/getopt.1.gz %core %{_mandir}/man1/hardlink.1.gz %core %{_mandir}/man1/hexdump.1.gz @@ -1410,7 +1427,6 @@ %exclude %{_datadir}/bash-completion/completions/logger %exclude %{_datadir}/bash-completion/completions/lsblk %exclude %{_datadir}/bash-completion/completions/lslogins -%exclude %{_datadir}/user-tmpfiles.d/uuidd.conf %exclude %{_bindir}/findmnt %exclude %{_bindir}/logger @@ -1470,7 +1486,6 @@ %exclude %{_datadir}/bash-completion/completions/colcrt %exclude %{_datadir}/bash-completion/completions/colrm %exclude %{_datadir}/bash-completion/completions/column -%exclude %{_datadir}/bash-completion/completions/copyfilerange %exclude %{_datadir}/bash-completion/completions/coresched %exclude %{_datadir}/bash-completion/completions/ctrlaltdel %exclude %{_datadir}/bash-completion/completions/delpart @@ -1490,7 +1505,6 @@ %exclude %{_datadir}/bash-completion/completions/fsck.minix %exclude %{_datadir}/bash-completion/completions/fsfreeze %exclude %{_datadir}/bash-completion/completions/fstrim -%exclude %{_datadir}/bash-completion/completions/getino %exclude %{_datadir}/bash-completion/completions/getopt %exclude %{_datadir}/bash-completion/completions/hardlink %exclude %{_datadir}/bash-completion/completions/hexdump @@ -1770,11 +1784,10 @@ %if "%ulsubset" == "systemd" %files -n uuidd %{_sbindir}/uuidd -%attr(-,uuidd,uuidd) %ghost %dir %{_sharedstatedir}/libuuid +%attr(-,uuidd,uuidd) %dir %{_sharedstatedir}/libuuid %attr(-,uuidd,uuidd) %ghost %{_sharedstatedir}/libuuid/clock.txt %attr(-,uuidd,uuidd) %ghost %dir /run/uuidd %{_datadir}/bash-completion/completions/uuidd -%{_datadir}/user-tmpfiles.d/uuidd.conf %{_mandir}/man8/uuidd.8.gz %{_unitdir}/uuidd.service %{_unitdir}/uuidd.socket ++++++ make-sure-sbin-resp-usr-sbin-are-in-PATH.diff ++++++ --- /var/tmp/diff_new_pack.pMyfFQ/_old 2026-05-09 12:59:51.077179419 +0200 +++ /var/tmp/diff_new_pack.pMyfFQ/_new 2026-05-09 12:59:51.081179583 +0200 @@ -2,12 +2,12 @@ Date: 2013-06-06 08:27:43+0000 Subject: let `su' handle /sbin and /usr/sbin in path -Index: util-linux-2.42/login-utils/su-common.c +Index: util-linux-2.31/login-utils/su-common.c =================================================================== ---- util-linux-2.42.orig/login-utils/su-common.c -+++ util-linux-2.42/login-utils/su-common.c -@@ -674,6 +674,117 @@ static void create_watching_parent(struc - exit(status); +--- util-linux-2.31.orig/login-utils/su-common.c ++++ util-linux-2.31/login-utils/su-common.c +@@ -944,6 +944,117 @@ static void setenv_path(const struct pas + err(EXIT_FAILURE, _("failed to set the PATH environment variable")); } +/* Add or clear /sbin and /usr/sbin for the su command @@ -124,18 +124,10 @@ static void modify_environment(struct su_context *su, const char *shell) { const struct passwd *pw = su->pwd; -@@ -726,9 +837,27 @@ static void modify_environment(struct su - if (shell) - xsetenv("SHELL", shell, 1); +@@ -982,6 +1093,22 @@ static void modify_environment(struct su -- if (getlogindefs_bool("ALWAYS_SET_PATH", 0) -- && logindefs_setenv_path(pw->pw_uid) != 0) -- err(EXIT_FAILURE, _("failed to set the PATH environment variable")); -+ if (getlogindefs_bool("ALWAYS_SET_PATH", 0)) -+ { -+ if (logindefs_setenv_path(pw->pw_uid) != 0) -+ err(EXIT_FAILURE, _("failed to set the PATH environment variable")); -+ } + if (getlogindefs_bool("ALWAYS_SET_PATH", 0)) + setenv_path(pw); + else + { + char const *path = getenv ("PATH"); ++++++ util-linux-2.42.tar.xz -> util-linux-2.41.3.tar.xz ++++++ /work/SRC/openSUSE:Factory/util-linux/util-linux-2.42.tar.xz /work/SRC/openSUSE:Factory/.util-linux.new.1966/util-linux-2.41.3.tar.xz differ: char 15, line 1 ++++++ util-linux-CVE-2026-3184.patch ++++++ >From 8b29aeb081e297e48c4c1ac53d88ae07e1331984 Mon Sep 17 00:00:00 2001 From: Karel Zak <[email protected]> Date: Thu, 19 Feb 2026 12:20:28 +0100 Subject: [PATCH] login: use original FQDN for PAM_RHOST When login -h <remotehost> is invoked, init_remote_info() strips the local domain suffix from the hostname (FQDN to short name) before storing it in cxt->hostname. This truncated value is then used for PAM_RHOST, which can bypass pam_access host deny rules that match on the FQDN. Preserve the original -h hostname in a new cmd_hostname field and use it for PAM_RHOST, while keeping the truncated hostname for utmp/wtmp and logging unchanged. Note, the real-world impact is low -- login -h is only used by legacy telnet/rlogin daemons, and exploitation requires FQDN-specific pam_access rules on a system still using these obsolete services. Reported-by: Asim Viladi Oglu Manizada <[email protected]> Signed-off-by: Karel Zak <[email protected]> --- login-utils/login.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/login-utils/login.c b/login-utils/login.c index 74c42f422..0990d5e8f 100644 --- a/login-utils/login.c +++ b/login-utils/login.c @@ -130,6 +130,7 @@ struct login_context { char *thishost; /* this machine */ char *thisdomain; /* this machine's domain */ char *hostname; /* remote machine */ + char *cmd_hostname; /* remote machine as specified on command line */ char hostaddress[16]; /* remote address */ pid_t pid; @@ -912,7 +913,7 @@ static pam_handle_t *init_loginpam(struct login_context *cxt) /* hostname & tty are either set to NULL or their correct values, * depending on how much we know. */ - rc = pam_set_item(pamh, PAM_RHOST, cxt->hostname); + rc = pam_set_item(pamh, PAM_RHOST, cxt->cmd_hostname); if (is_pam_failure(rc)) loginpam_err(pamh, rc); @@ -1250,6 +1251,8 @@ static void init_remote_info(struct login_context *cxt, char *remotehost) get_thishost(cxt, &domain); + cxt->cmd_hostname = xstrdup(remotehost); + if (domain && (p = strchr(remotehost, '.')) && strcasecmp(p + 1, domain) == 0) *p = '\0'; -- 2.51.0 ++++++ util-linux-agetty-configs.patch ++++++ >From d1cf7efb17869d0fdf132bb3581d9b74a459bb87 Mon Sep 17 00:00:00 2001 From: Stefan Schubert <[email protected]> Date: Wed, 17 Sep 2025 13:43:55 +0200 Subject: [PATCH 2/8] agetty: using configs lib for parsing issue files --- term-utils/agetty.c | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) Index: util-linux-2.41.2/term-utils/agetty.c =================================================================== --- util-linux-2.41.2.orig/term-utils/agetty.c +++ util-linux-2.41.2/term-utils/agetty.c @@ -122,10 +122,11 @@ #ifdef SYSV_STYLE # define ISSUE_SUPPORT # if defined(HAVE_SCANDIRAT) && defined(HAVE_OPENAT) +# include "configs.h" # include <dirent.h> # define ISSUEDIR_SUPPORT -# define ISSUEDIR_EXT ".issue" -# define ISSUEDIR_EXTSIZ (sizeof(ISSUEDIR_EXT) - 1) +# define ISSUEDIR_EXT "issue" +# define ISSUEDIR_EXTSIZ sizeof(ISSUEDIR_EXT) # endif #endif @@ -1683,7 +1684,7 @@ static int issuedir_filter(const struct namesz = strlen(d->d_name); if (!namesz || namesz < ISSUEDIR_EXTSIZ + 1 || - strcmp(d->d_name + (namesz - ISSUEDIR_EXTSIZ), ISSUEDIR_EXT) != 0) + strcmp(d->d_name + (namesz - ISSUEDIR_EXTSIZ), "." ISSUEDIR_EXT) != 0) return 0; /* Accept this */ @@ -1930,22 +1931,28 @@ skip: goto done; } - /* The default /etc/issue and optional /etc/issue.d directory as - * extension to the file. The /etc/issue.d directory is ignored if - * there is no /etc/issue file. The file may be empty or symlink. +#ifdef ISSUEDIR_SUPPORT + struct list_head file_list; + struct list_head *current = NULL; + char *name = NULL; + + /* Reading all issue files and concatinating all contents to one content. + * The ordering rules are defineded in: + * https://github.com/uapi-group/specifications/blob/main/specs/configuration_files_specification.md */ - if (access(_PATH_ISSUE, F_OK|R_OK) == 0) { - issuefile_read(ie, _PATH_ISSUE, op, tp); - issuedir_read(ie, _PATH_ISSUEDIR, op, tp); + ul_configs_file_list(&file_list, + NULL, + _PATH_ETC_ISSUEDIR, + _PATH_USR_ISSUEDIR, + _PATH_ISSUE_FILENAME, + ISSUEDIR_EXT); + + while (ul_configs_next_filename(&file_list, ¤t, &name) == 0) { + issuefile_read(ie, name, op, tp); } - /* Fallback @runstatedir (usually /run) */ - issuefile_read(ie, _PATH_RUNSTATEDIR "/" _PATH_ISSUE_FILENAME, op, tp); - issuedir_read(ie, _PATH_RUNSTATEDIR "/" _PATH_ISSUE_DIRNAME, op, tp); - - /* Fallback @sysconfstaticdir (usually /usr/lib)*/ - issuefile_read(ie, _PATH_SYSCONFSTATICDIR "/" _PATH_ISSUE_FILENAME, op, tp); - issuedir_read(ie, _PATH_SYSCONFSTATICDIR "/" _PATH_ISSUE_DIRNAME, op, tp); + ul_configs_free_list(&file_list); +#endif done: if (ie->output) { ++++++ util-linux-agetty-escape-erase.patch ++++++ >From b462fdefe74836c22cb02039dca419a512dc6c88 Mon Sep 17 00:00:00 2001 From: Karel Zak <[email protected]> Date: Wed, 17 Sep 2025 12:58:59 +0200 Subject: [PATCH] agetty: fix erasure of escape sequences and tab characters When escape sequences (like arrow keys) or tab characters are entered at the login prompt, they are properly visualized but only partially erasable with backspace. This is because the erase logic assumes each stored character corresponds to one visual character, but escape sequences display as "^[" (2 chars) and tabs expand to multiple spaces. Track visual character width for each stored byte in a parallel array. When erasing, use the stored visual width to properly erase all displayed characters for that input byte. Fixes: https://github.com/util-linux/util-linux/issues/3624 Signed-off-by: Karel Zak <[email protected]> --- term-utils/agetty.c | 51 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/term-utils/agetty.c b/term-utils/agetty.c index 5e564c4f0..c6cb48081 100644 --- a/term-utils/agetty.c +++ b/term-utils/agetty.c @@ -2131,20 +2131,30 @@ static void next_speed(struct options *op, struct termios *tp) tcsetattr(STDIN_FILENO, TCSANOW, tp); } +/* Erase visual characters for one stored character */ +static void erase_char(int visual_count, struct chardata *cp) +{ + static const char *const erase[] = { /* backspace-space-backspace */ + "\010\040\010", /* space parity */ + "\010\040\010", /* odd parity */ + "\210\240\210", /* even parity */ + "\210\240\210", /* no parity */ + }; + int i; + for (i = 0; i < visual_count; i++) + write_all(1, erase[cp->parity], 3); +} + /* Get user name, establish parity, speed, erase, kill & eol. */ static char *get_logname(struct issue *ie, struct options *op, struct termios *tp, struct chardata *cp) { static char logname[BUFSIZ]; + static int visual_widths[BUFSIZ]; /* visual char count for each stored byte */ char *bp; + int *visual_bp; char c; /* input character, full eight bits */ char ascval; /* low 7 bits of input character */ int eightbit; - static const char *const erase[] = { /* backspace-space-backspace */ - "\010\040\010", /* space parity */ - "\010\040\010", /* odd parity */ - "\210\240\210", /* even parity */ - "\210\240\210", /* no parity */ - }; /* Initialize kill, erase, parity etc. (also after switching speeds). */ INIT_CHARDATA(cp); @@ -2158,7 +2168,11 @@ static char *get_logname(struct issue *ie, struct options *op, struct termios *t tcflush(STDIN_FILENO, TCIFLUSH); eightbit = (op->flags & (F_EIGHTBITS|F_UTF8)); + + /* Initialize buffer pointers. visual_widths tracks how many visual + * characters each stored byte represents (e.g. ESC = 2 for "^[", tab = 1-8 spaces) */ bp = logname; + visual_bp = visual_widths; *bp = '\0'; eval_issue_file(ie, op, tp); @@ -2182,6 +2196,7 @@ static char *get_logname(struct issue *ie, struct options *op, struct termios *t && (op->flags & F_NOCLEAR) == 0) termio_clear(STDOUT_FILENO); bp = logname; + visual_bp = visual_widths; *bp = '\0'; continue; } @@ -2259,8 +2274,9 @@ static char *get_logname(struct issue *ie, struct options *op, struct termios *t cp->erase = ascval; /* set erase character */ if (bp > logname) { if ((tp->c_lflag & ECHO) == 0) - write_all(1, erase[cp->parity], 3); + erase_char(*(visual_bp - 1), cp); bp--; + visual_bp--; } break; case CTL('U'): @@ -2272,8 +2288,9 @@ static char *get_logname(struct issue *ie, struct options *op, struct termios *t break; while (bp > logname) { if ((tp->c_lflag & ECHO) == 0) - write_all(1, erase[cp->parity], 3); + erase_char(*(visual_bp - 1), cp); bp--; + visual_bp--; } break; case CTL('D'): @@ -2283,15 +2300,29 @@ static char *get_logname(struct issue *ie, struct options *op, struct termios *t log_err(_("%s: input overrun"), op->tty); if ((tp->c_lflag & ECHO) == 0) { /* Visualize escape sequence instead of its execution */ - if (ascval == CTL('[')) + if (ascval == CTL('[')) { /* Ideally it should be "\xe2\x90\x9b" * if (op->flags & (F_UTF8)), * but only some fonts contain it */ write_all(1, "^[", 2); - else + *visual_bp = 2; /* ESC shows as ^[ (2 chars) */ + } else if (ascval == '\t') { + /* Tab expands to spaces */ + int pos = bp - logname; + int spaces = 8 - (pos % 8); + int i; + for (i = 0; i < spaces; i++) + write_all(1, " ", 1); + *visual_bp = spaces; + } else { write_all(1, &c, 1); /* echo the character */ + *visual_bp = 1; /* normal char shows as 1 */ + } + } else { + *visual_bp = 1; /* when echo is on, assume 1 char */ } *bp++ = ascval; /* and store it */ + visual_bp++; break; } /* Everything was erased. */ -- 2.48.1 ++++++ util-linux-agetty-netlink-fix4.patch ++++++ >From fa9b5740f67bc64d7b58f9b2fcc4f2883d7dcc91 Mon Sep 17 00:00:00 2001 From: Stanislav Brabec <[email protected]> Date: Fri, 10 Oct 2025 13:17:26 +0200 Subject: [PATCH 6/7] agetty: Process all data from ul_nl_process() However select() normally triggers immediately after a partial read, it does not happen for netlink socket. It keeps unprocessed data until the next netlink message appears. It causes raising processing delays. Always read all data. It also potentially decreases number of issue redraws. Signed-off-by: Stanislav Brabec <[email protected]> --- include/netlink.h | 6 +++++- term-utils/agetty.c | 14 +++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/include/netlink.h b/include/netlink.h index 3d7c3da04..ee4917b39 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -40,7 +40,9 @@ * reach unprocessed NLMSG_DONE */ #define UL_NL_SOFT_ERROR 4 /* soft error, indicating a race condition or * message relating to events before program - * start); could be optionally ignored */ + * start); could be optionally ignored and it + * should not considered as a reason to leave the + * processing */ struct ul_nl_data; @@ -139,6 +141,8 @@ int ul_nl_request_dump(struct ul_nl_data *nl, uint16_t nlmsg_type); /* Process netlink messages. * async: If true, return UL_NL_WOULDBLOCK immediately if there is no data * ready. If false, wait for a message. + * NOTE: You should read all data until you get UL_NL_WOULDBLOCK, otherwise + * select() will not trigger even if there is a netlink message. * loop: If true, run in a loop until NLMSG_DONE is received. Returns after * finishing a reply from ul_nl_request_dump(), otherwise it acts as an * infinite loop. If false, it returns after processing one message. diff --git a/term-utils/agetty.c b/term-utils/agetty.c index ec922bd11..08d009261 100644 --- a/term-utils/agetty.c +++ b/term-utils/agetty.c @@ -1654,9 +1654,17 @@ static int wait_for_term_input(struct issue *ie, int fd) } if (ie->nl.fd >= 0 && FD_ISSET(ie->nl.fd, &rfds)) { - /* We are ignoring errors here to prevent unability of - * further processing. */ - ul_nl_process(&(ie->nl), UL_NL_ASYNC, UL_NL_ONESHOT); + int rc; + + /* We are looping until it returns UL_NL_WOULDBLOCK. + * To prevent infinite loop, we are leaving on any other + * error except UL_NL_SOFT_ERROR. To prevent unability + * of further processing, we never exit. */ + do { + rc = ul_nl_process(&(ie->nl), UL_NL_ASYNC, + UL_NL_ONESHOT); + } + while (!rc || rc == UL_NL_SOFT_ERROR); /* Just drain the inotify buffer */ } else if (inotify_fd >= 0 && FD_ISSET(inotify_fd, &rfds)) { -- 2.48.1 ++++++ util-linux-agetty-netlink.patch ++++++ ++++ 637 lines (skipped) ++++++ util-linux-bash-completion-su-chsh-l.patch ++++++ --- /var/tmp/diff_new_pack.pMyfFQ/_old 2026-05-09 12:59:51.253186641 +0200 +++ /var/tmp/diff_new_pack.pMyfFQ/_new 2026-05-09 12:59:51.257186805 +0200 @@ -8,15 +8,13 @@ package that does not include this feature. Use /etc/shells instead. -Index: util-linux-2.42/bash-completion/su -=================================================================== ---- util-linux-2.42.orig/bash-completion/su -+++ util-linux-2.42/bash-completion/su -@@ -15,7 +15,7 @@ _su_module() +--- util-linux/bash-completion/su ++++ util-linux/bash-completion/su +@@ -14,7 +14,7 @@ _su_module() return 0 ;; '-s'|'--shell') -- COMPREPLY=( $(compgen -W "$(command chsh -l)" -- $cur) ) +- COMPREPLY=( $(compgen -W "$(chsh -l)" -- $cur) ) + COMPREPLY=( $(compgen -W "$(</etc/shells)" -- $cur) ) return 0 ;; ++++++ util-linux-bsc-1222465.patch ++++++ >From 8b8da020f57414c90981371da71fdf32d2253ac7 Mon Sep 17 00:00:00 2001 From: Martin Jungblut Schreiner <[email protected]> Date: Mon, 29 Dec 2025 19:52:56 -0300 Subject: [PATCH 1/2] libfdisk: (dos) fix logical partition start MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fdisk could accept adjacent logical partitions, causing the EBR for the new logical partition to be written inside the previous partition’s data area. This can corrupt the EBR chain. Fix free-sector search to keep an EBR gap (first_lba) after logical partitions. --- libfdisk/src/dos.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/libfdisk/src/dos.c b/libfdisk/src/dos.c index c88d2a4f213..f85104b2828 100644 --- a/libfdisk/src/dos.c +++ b/libfdisk/src/dos.c @@ -1201,6 +1201,21 @@ static int find_first_free_sector_in_range( p_start -= cxt->first_lba; if (first < p_start) continue; + + /* if we're placing a logical partition start, ensure + there's room for the *next* EBR (stored at start - first_lba). + therefore enforce: + start(Lnew) >= end(Lprev) + first_lba + 1 */ + if (logical && first > p_end && (first - p_end) <= cxt->first_lba) { + first = p_end + 1 + cxt->first_lba; + first_moved = 1; + + if (first > end) + return -ENOSPC; + + continue; + } + if (first <= p_end) { first = p_end + 1 + (logical ? cxt->first_lba : 0); first_moved = 1; >From bf3d4aeec708fae7aa30530a1bf42ee1d35366f8 Mon Sep 17 00:00:00 2001 From: Martin Jungblut Schreiner <[email protected]> Date: Mon, 29 Dec 2025 20:46:39 -0300 Subject: [PATCH 2/2] tests: fdisk: add regression test for missing EBR gap between logical partitions Add a DOS/MBR test case where the first logical partition starts at 6145 (extended start 2048). In the regressed behaviour fdisk allows the next logical partition to start at prev_end+1, which would place its EBR (start - 2048) inside the previous logical partition. The expected behaviour is to require the next starting sector to be at least prev_end + 2048 + 1 (e.g. 790528 in the testcase). Closes issue #3925. --- tests/expected/fdisk/mbr-logical-ebr-gap | 15 ++++++++++ tests/ts/fdisk/mbr-logical-ebr-gap | 35 ++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 tests/expected/fdisk/mbr-logical-ebr-gap create mode 100755 tests/ts/fdisk/mbr-logical-ebr-gap diff --git a/tests/expected/fdisk/mbr-logical-ebr-gap b/tests/expected/fdisk/mbr-logical-ebr-gap new file mode 100644 index 00000000000..c25b9be7a8d --- /dev/null +++ b/tests/expected/fdisk/mbr-logical-ebr-gap @@ -0,0 +1,15 @@ + +---layout---------- +Disk <removed>: 1 GiB, 1073741824 bytes, 2097152 sectors +Units: sectors of 1 * 512 = 512 bytes +Sector size (logical/physical): 512 bytes / 512 bytes +I/O size (minimum/optimal): 512 bytes / <removed> bytes +Disklabel type: dos +Disk identifier: <removed> + +Device Boot Start End Sectors Id Type Start-C/H/S End-C/H/S Attrs +<removed>1 2048 2097151 2095104 5 Extended 0/32/33 130/138/8 +<removed>5 6145 788479 782335 83 Linux 0/97/35 49/20/35 +<removed>6 2097151 2097151 1 83 Linux 130/138/8 130/138/8 +------------------- + diff --git a/tests/ts/fdisk/mbr-logical-ebr-gap b/tests/ts/fdisk/mbr-logical-ebr-gap new file mode 100755 index 00000000000..ffc9f96bc31 --- /dev/null +++ b/tests/ts/fdisk/mbr-logical-ebr-gap @@ -0,0 +1,35 @@ +#!/bin/bash +TS_TOPDIR="${0%/*}/../.." +TS_DESC="MBR: default start for logical must reserve EBR gap" +. "$TS_TOPDIR"/functions.sh +ts_init "$*" +ts_check_test_command "$TS_CMD_FDISK" + +# 1GiB image => 2097152 sectors @ 512B +TEST_IMAGE_NAME=$(ts_image_init 1024) + +# key assertion is in the resulting layout: L2 must not start at 788480, +# but at 790528 (= 788480 + 2048), leaving room for the EBR. +echo -e \ +"o +n +e +1 +2048 +2097151 +n +6145 +788479 +n +788480 +2097151 +w +q +" | $TS_CMD_FDISK --noauto-pt "$TEST_IMAGE_NAME" &> /dev/null + +echo -ne "\n---layout----------\n" >> "$TS_OUTPUT" +$TS_CMD_FDISK -x "$TEST_IMAGE_NAME" >> "$TS_OUTPUT" +echo -ne "-------------------\n\n" >> "$TS_OUTPUT" +ts_fdisk_clean "$TEST_IMAGE_NAME" + +ts_finalize ++++++ util-linux-lib-configs-fix1.patch ++++++ >From 16826c6675df3b6b28851c72f2dd1d194d3c7189 Mon Sep 17 00:00:00 2001 From: Stefan Schubert <[email protected]> Date: Wed, 1 Oct 2025 12:19:08 +0200 Subject: [PATCH 3/8] Using fix issue dir path "/usr/lib" for agetty --- include/pathnames.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/include/pathnames.h b/include/pathnames.h index 298d94973..80a0ee00a 100644 --- a/include/pathnames.h +++ b/include/pathnames.h @@ -73,11 +73,7 @@ #define _PATH_ISSUE_FILENAME "issue" #define _PATH_ETC_ISSUEDIR "/etc" -#ifdef USE_VENDORDIR -# define _PATH_USR_ISSUEDIR _PATH_VENDORDIR -#else -# define _PATH_USR_ISSUEDIR "/usr/lib" -#endif +#define _PATH_USR_ISSUEDIR "/usr/lib" #define _PATH_OS_RELEASE_ETC "/etc/os-release" #define _PATH_OS_RELEASE_USR "/usr/lib/os-release" -- 2.48.1 ++++++ util-linux-lib-configs-fix2.patch ++++++ >From a7f5e5c9f9c00823e04e89e9030337239a5bd7b8 Mon Sep 17 00:00:00 2001 From: Karel Zak <[email protected]> Date: Wed, 1 Oct 2025 14:42:39 +0200 Subject: [PATCH 4/8] agetty: use standard path macros - remove unnecessary issuefile-related stuff from include/pathnames.h - use standard _PATH_* macros Signed-off-by: Karel Zak <[email protected]> --- include/pathnames.h | 4 ---- lib/configs.c | 4 +--- term-utils/agetty.c | 10 ++++++---- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/include/pathnames.h b/include/pathnames.h index 80a0ee00a..036f365fd 100644 --- a/include/pathnames.h +++ b/include/pathnames.h @@ -71,10 +71,6 @@ # define _PATH_BTMP "/var/log/btmp" #endif -#define _PATH_ISSUE_FILENAME "issue" -#define _PATH_ETC_ISSUEDIR "/etc" -#define _PATH_USR_ISSUEDIR "/usr/lib" - #define _PATH_OS_RELEASE_ETC "/etc/os-release" #define _PATH_OS_RELEASE_USR "/usr/lib/os-release" #define _PATH_NUMLOCK_ON _PATH_RUNSTATEDIR "/numlock-on" diff --git a/lib/configs.c b/lib/configs.c index b038844d2..0534c18ef 100644 --- a/lib/configs.c +++ b/lib/configs.c @@ -16,8 +16,6 @@ #include "list.h" #include "fileutils.h" -#define DEFAULT_ETC_SUBDIR "/etc" - struct file_element { struct list_head file_list; char *filename; @@ -212,7 +210,7 @@ int ul_configs_file_list(struct list_head *file_list, /* Default is /etc */ if (!etc_subdir) - etc_subdir = DEFAULT_ETC_SUBDIR; + etc_subdir = _PATH_SYSCONFDIR; if (!usr_subdir) usr_subdir = ""; diff --git a/term-utils/agetty.c b/term-utils/agetty.c index 3e0a4ec4f..31dbf2706 100644 --- a/term-utils/agetty.c +++ b/term-utils/agetty.c @@ -1969,7 +1969,7 @@ static void eval_issue_file(struct issue *ie, goto done; } -#ifdef ISSUEDIR_SUPPORT +#ifdef ISSUEDIR_SUPPORT struct list_head file_list; struct list_head *current = NULL; char *name = NULL; @@ -1977,12 +1977,14 @@ static void eval_issue_file(struct issue *ie, /* Reading all issue files and concatinating all contents to one content. * The ordering rules are defineded in: * https://github.com/uapi-group/specifications/blob/main/specs/configuration_files_specification.md + * + * Note that _PATH_RUNSTATEDIR (/run) is always read by ul_configs_file_list(). */ ul_configs_file_list(&file_list, NULL, - _PATH_ETC_ISSUEDIR, - _PATH_USR_ISSUEDIR, - _PATH_ISSUE_FILENAME, + _PATH_SYSCONFDIR, + _PATH_SYSCONFSTATICDIR, + "issue", ISSUEDIR_EXT); while (ul_configs_next_filename(&file_list, ¤t, &name) == 0) { -- 2.48.1 ++++++ util-linux-lib-configs-fix3.patch ++++++ >From dc1e88ff93f40f2f8093fcf35bda615a9384edcd Mon Sep 17 00:00:00 2001 From: Karel Zak <[email protected]> Date: Wed, 1 Oct 2025 14:39:01 +0200 Subject: [PATCH 5/8] build-sys: make sure _PATH_SYSCONFDIR is defined The autotools and meson define $sysconfdir, but this variable is not accessible for compiler. Fix it. Signed-off-by: Karel Zak <[email protected]> --- Makefile.am | 1 + meson.build | 1 + 2 files changed, 2 insertions(+) diff --git a/Makefile.am b/Makefile.am index 01e99701d..dd78a5345 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,6 +4,7 @@ AM_CPPFLAGS = \ -DLOCALEDIR=\"$(localedir)\" \ -D_PATH_RUNSTATEDIR=\"${runstatedir}\" \ -D_PATH_LOCALSTATEDIR=\"${localstatedir}\" \ + -D_PATH_SYSCONFDIR=\"${sysconfdir}\" \ -D_PATH_SYSCONFSTATICDIR=\"${sysconfstaticdir}\" if USE_VENDORDIR diff --git a/meson.build b/meson.build index c9d1e188e..cdaca47ee 100644 --- a/meson.build +++ b/meson.build @@ -73,6 +73,7 @@ conf.set('sysconfdir', sysconfdir) conf.set('usrbin_execdir', usrbin_exec_dir) conf.set('usrsbin_execdir', usrsbin_exec_dir) conf.set('docdir', docdir) +conf.set_quoted('_PATH_SYSCONFDIR', sysconfdir) conf.set_quoted('_PATH_SYSCONFSTATICDIR', sysconfstaticdir) conf.set_quoted('_PATH_RUNSTATEDIR', runstatedir) conf.set_quoted('_PATH_LOCALSTATEDIR', localstatedir) -- 2.48.1 ++++++ util-linux-lib-configs-fix4.patch ++++++ >From 03066584f148a8429386c4a928d093913b3e85e2 Mon Sep 17 00:00:00 2001 From: Karel Zak <[email protected]> Date: Wed, 1 Oct 2025 14:53:41 +0200 Subject: [PATCH 6/8] lib/configs: improve readability Signed-off-by: Karel Zak <[email protected]> --- include/configs.h | 5 +++-- lib/configs.c | 16 ++++++++++------ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/include/configs.h b/include/configs.h index 783c10e30..ea72afacc 100644 --- a/include/configs.h +++ b/include/configs.h @@ -3,7 +3,8 @@ * it what you wish. * * Evaluting a list of configuration filenames which have to be handled/parsed. - * The order of this file list has been defined by + * + * The order of this file list has been defined by * https://github.com/uapi-group/specifications/blob/main/specs/configuration_files_specification.md */ @@ -89,4 +90,4 @@ int ul_configs_next_filename(struct list_head *file_list, struct list_head **current_entry, char **name); -#endif +#endif /* UTIL_LINUX_CONFIGS_H */ diff --git a/lib/configs.c b/lib/configs.c index 0534c18ef..a5d714f23 100644 --- a/lib/configs.c +++ b/lib/configs.c @@ -12,6 +12,7 @@ #if defined(HAVE_SCANDIRAT) && defined(HAVE_OPENAT) #include <dirent.h> #endif + #include "configs.h" #include "list.h" #include "fileutils.h" @@ -21,8 +22,8 @@ struct file_element { char *filename; }; -/* Checking for main configuration file - * +/* Checking for main configuration file + * * Returning absolute path or NULL if not found * The return value has to be freed by the caller. */ @@ -34,7 +35,7 @@ static char *main_configs(const char *root, bool found = false; char *path = NULL; struct stat st; - + if (config_suffix) { if (asprintf(&path, "%s/%s/%s.%s", root, project, config_name, config_suffix) < 0) return NULL; @@ -179,7 +180,7 @@ finish: return counter; } -#endif +#endif /* HAVE_SCANDIRAT */ static void free_list_entry(struct file_element *element) { @@ -187,7 +188,6 @@ static void free_list_entry(struct file_element *element) free(element); } - int ul_configs_file_list(struct list_head *file_list, const char *project, const char *etc_subdir, @@ -201,7 +201,7 @@ int ul_configs_file_list(struct list_head *file_list, struct list_head *etc_entry = NULL, *usr_entry = NULL; struct file_element *add_element = NULL, *usr_element = NULL, *etc_element = NULL; int counter = 0; - + INIT_LIST_HEAD(file_list); if (!config_name){ @@ -256,11 +256,15 @@ int ul_configs_file_list(struct list_head *file_list, #endif list_for_each(etc_entry, &etc_file_list) { + etc_element = list_entry(etc_entry, struct file_element, file_list); etc_basename = ul_basename(etc_element->filename); + list_for_each(usr_entry, &usr_file_list) { + usr_element = list_entry(usr_entry, struct file_element, file_list); usr_basename = ul_basename(usr_element->filename); + if (strcmp(usr_basename, etc_basename) <= 0) { if (strcmp(usr_basename, etc_basename) < 0) { add_element = new_list_entry(usr_element->filename); -- 2.48.1 ++++++ util-linux-lib-configs-fix5.patch ++++++ >From ec71160db85acde32a9eca5fb238c82d6a6e52cb Mon Sep 17 00:00:00 2001 From: Karel Zak <[email protected]> Date: Thu, 2 Oct 2025 11:55:55 +0200 Subject: [PATCH 7/8] lib/configs: initialize FD to -1 Signed-off-by: Karel Zak <[email protected]> --- lib/configs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/configs.c b/lib/configs.c index a5d714f23..d40743198 100644 --- a/lib/configs.c +++ b/lib/configs.c @@ -107,7 +107,7 @@ static int read_dir(struct list_head *file_list, char *dirname = NULL; char *filename = NULL; struct stat st; - int dd = 0, nfiles = 0, i; + int dd = -1, nfiles = 0, i; int counter = 0; struct dirent **namelist = NULL; struct file_element *entry = NULL; @@ -175,7 +175,7 @@ finish: free(namelist[i]); free(namelist); free(dirname); - if (dd > 0) + if (dd >= 0) close(dd); return counter; } -- 2.48.1 ++++++ util-linux-lib-configs-fix6.patch ++++++ >From 6e723400a384c39f0df709b17af43e51c0a4f505 Mon Sep 17 00:00:00 2001 From: Stefan Schubert <[email protected]> Date: Tue, 7 Oct 2025 17:24:37 +0200 Subject: [PATCH 8/8] parsing /run/issue.d/* too --- lib/configs.c | 82 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 72 insertions(+), 10 deletions(-) diff --git a/lib/configs.c b/lib/configs.c index d40743198..09bfffb66 100644 --- a/lib/configs.c +++ b/lib/configs.c @@ -195,11 +195,15 @@ int ul_configs_file_list(struct list_head *file_list, const char *config_name, const char *config_suffix) { - char *filename = NULL, *usr_basename = NULL, *etc_basename = NULL; + char *filename = NULL, *run_basename = NULL, *usr_basename = NULL, + *etc_basename = NULL, *etc_run_basename = NULL; struct list_head etc_file_list; + struct list_head run_file_list; + struct list_head etc_run_file_list; struct list_head usr_file_list; - struct list_head *etc_entry = NULL, *usr_entry = NULL; - struct file_element *add_element = NULL, *usr_element = NULL, *etc_element = NULL; + struct list_head *etc_entry = NULL, *usr_entry = NULL, *run_entry = NULL, *etc_run_entry = NULL; + struct file_element *add_element = NULL, *usr_element = NULL, + *run_element = NULL, *etc_element = NULL, *etc_run_element = NULL; int counter = 0; INIT_LIST_HEAD(file_list); @@ -235,38 +239,94 @@ int ul_configs_file_list(struct list_head *file_list, } INIT_LIST_HEAD(&etc_file_list); + INIT_LIST_HEAD(&run_file_list); + INIT_LIST_HEAD(&etc_run_file_list); INIT_LIST_HEAD(&usr_file_list); #if defined(HAVE_SCANDIRAT) && defined(HAVE_OPENAT) - int ret_usr = 0, ret_etc = 0; + int ret_usr = 0, ret_etc = 0, ret_run = 0; ret_etc = read_dir(&etc_file_list, project, etc_subdir, config_name, config_suffix); + ret_run = read_dir(&run_file_list, + project, + _PATH_RUNSTATEDIR, + config_name, + config_suffix); ret_usr = read_dir(&usr_file_list, project, usr_subdir, config_name, config_suffix); - if (ret_etc == -ENOMEM || ret_usr == -ENOMEM) { + if (ret_etc == -ENOMEM || ret_usr == -ENOMEM || ret_run == -ENOMEM) { counter = -ENOMEM; goto finish; } #endif + /* Merging run and etc list in the correct order. Output: etc_run_list */ list_for_each(etc_entry, &etc_file_list) { etc_element = list_entry(etc_entry, struct file_element, file_list); etc_basename = ul_basename(etc_element->filename); + list_for_each(run_entry, &run_file_list) { + + run_element = list_entry(run_entry, struct file_element, file_list); + run_basename = ul_basename(run_element->filename); + + if (strcmp(run_basename, etc_basename) <= 0) { + if (strcmp(run_basename, etc_basename) < 0) { + add_element = new_list_entry(run_element->filename); + if (add_element == NULL) { + counter = -ENOMEM; + goto finish; + } + list_add_tail(&add_element->file_list, &etc_run_file_list); + counter++; + } + list_del(&run_element->file_list); + } else { + break; + } + } + add_element = new_list_entry(etc_element->filename); + if (add_element == NULL) { + counter = -ENOMEM; + goto finish; + } + list_add_tail(&add_element->file_list, &etc_run_file_list); + counter++; + } + + /* taking the rest of /run */ + list_for_each(run_entry, &run_file_list) { + run_element = list_entry(run_entry, struct file_element, file_list); + add_element = new_list_entry(run_element->filename); + if (add_element == NULL) { + counter = -ENOMEM; + goto finish; + } + list_add_tail(&add_element->file_list, &etc_run_file_list); + counter++; + } + + /* Merging etc_run list and var list in the correct order. Output: file_list + which will be returned. */ + list_for_each(etc_run_entry, &etc_run_file_list) { + + etc_run_element = list_entry(etc_run_entry, struct file_element, file_list); + etc_run_basename = ul_basename(etc_run_element->filename); + list_for_each(usr_entry, &usr_file_list) { usr_element = list_entry(usr_entry, struct file_element, file_list); usr_basename = ul_basename(usr_element->filename); - if (strcmp(usr_basename, etc_basename) <= 0) { - if (strcmp(usr_basename, etc_basename) < 0) { + if (strcmp(usr_basename, etc_run_basename) <= 0) { + if (strcmp(usr_basename, etc_run_basename) < 0) { add_element = new_list_entry(usr_element->filename); if (add_element == NULL) { counter = -ENOMEM; @@ -280,7 +340,7 @@ int ul_configs_file_list(struct list_head *file_list, break; } } - add_element = new_list_entry(etc_element->filename); + add_element = new_list_entry(etc_run_element->filename); if (add_element == NULL) { counter = -ENOMEM; goto finish; @@ -303,6 +363,7 @@ int ul_configs_file_list(struct list_head *file_list, finish: ul_configs_free_list(&etc_file_list); + ul_configs_free_list(&etc_run_file_list); ul_configs_free_list(&usr_file_list); return counter; @@ -319,11 +380,12 @@ int ul_configs_next_filename(struct list_head *file_list, { struct file_element *element = NULL; - if (*current_entry == file_list) + if (list_empty(file_list) || *current_entry == file_list) return 1; if (*current_entry == NULL) - *current_entry = file_list; + *current_entry = file_list->next; + element = list_entry(*current_entry, struct file_element, file_list); *name = element->filename; *current_entry = (*current_entry)->next; -- 2.48.1 ++++++ util-linux-lib-configs.patch ++++++ >From 4109f4bfefff9e6cd65815399af3eab2b0a59104 Mon Sep 17 00:00:00 2001 From: Stefan Schubert <[email protected]> Date: Wed, 17 Sep 2025 13:40:29 +0200 Subject: [PATCH 1/8] libcommon: added lib "configs" for parsing configuration files in the correct order --- include/Makemodule.am | 3 +- include/configs.h | 92 ++++++++++++ include/pathnames.h | 10 +- lib/Makemodule.am | 3 +- lib/configs.c | 330 ++++++++++++++++++++++++++++++++++++++++++ lib/meson.build | 1 + 6 files changed, 433 insertions(+), 6 deletions(-) create mode 100644 include/configs.h create mode 100644 lib/configs.c diff --git a/include/Makemodule.am b/include/Makemodule.am index 59ecc793f..bc2c73415 100644 --- a/include/Makemodule.am +++ b/include/Makemodule.am @@ -83,4 +83,5 @@ dist_noinst_HEADERS += \ include/ttyutils.h \ include/widechar.h \ include/xalloc.h \ - include/xxhash.h + include/xxhash.h \ + include/configs.h diff --git a/include/configs.h b/include/configs.h new file mode 100644 index 000000000..783c10e30 --- /dev/null +++ b/include/configs.h @@ -0,0 +1,92 @@ +/* + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. + * + * Evaluting a list of configuration filenames which have to be handled/parsed. + * The order of this file list has been defined by + * https://github.com/uapi-group/specifications/blob/main/specs/configuration_files_specification.md + */ + +#ifndef UTIL_LINUX_CONFIGS_H +#define UTIL_LINUX_CONFIGS_H + +#include "list.h" + +/** + * ul_configs_file_list - Evaluting a list of sorted configuration filenames which have to be handled + * in the correct order. + * + * @file_list: List of filenames which have to be parsed in that order + * @project: name of the project used as subdirectory, can be NULL + * @etc_subdir: absolute directory path for user changed configuration files, can be NULL (default "/etc"). + * @usr_subdir: absolute directory path of vendor defined settings (often "/usr/lib"). + * @config_name: basename of the configuration file. If it is NULL, drop-ins without a main configuration file will be parsed only. + * @config_suffix: suffix of the configuration file. Can also be NULL. + * + * Returns the length of the file_list, or -ENOMEM, or -ENOTEMPTY if config_name is NULL + * + * Example: + * int count = 0; + * struct list_head *file_list; + * + * count = ul_configs_file_list(&file_list, + * "foo", + * "/etc", + * "/usr/lib", + * "example", + * "conf"); + * + * The order of this file list has been defined by + * https://github.com/uapi-group/specifications/blob/main/specs/configuration_files_specification.md + * + */ +int ul_configs_file_list(struct list_head *file_list, + const char *project, + const char *etc_subdir, + const char *usr_subdir, + const char *config_name, + const char *config_suffix); + + +/** + * ul_configs_free_list - Freeing configuration list. + * + * @file_list: List of filenames which has to be freed. + * + */ +void ul_configs_free_list(struct list_head *file_list); + + +/** + * ul_configs_next_filename - Going through the file list which has to be handled/parsed. + * + * @file_list: List of filenames which have to be handled. + * @current_entry: Current list entry. Has to be initialized with NULL for the first call. + * @name: Returned file name for each call. + * + * Returns 0 on success, <0 on error and 1 if the end of the list has been reached. + * + * Example: + * int count = 0; + * struct list_head *file_list = NULL; + * struct list_head *current = NULL; + * char *name = NULL; + * + * count = ul_configs_file_list(&file_list, + * "foo", + * "/etc", + * "/usr/lib", + * "example", + * "conf"); + * + * while (ul_configs_next_filename(&file_list, ¤t, &name) == 0) + * printf("filename: %s\n", name); + * + * ul_configs_free_list(&file_list); + * + */ +int ul_configs_next_filename(struct list_head *file_list, + struct list_head **current_entry, + char **name); + +#endif diff --git a/include/pathnames.h b/include/pathnames.h index 0f9944f89..298d94973 100644 --- a/include/pathnames.h +++ b/include/pathnames.h @@ -72,10 +72,12 @@ #endif #define _PATH_ISSUE_FILENAME "issue" -#define _PATH_ISSUE_DIRNAME _PATH_ISSUE_FILENAME ".d" - -#define _PATH_ISSUE "/etc/" _PATH_ISSUE_FILENAME -#define _PATH_ISSUEDIR "/etc/" _PATH_ISSUE_DIRNAME +#define _PATH_ETC_ISSUEDIR "/etc" +#ifdef USE_VENDORDIR +# define _PATH_USR_ISSUEDIR _PATH_VENDORDIR +#else +# define _PATH_USR_ISSUEDIR "/usr/lib" +#endif #define _PATH_OS_RELEASE_ETC "/etc/os-release" #define _PATH_OS_RELEASE_USR "/usr/lib/os-release" diff --git a/lib/Makemodule.am b/lib/Makemodule.am index a60810d7d..84ab3e3ae 100644 --- a/lib/Makemodule.am +++ b/lib/Makemodule.am @@ -40,7 +40,8 @@ libcommon_la_SOURCES = \ lib/strv.c \ lib/timeutils.c \ lib/ttyutils.c \ - lib/xxhash.c + lib/xxhash.c \ + lib/configs.c if LINUX libcommon_la_SOURCES += \ diff --git a/lib/configs.c b/lib/configs.c new file mode 100644 index 000000000..b038844d2 --- /dev/null +++ b/lib/configs.c @@ -0,0 +1,330 @@ +/* + * configs_file.c instantiates functions defined and described in configs_file.h + */ +#include <err.h> +#include <errno.h> +#include <sys/syslog.h> +#include <sys/stat.h> +#include <stdbool.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#if defined(HAVE_SCANDIRAT) && defined(HAVE_OPENAT) +#include <dirent.h> +#endif +#include "configs.h" +#include "list.h" +#include "fileutils.h" + +#define DEFAULT_ETC_SUBDIR "/etc" + +struct file_element { + struct list_head file_list; + char *filename; +}; + +/* Checking for main configuration file + * + * Returning absolute path or NULL if not found + * The return value has to be freed by the caller. + */ +static char *main_configs(const char *root, + const char *project, + const char *config_name, + const char *config_suffix) +{ + bool found = false; + char *path = NULL; + struct stat st; + + if (config_suffix) { + if (asprintf(&path, "%s/%s/%s.%s", root, project, config_name, config_suffix) < 0) + return NULL; + if (stat(path, &st) == 0) { + found = true; + } else { + free(path); + path = NULL; + } + } + if (!found) { + /* trying filename without suffix */ + if (asprintf(&path, "%s/%s/%s", root, project, config_name) < 0) + return NULL; + if (stat(path, &st) != 0) { + /* not found */ + free(path); + path = NULL; + } + } + return path; +} + +static struct file_element *new_list_entry(const char *filename) +{ + struct file_element *file_element = calloc(1, sizeof(*file_element)); + + if (file_element == NULL) + return NULL; + + INIT_LIST_HEAD(&file_element->file_list); + + if (filename != NULL) { + file_element->filename = strdup(filename); + if (file_element->filename == NULL) { + free(file_element); + return NULL; + } + } else { + file_element->filename = NULL; + } + + return file_element; +} + +#if defined(HAVE_SCANDIRAT) && defined(HAVE_OPENAT) + +static int filter(const struct dirent *d) +{ +#ifdef _DIRENT_HAVE_D_TYPE + if (d->d_type != DT_UNKNOWN && d->d_type != DT_REG && + d->d_type != DT_LNK) + return 0; +#endif + if (*d->d_name == '.') + return 0; + + /* Accept this */ + return 1; +} + +static int read_dir(struct list_head *file_list, + const char *project, + const char *root, + const char *config_name, + const char *config_suffix) +{ + bool found = false; + char *dirname = NULL; + char *filename = NULL; + struct stat st; + int dd = 0, nfiles = 0, i; + int counter = 0; + struct dirent **namelist = NULL; + struct file_element *entry = NULL; + + if (config_suffix) { + if (asprintf(&dirname, "%s/%s/%s.%s.d", + root, project, config_name, config_suffix) < 0) + return -ENOMEM; + if (stat(dirname, &st) == 0) { + found = true; + } else { + free(dirname); + dirname = NULL; + } + } + if (!found) { + /* trying path without suffix */ + if (asprintf(&dirname, "%s/%s/%s.d", root, project, config_name) < 0) + return -ENOMEM; + if (stat(dirname, &st) != 0) { + /* not found */ + free(dirname); + dirname = NULL; + } + } + + if (dirname==NULL) + goto finish; + + dd = open(dirname, O_RDONLY|O_CLOEXEC|O_DIRECTORY); + if (dd < 0) + goto finish; + + nfiles = scandirat(dd, ".", &namelist, filter, alphasort); + if (nfiles <= 0) + goto finish; + + for (i = 0; i < nfiles; i++) { + struct dirent *d = namelist[i]; + size_t namesz = strlen(d->d_name); + if (config_suffix && strlen(config_suffix) > 0 && + (!namesz || namesz < strlen(config_suffix) + 1 || + strcmp(d->d_name + (namesz - strlen(config_suffix)), config_suffix) != 0)) { + /* filename does not have requested suffix */ + continue; + } + + if (asprintf(&filename, "%s/%s", dirname, d->d_name) < 0) { + counter = -ENOMEM; + break; + } + entry = new_list_entry(filename); + free(filename); + if (entry == NULL) { + counter = -ENOMEM; + break; + } + + list_add_tail(&entry->file_list, file_list); + counter++; + } + +finish: + for (i = 0; i < nfiles; i++) + free(namelist[i]); + free(namelist); + free(dirname); + if (dd > 0) + close(dd); + return counter; +} + +#endif + +static void free_list_entry(struct file_element *element) +{ + free(element->filename); + free(element); +} + + +int ul_configs_file_list(struct list_head *file_list, + const char *project, + const char *etc_subdir, + const char *usr_subdir, + const char *config_name, + const char *config_suffix) +{ + char *filename = NULL, *usr_basename = NULL, *etc_basename = NULL; + struct list_head etc_file_list; + struct list_head usr_file_list; + struct list_head *etc_entry = NULL, *usr_entry = NULL; + struct file_element *add_element = NULL, *usr_element = NULL, *etc_element = NULL; + int counter = 0; + + INIT_LIST_HEAD(file_list); + + if (!config_name){ + return -ENOTEMPTY; + } + + /* Default is /etc */ + if (!etc_subdir) + etc_subdir = DEFAULT_ETC_SUBDIR; + + if (!usr_subdir) + usr_subdir = ""; + + if (!project) + project = ""; + + /* Evaluating first "main" file which has to be parsed */ + /* in the following order : /etc /run /usr */ + filename = main_configs(etc_subdir, project, config_name, config_suffix); + if (filename == NULL) + filename = main_configs(_PATH_RUNSTATEDIR, project, config_name, config_suffix); + if (filename == NULL) + filename = main_configs(usr_subdir, project, config_name, config_suffix); + if (filename != NULL) { + add_element = new_list_entry(filename); + free(filename); + if (add_element == NULL) + return -ENOMEM; + list_add_tail(&add_element->file_list, file_list); + counter++; + } + + INIT_LIST_HEAD(&etc_file_list); + INIT_LIST_HEAD(&usr_file_list); + +#if defined(HAVE_SCANDIRAT) && defined(HAVE_OPENAT) + int ret_usr = 0, ret_etc = 0; + ret_etc = read_dir(&etc_file_list, + project, + etc_subdir, + config_name, + config_suffix); + ret_usr = read_dir(&usr_file_list, + project, + usr_subdir, + config_name, + config_suffix); + if (ret_etc == -ENOMEM || ret_usr == -ENOMEM) { + counter = -ENOMEM; + goto finish; + } +#endif + + list_for_each(etc_entry, &etc_file_list) { + etc_element = list_entry(etc_entry, struct file_element, file_list); + etc_basename = ul_basename(etc_element->filename); + list_for_each(usr_entry, &usr_file_list) { + usr_element = list_entry(usr_entry, struct file_element, file_list); + usr_basename = ul_basename(usr_element->filename); + if (strcmp(usr_basename, etc_basename) <= 0) { + if (strcmp(usr_basename, etc_basename) < 0) { + add_element = new_list_entry(usr_element->filename); + if (add_element == NULL) { + counter = -ENOMEM; + goto finish; + } + list_add_tail(&add_element->file_list, file_list); + counter++; + } + list_del(&usr_element->file_list); + } else { + break; + } + } + add_element = new_list_entry(etc_element->filename); + if (add_element == NULL) { + counter = -ENOMEM; + goto finish; + } + list_add_tail(&add_element->file_list, file_list); + counter++; + } + + /* taking the rest of /usr */ + list_for_each(usr_entry, &usr_file_list) { + usr_element = list_entry(usr_entry, struct file_element, file_list); + add_element = new_list_entry(usr_element->filename); + if (add_element == NULL) { + counter = -ENOMEM; + goto finish; + } + list_add_tail(&add_element->file_list, file_list); + counter++; + } + +finish: + ul_configs_free_list(&etc_file_list); + ul_configs_free_list(&usr_file_list); + + return counter; +} + +void ul_configs_free_list(struct list_head *file_list) +{ + list_free(file_list, struct file_element, file_list, free_list_entry); +} + +int ul_configs_next_filename(struct list_head *file_list, + struct list_head **current_entry, + char **name) +{ + struct file_element *element = NULL; + + if (*current_entry == file_list) + return 1; + + if (*current_entry == NULL) + *current_entry = file_list; + element = list_entry(*current_entry, struct file_element, file_list); + *name = element->filename; + *current_entry = (*current_entry)->next; + + return 0; +} diff --git a/lib/meson.build b/lib/meson.build index d62af238b..70e2703d5 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -29,6 +29,7 @@ lib_common_sources = ''' timeutils.c ttyutils.c xxhash.c + configs.c '''.split() idcache_c = files('idcache.c') -- 2.48.1 ++++++ util-linux-lib-netlink-fix1.patch ++++++ >From a5db8d0a9ed63969381feeee1eb0c3b39d32876b Mon Sep 17 00:00:00 2001 From: Stanislav Brabec <[email protected]> Date: Sun, 5 Oct 2025 02:29:00 +0200 Subject: [PATCH 3/7] ul_nl_addr_dup(): Fix address comparison When duplicating struct ul_nl_addr, set address to ifa_local, if it is set to ifa_local in the source. This fixes the address for PtP IPv4 network interfaces and avoids UL_NL_SOFT_ERROR during address removal. Signed-off-by: Stanislav Brabec <[email protected]> --- lib/netlink.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/netlink.c b/lib/netlink.c index 3def42e50..f8ac2c4c8 100644 --- a/lib/netlink.c +++ b/lib/netlink.c @@ -328,7 +328,7 @@ int ul_nl_close(struct ul_nl_data *nl) { return close(nl->fd); } -struct ul_nl_addr *ul_nl_addr_dup (struct ul_nl_addr *addr) { +struct ul_nl_addr *ul_nl_addr_dup(struct ul_nl_addr *addr) { struct ul_nl_addr *newaddr; newaddr = calloc(1, sizeof(struct ul_nl_addr)); if (!newaddr) @@ -348,7 +348,7 @@ struct ul_nl_addr *ul_nl_addr_dup (struct ul_nl_addr *addr) { memcpy(newaddr->ifa_local, addr->ifa_local, addr->ifa_local_len); } - if (&(addr->ifa_address) == &(addr->ifa_local)) + if (addr->address == addr->ifa_local) newaddr->address = newaddr->ifa_local; else newaddr->address = newaddr->ifa_address; @@ -360,7 +360,7 @@ error: return NULL; } -void ul_nl_addr_free (struct ul_nl_addr *addr) { +void ul_nl_addr_free(struct ul_nl_addr *addr) { if (addr) { free(addr->ifa_address); free(addr->ifa_local); -- 2.48.1 ++++++ util-linux-lib-netlink-fix2.patch ++++++ >From 030303e4b93b65a5172a0c80f9f864b06f76cb81 Mon Sep 17 00:00:00 2001 From: Stanislav Brabec <[email protected]> Date: Sun, 5 Oct 2025 02:53:17 +0200 Subject: [PATCH 4/7] netlink process_addr(): Ignore UL_NL_SOFT_ERROR UL_NL_SOFT_ERROR can be issued if kernel sends unpaired RTM_DELADDR. It should not happen, but it can happen due to race condition. And it happened in some kernel versions. It is not reason to exit the processing loop. Signed-off-by: Stanislav Brabec <[email protected]> --- lib/netlink.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/netlink.c b/lib/netlink.c index f8ac2c4c8..3e58e17da 100644 --- a/lib/netlink.c +++ b/lib/netlink.c @@ -130,7 +130,9 @@ static int process_addr(struct ul_nl_data *nl, struct nlmsghdr *nh) nl->addr.ifname = ifname; else { - /* There can be race, we do not return error here */ + /* There can be race, we do not return error here. + * It also happens on RTM_DELADDR, as interface name could + * disappear from kernel tables before we process it. */ /* FIXME I18N: *"unknown"* is too generic. Use context. */ /* TRANSLATORS: unknown network interface, maximum 15 * (IF_NAMESIZE-1) bytes */ @@ -289,7 +291,8 @@ int ul_nl_process(struct ul_nl_data *nl, bool async, bool loop) ul_debugobj(nl, "process_msg() returned %d", rc)); - return rc; + if (rc != UL_NL_SOFT_ERROR) + return rc; } } if (!loop) -- 2.48.1 ++++++ util-linux-lib-netlink-fix3.patch ++++++ >From 60c5c0516e6ce52863b12343a1cd276423ab3bae Mon Sep 17 00:00:00 2001 From: Stanislav Brabec <[email protected]> Date: Wed, 8 Oct 2025 01:14:32 +0200 Subject: [PATCH 5/7] netaddrq: Fix crash if there are no IP addresses If there are no IP addresses, ul_netaddrq_bestaddr() returns threshold ULNETLINK_RATING_BAD, but there were no addresses in the best array, and best_ifaceq remains unset, which caused crash. Setting the initial threshold to __ULNETLINK_RATING_MAX and checking for that value fixes that. And more, it also allows to accept IP addresses with ULNETLINK_RATING_BAD rating. Signed-off-by: Stanislav Brabec <[email protected]> --- include/netaddrq.h | 14 ++++++++++---- lib/netaddrq.c | 10 +++++----- term-utils/agetty.c | 2 +- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/include/netaddrq.h b/include/netaddrq.h index 6d5e655f5..d9c595f32 100644 --- a/include/netaddrq.h +++ b/include/netaddrq.h @@ -94,8 +94,11 @@ ul_netaddrq_iface_bestaddr(struct list_head *ipq_list, * best_iface: interface where the best address was seen * best array: best ifa_valid lifetime seen per quality rating * return value: best rating seen - * Note: It can be needed to call it twice: once for ip_quality_list_4, once - * for ip_quality_list_6. + * Notes: + * - It can be needed to call it twice: once for ip_quality_list_4, once + * for ip_quality_list_6. + * - If no IP addresses are found, the function can return + * _ULNETLINK_RATING_MAX! */ enum ul_netaddrq_ip_rating ul_netaddrq_bestaddr(struct ul_nl_data *nl, @@ -109,8 +112,11 @@ ul_netaddrq_bestaddr(struct ul_nl_data *nl, * return value: The best address as a string * threshold: The best rating ever seen. * best_ifaceq: The best rated interfece ever seen. - * Note: It can be needed to call it twice: once for AF_INET, once - * for AF_INET6. + * Notes: + * - It can be needed to call it twice: once for AF_INET, once + * for AF_INET6. + * - If the return value is NULL (i. e. there are no usable interfaces), then + * *best_ifaceq remains unchanges and cannot be used. */ const char *ul_netaddrq_get_best_ipp(struct ul_nl_data *nl, uint8_t ifa_family, diff --git a/lib/netaddrq.c b/lib/netaddrq.c index 34431d8d3..1ce454aaf 100644 --- a/lib/netaddrq.c +++ b/lib/netaddrq.c @@ -296,7 +296,7 @@ ul_netaddrq_iface_bestaddr(struct list_head *ipq_list, struct ul_netaddrq_ip *ipq; enum ul_netaddrq_ip_rating threshold; - threshold = ULNETLINK_RATING_BAD; + threshold = __ULNETLINK_RATING_MAX; list_for_each(li, ipq_list) { ipq = list_entry(li, struct ul_netaddrq_ip, entry); @@ -342,7 +342,7 @@ ul_netaddrq_bestaddr(struct ul_nl_data *nl, ipqo = offsetof(struct ul_netaddrq_iface, ip_quality_list_6); } - threshold = ULNETLINK_RATING_BAD; + threshold = __ULNETLINK_RATING_MAX; list_for_each(li, &(addrq->ifaces)) { struct list_head *ipq_list; @@ -374,7 +374,7 @@ const char *ul_netaddrq_get_best_ipp(struct ul_nl_data *nl, memset(best, 0, sizeof(best)); *threshold = ul_netaddrq_bestaddr(nl, best_ifaceq, &best, ifa_family); - if (best[*threshold]) + if (*threshold != __ULNETLINK_RATING_MAX) return ul_nl_addr_ntop_address(best[*threshold]->addr); return NULL; } @@ -423,7 +423,7 @@ static void dump_iface_best(struct ul_nl_data *nl, memset(best, 0, sizeof(best)); threshold = ul_netaddrq_iface_bestaddr(&(ifaceq->ip_quality_list_4), &best); - if (best[threshold]) + if (threshold != __ULNETLINK_RATING_MAX) { fprintf(netout, "%s IPv4: %s", (first ? "best address" : " "), ul_nl_addr_ntop_address(best[threshold]->addr)); @@ -432,7 +432,7 @@ static void dump_iface_best(struct ul_nl_data *nl, memset(best, 0, sizeof(best)); threshold = ul_netaddrq_iface_bestaddr(&(ifaceq->ip_quality_list_6), &best); - if (best[threshold]) + if (threshold != __ULNETLINK_RATING_MAX) { fprintf(netout, "%s IPv6: %s", (first ? "best address" : " "), ul_nl_addr_ntop_address(best[threshold]->addr)); diff --git a/term-utils/agetty.c b/term-utils/agetty.c index b7786ce7d..ec922bd11 100644 --- a/term-utils/agetty.c +++ b/term-utils/agetty.c @@ -2603,7 +2603,7 @@ static void print_iface_best(struct issue *ie, threshold = ul_netaddrq_iface_bestaddr(l, &best); - if (best[threshold]) + if (threshold != __ULNETLINK_RATING_MAX) fputs(ul_nl_addr_ntop_address(best[threshold]->addr), ie->output); } -- 2.48.1 ++++++ util-linux-lib-netlink-fix5.patch ++++++ >From 889d454aaa10b70e6cdbca3183414ead52f0e379 Mon Sep 17 00:00:00 2001 From: Karel Zak <[email protected]> Date: Tue, 17 Feb 2026 11:35:17 +0100 Subject: [PATCH 7/7] lib/netlink: set SOCK_CLOEXEC on netlink socket Set SOCK_CLOEXEC when creating the NETLINK_ROUTE socket in ul_nl_open() to prevent the file descriptor from leaking to child processes across execv(). In agetty, the netlink socket used to monitor IP address changes for \4/\6 issue escapes was inherited by the login program, causing SELinux AVC denials (local_login_t denied read/write on getty_t's netlink_route_socket). Fixes: https://github.com/util-linux/util-linux/issues/4032 Signed-off-by: Karel Zak <[email protected]> --- lib/netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netlink.c b/lib/netlink.c index a6c7f25f2..28eb185d5 100644 --- a/lib/netlink.c +++ b/lib/netlink.c @@ -310,7 +310,7 @@ int ul_nl_open(struct ul_nl_data *nl, uint32_t nl_groups) int rc; DBG(NLMSG, ul_debugobj(nl, "opening socket")); - sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + sock = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE); if (sock < 0) return sock; addr.nl_family = AF_NETLINK; -- 2.51.0 ++++++ util-linux-lib-netlink.patch ++++++ ++++ 1603 lines (skipped) ++++++ util-linux-login_defs-check.sh ++++++ --- /var/tmp/diff_new_pack.pMyfFQ/_old 2026-05-09 12:59:51.433194028 +0200 +++ /var/tmp/diff_new_pack.pMyfFQ/_new 2026-05-09 12:59:51.437194192 +0200 @@ -15,7 +15,7 @@ sed -n 's/^.*logindefs_setenv*("[A-Z0-9_]*", "\([A-Z0-9_]*\)".*$/\1/p' ) | LC_ALL=C sort -u >util-linux-login_defs-vars.lst -if test $(sha1sum util-linux-login_defs-vars.lst | sed 's/ .*$//') != d13dc1cf4efb635deaf6da34ba1a39cf7ecc77d1 ; then +if test $(sha1sum util-linux-login_defs-vars.lst | sed 's/ .*$//') != 713b442bf6d16353b7f74538ece165b424f90932 ; then echo "does not match!" >&2 echo "Checksum is: $(sha1sum util-linux-login_defs-vars.lst | sed 's/ .*$//')" >&2 ++++++ util-linux-man-generated.patch ++++++ Index: util-linux-2.41.2/term-utils/agetty.8 =================================================================== --- util-linux-2.41.2.orig/term-utils/agetty.8 +++ util-linux-2.41.2/term-utils/agetty.8 @@ -456,6 +458,16 @@ Insert the IPv4 address of the specified The same as \(rs4 but for IPv6. .RE .sp +a +.RS 4 +Insert list of "good" IP addresses for all interfaces. It prints best candidates for remote login IP addresses: global and site addresses; if not available, temporary address with the longest lifetime, if not available, link address. Note that link addresses are printed with local interface name, but they has to be done with the interface name on the machine where they will be used. +.RE +.sp +A +.RS 4 +Insert list of all IP addresses for all interfaces. +.RE +.sp b .RS 4 Insert the baudrate of the current line.
