20 Commits

Author SHA256 Message Date
6f6f0a54ea Accepting request 1311767 from Base:System
OBS-URL: https://build.opensuse.org/request/show/1311767
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/util-linux?expand=0&rev=302
2025-10-18 12:35:53 +00:00
8c2d1ee9ab Simplify %post.
OBS-URL: https://build.opensuse.org/package/show/Base:System/util-linux?expand=0&rev=610
2025-10-16 16:37:46 +00:00
02e8e761c8 Typo fix.
OBS-URL: https://build.opensuse.org/package/show/Base:System/util-linux?expand=0&rev=609
2025-10-16 03:23:26 +00:00
6c9131c836 Add boo#1244446 to changes.
OBS-URL: https://build.opensuse.org/package/show/Base:System/util-linux?expand=0&rev=608
2025-10-16 03:14:55 +00:00
a1436eef7b - 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
  (util-linux-lib-netlink-fix1.patch,
  util-linux-lib-netlink-fix2.patch,
  util-linux-lib-netlink-fix3.patch and
  util-linux-agetty-netlink-fix4.patch).
- Fix configs library use in agetty (replace
  util-linux-issuedir-usr-lib.patch by upstream
  util-linux-lib-configs-fix1.patch,
  add util-linux-lib-configs-fix2.patch,
  util-linux-lib-configs-fix3.patch,
  util-linux-lib-configs-fix4.patch,
  util-linux-lib-configs-fix5.patch and
  util-linux-lib-configs-fix6.patch).
- Fix agetty erase of escape characters (relevant to bsc#1194818,
  util-linux-agetty-escape-erase.patch).
- Own /usr/lib/issue.d directory.
- Perform migration from issue-generator (jsc#PED-8734).
- Drop util-linux-agetty-ssh-host-keys.patch. This feature is not
  used in MicroOS any more.
- Remove Provides/Obsoletes for s390-32, upgrade from SLE11 SP1 is
  no more supported.

OBS-URL: https://build.opensuse.org/package/show/Base:System/util-linux?expand=0&rev=607
2025-10-16 03:08:35 +00:00
f19df5814c - agetty: use /usr/lib/issue.d for backward compatibility
(util-linux-issuedir-usr-lib.patch).

OBS-URL: https://build.opensuse.org/package/show/Base:System/util-linux?expand=0&rev=606
2025-09-30 20:20:00 +00:00
d038bb277e Fix problems caused by superfluous flavor definition.
OBS-URL: https://build.opensuse.org/package/show/Base:System/util-linux?expand=0&rev=605
2025-09-29 10:40:52 +00:00
a07bc6db40 - Mark test script/options as failing (needs research on arm7l and
s390x).

OBS-URL: https://build.opensuse.org/package/show/Base:System/util-linux?expand=0&rev=604
2025-09-29 08:51:47 +00:00
748493ae25 Remove flavor definition that should not appear in OBS.
OBS-URL: https://build.opensuse.org/package/show/Base:System/util-linux?expand=0&rev=603
2025-09-29 08:50:30 +00:00
d58ac4d1e8 - Fix address matching in agetty (boo#1247371,
util-linux-lib-netlink.patch).
- Update generated man pages (util-linux-man-generated.patch).

OBS-URL: https://build.opensuse.org/package/show/Base:System/util-linux?expand=0&rev=602
2025-09-28 07:44:23 +00:00
d61749eafc Test fail.
OBS-URL: https://build.opensuse.org/package/show/Base:System/util-linux?expand=0&rev=601
2025-09-28 07:29:32 +00:00
6b1617ff28 - Add configs library and use it in agetty
- Update to version 2.41.2...

OBS-URL: https://build.opensuse.org/package/show/Base:System/util-linux?expand=0&rev=600
2025-09-26 19:27:26 +00:00
4ec1ddfe0e Accepting request 1303156 from Base:System
- Implement escape code for printing of ssh host keys in agetty
  issue file (util-linux-agetty-ssh-host-keys.patch.
- Include fixes from
  https://github.com/util-linux/util-linux/pull/3649 (jsc#PED-8734,
  util-linux-lib-netlink.patch, util-linux-agetty-netlink.patch).

OBS-URL: https://build.opensuse.org/request/show/1303156
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/util-linux?expand=0&rev=301
2025-09-10 15:30:10 +00:00
b2359319b4 Accepting request 1302271 from home:sbrabec:branches:util-linux-b1247371
- Implement escape code for printing of ssh host keys in agetty
  issue file (util-linux-agetty-ssh-host-keys.patch.
- Include fixes from
  https://github.com/util-linux/util-linux/pull/3649 (jsc#PED-8734,
  util-linux-lib-netlink.patch, util-linux-agetty-netlink.patch).

OBS-URL: https://build.opensuse.org/request/show/1302271
OBS-URL: https://build.opensuse.org/package/show/Base:System/util-linux?expand=0&rev=598
2025-09-01 22:52:21 +00:00
2074f8c639 Accepting request 1295529 from Base:System
- For bash 5.3 add (SIG)INT tests/expected/kill/decode as ignored
  signal for asynchronous coprocesses (boo#1246830)

OBS-URL: https://build.opensuse.org/request/show/1295529
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/util-linux?expand=0&rev=300
2025-08-13 14:23:37 +00:00
37724ca4d2 .
OBS-URL: https://build.opensuse.org/package/show/Base:System/util-linux?expand=0&rev=597
2025-07-24 11:03:15 +00:00
7408b8b11c .
OBS-URL: https://build.opensuse.org/package/show/Base:System/util-linux?expand=0&rev=596
2025-07-24 10:58:36 +00:00
27748685ae Accepting request 1291647 from Base:System
- agetty: Implement netlink based IP address detection

OBS-URL: https://build.opensuse.org/request/show/1291647
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/util-linux?expand=0&rev=299
2025-07-14 08:49:38 +00:00
f3ed77a008 Add upstream issue links
OBS-URL: https://build.opensuse.org/package/show/Base:System/util-linux?expand=0&rev=595
2025-07-10 09:41:40 +00:00
b226ea0a85 - Implement netlink based IP address detection and issue reload.
It makes possible to identify IP addresses usability and prefer
  stable global addresses over ephemeral or link-local addresses.
  New issue keywords \a and \A were added. (boo#1139983,
  jsc#PED-8734, util-linux-lib-netlink.patch,
  util-linux-agetty-netlink.patch)

OBS-URL: https://build.opensuse.org/package/show/Base:System/util-linux?expand=0&rev=594
2025-07-10 09:40:23 +00:00
22 changed files with 3935 additions and 29 deletions

View File

@@ -1,16 +0,0 @@
-----BEGIN PGP SIGNATURE-----
iQIzBAABCAAdFiEEsMZNFDAcxu+u32Dk5LcdXuw5woQFAmhaXXIACgkQ5LcdXuw5
woTvGg/8DVhCA5WWXbRh+fxsTwb2vIWPgBpjV+wUqxiNeijPXDK7tDcNF9bHvXy7
X7ajs4y+ULzw2hBpBmI/k/Oi/enDYNo+Q76du6POjJkasgO0bY9kGVVFhd61BFfk
86yY0uOud3n/F/ht1rR3TdFaatA2QtK7AqGmh3xpQh7ELJ8v7uNT/uyU7ZtKJXT3
uEa217G1OYxxJlmLmob0jWYYuyjtg0nB/Xw4MiXrTqQbD4K0304eDsYu10DaRPW6
ZNEjnCYEaPPkZ1xH3L29ZZlrwZ47ApN52dsTRzoymQGhak5UsKvcL7pWAa3gIlk9
m3cL6TnuFXemBF6FqdAu2+xs1gX6zzPW8+2iff+9PrvODXSZPNBamwsVY6Ae39g9
8lRQH1RpyXdIB+wg3ItgaGxTYz6aEJU9nCsE2uHQF/IRSdEHsqG5rc00ax0h4Ihk
M+3z94Wuo+8NceY7kIM/lkH5sCnVV4WcpGImA3kvaVDkjYhb8XK8Yb3KFR8RE/rH
LOCRavkKXaKT4CaS+SLvOZoFTTLciw7oNqecopSsREPk0y4HKbPdfRrfcS38m4ex
HXp9yI2Rl7vThtDuNi0Bcp6GmLo4cgWgHBYSNZcnGH88LJk2Ya7Yamg+tUeynGCI
6RvQxxfDT8mMf5deEiiLgG9RxjSVlA53dIZf1tB1RUjjh61aLdQ=
=mm3H
-----END PGP SIGNATURE-----

Binary file not shown.

View File

@@ -0,0 +1,16 @@
-----BEGIN PGP SIGNATURE-----
iQIzBAABCAAdFiEEsMZNFDAcxu+u32Dk5LcdXuw5woQFAmjRMm4ACgkQ5LcdXuw5
woQNYw//SUP++cpixHLgMot/k3KjVXEP6H9R0YQnD2NP9XQpmQpDsT4LgQeDZz2Z
9HHWzOUEscmdVs0QZa/UVHOTtOCTYq4iQy0qpwuxD6/c5wdB/RF6gyOI91OKqmUP
q4vgnYpv6glcElpNXC7xJf4DxsdfPD3GTUOeC5svaelDtCp8KWFSVz6Q3mU7jpy2
BKFB9OAC23/xxydlcJZ3oD1JefVHZqGOHnPzxstnagCczsHJ0cxQ/KLvN8BUPiXL
k4S2X0zvtlfgj8vSdAb1t1/a4OqPfzgQSsqjeCdoO8bICnbLmbe+56OF4S5XNuHv
rQadEvMEMyhl9I8gVpfunkKlxN4c8uDPm59QjWkiyetT3THsI+QWRIF8s9IEcMsj
+vVvfCwSR1S1lYjvIvh3WQF1R28yp5M23l6yHYqdCmRq2+QSBN0Sd2OcxWWM1YYF
nN38jCDaqU8P1T7NnqSrbmAm4NBCjpFcqSZ8Z47/g9Nd1fp3/wT6J230ve/nomMq
LuNjGBOIIctDvo6RsBZWTX24f7Q5hyip5G0Wfp7tc+00PPiVvVo66TesJcvCQ1RS
dfjTJncrBwrOx9gFFSH0B28gSEknRIDkEmu1b/UhypOfEOBFwpqvfkl+WHAlUVye
016O7PUoyBWS8br1BzaO/I9srA1T4Udtz+75/DJULe5cf8APcxI=
=TrzC
-----END PGP SIGNATURE-----

BIN
util-linux-2.41.2.tar.xz LFS Normal file

Binary file not shown.

View File

@@ -0,0 +1,78 @@
From d1cf7efb17869d0fdf132bb3581d9b74a459bb87 Mon Sep 17 00:00:00 2001
From: Stefan Schubert <schubi@suse.de>
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, &current, &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) {

View File

@@ -0,0 +1,139 @@
From b462fdefe74836c22cb02039dca419a512dc6c88 Mon Sep 17 00:00:00 2001
From: Karel Zak <kzak@redhat.com>
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 <kzak@redhat.com>
---
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

View File

@@ -0,0 +1,69 @@
From fa9b5740f67bc64d7b58f9b2fcc4f2883d7dcc91 Mon Sep 17 00:00:00 2001
From: Stanislav Brabec <sbrabec@suse.cz>
Date: Fri, 10 Oct 2025 13:17:26 +0200
Subject: [PATCH 6/6] 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 <sbrabec@suse.cz>
---
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

View File

@@ -0,0 +1,636 @@
From b8b5030d792c0ffe51ee4a5925d43735b5d782d8 Mon Sep 17 00:00:00 2001
From: Stanislav Brabec <sbrabec@suse.cz>
Date: Wed, 9 Jul 2025 14:35:28 +0200
Subject: [PATCH 2/6] agetty: Implement netlink based IP processing
The current \4 and \6 issue file escapes implementation is inferior. It
uses get getifaddrs() to get a list of IP addresses. This function does not
provide enough information to discriminate between stable IP addresses and
ephemeral addresses. As a result, especially \6 often gives unreliable
results.
The code is actually unable to get list of all interfaces, so a proper out
of the box IP address reporting depends on external tools that generate
issue file with the interfaces list.
The netlink messages are already used, but only as a change notifier. The
contents is not used, even if it contains exact information about the
change. As a result, change processing is triggered even for unrelated
network changes like IPv6 router advertisement.
The new implementation uses the new netaddrq library. It reports more
reliable results especially for IPv6.
Additionally, two new escapes are implemented:
\a Report all interfaces and assigned addresses that are considered as
reliable.
\A Report all interfaces and all assigned addresses.
TODO:
To prevent overflooding of the console, the list is currently limited to 12
interfaces. It would be nice to make it configurable.
Two pass processing of issue files. First pass just collects IP protocols
and list of interfaces (in future interface patterns). Now it always
processes both IPv4 and IPv6 on all interfaces. Not so bad, as \a is smart
enough to display just the useful part.
Maybe implement more options and formatting support for \a and \A.
Maybe implement interface filter globs or regexps for \a and \A. Still not
so bad, as \a automatically skips interfaces without reliable addresses
(e. g. lo or TUN).
Signed-off-by: Stanislav Brabec <sbrabec@suse.cz>
---
term-utils/agetty.8.adoc | 6 +
term-utils/agetty.c | 417 ++++++++++++++++++++++-----------------
2 files changed, 246 insertions(+), 177 deletions(-)
Index: util-linux-2.41.2/term-utils/agetty.8.adoc
===================================================================
--- util-linux-2.41.2.orig/term-utils/agetty.8.adoc
+++ util-linux-2.41.2/term-utils/agetty.8.adoc
@@ -247,6 +247,12 @@ Insert the IPv4 address of the specified
6 or 6{_interface_}::
The same as \4 but for IPv6.
+a::
+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.
+
+A::
+Insert list of all IP addresses for all interfaces.
+
b::
Insert the baudrate of the current line.
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
@@ -32,10 +32,7 @@
#include <langinfo.h>
#include <grp.h>
#include <pwd.h>
-#include <arpa/inet.h>
#include <netdb.h>
-#include <ifaddrs.h>
-#include <net/if.h>
#include <sys/utsname.h>
#include "strutils.h"
@@ -50,6 +47,9 @@
#include "env.h"
#include "path.h"
#include "fileutils.h"
+#ifdef AGETTY_RELOAD
+#include "netaddrq.h"
+#endif
#include "logindefs.h"
@@ -144,7 +144,6 @@
# define AGETTY_RELOAD_FILENAME "/run/agetty.reload" /* trigger file */
# define AGETTY_RELOAD_FDNONE -2 /* uninitialized fd */
static int inotify_fd = AGETTY_RELOAD_FDNONE;
-static int netlink_fd = AGETTY_RELOAD_FDNONE;
static uint32_t netlink_groups;
#endif
@@ -154,6 +153,7 @@ struct issue {
size_t mem_sz;
#ifdef AGETTY_RELOAD
+ struct ul_nl_data nl;
char *mem_old;
#endif
unsigned int do_tcsetattr : 1,
@@ -364,6 +364,7 @@ int main(int argc, char **argv)
};
struct issue issue = {
.mem = NULL,
+ .nl.fd = -1
};
char *login_argv[LOGIN_ARGV_MAX + 1];
int login_argc = 0;
@@ -1603,81 +1604,7 @@ done:
}
#ifdef AGETTY_RELOAD
-static void open_netlink(void)
-{
- struct sockaddr_nl addr = { 0, };
- int sock;
-
- if (netlink_fd != AGETTY_RELOAD_FDNONE)
- return;
-
- sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (sock >= 0) {
- addr.nl_family = AF_NETLINK;
- addr.nl_pid = getpid();
- addr.nl_groups = netlink_groups;
- if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
- close(sock);
- else
- netlink_fd = sock;
- }
-}
-
-static int process_netlink_msg(int *triggered)
-{
- char buf[4096];
- struct sockaddr_nl snl;
- struct nlmsghdr *h;
- int rc;
-
- struct iovec iov = {
- .iov_base = buf,
- .iov_len = sizeof(buf)
- };
- struct msghdr msg = {
- .msg_name = &snl,
- .msg_namelen = sizeof(snl),
- .msg_iov = &iov,
- .msg_iovlen = 1,
- .msg_control = NULL,
- .msg_controllen = 0,
- .msg_flags = 0
- };
-
- rc = recvmsg(netlink_fd, &msg, MSG_DONTWAIT);
- if (rc < 0) {
- if (errno == EWOULDBLOCK || errno == EAGAIN)
- return 0;
-
- /* Failure, just stop listening for changes */
- close(netlink_fd);
- netlink_fd = AGETTY_RELOAD_FDNONE;
- return 0;
- }
-
- for (h = (struct nlmsghdr *)buf; NLMSG_OK(h, (unsigned int)rc); h = NLMSG_NEXT(h, rc)) {
- if (h->nlmsg_type == NLMSG_DONE ||
- h->nlmsg_type == NLMSG_ERROR) {
- close(netlink_fd);
- netlink_fd = AGETTY_RELOAD_FDNONE;
- return 0;
- }
-
- *triggered = 1;
- break;
- }
-
- return 1;
-}
-
-static int process_netlink(void)
-{
- int triggered = 0;
- while (process_netlink_msg(&triggered));
- return triggered;
-}
-
-static int wait_for_term_input(int fd)
+static int wait_for_term_input(struct issue *ie, int fd)
{
char buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
fd_set rfds;
@@ -1711,9 +1638,9 @@ static int wait_for_term_input(int fd)
FD_SET(inotify_fd, &rfds);
nfds = max(nfds, inotify_fd);
}
- if (netlink_fd >= 0) {
- FD_SET(netlink_fd, &rfds);
- nfds = max(nfds, netlink_fd);
+ if (ie->nl.fd >= 0) {
+ FD_SET(ie->nl.fd, &rfds);
+ nfds = max(nfds, ie->nl.fd);
}
/* If waiting fails, just fall through, presumably reading input will fail */
@@ -1725,9 +1652,10 @@ static int wait_for_term_input(int fd)
}
- if (netlink_fd >= 0 && FD_ISSET(netlink_fd, &rfds)) {
- if (!process_netlink())
- continue;
+ 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);
/* Just drain the inotify buffer */
} else if (inotify_fd >= 0 && FD_ISSET(inotify_fd, &rfds)) {
@@ -1937,11 +1865,44 @@ static void eval_issue_file(struct issue
struct options *op,
struct termios *tp)
{
-#ifdef AGETTY_RELOAD
- netlink_groups = 0;
-#endif
if (!(op->flags & F_ISSUE))
goto done;
+
+#ifdef AGETTY_RELOAD
+/* TODO:
+ * Two pass processing for eval_issue_file()
+ * Implement pass 1: Just evaluate list of netlink_groups (IP protocols) and
+ * intefaces to monitor.
+ * That is why again label is here: netlink_groups will be re-evaluated and
+ * dump will be performed again.
+ */
+ /* netlink_groups = 0; */
+ netlink_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;
+
+ /* Already initialized? */
+ if (ie->nl.fd >= 0)
+ goto skip;
+ /* Prepare netlink. */
+ ul_nl_init(&(ie->nl));
+ if ((ul_netaddrq_init(&(ie->nl), NULL, NULL, (void *)ie)))
+ goto skip;
+
+ /* Open netlink and create address list. */
+ if (ul_nl_open(&(ie->nl),
+ RTMGRP_LINK | netlink_groups))
+ goto skip;
+ if (ul_nl_request_dump(&(ie->nl), RTM_GETADDR))
+ goto error;
+ if (ul_nl_process(&(ie->nl), UL_NL_SYNC, UL_NL_LOOP) != UL_NL_DONE)
+ goto error;
+ goto skip;
+error:
+ /* In case of any error, the addrq list is just empty, and we can use
+ * the code without any error checking. */
+ ul_nl_close(&(ie->nl));
+ ie->nl.fd = -1;
+skip:
+#endif
/*
* The custom issue file or directory list specified by:
* agetty --issue-file <path[:path]...>
@@ -1986,11 +1947,6 @@ static void eval_issue_file(struct issue
issuedir_read(ie, _PATH_SYSCONFSTATICDIR "/" _PATH_ISSUE_DIRNAME, op, tp);
done:
-
-#ifdef AGETTY_RELOAD
- if (netlink_groups != 0)
- open_netlink();
-#endif
if (ie->output) {
fclose(ie->output);
ie->output = NULL;
@@ -2002,7 +1958,7 @@ done:
*/
static void show_issue(struct options *op)
{
- struct issue ie = { .output = NULL };
+ struct issue ie = { .output = NULL, .nl.fd = -1 };
struct termios tp;
memset(&tp, 0, sizeof(struct termios));
@@ -2032,13 +1988,19 @@ again:
puts(_("[press ENTER to login]"));
#ifdef AGETTY_RELOAD
/* reload issue */
- if (!wait_for_term_input(STDIN_FILENO)) {
+ if (!wait_for_term_input(ie, STDIN_FILENO)) {
eval_issue_file(ie, op, tp);
if (issue_is_changed(ie)) {
if ((op->flags & F_VCONSOLE)
&& (op->flags & F_NOCLEAR) == 0)
termio_clear(STDOUT_FILENO);
- goto again;
+ {
+ /* TODO: Close to set netlink_groups again using pass 1 */
+ /* if (ie->nl.fd >= 0) ul_nl_close(&(ie->nl));
+ * ie->nl.fd = -1; */
+
+ goto again;
+ }
}
}
#endif
@@ -2168,7 +2130,7 @@ static char *get_logname(struct issue *i
no_reload:
#ifdef AGETTY_RELOAD
- if (!wait_for_term_input(STDIN_FILENO)) {
+ if (!wait_for_term_input(ie, STDIN_FILENO)) {
/* refresh prompt -- discard input data, clear terminal
* and call do_prompt() again
*/
@@ -2177,6 +2139,8 @@ static char *get_logname(struct issue *i
eval_issue_file(ie, op, tp);
if (!issue_is_changed(ie))
goto no_reload;
+ /* if (ie->nl.fd >= 0) ul_nl_close(&(ie->nl));
+ * ie->nl.fd = -1; */
tcflush(STDIN_FILENO, TCIFLUSH);
if ((op->flags & F_VCONSOLE)
&& (op->flags & F_NOCLEAR) == 0)
@@ -2576,92 +2540,170 @@ static void log_warn(const char *fmt, ..
va_end(ap);
}
-static void print_addr(struct issue *ie, sa_family_t family, void *addr)
-{
- char buff[INET6_ADDRSTRLEN + 1];
+static void print_iface_best(struct issue *ie,
+ const char *ifname,
+ uint8_t ifa_family)
+{
+ struct ul_netaddrq_ip *best[__ULNETLINK_RATING_MAX];
+ struct ul_netaddrq_iface *ifaceq;
+ struct list_head *l;
+ enum ul_netaddrq_ip_rating threshold;
+
+ if (!ie->nl.data_addr)
+ return; /* error: init failed */
- inet_ntop(family, addr, buff, sizeof(buff));
- fprintf(ie->output, "%s", buff);
+ if ((ifaceq = ul_netaddrq_iface_by_name(&(ie->nl), ifname)))
+ {
+ memset(best, 0, sizeof(best));
+ if (ifa_family == AF_INET)
+ l = &(ifaceq->ip_quality_list_4);
+ else
+ /* if (ifa_family == AF_INET6) */
+ l = &(ifaceq->ip_quality_list_6);
+
+ threshold =
+ ul_netaddrq_iface_bestaddr(l, &best);
+ if (best[threshold])
+ fputs(ul_nl_addr_ntop_address(best[threshold]->addr),
+ ie->output);
+ }
}
-/*
- * Prints IP for the specified interface (@iface), if the interface is not
- * specified then prints the "best" one (UP, RUNNING, non-LOOPBACK). If not
- * found the "best" interface then prints at least host IP.
- */
-static void output_iface_ip(struct issue *ie,
- struct ifaddrs *addrs,
- const char *iface,
- sa_family_t family)
-{
- struct ifaddrs *p;
- struct addrinfo hints, *info = NULL;
- char *host = NULL;
- void *addr = NULL;
+static void print_addrq_bestofall(struct issue *ie,
+ uint8_t ifa_family)
+{
+ struct ul_netaddrq_iface *best_ifaceq;
+ enum ul_netaddrq_ip_rating threshold;
+ const char *best_ipp;
- if (!addrs)
- return;
+ if (!ie->nl.data_addr)
+ return; /* error: init failed */
- for (p = addrs; p; p = p->ifa_next) {
+ best_ipp = ul_netaddrq_get_best_ipp(&(ie->nl), ifa_family,
+ &threshold, &best_ifaceq);
+ if (best_ipp)
+ fputs(best_ipp, ie->output);
+}
- if (!p->ifa_name ||
- !p->ifa_addr ||
- p->ifa_addr->sa_family != family)
- continue;
+static void dump_iface_good(struct issue *ie,
+ struct ul_netaddrq_iface *ifaceq)
+{
+ struct ul_netaddrq_ip *best4[__ULNETLINK_RATING_MAX];
+ struct ul_netaddrq_ip *best6[__ULNETLINK_RATING_MAX];
+ struct list_head *li;
+ enum ul_netaddrq_ip_rating threshold = __ULNETLINK_RATING_MAX - 1;
+ enum ul_netaddrq_ip_rating fthreshold; /* per family threshold */
+ bool first = true;
- if (iface) {
- /* Filter out by interface name */
- if (strcmp(p->ifa_name, iface) != 0)
- continue;
- } else {
- /* Select the "best" interface */
- if ((p->ifa_flags & IFF_LOOPBACK) ||
- !(p->ifa_flags & IFF_UP) ||
- !(p->ifa_flags & IFF_RUNNING))
- continue;
- }
+ memset(best4, 0, sizeof(best4));
+ threshold = ul_netaddrq_iface_bestaddr(&(ifaceq->ip_quality_list_4),
+ &best4);
+ memset(best6, 0, sizeof(best6));
+ fthreshold = ul_netaddrq_iface_bestaddr(&(ifaceq->ip_quality_list_6),
+ &best6);
+ if (fthreshold < threshold)
+ threshold = fthreshold;
- addr = NULL;
- switch (p->ifa_addr->sa_family) {
- case AF_INET:
- addr = &((struct sockaddr_in *) p->ifa_addr)->sin_addr;
- break;
- case AF_INET6:
- addr = &((struct sockaddr_in6 *) p->ifa_addr)->sin6_addr;
- break;
- }
+ list_for_each(li, &(ifaceq->ip_quality_list_4))
+ {
+ struct ul_netaddrq_ip *ipq;
- if (addr) {
- print_addr(ie, family, addr);
- return;
+ ipq = list_entry(li, struct ul_netaddrq_ip, entry);
+ if (threshold <= ULNETLINK_RATING_SCOPE_LINK &&
+ ( ipq->quality <= threshold ||
+ /* Consider site addresses equally good as global */
+ ipq->quality == ULNETLINK_RATING_SCOPE_SITE) &&
+ best4[threshold])
+ {
+ if (first)
+ {
+ fprintf(ie->output, "%s: ", ifaceq->ifname);
+ first = false;
+ }
+ else
+ fprintf(ie->output, " ");
+ /* Write only the longest living temporary address */
+ if (threshold == ULNETLINK_RATING_F_TEMPORARY)
+ {
+ fputs(ul_nl_addr_ntop_address(best4[ULNETLINK_RATING_F_TEMPORARY]->addr),
+ ie->output);
+ goto temp_cont4;
+ }
+ else
+ fputs(ul_nl_addr_ntop_address(ipq->addr),
+ ie->output);
}
+ temp_cont4:;
}
- if (iface)
- return;
-
- /* Hmm.. not found the best interface, print host IP at least */
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = family;
- if (family == AF_INET6)
- hints.ai_flags = AI_V4MAPPED;
+ list_for_each(li, &(ifaceq->ip_quality_list_6))
+ {
+ struct ul_netaddrq_ip *ipq;
- host = xgethostname();
- if (host && getaddrinfo(host, NULL, &hints, &info) == 0 && info) {
- switch (info->ai_family) {
- case AF_INET:
- addr = &((struct sockaddr_in *) info->ai_addr)->sin_addr;
- break;
- case AF_INET6:
- addr = &((struct sockaddr_in6 *) info->ai_addr)->sin6_addr;
- break;
+ ipq = list_entry(li, struct ul_netaddrq_ip, entry);
+ if (threshold <= ULNETLINK_RATING_SCOPE_LINK &&
+ ( ipq->quality <= threshold ||
+ /* Consider site addresses equally good as global */
+ ipq->quality == ULNETLINK_RATING_SCOPE_SITE) &&
+ best6[threshold])
+ {
+ if (first)
+ {
+ fprintf(ie->output, "%s: ", ifaceq->ifname);
+ first = false;
+ }
+ else
+ fprintf(ie->output, " ");
+ /* Write only the longest living temporary address */
+ if (threshold == ULNETLINK_RATING_F_TEMPORARY)
+ {
+ fputs(ul_nl_addr_ntop_address(best6[ULNETLINK_RATING_F_TEMPORARY]->addr),
+ ie->output);
+ goto temp_cont6;
+ }
+ else
+ fputs(ul_nl_addr_ntop_address(ipq->addr),
+ ie->output);
}
- if (addr)
- print_addr(ie, family, addr);
+ temp_cont6:;
+ }
+ if (!first)
+ fputs("\n", ie->output);
+}
- freeaddrinfo(info);
+static void dump_iface_all(struct issue *ie,
+ struct ul_netaddrq_iface *ifaceq)
+{
+ struct list_head *li;
+ struct ul_netaddrq_ip *ipq;
+ bool first = true;
+
+ list_for_each(li, &(ifaceq->ip_quality_list_4))
+ {
+ ipq = list_entry(li, struct ul_netaddrq_ip, entry);
+ if (first)
+ {
+ fprintf(ie->output, "%s: ", ifaceq->ifname);
+ first = false;
+ }
+ else
+ fprintf(ie->output, " ");
+ fputs(ul_nl_addr_ntop_address(ipq->addr), ie->output);
+ }
+ list_for_each(li, &(ifaceq->ip_quality_list_6))
+ {
+ ipq = list_entry(li, struct ul_netaddrq_ip, entry);
+ if (first)
+ {
+ fprintf(ie->output, "%s: ", ifaceq->ifname);
+ first = false;
+ }
+ else
+ fprintf(ie->output, " ");
+ fputs(ul_nl_addr_ntop_address(ipq->addr), ie->output);
}
- free(host);
+ if (!first)
+ fputs("\n", ie->output);
}
/*
@@ -2860,26 +2902,47 @@ static void output_special_char(struct i
case '4':
case '6':
{
- sa_family_t family = c == '4' ? AF_INET : AF_INET6;
- struct ifaddrs *addrs = NULL;
- char iface[128];
-
- if (getifaddrs(&addrs))
- break;
+ char iface[IF_NAMESIZE];
+ uint8_t ifa_family = c == '4' ? AF_INET : AF_INET6;
if (get_escape_argument(fp, iface, sizeof(iface)))
- output_iface_ip(ie, addrs, iface, family);
+ print_iface_best(ie, iface, ifa_family);
else
- output_iface_ip(ie, addrs, NULL, family);
-
- freeifaddrs(addrs);
+ print_addrq_bestofall(ie, ifa_family);
+ /* TODO: Move to pass 1 */
if (c == '4')
netlink_groups |= RTMGRP_IPV4_IFADDR;
else
netlink_groups |= RTMGRP_IPV6_IFADDR;
break;
}
+ case 'a':
+ {
+ struct list_head *li;
+ struct ul_netaddrq_iface *ifaceq;
+
+ list_for_each_netaddrq_iface(li, &(ie->nl))
+ {
+ ifaceq = list_entry(li, struct ul_netaddrq_iface, entry);
+
+ dump_iface_good(ie, ifaceq);
+ }
+ }
+ break;
+ case 'A':
+ {
+ struct list_head *li;
+ struct ul_netaddrq_iface *ifaceq;
+
+ list_for_each_netaddrq_iface(li, &(ie->nl))
+ {
+ ifaceq = list_entry(li, struct ul_netaddrq_iface, entry);
+
+ dump_iface_all(ie, ifaceq);
+ }
+ }
+ break;
#endif
default:
putc(c, ie->output);

View File

@@ -0,0 +1,29 @@
From 16826c6675df3b6b28851c72f2dd1d194d3c7189 Mon Sep 17 00:00:00 2001
From: Stefan Schubert <schubi@suse.de>
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

View File

@@ -0,0 +1,86 @@
From a7f5e5c9f9c00823e04e89e9030337239a5bd7b8 Mon Sep 17 00:00:00 2001
From: Karel Zak <kzak@redhat.com>
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 <kzak@redhat.com>
---
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, &current, &name) == 0) {
--
2.48.1

View File

@@ -0,0 +1,41 @@
From dc1e88ff93f40f2f8093fcf35bda615a9384edcd Mon Sep 17 00:00:00 2001
From: Karel Zak <kzak@redhat.com>
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 <kzak@redhat.com>
---
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

View File

@@ -0,0 +1,108 @@
From 03066584f148a8429386c4a928d093913b3e85e2 Mon Sep 17 00:00:00 2001
From: Karel Zak <kzak@redhat.com>
Date: Wed, 1 Oct 2025 14:53:41 +0200
Subject: [PATCH 6/8] lib/configs: improve readability
Signed-off-by: Karel Zak <kzak@redhat.com>
---
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

View File

@@ -0,0 +1,35 @@
From ec71160db85acde32a9eca5fb238c82d6a6e52cb Mon Sep 17 00:00:00 2001
From: Karel Zak <kzak@redhat.com>
Date: Thu, 2 Oct 2025 11:55:55 +0200
Subject: [PATCH 7/8] lib/configs: initialize FD to -1
Signed-off-by: Karel Zak <kzak@redhat.com>
---
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

View File

@@ -0,0 +1,166 @@
From 6e723400a384c39f0df709b17af43e51c0a4f505 Mon Sep 17 00:00:00 2001
From: Stefan Schubert <schubi@suse.de>
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

View File

@@ -0,0 +1,512 @@
From 4109f4bfefff9e6cd65815399af3eab2b0a59104 Mon Sep 17 00:00:00 2001
From: Stefan Schubert <schubi@suse.de>
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, &current, &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

View File

@@ -0,0 +1,48 @@
From a5db8d0a9ed63969381feeee1eb0c3b39d32876b Mon Sep 17 00:00:00 2001
From: Stanislav Brabec <sbrabec@suse.cz>
Date: Sun, 5 Oct 2025 02:29:00 +0200
Subject: [PATCH 3/6] 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 <sbrabec@suse.cz>
---
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

View File

@@ -0,0 +1,42 @@
From 030303e4b93b65a5172a0c80f9f864b06f76cb81 Mon Sep 17 00:00:00 2001
From: Stanislav Brabec <sbrabec@suse.cz>
Date: Sun, 5 Oct 2025 02:53:17 +0200
Subject: [PATCH 4/6] 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 <sbrabec@suse.cz>
---
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

View File

@@ -0,0 +1,116 @@
From 60c5c0516e6ce52863b12343a1cd276423ab3bae Mon Sep 17 00:00:00 2001
From: Stanislav Brabec <sbrabec@suse.cz>
Date: Wed, 8 Oct 2025 01:14:32 +0200
Subject: [PATCH 5/6] 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 <sbrabec@suse.cz>
---
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

1602
util-linux-lib-netlink.patch Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,21 @@
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.

View File

@@ -1,3 +1,137 @@
-------------------------------------------------------------------
Thu Oct 16 01:24:14 UTC 2025 - Stanislav Brabec <sbrabec@suse.com>
- 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
(util-linux-lib-netlink-fix1.patch,
util-linux-lib-netlink-fix2.patch,
util-linux-lib-netlink-fix3.patch and
util-linux-agetty-netlink-fix4.patch).
- Fix configs library use in agetty (replace
util-linux-issuedir-usr-lib.patch by upstream
util-linux-lib-configs-fix1.patch,
add util-linux-lib-configs-fix2.patch,
util-linux-lib-configs-fix3.patch,
util-linux-lib-configs-fix4.patch,
util-linux-lib-configs-fix5.patch and
util-linux-lib-configs-fix6.patch).
- Fix agetty erase of escape characters (relevant to bsc#1194818,
util-linux-agetty-escape-erase.patch).
- Own /usr/lib/issue.d directory.
- Perform migration from issue-generator (jsc#PED-8734, fixes
boo#1244446).
- Drop util-linux-agetty-ssh-host-keys.patch. This feature is not
used in MicroOS any more.
- Remove Provides/Obsoletes for s390-32, upgrade from SLE11 SP1 is
no more supported.
-------------------------------------------------------------------
Tue Sep 30 18:35:50 UTC 2025 - Stanislav Brabec <sbrabec@suse.com>
- agetty: use /usr/lib/issue.d for backward compatibility
(util-linux-issuedir-usr-lib.patch).
-------------------------------------------------------------------
Sun Sep 28 07:15:32 UTC 2025 - Stanislav Brabec <sbrabec@suse.com>
- Fix address matching in agetty (boo#1247371,
util-linux-lib-netlink.patch).
- Update generated man pages (util-linux-man-generated.patch).
-------------------------------------------------------------------
Fri Sep 26 02:28:52 UTC 2025 - Stanislav Brabec <sbrabec@suse.com>
- Add configs library and use it in agetty
(gh#util-linux/util-linux#3752,
util-linux-lib-configs.patch, util-linux-agetty-configs.patch).
-------------------------------------------------------------------
Wed Sep 24 22:48:35 UTC 2025 - Stanislav Brabec <sbrabec@suse.com>
- Update to version 2.41.2:
* bash-completion:
* fix function name of enosys completion
* add choom and coresched
* blkid: correct an erroneous error message
* findmnt:
* (usage) add a needed equals sign before an optional argument
* add missing newline in --raw, --pair and --list output
formats
* fsck.cramfs: check buffer size for memcpy()
* getopt: document special symbols that should not be used as
option characters
* hardlink (man): add note note about ULFILEEQ_DEBUG=
* libblkid:
* Fix probe_ioctl_tp assigning BLKGETDISKSEQ as physical sector
size
* (ext) reduce false positive
* improve UUID_SUB= description
* lib/color-names:
* fix stupid bugs
* Fix color name canonicalization
* libfdisk:
* (script) improve separator usage in named-fields dump
* (script) fix device name separator parsing
* liblastlog2: markup fixes for man pages
* libmount: don't report fsconfig errors with "nofail"
* lib/path: avoid double free() for cpusets
* lib (treewide): add ul_ prefix to functions with generic names
* logger:
* fix buffer overflow when read stdin
* fix incorrect warning message when both --file and a message
are specified
* lsblk:
* fix possible use-after-free
* fix memory leak [coverity scan]
* use md as fallback TYPE when md/level empty
* lscpu:
* New Arm C1 parts
* Add NVIDIA Olympus arm64 core (jsc#PED-13683)
* man:
* Fixed incorrect ipcrm options
* Replace RETURN VALUE with EXIT STATUS in section 1
* mkfs.cramfs: avoid uninitialized value [coverity scan]
* more: temporarily ignore stdin when waiting for stderr
* rev: add --zero option to --help output
* setpriv: Improve getgroups() Portability
* sfdisk: reject spurious arguments for
--reorder/--backup-pt-sectors
* zramctl:
* ignore ENOENT when setting max_comp_streams
* fix MEM-USED column description
* Misc: Add missing ;; to -m case (#1)
* tests fixes
* translation updates
- Remove bash 5.3 hack for kill/decode. It is now fixed.
- Mark test script/options as failing. It randomly fails on
aarch64, arm7l and s390x inside OBS (needs research).
-------------------------------------------------------------------
Mon Aug 11 23:54:47 UTC 2025 - Stanislav Brabec <sbrabec@suse.com>
- Implement escape code for printing of ssh host keys in agetty
issue file (util-linux-agetty-ssh-host-keys.patch).
- Include fixes from
https://github.com/util-linux/util-linux/pull/3649 (jsc#PED-8734,
util-linux-lib-netlink.patch, util-linux-agetty-netlink.patch).
-------------------------------------------------------------------
Thu Jul 24 10:35:23 UTC 2025 - Dr. Werner Fink <werner@suse.de>
- For bash 5.3 add (SIG)INT tests/expected/kill/decode as ignored
signal for asynchronous coprocesses (boo#1246830)
-------------------------------------------------------------------
Thu Jul 10 02:39:17 UTC 2025 - Stanislav Brabec <sbrabec@suse.com>
- agetty: Implement netlink based IP address detection and issue
reload. It makes possible to identify IP addresses usability and
prefer stable global addresses over ephemeral or link-local
addresses. New issue keywords \a and \A were added. (boo#1139983,
jsc#PED-8734, util-linux-lib-netlink.patch,
util-linux-agetty-netlink.patch)
-------------------------------------------------------------------
Tue Jun 24 22:41:18 UTC 2025 - Stanislav Brabec <sbrabec@suse.com>

View File

@@ -85,7 +85,7 @@ Group: Development/Languages/Python
%endif
# ulbuild == python
Version: 2.41.1
Version: 2.41.2
Release: 0
License: GPL-2.0-or-later
URL: https://www.kernel.org/pub/linux/utils/util-linux/
@@ -110,6 +110,38 @@ 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.
Patch3: util-linux-bash-completion-su-chsh-l.patch
Patch5: static_lib.patch
# PATCH-FEATURE-UPSTREAM util-linux-lib-netlink.patch boo1139983 jsc#PED-8734 sbrabec@suse.com -- 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 sbrabec@suse.com -- 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 sbrabec@suse.com -- 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 sbrabec@suse.com -- 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 sbrabec@suse.com -- 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 sbrabec@suse.com -- Implement netlink based IP address detection and issue reload.
Patch11: util-linux-agetty-netlink-fix4.patch
# PATCH-FEATURE-UPSTREAM util-linux-lib-configs.patch gh#util-linux/util-linux#3752 schubi@suse.com -- Added lib "configs" for parsing configuration.
Patch12: util-linux-lib-configs.patch
# PATCH-FEATURE-UPSTREAM util-linux-agetty-configs.patch gh#util-linux/util-linux#3752 schubi@suse.com -- agetty: using configs lib for parsing issue files.
Patch13: util-linux-agetty-configs.patch
# PATCH-FIX-UPSTREAM util-linux-lib-configs-fix1.patch schubi@suse.com -- Fix agetty: using configs lib.
Patch14: util-linux-lib-configs-fix1.patch
# PATCH-FIX-UPSTREAM util-linux-lib-configs-fix2.patch sbrabec@suse.com -- Fix agetty: using configs lib.
Patch15: util-linux-lib-configs-fix2.patch
# PATCH-FIX-UPSTREAM util-linux-lib-configs-fix3.patch sbrabec@suse.com -- Fix agetty: using configs lib.
Patch16: util-linux-lib-configs-fix3.patch
# PATCH-FIX-UPSTREAM util-linux-lib-configs-fix4.patch sbrabec@suse.com -- Fix agetty: using configs lib.
Patch17: util-linux-lib-configs-fix4.patch
# PATCH-FIX-UPSTREAM util-linux-lib-configs-fix5.patch sbrabec@suse.com -- Fix agetty: using configs lib.
Patch18: util-linux-lib-configs-fix5.patch
# PATCH-FIX-UPSTREAM util-linux-lib-configs-fix6.patch schubi@suse.com -- Fix agetty: using configs lib.
Patch19: util-linux-lib-configs-fix6.patch
# PATCH-FIX-UPSTREAM util-linux-agetty-escape-erase.patch bsc#1194818 sbrabec@suse.com -- Fix agetty erase of escape characters.
Patch20: util-linux-agetty-escape-erase.patch
# PATCH-FIX-BUILD util-linux-man-generated.patch sbrabec@suse.com -- Update generated man pages modified by patches.
Patch21: util-linux-man-generated.patch
BuildRequires: audit-devel
BuildRequires: bc
BuildRequires: binutils-devel
@@ -173,20 +205,16 @@ Obsoletes: rfkill <= 0.5
# The last version was 1.0+git.e66999f.
Provides: hardlink = 1.1
Obsoletes: hardlink < 1.1
# bnc#805684:
%ifarch s390x
Obsoletes: s390-32
Provides: s390-32
%endif
# arch s390x
# New agetty fetures obsoleted issue-generator (up to SLE16 GA).
Provides: issue-generator = 1.13
Obsoletes: issue-generator <= 1.13
Supplements: filesystem(minix)
# All login.defs variables require support from shadow side.
# 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.17.4
Requires(post): coreutils
%endif
# ulsubset == core
@@ -613,7 +641,7 @@ fi
################
%if "%ulbuild" == "base"
%make_install
mkdir -p "%{buildroot}/%{_distconfdir}/default" "%{buildroot}/%{_pam_vendordir}" "%{buildroot}/%{_sysconfdir}/issue.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
@@ -768,6 +796,8 @@ export TS_OPT_hardlink_options_known_fail="yes"
export TS_OPT_misc_mountpoint_known_fail="yes"
# This test appears to be racy
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
#
# hacks
export PATH="$PATH:/sbin:/usr/sbin"
@@ -879,6 +909,17 @@ done
%post
%service_add_post fstrim.service fstrim.timer
# Migrate from issue-generator. Existed up to SLE16 GA
if systemctl is-enabled --quiet issue-generator.service ; then
rm -f `grep -l '\\\\[46]' /run/issue.d/70-*.conf 2>/dev/null` 2>/dev/null
rm -f /run/issue
fi
# The old issue layout causes double printing in util-linux >= 2.41. Existed up to SLE16 GA
if test -L /etc/issue ; then
if test "`readlink /etc/issue`" = ../run/issue ; then
rm /etc/issue
fi
fi
%preun
%service_del_preun fstrim.service fstrim.timer
@@ -977,6 +1018,7 @@ rmdir --ignore-fail-on-non-empty /run/run >/dev/null 2>&1 || :
# defined no_config
%config %dir %{_sysconfdir}/issue.d
%dir /usr/lib/issue.d
%if %{ul_extra_bin_sbin}
%core /bin/kill
%core %verify(not mode) %attr(%ul_suid,root,root) /bin/su
@@ -1429,11 +1471,13 @@ rmdir --ignore-fail-on-non-empty /run/run >/dev/null 2>&1 || :
%exclude %{_datadir}/bash-completion/completions/cfdisk
%exclude %{_datadir}/bash-completion/completions/chcpu
%exclude %{_datadir}/bash-completion/completions/chmem
%exclude %{_datadir}/bash-completion/completions/choom
%exclude %{_datadir}/bash-completion/completions/chrt
%exclude %{_datadir}/bash-completion/completions/col
%exclude %{_datadir}/bash-completion/completions/colcrt
%exclude %{_datadir}/bash-completion/completions/colrm
%exclude %{_datadir}/bash-completion/completions/column
%exclude %{_datadir}/bash-completion/completions/coresched
%exclude %{_datadir}/bash-completion/completions/ctrlaltdel
%exclude %{_datadir}/bash-completion/completions/delpart
%exclude %{_datadir}/bash-completion/completions/dmesg