import systemd-252-27.el9

i9c-beta changed/i9c-beta/systemd-252-27.el9
MSVSphere Packaging Team 8 months ago
parent ad07932520
commit d39f796a07

1
.gitignore vendored

@ -1 +1,2 @@
SOURCES/rhel-net-naming-sysattrs-v0.4.tar.gz
SOURCES/systemd-252.tar.gz SOURCES/systemd-252.tar.gz

@ -1 +1,2 @@
89b6d8ec519fd7d8b64f8d96b6cd0a65af97822b SOURCES/rhel-net-naming-sysattrs-v0.4.tar.gz
7c961dc6e8bb950825b85129f59dc80f4536cabb SOURCES/systemd-252.tar.gz 7c961dc6e8bb950825b85129f59dc80f4536cabb SOURCES/systemd-252.tar.gz

@ -0,0 +1,223 @@
From 55d337de1940076855c1687ffd588498d068724e Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Mon, 18 Sep 2023 13:51:43 +0200
Subject: [PATCH] ci: Extend source-git-automation
* on schedule and on demand workflows
* Added Tracker validation for Bugzilla and Jira
rhel-only
Resolves: RHEL-1086
---
.github/advanced-commit-linter.yml | 2 +
.github/tracker-validator.yml | 18 ++++
.../source-git-automation-on-demand.yml | 100 ++++++++++++++++++
.github/workflows/source-git-automation.yml | 29 ++++-
4 files changed, 147 insertions(+), 2 deletions(-)
create mode 100644 .github/tracker-validator.yml
create mode 100644 .github/workflows/source-git-automation-on-demand.yml
diff --git a/.github/advanced-commit-linter.yml b/.github/advanced-commit-linter.yml
index 0fb74a9dc8..86f0e911f2 100644
--- a/.github/advanced-commit-linter.yml
+++ b/.github/advanced-commit-linter.yml
@@ -11,6 +11,7 @@ policy:
- 'Resolves: #?'
- 'Related: #?'
- 'Reverts: #?'
+ type: bugzilla
issue-format:
- '\d+$'
url: 'https://bugzilla.redhat.com/show_bug.cgi?id='
@@ -18,6 +19,7 @@ policy:
- 'Resolves: '
- 'Related: '
- 'Reverts: '
+ type: jira
issue-format:
- 'RHEL-\d+$'
url: 'https://issues.redhat.com/browse/'
diff --git a/.github/tracker-validator.yml b/.github/tracker-validator.yml
new file mode 100644
index 0000000000..9e43e4e7d5
--- /dev/null
+++ b/.github/tracker-validator.yml
@@ -0,0 +1,18 @@
+labels:
+ missing-tracker: tracker/missing
+ invalid-product: tracker/invalid-product
+ invalid-component: tracker/invalid-component
+ unapproved: tracker/unapproved
+products:
+ - Red Hat Enterprise Linux 9
+ - CentOS Stream 9
+ - rhel-9.0.0
+ - rhel-9.2.0
+ - rhel-9.3.0
+ - rhel-9.4.0
+ - rhel-9.5.0
+ - rhel-9.6.0
+ - rhel-9.7.0
+ - rhel-9.8.0
+ - rhel-9.9.0
+ - rhel-9.10.0
diff --git a/.github/workflows/source-git-automation-on-demand.yml b/.github/workflows/source-git-automation-on-demand.yml
new file mode 100644
index 0000000000..60d7bcf32d
--- /dev/null
+++ b/.github/workflows/source-git-automation-on-demand.yml
@@ -0,0 +1,100 @@
+---
+
+name: Source git Automation Scheduled/On Demand
+on:
+ schedule:
+ # Workflow runs every 15 minutes
+ - cron: '*/15 * * * *'
+ workflow_dispatch:
+ inputs:
+ pr-number:
+ description: 'Pull Request number/s ; when not provided, the workflow will run for all open PRs'
+ required: true
+ default: '0'
+
+permissions:
+ contents: read
+
+jobs:
+ # Get all open PRs
+ gather-pull-requests:
+ if: github.repository == 'redhat-plumbers/systemd-rhel9'
+ runs-on: ubuntu-latest
+
+ outputs:
+ pr-numbers: ${{ steps.get-pr-numbers.outputs.result }}
+ pr-numbers-manual: ${{ steps.parse-manual-input.outputs.result }}
+
+ steps:
+ - id: get-pr-numbers
+ if: inputs.pr-number == '0'
+ name: Get all open PRs
+ uses: actions/github-script@v6
+ with:
+ # !FIXME: this is not working if there is more than 100 PRs opened
+ script: |
+ const { data: pullRequests } = await github.rest.pulls.list({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ state: 'open',
+ per_page: 100
+ });
+ return pullRequests.map(pr => pr.number);
+
+ - id: parse-manual-input
+ if: inputs.pr-number != '0'
+ name: Parse manual input
+ run: |
+ # shellcheck disable=SC2086
+ echo "result="[ ${{ inputs.pr-number }} ]"" >> $GITHUB_OUTPUT
+ shell: bash
+
+ validate-pr:
+ name: 'Validation of Pull Request #${{ matrix.pr-number }}'
+ needs: [ gather-pull-requests ]
+ runs-on: ubuntu-latest
+
+ strategy:
+ fail-fast: false
+ matrix:
+ pr-number: ${{ inputs.pr-number == 0 && fromJSON(needs.gather-pull-requests.outputs.pr-numbers) || fromJSON(needs.gather-pull-requests.outputs.pr-numbers-manual) }}
+
+ permissions:
+ statuses: write
+ checks: write
+ pull-requests: write
+
+ steps:
+ - name: Repository checkout
+ uses: actions/checkout@v3
+
+ - id: metadata
+ name: Gather Pull Request Metadata
+ uses: redhat-plumbers-in-action/gather-pull-request-metadata@v1
+ with:
+ pr-number: ${{ matrix.pr-number }}
+
+ - id: commit-linter
+ name: Lint Commits
+ uses: redhat-plumbers-in-action/advanced-commit-linter@v2
+ with:
+ pr-metadata: ${{ steps.metadata.outputs.metadata }}
+ token: ${{ secrets.GITHUB_TOKEN }}
+
+ # Validates tracker, changes tracker status, updates PR title
+ - id: tracker-validator
+ name: Validate Tracker
+ uses: redhat-plumbers-in-action/tracker-validator@v1
+ with:
+ pr-metadata: ${{ steps.metadata.outputs.metadata }}
+ component: systemd
+ tracker: ${{ fromJSON(steps.commit-linter.outputs.validated-pr-metadata).validation.tracker.id }}
+ tracker-type: ${{ fromJSON(steps.commit-linter.outputs.validated-pr-metadata).validation.tracker.type }}
+ bugzilla-instance: https://bugzilla.redhat.com
+ bugzilla-api-token: ${{ secrets.BUGZILLA_API_TOKEN }}
+ jira-instance: https://issues.redhat.com
+ jira-api-token: ${{ secrets.JIRA_API_TOKEN }}
+ token: ${{ secrets.GITHUB_TOKEN }}
+
+ # TODO: merge PR if all checks passed
+ # TODO: add comment to Tracker that PR was merged ...
diff --git a/.github/workflows/source-git-automation.yml b/.github/workflows/source-git-automation.yml
index e653e28a7f..7fabb88a83 100644
--- a/.github/workflows/source-git-automation.yml
+++ b/.github/workflows/source-git-automation.yml
@@ -12,7 +12,8 @@ jobs:
download-metadata:
if: >
github.event.workflow_run.event == 'pull_request' &&
- github.event.workflow_run.conclusion == 'success'
+ github.event.workflow_run.conclusion == 'success' &&
+ github.repository == 'redhat-plumbers/systemd-rhel9'
runs-on: ubuntu-latest
outputs:
@@ -33,13 +34,37 @@ jobs:
validated-pr-metadata: ${{ steps.commit-linter.outputs.validated-pr-metadata }}
permissions:
+ statuses: write
checks: write
pull-requests: write
steps:
- id: commit-linter
name: Lint Commits
- uses: redhat-plumbers-in-action/advanced-commit-linter@v1
+ uses: redhat-plumbers-in-action/advanced-commit-linter@v2
with:
pr-metadata: ${{ needs.download-metadata.outputs.pr-metadata }}
token: ${{ secrets.GITHUB_TOKEN }}
+
+ # Validates tracker, changes tracker status, updates PR title
+ tracker-validation:
+ needs: [ download-metadata, commit-linter ]
+ runs-on: ubuntu-latest
+
+ permissions:
+ checks: write
+ pull-requests: write
+
+ steps:
+ - name: Validate Tracker
+ uses: redhat-plumbers-in-action/tracker-validator@v1
+ with:
+ pr-metadata: ${{ needs.download-metadata.outputs.pr-metadata }}
+ component: systemd
+ tracker: ${{ fromJSON(needs.commit-linter.outputs.validated-pr-metadata).validation.tracker.id }}
+ tracker-type: ${{ fromJSON(needs.commit-linter.outputs.validated-pr-metadata).validation.tracker.type }}
+ bugzilla-instance: https://bugzilla.redhat.com
+ bugzilla-api-token: ${{ secrets.BUGZILLA_API_TOKEN }}
+ jira-instance: https://issues.redhat.com
+ jira-api-token: ${{ secrets.JIRA_API_TOKEN }}
+ token: ${{ secrets.GITHUB_TOKEN }}

@ -0,0 +1,159 @@
From dcc59dffa5116bf96618065cd60742cb660224b8 Mon Sep 17 00:00:00 2001
From: Lukas Nykryn <lnykryn@redhat.com>
Date: Fri, 22 Sep 2023 13:28:02 +0200
Subject: [PATCH] netif-naming-scheme: let's also include rhel8 schemes
With this patch user in rhel9 can also pick a scheme from rhel8.
This could be useful on in-place upgrades.
rhel-only
Resolves: RHEL-7026
---
man/systemd.net-naming-scheme.xml | 88 +++++++++++++++++++++++++++++++
src/shared/netif-naming-scheme.c | 10 ++++
src/shared/netif-naming-scheme.h | 12 +++++
3 files changed, 110 insertions(+)
diff --git a/man/systemd.net-naming-scheme.xml b/man/systemd.net-naming-scheme.xml
index ade4e27e31..c6ab86906a 100644
--- a/man/systemd.net-naming-scheme.xml
+++ b/man/systemd.net-naming-scheme.xml
@@ -459,6 +459,94 @@
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><constant>rhel-8.0</constant></term>
+
+ <listitem><para>Naming was changed for virtual network interfaces created with SR-IOV and NPAR and
+ for devices where the PCI network controller device does not have a slot number associated.</para>
+
+ <para>SR-IOV virtual devices are named based on the name of the parent interface, with a suffix of
+ <literal>v<replaceable>port</replaceable></literal>, where <replaceable>port</replaceable> is the
+ virtual device number. Previously those virtual devices were named as if completely independent.
+ </para>
+
+ <para>The ninth and later NPAR virtual devices are named following the scheme used for the first
+ eight NPAR partitions. Previously those devices were not renamed and the kernel default
+ ("eth<replaceable>N</replaceable>") was used.</para>
+
+ <para>Names are also generated for PCI devices where the PCI network controller device does not
+ have an associated slot number itself, but one of its parents does. Previously those devices were
+ not renamed and the kernel default was used.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>rhel-8.1</constant></term>
+
+ <para>Same as naming scheme <constant>rhel-8.0</constant>.</para>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>rhel-8.2</constant></term>
+
+ <para>Same as naming scheme <constant>rhel-8.0</constant>.</para>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>rhel-8.3</constant></term>
+
+ <para>Same as naming scheme <constant>rhel-8.0</constant>.</para>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>rhel-8.4</constant></term>
+
+ <listitem><para>If the PCI slot is assocated with PCI bridge and that has multiple child network
+ controllers then all of them might derive the same value of <varname>ID_NET_NAME_SLOT</varname>
+ property. That could cause naming conflict if the property is selected as a device name. Now, we detect the
+ situation, slot - bridge relation, and we don't produce the <varname>ID_NET_NAME_SLOT</varname> property to
+ avoid possible naming conflict.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>rhel-8.5</constant></term>
+
+ <para>Same as naming scheme <constant>rhel-8.4</constant>.</para>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>rhel-8.6</constant></term>
+
+ <para>Same as naming scheme <constant>rhel-8.4</constant>.</para>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>rhel-8.7</constant></term>
+
+ <listitem><para>PCI hotplug slot names for the s390 PCI driver are a hexadecimal representation
+ of the <filename>function_id</filename> device attribute. This attribute is now used to build the
+ <varname>ID_NET_NAME_SLOT</varname>. Before that, all slot names were parsed as decimal
+ numbers, which could either result in an incorrect value of the <varname>ID_NET_NAME_SLOT</varname>
+ property or none at all.</para>
+
+ <para>Some firmware and hypervisor implementations report unreasonable high numbers for the onboard
+ index. To prevent the generation of bogus onbard interface names, index numbers greater than 16381
+ (2^14-1) were ignored. For s390 PCI devices index values up to 65535 (2^16-1) are valid. To account
+ for that, the limit is increased to now 65535.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>rhel-8.8</constant></term>
+
+ <para>Same as naming scheme <constant>rhel-8.7</constant>.</para>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>rhel-8.9</constant></term>
+
+ <para>Same as naming scheme <constant>rhel-8.7</constant>.</para>
+ </varlistentry>
+
<varlistentry>
<term><constant>rhel-9.0</constant></term>
diff --git a/src/shared/netif-naming-scheme.c b/src/shared/netif-naming-scheme.c
index 0f50533279..9cfa5ca8e6 100644
--- a/src/shared/netif-naming-scheme.c
+++ b/src/shared/netif-naming-scheme.c
@@ -25,6 +25,16 @@ static const NamingScheme naming_schemes[] = {
{ "v250", NAMING_V250 },
{ "v251", NAMING_V251 },
{ "v252", NAMING_V252 },
+ { "rhel-8.0", NAMING_RHEL_8_0 },
+ { "rhel-8.1", NAMING_RHEL_8_1 },
+ { "rhel-8.2", NAMING_RHEL_8_2 },
+ { "rhel-8.3", NAMING_RHEL_8_3 },
+ { "rhel-8.4", NAMING_RHEL_8_4 },
+ { "rhel-8.5", NAMING_RHEL_8_5 },
+ { "rhel-8.6", NAMING_RHEL_8_6 },
+ { "rhel-8.7", NAMING_RHEL_8_7 },
+ { "rhel-8.8", NAMING_RHEL_8_8 },
+ { "rhel-8.9", NAMING_RHEL_8_9 },
{ "rhel-9.0", NAMING_RHEL_9_0 },
{ "rhel-9.1", NAMING_RHEL_9_1 },
{ "rhel-9.2", NAMING_RHEL_9_2 },
diff --git a/src/shared/netif-naming-scheme.h b/src/shared/netif-naming-scheme.h
index fb3c8eb9b3..ed45536f65 100644
--- a/src/shared/netif-naming-scheme.h
+++ b/src/shared/netif-naming-scheme.h
@@ -52,6 +52,18 @@ typedef enum NamingSchemeFlags {
NAMING_V250 = NAMING_V249 | NAMING_XEN_VIF,
NAMING_V251 = NAMING_V250 | NAMING_BRIDGE_MULTIFUNCTION_SLOT,
NAMING_V252 = NAMING_V251 | NAMING_DEVICETREE_ALIASES,
+
+ NAMING_RHEL_8_0 = NAMING_V239,
+ NAMING_RHEL_8_1 = NAMING_V239,
+ NAMING_RHEL_8_2 = NAMING_V239,
+ NAMING_RHEL_8_3 = NAMING_V239,
+ NAMING_RHEL_8_4 = NAMING_V239 | NAMING_BRIDGE_NO_SLOT,
+ NAMING_RHEL_8_5 = NAMING_RHEL_8_4,
+ NAMING_RHEL_8_6 = NAMING_RHEL_8_4,
+ NAMING_RHEL_8_7 = NAMING_RHEL_8_4 | NAMING_SLOT_FUNCTION_ID | NAMING_16BIT_INDEX,
+ NAMING_RHEL_8_8 = NAMING_RHEL_8_7,
+ NAMING_RHEL_8_9 = NAMING_RHEL_8_7,
+
NAMING_RHEL_9_0 = NAMING_V250 | NAMING_BRIDGE_MULTIFUNCTION_SLOT,
NAMING_RHEL_9_1 = NAMING_RHEL_9_0,
NAMING_RHEL_9_2 = NAMING_RHEL_9_0,

@ -0,0 +1,368 @@
From f898f9d1290a25d70f2be99f4cf142060ca7ae63 Mon Sep 17 00:00:00 2001
From: Joshua Zivkovic <joshua.zivkovic@codethink.co.uk>
Date: Wed, 2 Nov 2022 08:55:50 +0000
Subject: [PATCH] systemd-analyze: Add table and JSON output implementation to
plot
(cherry picked from commit ff46b2f97c42d73401ca3ffaaef54a017dc23923)
Resolves: RHEL-5070
---
src/analyze/analyze-plot.c | 168 ++++++++++++++++++++++++++-----------
src/analyze/analyze.c | 36 ++++++--
src/analyze/analyze.h | 2 +
3 files changed, 154 insertions(+), 52 deletions(-)
diff --git a/src/analyze/analyze-plot.c b/src/analyze/analyze-plot.c
index 100bdc3787..24f4add099 100644
--- a/src/analyze/analyze-plot.c
+++ b/src/analyze/analyze-plot.c
@@ -5,6 +5,7 @@
#include "analyze-time-data.h"
#include "bus-error.h"
#include "bus-map-properties.h"
+#include "format-table.h"
#include "sort-util.h"
#include "version.h"
@@ -37,7 +38,7 @@ typedef struct HostInfo {
char *architecture;
} HostInfo;
-static HostInfo* free_host_info(HostInfo *hi) {
+static HostInfo *free_host_info(HostInfo *hi) {
if (!hi)
return NULL;
@@ -87,7 +88,7 @@ static int acquire_host_info(sd_bus *bus, HostInfo **hi) {
}
r = bus_map_all_properties(
- system_bus ?: bus,
+ system_bus ? : bus,
"org.freedesktop.hostname1",
"/org/freedesktop/hostname1",
hostname_map,
@@ -156,15 +157,14 @@ static void svg_graph_box(double height, double begin, double end) {
SCALE_Y * height);
}
}
-
static int plot_unit_times(UnitTimes *u, double width, int y) {
bool b;
if (!u->name)
return 0;
- svg_bar("activating", u->activating, u->activated, y);
- svg_bar("active", u->activated, u->deactivating, y);
+ svg_bar("activating", u->activating, u->activated, y);
+ svg_bar("active", u->activated, u->deactivating, y);
svg_bar("deactivating", u->deactivating, u->deactivated, y);
/* place the text on the left if we have passed the half of the svg width */
@@ -178,41 +178,27 @@ static int plot_unit_times(UnitTimes *u, double width, int y) {
return 1;
}
-int verb_plot(int argc, char *argv[], void *userdata) {
- _cleanup_(free_host_infop) HostInfo *host = NULL;
- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
- _cleanup_(unit_times_free_arrayp) UnitTimes *times = NULL;
- _cleanup_free_ char *pretty_times = NULL;
- bool use_full_bus = arg_scope == LOOKUP_SCOPE_SYSTEM;
- BootTimes *boot;
+static void limit_times_to_boot(const BootTimes *boot, UnitTimes *u) {
+ if (u->deactivated > u->activating && u->deactivated <= boot->finish_time && u->activated == 0
+ && u->deactivating == 0)
+ u->activated = u->deactivating = u->deactivated;
+ if (u->activated < u->activating || u->activated > boot->finish_time)
+ u->activated = boot->finish_time;
+ if (u->deactivating < u->activated || u->deactivating > boot->finish_time)
+ u->deactivating = boot->finish_time;
+ if (u->deactivated < u->deactivating || u->deactivated > boot->finish_time)
+ u->deactivated = boot->finish_time;
+}
+
+static int produce_plot_as_svg(
+ UnitTimes *times,
+ const HostInfo *host,
+ const BootTimes *boot,
+ const char *pretty_times) {
+ int m = 1, y = 0;
UnitTimes *u;
- int n, m = 1, y = 0, r;
double width;
- r = acquire_bus(&bus, &use_full_bus);
- if (r < 0)
- return bus_log_connect_error(r, arg_transport);
-
- n = acquire_boot_times(bus, &boot);
- if (n < 0)
- return n;
-
- n = pretty_boot_time(bus, &pretty_times);
- if (n < 0)
- return n;
-
- if (use_full_bus || arg_scope != LOOKUP_SCOPE_SYSTEM) {
- n = acquire_host_info(bus, &host);
- if (n < 0)
- return n;
- }
-
- n = acquire_time_data(bus, &times);
- if (n <= 0)
- return n;
-
- typesafe_qsort(times, n, compare_unit_start);
-
width = SCALE_X * (boot->firmware_time + boot->finish_time);
if (width < 800.0)
width = 800.0;
@@ -245,16 +231,8 @@ int verb_plot(int argc, char *argv[], void *userdata) {
if (text_width > text_start && text_width + text_start > width)
width = text_width + text_start;
- if (u->deactivated > u->activating &&
- u->deactivated <= boot->finish_time &&
- u->activated == 0 && u->deactivating == 0)
- u->activated = u->deactivating = u->deactivated;
- if (u->activated < u->activating || u->activated > boot->finish_time)
- u->activated = boot->finish_time;
- if (u->deactivating < u->activated || u->deactivating > boot->finish_time)
- u->deactivating = boot->finish_time;
- if (u->deactivated < u->deactivating || u->deactivated > boot->finish_time)
- u->deactivated = boot->finish_time;
+ limit_times_to_boot(boot, u);
+
m++;
}
@@ -391,5 +369,101 @@ int verb_plot(int argc, char *argv[], void *userdata) {
svg("</svg>\n");
+ return 0;
+}
+
+static int show_table(Table *table, const char *word) {
+ int r;
+
+ assert(table);
+ assert(word);
+
+ if (table_get_rows(table) > 1) {
+ table_set_header(table, arg_legend);
+
+ if (!FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF))
+ r = table_print_json(table, NULL, arg_json_format_flags | JSON_FORMAT_COLOR_AUTO);
+ else
+ r = table_print(table, NULL);
+ if (r < 0)
+ return table_log_print_error(r);
+ }
+
+ if (arg_legend) {
+ if (table_get_rows(table) > 1)
+ printf("\n%zu %s listed.\n", table_get_rows(table) - 1, word);
+ else
+ printf("No %s.\n", word);
+ }
+
+ return 0;
+}
+
+static int produce_plot_as_text(UnitTimes *times, const BootTimes *boot) {
+ _cleanup_(table_unrefp) Table *table = NULL;
+ int r;
+
+ table = table_new("name", "activated", "activating", "time", "deactivated", "deactivating");
+ if (!table)
+ return log_oom();
+
+ for (; times->has_data; times++) {
+ limit_times_to_boot(boot, times);
+
+ r = table_add_many(
+ table,
+ TABLE_STRING, times->name,
+ TABLE_TIMESPAN_MSEC, times->activated,
+ TABLE_TIMESPAN_MSEC, times->activating,
+ TABLE_TIMESPAN_MSEC, times->time,
+ TABLE_TIMESPAN_MSEC, times->deactivated,
+ TABLE_TIMESPAN_MSEC, times->deactivating);
+ if (r < 0)
+ return table_log_add_error(r);
+ }
+
+ return show_table(table, "Units");
+}
+
+int verb_plot(int argc, char *argv[], void *userdata) {
+ _cleanup_(free_host_infop) HostInfo *host = NULL;
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+ _cleanup_(unit_times_free_arrayp) UnitTimes *times = NULL;
+ _cleanup_free_ char *pretty_times = NULL;
+ bool use_full_bus = arg_scope == LOOKUP_SCOPE_SYSTEM;
+ BootTimes *boot;
+ int n, r;
+
+ r = acquire_bus(&bus, &use_full_bus);
+ if (r < 0)
+ return bus_log_connect_error(r, arg_transport);
+
+ n = acquire_boot_times(bus, &boot);
+ if (n < 0)
+ return n;
+
+ n = pretty_boot_time(bus, &pretty_times);
+ if (n < 0)
+ return n;
+
+ if (use_full_bus || arg_scope != LOOKUP_SCOPE_SYSTEM) {
+ n = acquire_host_info(bus, &host);
+ if (n < 0)
+ return n;
+ }
+
+ n = acquire_time_data(bus, &times);
+ if (n <= 0)
+ return n;
+
+ typesafe_qsort(times, n, compare_unit_start);
+
+ if (!FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF) || arg_table)
+ r = produce_plot_as_text(times, boot);
+ else
+ r = produce_plot_as_svg(times, host, boot, pretty_times);
+ if (r < 0)
+ return r;
+
return EXIT_SUCCESS;
}
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index 6e47357a11..825c19c6f4 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -105,6 +105,8 @@ char *arg_unit = NULL;
JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
bool arg_quiet = false;
char *arg_profile = NULL;
+bool arg_legend = true;
+bool arg_table = false;
STATIC_DESTRUCTOR_REGISTER(arg_dot_from_patterns, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_dot_to_patterns, strv_freep);
@@ -217,8 +219,10 @@ static int help(int argc, char *argv[], void *userdata) {
" --security-policy=PATH Use custom JSON security policy instead\n"
" of built-in one\n"
" --json=pretty|short|off Generate JSON output of the security\n"
- " analysis table\n"
+ " analysis table, or plot's raw time data\n"
" --no-pager Do not pipe output into a pager\n"
+ " --no-legend Disable column headers and hints in plot\n"
+ " with either --table or --json=\n"
" --system Operate on system systemd instance\n"
" --user Operate on user systemd instance\n"
" --global Operate on global user configuration\n"
@@ -238,6 +242,7 @@ static int help(int argc, char *argv[], void *userdata) {
" specified time\n"
" --profile=name|PATH Include the specified profile in the\n"
" security review of the unit(s)\n"
+ " --table Output plot's raw time data as a table\n"
" -h --help Show this help\n"
" --version Show package version\n"
" -q --quiet Do not emit hints\n"
@@ -280,6 +285,8 @@ static int parse_argv(int argc, char *argv[]) {
ARG_SECURITY_POLICY,
ARG_JSON,
ARG_PROFILE,
+ ARG_TABLE,
+ ARG_NO_LEGEND,
};
static const struct option options[] = {
@@ -310,6 +317,8 @@ static int parse_argv(int argc, char *argv[]) {
{ "unit", required_argument, NULL, 'U' },
{ "json", required_argument, NULL, ARG_JSON },
{ "profile", required_argument, NULL, ARG_PROFILE },
+ { "table", optional_argument, NULL, ARG_TABLE },
+ { "no-legend", optional_argument, NULL, ARG_NO_LEGEND },
{}
};
@@ -448,14 +457,12 @@ static int parse_argv(int argc, char *argv[]) {
r = safe_atou(optarg, &arg_iterations);
if (r < 0)
return log_error_errno(r, "Failed to parse iterations: %s", optarg);
-
break;
case ARG_BASE_TIME:
r = parse_timestamp(optarg, &arg_base_time);
if (r < 0)
return log_error_errno(r, "Failed to parse --base-time= parameter: %s", optarg);
-
break;
case ARG_PROFILE:
@@ -486,6 +493,15 @@ static int parse_argv(int argc, char *argv[]) {
free_and_replace(arg_unit, mangled);
break;
}
+
+ case ARG_TABLE:
+ arg_table = true;
+ break;
+
+ case ARG_NO_LEGEND:
+ arg_legend = false;
+ break;
+
case '?':
return -EINVAL;
@@ -497,9 +513,9 @@ static int parse_argv(int argc, char *argv[]) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --offline= is only supported for security right now.");
- if (arg_json_format_flags != JSON_FORMAT_OFF && !STRPTR_IN_SET(argv[optind], "security", "inspect-elf"))
+ if (arg_json_format_flags != JSON_FORMAT_OFF && !STRPTR_IN_SET(argv[optind], "security", "inspect-elf", "plot"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Option --json= is only supported for security and inspect-elf right now.");
+ "Option --json= is only supported for security, inspect-elf, and plot right now.");
if (arg_threshold != 100 && !streq_ptr(argv[optind], "security"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
@@ -536,6 +552,16 @@ static int parse_argv(int argc, char *argv[]) {
if (streq_ptr(argv[optind], "condition") && arg_unit && optind < argc - 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No conditions can be passed if --unit= is used.");
+ if ((!arg_legend && !streq_ptr(argv[optind], "plot")) ||
+ (streq_ptr(argv[optind], "plot") && !arg_legend && !arg_table && FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Option --no-legend is only supported for plot with either --table or --json=.");
+
+ if (arg_table && !streq_ptr(argv[optind], "plot"))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Option --table is only supported for plot right now.");
+
+ if (arg_table && !FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--table and --json= are mutually exclusive.");
+
return 1; /* work to do */
}
diff --git a/src/analyze/analyze.h b/src/analyze/analyze.h
index da12058c43..e4af7b47e0 100644
--- a/src/analyze/analyze.h
+++ b/src/analyze/analyze.h
@@ -36,6 +36,8 @@ extern char *arg_unit;
extern JsonFormatFlags arg_json_format_flags;
extern bool arg_quiet;
extern char *arg_profile;
+extern bool arg_legend;
+extern bool arg_table;
int acquire_bus(sd_bus **bus, bool *use_full_bus);

@ -0,0 +1,69 @@
From 09514fbcaf51f1c12b651420e24400ff7319c638 Mon Sep 17 00:00:00 2001
From: joshuazivkovic <joshua.zivkovic@codethink.co.uk>
Date: Wed, 14 Dec 2022 12:31:22 +0000
Subject: [PATCH] systemd-analyze: Update man/systemd-analyze.xml with Plot
JSON and table
(cherry picked from commit dc57a3387bbe7770491f35e0d993f411237636b5)
Resolves: RHEL-5070
---
man/systemd-analyze.xml | 31 ++++++++++++++++++++++++++++---
1 file changed, 28 insertions(+), 3 deletions(-)
diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml
index 0d91cdd7d0..5ba0d40fa0 100644
--- a/man/systemd-analyze.xml
+++ b/man/systemd-analyze.xml
@@ -274,8 +274,8 @@ Timestamp units-load-finish: Thu 2019-03-14 23:28:07 CET
<refsect2>
<title><command>systemd-analyze plot</command></title>
- <para>This command prints an SVG graphic detailing which system services have been started at what
- time, highlighting the time they spent on initialization.</para>
+ <para>This command prints either an SVG graphic, detailing which system services have been started at what
+ time, highlighting the time they spent on initialization, or the raw time data in JSON or table format.</para>
<example>
<title><command>Plot a bootchart</command></title>
@@ -1204,7 +1204,17 @@ $ systemd-analyze verify /tmp/source:alias.service
corresponds to a higher security threat. The JSON version of the table is printed to standard
output. The <replaceable>MODE</replaceable> passed to the option can be one of three:
<option>off</option> which is the default, <option>pretty</option> and <option>short</option>
- which respectively output a prettified or shorted JSON version of the security table.</para></listitem>
+ which respectively output a prettified or shorted JSON version of the security table.
+
+ With the <command>plot</command> command, genereate a JSON formatted output of the raw time data.
+ The format is a JSON array with objects containing the following fields: <varname>name</varname>
+ which is the unit name, <varname>activated</varname> which is the time after startup the
+ service was activated, <varname>activating</varname> which is how long after startup the service
+ was initially started, <varname>time</varname> which is how long the service took to activate
+ from when it was initially started, <varname>deactivated</varname> which is the time after startup
+ that the service was deactivated, <varname>deactivating</varname> whcih is the time after startup
+ that the service was initially told to deactivate.
+ </para></listitem>
</varlistentry>
<varlistentry>
@@ -1235,6 +1245,21 @@ $ systemd-analyze verify /tmp/source:alias.service
other paths.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--table</option></term>
+
+ <listitem><para>When used with the <command>plot</command> command, the raw time data is output in a table.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--no-legend</option></term>
+
+ <listitem><para>When used with the <command>plot</command> command in combination with either
+ <option>--table</option> or <option>--json=</option>, no legends or hints are included in the output.
+ </para></listitem>
+ </varlistentry>
+
<xi:include href="user-system-options.xml" xpointer="host" />
<xi:include href="user-system-options.xml" xpointer="machine" />

@ -0,0 +1,87 @@
From a1bc66bfeac890107411686cb7567c9ffa926972 Mon Sep 17 00:00:00 2001
From: joshuazivkovic <joshua.zivkovic@codethink.co.uk>
Date: Wed, 14 Dec 2022 12:31:59 +0000
Subject: [PATCH] systemd-analyze: Add tab complete logic for plot
(cherry picked from commit f21a6502d81ca5690467cb161dafd4b875e4430e)
Resolves: RHEL-5070
---
shell-completion/bash/systemd-analyze | 8 +++++++-
shell-completion/zsh/_systemd-analyze | 14 ++++++++++++--
2 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/shell-completion/bash/systemd-analyze b/shell-completion/bash/systemd-analyze
index b1baec9978..5edba7bf58 100644
--- a/shell-completion/bash/systemd-analyze
+++ b/shell-completion/bash/systemd-analyze
@@ -62,7 +62,7 @@ _systemd_analyze() {
)
local -A VERBS=(
- [STANDALONE]='time blame plot unit-paths exit-status calendar timestamp timespan'
+ [STANDALONE]='time blame unit-paths exit-status calendar timestamp timespan'
[CRITICAL_CHAIN]='critical-chain'
[DOT]='dot'
[DUMP]='dump'
@@ -72,6 +72,7 @@ _systemd_analyze() {
[SECURITY]='security'
[CONDITION]='condition'
[INSPECT_ELF]='inspect-elf'
+ [PLOT]='plot'
)
local CONFIGS='systemd/bootchart.conf systemd/coredump.conf systemd/journald.conf
@@ -195,6 +196,11 @@ _systemd_analyze() {
comps=$( compgen -A file -- "$cur" )
compopt -o filenames
fi
+
+ elif __contains_word "$verb" ${VERBS[PLOT]}; then
+ if [[ $cur = -* ]]; then
+ comps='--help --version --system --user --global --no-pager --json=off --json=pretty --json=short --table --no-legend'
+ fi
fi
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
diff --git a/shell-completion/zsh/_systemd-analyze b/shell-completion/zsh/_systemd-analyze
index e305995cef..2e046ea111 100644
--- a/shell-completion/zsh/_systemd-analyze
+++ b/shell-completion/zsh/_systemd-analyze
@@ -40,6 +40,13 @@
_describe -t groups 'file system groups' _groups || compadd "$@"
}
+(( $+functions[_systemd-analyze_plot] )) ||
+ _systemd-analyze_plot() {
+ local -a _options
+ _options=( '--json=off' '--json=pretty' '--json=short' '--table' '--no-legend' )
+ _describe 'plot options' _options
+ }
+
(( $+functions[_systemd-analyze_commands] )) ||
_systemd-analyze_commands(){
local -a _systemd_analyze_cmds
@@ -48,7 +55,8 @@
'time:Print time spent in the kernel before reaching userspace'
'blame:Print list of running units ordered by time to init'
'critical-chain:Print a tree of the time critical chain of units'
- 'plot:Output SVG graphic showing service initialization'
+ 'plot:Output SVG graphic showing service initialization, or raw time data in
+JSON or table format'
'dot:Dump dependency graph (in dot(1) format)'
'dump:Dump server status'
'cat-config:Cat systemd config files'
@@ -97,9 +105,11 @@ _arguments \
'--offline=[Perform a security review of the specified unit files]:BOOL:(yes no)' \
'--threshold=[Set a value to compare the overall security exposure level with]: NUMBER' \
'--security-policy=[Use customized requirements to compare unit files against]: PATH' \
- '--json=[Generate a JSON output of the security analysis table]:MODE:(pretty short off)' \
+ "--json=[Generate a JSON output of the security analysis table or plot's raw time data]:MODE:(pretty short off)" \
+ "--table=[Generate a table of plot's raw time data]" \
'--profile=[Include the specified profile in the security review of units]: PATH' \
'--no-pager[Do not pipe output into a pager]' \
+ "--no-legend[Do not show the headers and footers for plot's raw time data formats]" \
'--man=[Do (not) check for existence of man pages]:BOOL:(yes no)' \
'--generators=[Do (not) run unit generators]:BOOL:(yes no)' \
'--order[When generating graph for dot, show only order]' \

@ -0,0 +1,34 @@
From 503c6777cc0a05e4ba174ff674fdf9ce3ed87341 Mon Sep 17 00:00:00 2001
From: joshuazivkovic <joshua.zivkovic@codethink.co.uk>
Date: Fri, 13 Jan 2023 09:17:27 +0000
Subject: [PATCH] systemd-analyze: Add --json=, --table and -no-legend tests
for plot
(cherry picked from commit a23be57de3a5c5afb9ca878775ae838c3341f90c)
Resolves: RHEL-5070
---
test/units/testsuite-65.sh | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/test/units/testsuite-65.sh b/test/units/testsuite-65.sh
index ebe1f57b52..4093c5a2a7 100755
--- a/test/units/testsuite-65.sh
+++ b/test/units/testsuite-65.sh
@@ -18,7 +18,16 @@ systemd-analyze || :
systemd-analyze time || :
systemd-analyze blame || :
systemd-analyze critical-chain || :
+# plot
systemd-analyze plot >/dev/null || :
+systemd-analyze plot --json=pretty >/dev/null || :
+systemd-analyze plot --json=short >/dev/null || :
+systemd-analyze plot --json=off >/dev/null || :
+systemd-analyze plot --json=pretty --no-legend >/dev/null || :
+systemd-analyze plot --json=short --no-legend >/dev/null || :
+systemd-analyze plot --json=off --no-legend >/dev/null || :
+systemd-analyze plot --table >/dev/null || :
+systemd-analyze plot --table --no-legend >/dev/null || :
# legacy/deprecated options (moved to systemctl, but still usable from analyze)
systemd-analyze log-level
systemd-analyze log-level "$(systemctl log-level)"

@ -0,0 +1,95 @@
From 16f06c8cfbdf660e1c4e2052b7dd121f3497ff0f Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Wed, 18 Oct 2023 15:24:23 +0200
Subject: [PATCH] ci: enable source-git automation to validate reviews and ci
results
rhel-only
Related: RHEL-1086
---
.github/pull-request-validator.yml | 4 ++++
.../source-git-automation-on-demand.yml | 14 ++++++++++----
.github/workflows/source-git-automation.yml | 18 +++++++++++++++++-
3 files changed, 31 insertions(+), 5 deletions(-)
create mode 100644 .github/pull-request-validator.yml
diff --git a/.github/pull-request-validator.yml b/.github/pull-request-validator.yml
new file mode 100644
index 0000000000..4bb5bbec12
--- /dev/null
+++ b/.github/pull-request-validator.yml
@@ -0,0 +1,4 @@
+labels:
+ missing-review: pr/needs-review
+ changes-requested: pr/changes-requested
+ missing-failing-ci: pr/needs-ci
diff --git a/.github/workflows/source-git-automation-on-demand.yml b/.github/workflows/source-git-automation-on-demand.yml
index 60d7bcf32d..2dd6af3113 100644
--- a/.github/workflows/source-git-automation-on-demand.yml
+++ b/.github/workflows/source-git-automation-on-demand.yml
@@ -74,7 +74,8 @@ jobs:
with:
pr-number: ${{ matrix.pr-number }}
- - id: commit-linter
+ - if: ${{ !cancelled() }}
+ id: commit-linter
name: Lint Commits
uses: redhat-plumbers-in-action/advanced-commit-linter@v2
with:
@@ -82,7 +83,8 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }}
# Validates tracker, changes tracker status, updates PR title
- - id: tracker-validator
+ - if: ${{ !cancelled() }}
+ id: tracker-validator
name: Validate Tracker
uses: redhat-plumbers-in-action/tracker-validator@v1
with:
@@ -96,5 +98,9 @@ jobs:
jira-api-token: ${{ secrets.JIRA_API_TOKEN }}
token: ${{ secrets.GITHUB_TOKEN }}
- # TODO: merge PR if all checks passed
- # TODO: add comment to Tracker that PR was merged ...
+ - if: ${{ !cancelled() }}
+ name: Pull Request Validator
+ uses: redhat-plumbers-in-action/pull-request-validator@v1
+ with:
+ pr-metadata: ${{ steps.metadata.outputs.metadata }}
+ token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/source-git-automation.yml b/.github/workflows/source-git-automation.yml
index 7fabb88a83..214e72de6f 100644
--- a/.github/workflows/source-git-automation.yml
+++ b/.github/workflows/source-git-automation.yml
@@ -47,7 +47,8 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }}
# Validates tracker, changes tracker status, updates PR title
- tracker-validation:
+ tracker-validator:
+ if: ${{ !cancelled() }}
needs: [ download-metadata, commit-linter ]
runs-on: ubuntu-latest
@@ -68,3 +69,18 @@ jobs:
jira-instance: https://issues.redhat.com
jira-api-token: ${{ secrets.JIRA_API_TOKEN }}
token: ${{ secrets.GITHUB_TOKEN }}
+
+ pull-request-validator:
+ needs: [ download-metadata ]
+ runs-on: ubuntu-latest
+
+ permissions:
+ checks: write
+ pull-requests: write
+
+ steps:
+ - name: Pull Request Validator
+ uses: redhat-plumbers-in-action/pull-request-validator@v1
+ with:
+ pr-metadata: ${{ needs.download-metadata.outputs.pr-metadata }}
+ token: ${{ secrets.GITHUB_TOKEN }}

@ -0,0 +1,181 @@
From c31597c9112c4676f918b14999506a586d6ef8f4 Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Wed, 18 Oct 2023 15:47:54 +0200
Subject: [PATCH] ci: remove Mergify config - replaced by Pull Request
Validator
rhel-only
Related: RHEL-1086
---
.mergify.yml | 161 ---------------------------------------------------
1 file changed, 161 deletions(-)
delete mode 100644 .mergify.yml
diff --git a/.mergify.yml b/.mergify.yml
deleted file mode 100644
index e862808ca7..0000000000
--- a/.mergify.yml
+++ /dev/null
@@ -1,161 +0,0 @@
-# doc: https://docs.mergify.com
----
-
-pull_request_rules:
- - name: Add `needs-ci` label on CI fail - v252
- conditions:
- # Policy is relevant for rhel-9.2.0 branches and newer & main branch
- - base~=^main$|^rhel-9.([2-9]|\d{2,}).0$
- - label!=ci-waived
- - or:
- # Build test
- # test build check only when the tests have been run ...
- - and:
- - files~=^(\S+\/meson\.build|\.github\/workflows\/\S+|meson_options\.txt|src\/\S+|test\/fuzz\/\S+)
- - or:
- - -check-success=build (gcc, 11, bfd, gcrypt)
- - -check-success=build (gcc, 12, gold, openssl)
- - -check-success=build (clang, 13, mold, gcrypt)
- - -check-success=build (clang, 14, lld, openssl)
- - -check-success=build (clang, 15, bfd, auto)
- # Unit tests
- - -check-success=build (GCC, auto)
- - -check-success=build (GCC_ASAN_UBSAN, auto)
- - -check-success=build (CLANG, auto)
- - -check-success=build (CLANG_RELEASE, auto)
- - -check-success=build (CLANG_ASAN_UBSAN, auto)
- - -check-success=build (CLANG_ASAN_UBSAN_NO_DEPS, auto)
- - -check-success=build (GCC, openssl)
- - -check-success=build (CLANG, gcrypt)
- # ClusterFuzzingLite
- - -check-success=PR (address)
- - -check-success=PR (undefined)
- - -check-success=PR (memory)
- # CentOS CI
- - -check-success=CentOS CI (CentOS Stream 9)
- - -check-success=CentOS CI (CentOS Stream 9 + sanitizers)
- # Packit
- - -check-success=rpm-build:centos-stream-9-aarch64
- - -check-success=rpm-build:centos-stream-9-x86_64
- # Other
- - -check-success=Lint Code Base
- - -check-success=Differential ShellCheck
- # CodeQL
- # test CodeQL check only when the CodeQL have been run ...
- - and:
- - files~=^(\S+\/meson\.build|\.github\/\S+\/codeql|src\/\S+|test\/\S+|tools\/\S+)
- - -check-success=CodeQL
- actions:
- label:
- add:
- - needs-ci
-
- - name: Add `needs-ci` label on CI fail - v250
- conditions:
- # Policy is relevant branches before rhel-9.2.0
- - base~=^rhel-9.0.0-beta$|^rhel-9.[0-1].0$
- - label!=ci-waived
- - or:
- # Build test
- - -check-success=build (gcc, 10, bfd)
- - -check-success=build (gcc, 11, gold)
- - -check-success=build (clang, 11, bfd)
- - -check-success=build (clang, 12, gold)
- - -check-success=build (clang, 13, lld)
- # Unit tests
- - -check-success=build (GCC, auto)
- - -check-success=build (GCC_ASAN_UBSAN, auto)
- - -check-success=build (CLANG, auto)
- - -check-success=build (CLANG_ASAN_UBSAN, auto)
- - -check-success=build (GCC, openssl)
- - -check-success=build (CLANG, gcrypt)
- # CentOS CI
- - -check-success=CentOS CI (CentOS Stream 9)
- - -check-success=CentOS CI (CentOS Stream 9 + sanitizers)
- # Packit
- - -check-success=rpm-build:centos-stream-9-aarch64
- - -check-success=rpm-build:centos-stream-9-x86_64
- actions:
- label:
- add:
- - needs-ci
-
- - name: Remove `needs-ci` label on CI success - v252
- conditions:
- # Policy is relevant for rhel-9.2.0 branches and newer & main branch
- - base~=^main$|^rhel-9.([2-9]|\d{2,}).0$
- - or:
- - label=ci-waived
- - and:
- # Build test
- # test build check only when specific files are changed ...
- - or:
- - -files~=^(\S+\/meson\.build|\.github\/workflows\/\S+|meson_options\.txt|src\/\S+|test\/fuzz\/\S+)
- - and:
- - check-success=build (gcc, 11, bfd, gcrypt)
- - check-success=build (gcc, 12, gold, openssl)
- - check-success=build (clang, 13, mold, gcrypt)
- - check-success=build (clang, 14, lld, openssl)
- - check-success=build (clang, 15, bfd, auto)
- # Unit tests
- - check-success=build (GCC, auto)
- - check-success=build (GCC_ASAN_UBSAN, auto)
- - check-success=build (CLANG, auto)
- - check-success=build (CLANG_RELEASE, auto)
- - check-success=build (CLANG_ASAN_UBSAN, auto)
- - check-success=build (CLANG_ASAN_UBSAN_NO_DEPS, auto)
- - check-success=build (GCC, openssl)
- - check-success=build (CLANG, gcrypt)
- # ClusterFuzzingLite
- - check-success=PR (address)
- - check-success=PR (undefined)
- - check-success=PR (memory)
- # CentOS CI
- - check-success=CentOS CI (CentOS Stream 9)
- - check-success=CentOS CI (CentOS Stream 9 + sanitizers)
- # CodeQL
- # test CodeQL check only when specific files are changed ...
- - or:
- - -files~=^(\S+\/meson\.build|\.github\/\S+\/codeql|src\/\S+|test\/\S+|tools\/\S+)
- - check-success=CodeQL
- # Packit
- - check-success=rpm-build:centos-stream-9-aarch64
- - check-success=rpm-build:centos-stream-9-x86_64
- # Other
- - check-success=Lint Code Base
- - check-success=Differential ShellCheck
- actions:
- label:
- remove:
- - needs-ci
-
- - name: Remove `needs-ci` label on CI success - v250
- conditions:
- # Policy is relevant branches before rhel-9.2.0
- - base~=^rhel-9.0.0-beta$|^rhel-9.[0-1].0$
- - or:
- - label=ci-waived
- - and:
- # Build test
- - check-success=build (gcc, 10, bfd)
- - check-success=build (gcc, 11, gold)
- - check-success=build (clang, 11, bfd)
- - check-success=build (clang, 12, gold)
- - check-success=build (clang, 13, lld)
- # Unit tests
- - check-success=build (GCC, auto)
- - check-success=build (GCC_ASAN_UBSAN, auto)
- - check-success=build (CLANG, auto)
- - check-success=build (CLANG_ASAN_UBSAN, auto)
- - check-success=build (GCC, openssl)
- - check-success=build (CLANG, gcrypt)
- # CentOS CI
- - check-success=CentOS CI (CentOS Stream 9)
- - check-success=CentOS CI (CentOS Stream 9 + sanitizers)
- # Packit
- - check-success=rpm-build:centos-stream-9-aarch64
- - check-success=rpm-build:centos-stream-9-x86_64
- actions:
- label:
- remove:
- - needs-ci

@ -0,0 +1,84 @@
From 34adeef90a0a8cc1210742e5623968cbb39222eb Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Fri, 3 Nov 2023 12:32:18 +0100
Subject: [PATCH] ci: enable auto-merge GH Action
rhel-only
Related: RHEL-1086
---
.github/auto-merge.yml | 4 ++++
.../source-git-automation-on-demand.yml | 14 ++++++++++++
.github/workflows/source-git-automation.yml | 22 +++++++++++++++++++
3 files changed, 40 insertions(+)
create mode 100644 .github/auto-merge.yml
diff --git a/.github/auto-merge.yml b/.github/auto-merge.yml
new file mode 100644
index 0000000000..35c2539295
--- /dev/null
+++ b/.github/auto-merge.yml
@@ -0,0 +1,4 @@
+labels:
+ dont-merge: dont-merge
+ manual-merge: pr/needs-manual-merge
+target-branch': ['main']
diff --git a/.github/workflows/source-git-automation-on-demand.yml b/.github/workflows/source-git-automation-on-demand.yml
index 2dd6af3113..2c506f2b3e 100644
--- a/.github/workflows/source-git-automation-on-demand.yml
+++ b/.github/workflows/source-git-automation-on-demand.yml
@@ -60,6 +60,7 @@ jobs:
pr-number: ${{ inputs.pr-number == 0 && fromJSON(needs.gather-pull-requests.outputs.pr-numbers) || fromJSON(needs.gather-pull-requests.outputs.pr-numbers-manual) }}
permissions:
+ contents: write
statuses: write
checks: write
pull-requests: write
@@ -104,3 +105,16 @@ jobs:
with:
pr-metadata: ${{ steps.metadata.outputs.metadata }}
token: ${{ secrets.GITHUB_TOKEN }}
+
+ - id: auto-merge
+ name: Auto Merge
+ uses: redhat-plumbers-in-action/auto-merge@v1
+ with:
+ pr-metadata: ${{ steps.metadata.outputs.metadata }}
+ tracker: ${{ fromJSON(steps.commit-linter.outputs.validated-pr-metadata).validation.tracker.id }}
+ tracker-type: ${{ fromJSON(steps.commit-linter.outputs.validated-pr-metadata).validation.tracker.type }}
+ bugzilla-instance: https://bugzilla.redhat.com
+ bugzilla-api-token: ${{ secrets.BUGZILLA_API_TOKEN }}
+ jira-instance: https://issues.redhat.com
+ jira-api-token: ${{ secrets.JIRA_API_TOKEN }}
+ token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/source-git-automation.yml b/.github/workflows/source-git-automation.yml
index 214e72de6f..17135b590f 100644
--- a/.github/workflows/source-git-automation.yml
+++ b/.github/workflows/source-git-automation.yml
@@ -84,3 +84,25 @@ jobs:
with:
pr-metadata: ${{ needs.download-metadata.outputs.pr-metadata }}
token: ${{ secrets.GITHUB_TOKEN }}
+
+ auto-merge:
+ needs: [ download-metadata, commit-linter, tracker-validator, pull-request-validator ]
+ runs-on: ubuntu-latest
+
+ permissions:
+ contents: write
+ checks: write
+ pull-requests: write
+
+ steps:
+ - name: Auto Merge
+ uses: redhat-plumbers-in-action/auto-merge@v1
+ with:
+ pr-metadata: ${{ needs.download-metadata.outputs.pr-metadata }}
+ tracker: ${{ fromJSON(needs.commit-linter.outputs.validated-pr-metadata).validation.tracker.id }}
+ tracker-type: ${{ fromJSON(needs.commit-linter.outputs.validated-pr-metadata).validation.tracker.type }}
+ bugzilla-instance: https://bugzilla.redhat.com
+ bugzilla-api-token: ${{ secrets.BUGZILLA_API_TOKEN }}
+ jira-instance: https://issues.redhat.com
+ jira-api-token: ${{ secrets.JIRA_API_TOKEN }}
+ token: ${{ secrets.GITHUB_TOKEN }}

@ -0,0 +1,41 @@
From 715b05f97cde12424bb6d425264569f7f921dc72 Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Tue, 7 Nov 2023 13:33:40 +0100
Subject: [PATCH] ci: add missing permissions
issues: write is required for the pull request merging according to:
https://github.com/cli/cli/discussions/6379#discussioncomment-3806051
rhel-only
Related: RHEL-1086
---
.github/workflows/source-git-automation-on-demand.yml | 1 +
.github/workflows/source-git-automation.yml | 1 +
2 files changed, 2 insertions(+)
diff --git a/.github/workflows/source-git-automation-on-demand.yml b/.github/workflows/source-git-automation-on-demand.yml
index 2c506f2b3e..bf2ea2260c 100644
--- a/.github/workflows/source-git-automation-on-demand.yml
+++ b/.github/workflows/source-git-automation-on-demand.yml
@@ -63,6 +63,7 @@ jobs:
contents: write
statuses: write
checks: write
+ issues: write
pull-requests: write
steps:
diff --git a/.github/workflows/source-git-automation.yml b/.github/workflows/source-git-automation.yml
index 17135b590f..d71664efa0 100644
--- a/.github/workflows/source-git-automation.yml
+++ b/.github/workflows/source-git-automation.yml
@@ -92,6 +92,7 @@ jobs:
permissions:
contents: write
checks: write
+ issues: write
pull-requests: write
steps:

@ -0,0 +1,47 @@
From 3d7593697ac29c7308ef72453a621a1d24662415 Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Tue, 7 Nov 2023 14:25:02 +0100
Subject: [PATCH] ci: `permissions: write-all`
rhel-only
Related: RHEL-1086
---
.github/workflows/source-git-automation-on-demand.yml | 11 +++++------
.github/workflows/source-git-automation.yml | 1 -
2 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/.github/workflows/source-git-automation-on-demand.yml b/.github/workflows/source-git-automation-on-demand.yml
index bf2ea2260c..3f3da959c4 100644
--- a/.github/workflows/source-git-automation-on-demand.yml
+++ b/.github/workflows/source-git-automation-on-demand.yml
@@ -59,12 +59,11 @@ jobs:
matrix:
pr-number: ${{ inputs.pr-number == 0 && fromJSON(needs.gather-pull-requests.outputs.pr-numbers) || fromJSON(needs.gather-pull-requests.outputs.pr-numbers-manual) }}
- permissions:
- contents: write
- statuses: write
- checks: write
- issues: write
- pull-requests: write
+ permissions: write-all
+ # contents: write
+ # statuses: write
+ # checks: write
+ # pull-requests: write
steps:
- name: Repository checkout
diff --git a/.github/workflows/source-git-automation.yml b/.github/workflows/source-git-automation.yml
index d71664efa0..17135b590f 100644
--- a/.github/workflows/source-git-automation.yml
+++ b/.github/workflows/source-git-automation.yml
@@ -92,7 +92,6 @@ jobs:
permissions:
contents: write
checks: write
- issues: write
pull-requests: write
steps:

@ -0,0 +1,33 @@
From 594d2eb17d4548313eddf4e13ac8c734b268ae93 Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Mon, 7 Aug 2023 15:11:00 +0200
Subject: [PATCH] ci(lint): exclude `.in` files from ShellCheck lint
Exclude all `.in` files because they may contain unsupported syntax, and
they have to be preprocessed first. For example:
```sh
Error: SHELLCHECK_WARNING:
./src/rpm/systemd-update-helper.in:130:37: warning[SC1083]: This { is literal. Check expression (missing ;/\n?) or quote it.
```
Related to: https://github.com/systemd/systemd/pull/28521
(cherry picked from commit 97eb82682126e7f3ee956a025078ea2b801955cb)
Related: RHEL-1086
---
.github/workflows/differential-shellcheck.yml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.github/workflows/differential-shellcheck.yml b/.github/workflows/differential-shellcheck.yml
index 3662126304..0d3eee48e2 100644
--- a/.github/workflows/differential-shellcheck.yml
+++ b/.github/workflows/differential-shellcheck.yml
@@ -32,4 +32,6 @@ jobs:
- name: Differential ShellCheck
uses: redhat-plumbers-in-action/differential-shellcheck@v4
with:
+ # exclude all `.in` files because they may contain unsupported syntax, and they have to be preprocessed first
+ exclude-path: '**/*.in'
token: ${{ secrets.GITHUB_TOKEN }}

@ -0,0 +1,43 @@
From 5221edaee281175e3a8ba3e676ba5622085eb1ef Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 26 Sep 2023 09:52:05 +0200
Subject: [PATCH] udev: raise RLIMIT_NOFILE as high as we can
We might need a lot of fds on large systems, hence raise RLIMIT_NOFILE
to what the service manager allows us, which is quite a lot these days.
udev already sets FORK_RLIMIT_NOFILE_SAFE when forking of chilren, thus
ensuring that forked off processes get their RLIMIT_NOFILE soft limit
reset to 1K for compat with crappy old select().
Replaces: #29298
Fixes: #28583
(cherry picked from commit 1617424ce76d797d081dd6cb1082b954c4d2bf38)
Resolves: RHEL-11040
---
src/udev/udevd.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index e3a2742733..ccc3c0eece 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -55,6 +55,7 @@
#include "pretty-print.h"
#include "proc-cmdline.h"
#include "process-util.h"
+#include "rlimit-util.h"
#include "selinux-util.h"
#include "signal-util.h"
#include "socket-util.h"
@@ -2040,6 +2041,9 @@ int run_udevd(int argc, char *argv[]) {
if (r < 0)
return r;
+ /* Make sure we can have plenty fds (for example for pidfds) */
+ (void) rlimit_nofile_bump(-1);
+
r = RET_NERRNO(mkdir("/run/udev", 0755));
if (r < 0 && r != -EEXIST)
return log_error_errno(r, "Failed to create /run/udev: %m");

@ -0,0 +1,37 @@
From 57d5e48a572b98d6ab978072daddac2f7faf8dc8 Mon Sep 17 00:00:00 2001
From: Nick Rosbrook <nick.rosbrook@canonical.com>
Date: Wed, 2 Nov 2022 11:05:01 -0400
Subject: [PATCH] udev/net: allow new link name as an altname before renaming
happens
When configuring a link's alternative names, the link's new name to-be
is not allowed to be included because interface renaming will fail if
the new name is already present as an alternative name. However,
rtnl_set_link_name will delete the conflicting alternative name before
renaming the device, if necessary.
Allow the new link name to be set as an alternative name before the
device is renamed. This means that if the rename is later skipped (i.e.
because the link is already up), then the name can at least still be
present as an alternative name.
(cherry picked from commit d0b31efc1ab7f6826ad834cf6b9e371bf73776aa)
Related: RHEL-5988
---
src/udev/net/link-config.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
index e408725b08..5d28526527 100644
--- a/src/udev/net/link-config.c
+++ b/src/udev/net/link-config.c
@@ -841,8 +841,6 @@ static int link_apply_alternative_names(Link *link, sd_netlink **rtnl) {
}
}
- if (link->new_name)
- strv_remove(altnames, link->new_name);
strv_remove(altnames, link->ifname);
r = rtnl_get_link_alternative_names(rtnl, link->ifindex, &current_altnames);

@ -0,0 +1,64 @@
From ded04e17443f1e9a99705d39ae7dde72eb24ef34 Mon Sep 17 00:00:00 2001
From: Nick Rosbrook <nick.rosbrook@canonical.com>
Date: Fri, 2 Dec 2022 15:26:18 -0500
Subject: [PATCH] sd-netlink: do not swap old name and alternative name
Commit 434a348380 ("netlink: do not fail when new interface name is
already used as an alternative name") added logic to set the old
interface name as an alternative name, but only when the new name is
currently an alternative name. This is not the desired outcome in most
cases, and the important part of this commit was to delete the new name
from the list of alternative names if necessary.
(cherry picked from commit 080afbb57c4b2d592c5cf77ab10c6e0be74f0732)
Related: RHEL-5988
---
src/libsystemd/sd-netlink/netlink-util.c | 13 -------------
1 file changed, 13 deletions(-)
diff --git a/src/libsystemd/sd-netlink/netlink-util.c b/src/libsystemd/sd-netlink/netlink-util.c
index 12cdc99ff2..6b4c25fe5a 100644
--- a/src/libsystemd/sd-netlink/netlink-util.c
+++ b/src/libsystemd/sd-netlink/netlink-util.c
@@ -3,7 +3,6 @@
#include "sd-netlink.h"
#include "fd-util.h"
-#include "format-util.h"
#include "io-util.h"
#include "memory-util.h"
#include "netlink-internal.h"
@@ -15,7 +14,6 @@
int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
_cleanup_strv_free_ char **alternative_names = NULL;
- char old_name[IF_NAMESIZE] = {};
int r;
assert(rtnl);
@@ -35,10 +33,6 @@ int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
if (r < 0)
return log_debug_errno(r, "Failed to remove '%s' from alternative names on network interface %i: %m",
name, ifindex);
-
- r = format_ifname(ifindex, old_name);
- if (r < 0)
- return log_debug_errno(r, "Failed to get current name of network interface %i: %m", ifindex);
}
r = sd_rtnl_message_new_link(*rtnl, &message, RTM_SETLINK, ifindex);
@@ -53,13 +47,6 @@ int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
if (r < 0)
return r;
- if (!isempty(old_name)) {
- r = rtnl_set_link_alternative_names(rtnl, ifindex, STRV_MAKE(old_name));
- if (r < 0)
- log_debug_errno(r, "Failed to set '%s' as an alternative name on network interface %i, ignoring: %m",
- old_name, ifindex);
- }
-
return 0;
}

@ -0,0 +1,66 @@
From 9b6a3b192ba0f22ce99aa5c48c6c7143d12dddba Mon Sep 17 00:00:00 2001
From: Nick Rosbrook <nick.rosbrook@canonical.com>
Date: Wed, 2 Nov 2022 05:36:14 -0400
Subject: [PATCH] sd-netlink: restore altname on error in rtnl_set_link_name
If a current alternative name is to be used to rename a network
interface, the alternative name must be removed first. If interface
renaming fails, restore the alternative name that was deleted if
necessary.
(cherry picked from commit 4d600667f8af2985850b03a46357e068d3fb8570)
Related: RHEL-5988
---
src/libsystemd/sd-netlink/netlink-util.c | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/src/libsystemd/sd-netlink/netlink-util.c b/src/libsystemd/sd-netlink/netlink-util.c
index 6b4c25fe5a..cfcf2578d6 100644
--- a/src/libsystemd/sd-netlink/netlink-util.c
+++ b/src/libsystemd/sd-netlink/netlink-util.c
@@ -14,6 +14,7 @@
int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
_cleanup_strv_free_ char **alternative_names = NULL;
+ bool altname_deleted = false;
int r;
assert(rtnl);
@@ -33,21 +34,33 @@ int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
if (r < 0)
return log_debug_errno(r, "Failed to remove '%s' from alternative names on network interface %i: %m",
name, ifindex);
+
+ altname_deleted = true;
}
r = sd_rtnl_message_new_link(*rtnl, &message, RTM_SETLINK, ifindex);
if (r < 0)
- return r;
+ goto fail;
r = sd_netlink_message_append_string(message, IFLA_IFNAME, name);
if (r < 0)
- return r;
+ goto fail;
r = sd_netlink_call(*rtnl, message, 0, NULL);
if (r < 0)
- return r;
+ goto fail;
return 0;
+
+fail:
+ if (altname_deleted) {
+ int q = rtnl_set_link_alternative_names(rtnl, ifindex, STRV_MAKE(name));
+ if (q < 0)
+ log_debug_errno(q, "Failed to restore '%s' as an alternative name on network interface %i, ignoring: %m",
+ name, ifindex);
+ }
+
+ return r;
}
int rtnl_set_link_properties(

@ -0,0 +1,65 @@
From ca122b3f1e00ba6a70e7575266502579108c4b47 Mon Sep 17 00:00:00 2001
From: Nick Rosbrook <nick.rosbrook@canonical.com>
Date: Fri, 2 Dec 2022 15:35:25 -0500
Subject: [PATCH] udev: attempt device rename even if interface is up
Currently rename_netif() will not attempt to rename a device if it is
already up, because the kernel will return -EBUSY unless live renaming
is allowed on the device. This restriction will be removed in a future
kernel version [1].
To cover both cases, always attempt to rename the interface and return 0
if we get -EBUSY.
[1] https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/commit/?id=bd039b5ea2a9
(cherry picked from commit 53584e7b61373c26635b906eb64e98fbd3fd3ba4)
Related: RHEL-5988
---
src/udev/udev-event.c | 18 ++++++------------
1 file changed, 6 insertions(+), 12 deletions(-)
diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
index b3d92d5150..08d69cf1f0 100644
--- a/src/udev/udev-event.c
+++ b/src/udev/udev-event.c
@@ -862,7 +862,6 @@ int udev_event_spawn(
static int rename_netif(UdevEvent *event) {
const char *oldname;
sd_device *dev;
- unsigned flags;
int ifindex, r;
assert(event);
@@ -896,17 +895,7 @@ static int rename_netif(UdevEvent *event) {
return 0;
}
- r = rtnl_get_link_info(&event->rtnl, ifindex, NULL, &flags, NULL, NULL, NULL);
- if (r < 0)
- return log_device_warning_errno(dev, r, "Failed to get link flags: %m");
-
- if (FLAGS_SET(flags, IFF_UP)) {
- log_device_info(dev, "Network interface '%s' is already up, refusing to rename to '%s'.",
- oldname, event->name);
- return 0;
- }
-
- /* Set ID_RENAMING boolean property here, and drop it in the corresponding move uevent later. */
+ /* Set ID_RENAMING boolean property here. It will be dropped when the corresponding move uevent is processed. */
r = device_add_property(dev, "ID_RENAMING", "1");
if (r < 0)
return log_device_warning_errno(dev, r, "Failed to add 'ID_RENAMING' property: %m");
@@ -927,6 +916,11 @@ static int rename_netif(UdevEvent *event) {
return log_device_debug_errno(event->dev_db_clone, r, "Failed to update database under /run/udev/data/: %m");
r = rtnl_set_link_name(&event->rtnl, ifindex, event->name);
+ if (r == -EBUSY) {
+ log_device_info(dev, "Network interface '%s' is already up, cannot rename to '%s'.",
+ oldname, event->name);
+ return 0;
+ }
if (r < 0)
return log_device_error_errno(dev, r, "Failed to rename network interface %i from '%s' to '%s': %m",
ifindex, oldname, event->name);

@ -0,0 +1,74 @@
From 32188058ad3b9a8bfc555215982145a128adfc44 Mon Sep 17 00:00:00 2001
From: Nick Rosbrook <nick.rosbrook@canonical.com>
Date: Tue, 22 Nov 2022 17:01:47 -0500
Subject: [PATCH] sd-netlink: add a test for rtnl_set_link_name()
Add a test that verifies a deleted alternative name is restored on error
in rtnl_set_link_name().
(cherry picked from commit b338a8bb402a3ab241a617e096b21ae6a7b7badf)
Related: RHEL-5988
---
src/libsystemd/sd-netlink/test-netlink.c | 27 ++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c
index 3f74ecc068..2d93f9eba0 100644
--- a/src/libsystemd/sd-netlink/test-netlink.c
+++ b/src/libsystemd/sd-netlink/test-netlink.c
@@ -8,6 +8,7 @@
#include <linux/if_macsec.h>
#include <linux/l2tp.h>
#include <linux/nl80211.h>
+#include <unistd.h>
#include "sd-netlink.h"
@@ -16,6 +17,7 @@
#include "macro.h"
#include "netlink-genl.h"
#include "netlink-internal.h"
+#include "netlink-util.h"
#include "socket-util.h"
#include "stdio-util.h"
#include "string-util.h"
@@ -667,6 +669,30 @@ static void test_genl(void) {
}
}
+static void test_rtnl_set_link_name(sd_netlink *rtnl, int ifindex) {
+ _cleanup_strv_free_ char **alternative_names = NULL;
+ int r;
+
+ log_debug("/* %s */", __func__);
+
+ if (geteuid() != 0)
+ return (void) log_tests_skipped("not root");
+
+ /* Test that the new name (which is currently an alternative name) is
+ * restored as an alternative name on error. Create an error by using
+ * an invalid device name, namely one that exceeds IFNAMSIZ
+ * (alternative names can exceed IFNAMSIZ, but not regular names). */
+ r = rtnl_set_link_alternative_names(&rtnl, ifindex, STRV_MAKE("testlongalternativename"));
+ if (r == -EPERM)
+ return (void) log_tests_skipped("missing required capabilities");
+
+ assert_se(r >= 0);
+ assert_se(rtnl_set_link_name(&rtnl, ifindex, "testlongalternativename") == -EINVAL);
+ assert_se(rtnl_get_link_alternative_names(&rtnl, ifindex, &alternative_names) >= 0);
+ assert_se(strv_contains(alternative_names, "testlongalternativename"));
+ assert_se(rtnl_delete_link_alternative_names(&rtnl, ifindex, STRV_MAKE("testlongalternativename")) >= 0);
+}
+
int main(void) {
sd_netlink *rtnl;
sd_netlink_message *m;
@@ -698,6 +724,7 @@ int main(void) {
test_pipe(if_loopback);
test_event_loop(if_loopback);
test_link_configure(rtnl, if_loopback);
+ test_rtnl_set_link_name(rtnl, if_loopback);
test_get_addresses(rtnl);
test_message_link_bridge(rtnl);

@ -0,0 +1,50 @@
From 6e095bdbd88ddbe289210720e7a55b62fa593ab8 Mon Sep 17 00:00:00 2001
From: Nick Rosbrook <nick.rosbrook@canonical.com>
Date: Wed, 7 Dec 2022 12:28:28 -0500
Subject: [PATCH] test-network: add a test for renaming device to current
altname
(cherry picked from commit f68f644a167af3452be853b631fa9144c6716c28)
Related: RHEL-5988
---
.../test-network/conf/12-dummy-rename-to-altname.link | 7 +++++++
test/test-network/systemd-networkd-tests.py | 11 +++++++++++
2 files changed, 18 insertions(+)
create mode 100644 test/test-network/conf/12-dummy-rename-to-altname.link
diff --git a/test/test-network/conf/12-dummy-rename-to-altname.link b/test/test-network/conf/12-dummy-rename-to-altname.link
new file mode 100644
index 0000000000..bef4bf3dc5
--- /dev/null
+++ b/test/test-network/conf/12-dummy-rename-to-altname.link
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+OriginalName=dummy98
+
+[Link]
+Name=dummyalt
+AlternativeName=dummyalt hogehogehogehogehogehoge
diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py
index 87710ef3fb..696618790a 100755
--- a/test/test-network/systemd-networkd-tests.py
+++ b/test/test-network/systemd-networkd-tests.py
@@ -936,6 +936,17 @@ class NetworkctlTests(unittest.TestCase, Utilities):
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'dummy98', env=env)
self.assertRegex(output, 'hogehogehogehogehogehoge')
+ @expectedFailureIfAlternativeNameIsNotAvailable()
+ def test_rename_to_altname(self):
+ copy_network_unit('26-netdev-link-local-addressing-yes.network',
+ '12-dummy.netdev', '12-dummy-rename-to-altname.link')
+ start_networkd()
+ self.wait_online(['dummyalt:degraded'])
+
+ output = check_output(*networkctl_cmd, '-n', '0', 'status', 'dummyalt', env=env)
+ self.assertIn('hogehogehogehogehogehoge', output)
+ self.assertNotIn('dummy98', output)
+
def test_reconfigure(self):
copy_network_unit('25-address-static.network', '12-dummy.netdev')
start_networkd()

@ -0,0 +1,58 @@
From d808bd97790dd8a38d844c827d2d9dbcb700d8c0 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 9 Jan 2023 11:20:35 +0900
Subject: [PATCH] udev: align table
(cherry picked from commit bb1234d1d6b7b14424093a917890bb4013b4ff3e)
Related: RHEL-5988
---
src/udev/udev-event.c | 34 +++++++++++++++++-----------------
1 file changed, 17 insertions(+), 17 deletions(-)
diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
index 08d69cf1f0..3ac12d9b52 100644
--- a/src/udev/udev-event.c
+++ b/src/udev/udev-event.c
@@ -119,24 +119,24 @@ struct subst_map_entry {
};
static const struct subst_map_entry map[] = {
- { .name = "devnode", .fmt = 'N', .type = FORMAT_SUBST_DEVNODE },
- { .name = "tempnode", .fmt = 'N', .type = FORMAT_SUBST_DEVNODE }, /* deprecated */
- { .name = "attr", .fmt = 's', .type = FORMAT_SUBST_ATTR },
- { .name = "sysfs", .fmt = 's', .type = FORMAT_SUBST_ATTR }, /* deprecated */
- { .name = "env", .fmt = 'E', .type = FORMAT_SUBST_ENV },
- { .name = "kernel", .fmt = 'k', .type = FORMAT_SUBST_KERNEL },
+ { .name = "devnode", .fmt = 'N', .type = FORMAT_SUBST_DEVNODE },
+ { .name = "tempnode", .fmt = 'N', .type = FORMAT_SUBST_DEVNODE }, /* deprecated */
+ { .name = "attr", .fmt = 's', .type = FORMAT_SUBST_ATTR },
+ { .name = "sysfs", .fmt = 's', .type = FORMAT_SUBST_ATTR }, /* deprecated */
+ { .name = "env", .fmt = 'E', .type = FORMAT_SUBST_ENV },
+ { .name = "kernel", .fmt = 'k', .type = FORMAT_SUBST_KERNEL },
{ .name = "number", .fmt = 'n', .type = FORMAT_SUBST_KERNEL_NUMBER },
- { .name = "driver", .fmt = 'd', .type = FORMAT_SUBST_DRIVER },
- { .name = "devpath", .fmt = 'p', .type = FORMAT_SUBST_DEVPATH },
- { .name = "id", .fmt = 'b', .type = FORMAT_SUBST_ID },
- { .name = "major", .fmt = 'M', .type = FORMAT_SUBST_MAJOR },
- { .name = "minor", .fmt = 'm', .type = FORMAT_SUBST_MINOR },
- { .name = "result", .fmt = 'c', .type = FORMAT_SUBST_RESULT },
- { .name = "parent", .fmt = 'P', .type = FORMAT_SUBST_PARENT },
- { .name = "name", .fmt = 'D', .type = FORMAT_SUBST_NAME },
- { .name = "links", .fmt = 'L', .type = FORMAT_SUBST_LINKS },
- { .name = "root", .fmt = 'r', .type = FORMAT_SUBST_ROOT },
- { .name = "sys", .fmt = 'S', .type = FORMAT_SUBST_SYS },
+ { .name = "driver", .fmt = 'd', .type = FORMAT_SUBST_DRIVER },
+ { .name = "devpath", .fmt = 'p', .type = FORMAT_SUBST_DEVPATH },
+ { .name = "id", .fmt = 'b', .type = FORMAT_SUBST_ID },
+ { .name = "major", .fmt = 'M', .type = FORMAT_SUBST_MAJOR },
+ { .name = "minor", .fmt = 'm', .type = FORMAT_SUBST_MINOR },
+ { .name = "result", .fmt = 'c', .type = FORMAT_SUBST_RESULT },
+ { .name = "parent", .fmt = 'P', .type = FORMAT_SUBST_PARENT },
+ { .name = "name", .fmt = 'D', .type = FORMAT_SUBST_NAME },
+ { .name = "links", .fmt = 'L', .type = FORMAT_SUBST_LINKS },
+ { .name = "root", .fmt = 'r', .type = FORMAT_SUBST_ROOT },
+ { .name = "sys", .fmt = 'S', .type = FORMAT_SUBST_SYS },
};
static const char *format_type_to_string(FormatSubstitutionType t) {

@ -0,0 +1,47 @@
From 3b4d91e7ab44738f3773a3bfd4a6c5fb9bbc7322 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 9 Jan 2023 14:00:09 +0900
Subject: [PATCH] sd-device: make device_set_syspath() clear sysname and sysnum
Otherwise, when a new syspath is assigned to the sd-device object,
sd_device_get_sysname() or _sysnum() will provide an outdated device
name or number.
(cherry picked from commit 9a26098e90116fdb5fcffa03485b375ee0c82b6a)
Related: RHEL-5988
---
src/libsystemd/sd-device/device-private.c | 4 ----
src/libsystemd/sd-device/sd-device.c | 4 ++++
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/libsystemd/sd-device/device-private.c b/src/libsystemd/sd-device/device-private.c
index bc7a838608..2c1d922ea3 100644
--- a/src/libsystemd/sd-device/device-private.c
+++ b/src/libsystemd/sd-device/device-private.c
@@ -646,10 +646,6 @@ int device_rename(sd_device *device, const char *name) {
if (r < 0)
return r;
- /* Here, only clear the sysname and sysnum. They will be set when requested. */
- device->sysnum = NULL;
- device->sysname = mfree(device->sysname);
-
r = sd_device_get_property_value(device, "INTERFACE", &interface);
if (r == -ENOENT)
return 0;
diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c
index f2e142457b..c822a0b2f0 100644
--- a/src/libsystemd/sd-device/sd-device.c
+++ b/src/libsystemd/sd-device/sd-device.c
@@ -250,6 +250,10 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
free_and_replace(device->syspath, syspath);
device->devpath = devpath;
+
+ /* Unset sysname and sysnum, they will be assigned when requested. */
+ device->sysnum = NULL;
+ device->sysname = mfree(device->sysname);
return 0;
}

@ -0,0 +1,62 @@
From 2c6ea8a97986c58954603b587875a52b043e4d9b Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 9 Jan 2023 14:07:16 +0900
Subject: [PATCH] sd-device: do not directly access entry in sd-device object
No functional change, just refactoring.
(cherry picked from commit 1de6a49721957a85a4934ddbdf88d535774597b1)
Related: RHEL-5988
---
src/libsystemd/sd-device/device-private.c | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/src/libsystemd/sd-device/device-private.c b/src/libsystemd/sd-device/device-private.c
index 2c1d922ea3..9cec037237 100644
--- a/src/libsystemd/sd-device/device-private.c
+++ b/src/libsystemd/sd-device/device-private.c
@@ -621,7 +621,7 @@ int device_get_devlink_priority(sd_device *device, int *ret) {
int device_rename(sd_device *device, const char *name) {
_cleanup_free_ char *new_syspath = NULL;
- const char *interface;
+ const char *s;
int r;
assert(device);
@@ -630,7 +630,11 @@ int device_rename(sd_device *device, const char *name) {
if (!filename_is_valid(name))
return -EINVAL;
- r = path_extract_directory(device->syspath, &new_syspath);
+ r = sd_device_get_syspath(device, &s);
+ if (r < 0)
+ return r;
+
+ r = path_extract_directory(s, &new_syspath);
if (r < 0)
return r;
@@ -642,18 +646,18 @@ int device_rename(sd_device *device, const char *name) {
/* At the time this is called, the renamed device may not exist yet. Hence, we cannot validate
* the new syspath. */
- r = device_set_syspath(device, new_syspath, false);
+ r = device_set_syspath(device, new_syspath, /* verify = */ false);
if (r < 0)
return r;
- r = sd_device_get_property_value(device, "INTERFACE", &interface);
+ r = sd_device_get_property_value(device, "INTERFACE", &s);
if (r == -ENOENT)
return 0;
if (r < 0)
return r;
/* like DEVPATH_OLD, INTERFACE_OLD is not saved to the db, but only stays around for the current event */
- r = device_add_property_internal(device, "INTERFACE_OLD", interface);
+ r = device_add_property_internal(device, "INTERFACE_OLD", s);
if (r < 0)
return r;

@ -0,0 +1,148 @@
From 7f183125fbec97bd6e4c0b3ac792b0e0c23132e0 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 9 Jan 2023 15:00:30 +0900
Subject: [PATCH] udev: move device_rename() from device-private.c
The function is used only by udevd.
(cherry picked from commit ff88b949531e70639c507f74da875a7de2adf543)
Related: RHEL-5988
---
src/libsystemd/sd-device/device-private.c | 45 ----------------------
src/libsystemd/sd-device/device-private.h | 1 -
src/udev/udev-event.c | 46 +++++++++++++++++++++++
3 files changed, 46 insertions(+), 46 deletions(-)
diff --git a/src/libsystemd/sd-device/device-private.c b/src/libsystemd/sd-device/device-private.c
index 9cec037237..36b0da4f12 100644
--- a/src/libsystemd/sd-device/device-private.c
+++ b/src/libsystemd/sd-device/device-private.c
@@ -619,51 +619,6 @@ int device_get_devlink_priority(sd_device *device, int *ret) {
return 0;
}
-int device_rename(sd_device *device, const char *name) {
- _cleanup_free_ char *new_syspath = NULL;
- const char *s;
- int r;
-
- assert(device);
- assert(name);
-
- if (!filename_is_valid(name))
- return -EINVAL;
-
- r = sd_device_get_syspath(device, &s);
- if (r < 0)
- return r;
-
- r = path_extract_directory(s, &new_syspath);
- if (r < 0)
- return r;
-
- if (!path_extend(&new_syspath, name))
- return -ENOMEM;
-
- if (!path_is_safe(new_syspath))
- return -EINVAL;
-
- /* At the time this is called, the renamed device may not exist yet. Hence, we cannot validate
- * the new syspath. */
- r = device_set_syspath(device, new_syspath, /* verify = */ false);
- if (r < 0)
- return r;
-
- r = sd_device_get_property_value(device, "INTERFACE", &s);
- if (r == -ENOENT)
- return 0;
- if (r < 0)
- return r;
-
- /* like DEVPATH_OLD, INTERFACE_OLD is not saved to the db, but only stays around for the current event */
- r = device_add_property_internal(device, "INTERFACE_OLD", s);
- if (r < 0)
- return r;
-
- return device_add_property_internal(device, "INTERFACE", name);
-}
-
static int device_shallow_clone(sd_device *device, sd_device **ret) {
_cleanup_(sd_device_unrefp) sd_device *dest = NULL;
const char *val = NULL;
diff --git a/src/libsystemd/sd-device/device-private.h b/src/libsystemd/sd-device/device-private.h
index a59f130aff..e57b74ba24 100644
--- a/src/libsystemd/sd-device/device-private.h
+++ b/src/libsystemd/sd-device/device-private.h
@@ -53,7 +53,6 @@ int device_properties_prepare(sd_device *device);
int device_get_properties_nulstr(sd_device *device, const char **ret_nulstr, size_t *ret_len);
int device_get_properties_strv(sd_device *device, char ***ret);
-int device_rename(sd_device *device, const char *name);
int device_clone_with_db(sd_device *device, sd_device **ret);
int device_tag_index(sd_device *dev, sd_device *dev_old, bool add);
diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
index 3ac12d9b52..1dc05f863d 100644
--- a/src/udev/udev-event.c
+++ b/src/udev/udev-event.c
@@ -12,6 +12,7 @@
#include "sd-event.h"
#include "alloc-util.h"
+#include "device-internal.h"
#include "device-private.h"
#include "device-util.h"
#include "fd-util.h"
@@ -859,6 +860,51 @@ int udev_event_spawn(
return r; /* 0 for success, and positive if the program failed */
}
+static int device_rename(sd_device *device, const char *name) {
+ _cleanup_free_ char *new_syspath = NULL;
+ const char *s;
+ int r;
+
+ assert(device);
+ assert(name);
+
+ if (!filename_is_valid(name))
+ return -EINVAL;
+
+ r = sd_device_get_syspath(device, &s);
+ if (r < 0)
+ return r;
+
+ r = path_extract_directory(s, &new_syspath);
+ if (r < 0)
+ return r;
+
+ if (!path_extend(&new_syspath, name))
+ return -ENOMEM;
+
+ if (!path_is_safe(new_syspath))
+ return -EINVAL;
+
+ /* At the time this is called, the renamed device may not exist yet. Hence, we cannot validate
+ * the new syspath. */
+ r = device_set_syspath(device, new_syspath, /* verify = */ false);
+ if (r < 0)
+ return r;
+
+ r = sd_device_get_property_value(device, "INTERFACE", &s);
+ if (r == -ENOENT)
+ return 0;
+ if (r < 0)
+ return r;
+
+ /* like DEVPATH_OLD, INTERFACE_OLD is not saved to the db, but only stays around for the current event */
+ r = device_add_property_internal(device, "INTERFACE_OLD", s);
+ if (r < 0)
+ return r;
+
+ return device_add_property_internal(device, "INTERFACE", name);
+}
+
static int rename_netif(UdevEvent *event) {
const char *oldname;
sd_device *dev;

@ -0,0 +1,155 @@
From 1f4bc8c496d2a310ffa3e7174af40f7e596cd2d1 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 9 Jan 2023 14:58:58 +0900
Subject: [PATCH] udev: restore syspath and properties on failure
Otherwise, invalid sysname or properties may be broadcast to udev
listeners.
(cherry picked from commit 210033847c340c43dd6835520f21f8b23ba29579)
Related: RHEL-5988
---
src/udev/udev-event.c | 93 +++++++++++++++++++++++++++++--------------
1 file changed, 64 insertions(+), 29 deletions(-)
diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
index 1dc05f863d..fab454ae37 100644
--- a/src/udev/udev-event.c
+++ b/src/udev/udev-event.c
@@ -906,7 +906,8 @@ static int device_rename(sd_device *device, const char *name) {
}
static int rename_netif(UdevEvent *event) {
- const char *oldname;
+ _cleanup_free_ char *old_syspath = NULL, *old_sysname = NULL;
+ const char *s;
sd_device *dev;
int ifindex, r;
@@ -917,15 +918,6 @@ static int rename_netif(UdevEvent *event) {
dev = ASSERT_PTR(event->dev);
- /* Read sysname from cloned sd-device object, otherwise use-after-free is triggered, as the
- * main object will be renamed and dev->sysname will be freed in device_rename(). */
- r = sd_device_get_sysname(event->dev_db_clone, &oldname);
- if (r < 0)
- return log_device_error_errno(dev, r, "Failed to get sysname: %m");
-
- if (streq(event->name, oldname))
- return 0; /* The interface name is already requested name. */
-
if (!device_for_action(dev, SD_DEVICE_ADD))
return 0; /* Rename the interface only when it is added. */
@@ -933,7 +925,7 @@ static int rename_netif(UdevEvent *event) {
if (r == -ENOENT)
return 0; /* Device is not a network interface. */
if (r < 0)
- return log_device_error_errno(dev, r, "Failed to get ifindex: %m");
+ return log_device_warning_errno(dev, r, "Failed to get ifindex: %m");
if (naming_scheme_has(NAMING_REPLACE_STRICTLY) &&
!ifname_valid(event->name)) {
@@ -941,39 +933,82 @@ static int rename_netif(UdevEvent *event) {
return 0;
}
- /* Set ID_RENAMING boolean property here. It will be dropped when the corresponding move uevent is processed. */
- r = device_add_property(dev, "ID_RENAMING", "1");
+ r = sd_device_get_sysname(dev, &s);
if (r < 0)
- return log_device_warning_errno(dev, r, "Failed to add 'ID_RENAMING' property: %m");
+ return log_device_warning_errno(dev, r, "Failed to get sysname: %m");
- r = device_rename(dev, event->name);
+ if (streq(event->name, s))
+ return 0; /* The interface name is already requested name. */
+
+ old_sysname = strdup(s);
+ if (!old_sysname)
+ return -ENOMEM;
+
+ r = sd_device_get_syspath(dev, &s);
if (r < 0)
- return log_device_warning_errno(dev, r, "Failed to update properties with new name '%s': %m", event->name);
+ return log_device_warning_errno(dev, r, "Failed to get syspath: %m");
+
+ old_syspath = strdup(s);
+ if (!old_syspath)
+ return -ENOMEM;
+
+ r = device_rename(dev, event->name);
+ if (r < 0) {
+ log_device_warning_errno(dev, r, "Failed to update properties with new name '%s': %m", event->name);
+ goto revert;
+ }
+
+ /* Set ID_RENAMING boolean property here. It will be dropped when the corresponding move uevent is processed. */
+ r = device_add_property(dev, "ID_RENAMING", "1");
+ if (r < 0) {
+ log_device_warning_errno(dev, r, "Failed to add 'ID_RENAMING' property: %m");
+ goto revert;
+ }
/* Also set ID_RENAMING boolean property to cloned sd_device object and save it to database
* before calling rtnl_set_link_name(). Otherwise, clients (e.g., systemd-networkd) may receive
* RTM_NEWLINK netlink message before the database is updated. */
r = device_add_property(event->dev_db_clone, "ID_RENAMING", "1");
- if (r < 0)
- return log_device_warning_errno(event->dev_db_clone, r, "Failed to add 'ID_RENAMING' property: %m");
+ if (r < 0) {
+ log_device_warning_errno(event->dev_db_clone, r, "Failed to add 'ID_RENAMING' property: %m");
+ goto revert;
+ }
r = device_update_db(event->dev_db_clone);
- if (r < 0)
- return log_device_debug_errno(event->dev_db_clone, r, "Failed to update database under /run/udev/data/: %m");
+ if (r < 0) {
+ log_device_debug_errno(event->dev_db_clone, r, "Failed to update database under /run/udev/data/: %m");
+ goto revert;
+ }
r = rtnl_set_link_name(&event->rtnl, ifindex, event->name);
- if (r == -EBUSY) {
- log_device_info(dev, "Network interface '%s' is already up, cannot rename to '%s'.",
- oldname, event->name);
- return 0;
+ if (r < 0) {
+ if (r == -EBUSY) {
+ log_device_info(dev, "Network interface '%s' is already up, cannot rename to '%s'.",
+ old_sysname, event->name);
+ r = 0;
+ } else
+ log_device_error_errno(dev, r, "Failed to rename network interface %i from '%s' to '%s': %m",
+ ifindex, old_sysname, event->name);
+ goto revert;
}
- if (r < 0)
- return log_device_error_errno(dev, r, "Failed to rename network interface %i from '%s' to '%s': %m",
- ifindex, oldname, event->name);
-
- log_device_debug(dev, "Network interface %i is renamed from '%s' to '%s'", ifindex, oldname, event->name);
+ log_device_debug(dev, "Network interface %i is renamed from '%s' to '%s'", ifindex, old_sysname, event->name);
return 1;
+
+revert:
+ /* Restore 'dev_db_clone' */
+ (void) device_add_property(event->dev_db_clone, "ID_RENAMING", NULL);
+ (void) device_update_db(event->dev_db_clone);
+
+ /* Restore 'dev' */
+ (void) device_set_syspath(dev, old_syspath, /* verify = */ false);
+ if (sd_device_get_property_value(dev, "INTERFACE_OLD", &s) >= 0) {
+ (void) device_add_property_internal(dev, "INTERFACE", s);
+ (void) device_add_property_internal(dev, "INTERFACE_OLD", NULL);
+ }
+ (void) device_add_property(dev, "ID_RENAMING", NULL);
+
+ return r;
}
static int update_devnode(UdevEvent *event) {

@ -0,0 +1,56 @@
From 284d6f9171ba819bcccb6a2df7c3012ba8483a0c Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 9 Jan 2023 16:44:11 +0900
Subject: [PATCH] sd-device: introduce device_get_property_int()
(cherry picked from commit eedfef0f0d2654fcde2a3b694e62518d688af827)
Related: RHEL-5988
---
src/libsystemd/sd-device/device-private.h | 1 +
src/libsystemd/sd-device/sd-device.c | 20 ++++++++++++++++++++
2 files changed, 21 insertions(+)
diff --git a/src/libsystemd/sd-device/device-private.h b/src/libsystemd/sd-device/device-private.h
index e57b74ba24..d9a519a4d9 100644
--- a/src/libsystemd/sd-device/device-private.h
+++ b/src/libsystemd/sd-device/device-private.h
@@ -18,6 +18,7 @@ int device_new_from_strv(sd_device **ret, char **strv);
int device_opendir(sd_device *device, const char *subdir, DIR **ret);
int device_get_property_bool(sd_device *device, const char *key);
+int device_get_property_int(sd_device *device, const char *key, int *ret);
int device_get_sysattr_int(sd_device *device, const char *sysattr, int *ret_value);
int device_get_sysattr_unsigned(sd_device *device, const char *sysattr, unsigned *ret_value);
int device_get_sysattr_bool(sd_device *device, const char *sysattr);
diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c
index c822a0b2f0..7ee67b4641 100644
--- a/src/libsystemd/sd-device/sd-device.c
+++ b/src/libsystemd/sd-device/sd-device.c
@@ -2186,6 +2186,26 @@ int device_get_property_bool(sd_device *device, const char *key) {
return parse_boolean(value);
}
+int device_get_property_int(sd_device *device, const char *key, int *ret) {
+ const char *value;
+ int r, v;
+
+ assert(device);
+ assert(key);
+
+ r = sd_device_get_property_value(device, key, &value);
+ if (r < 0)
+ return r;
+
+ r = safe_atoi(value, &v);
+ if (r < 0)
+ return r;
+
+ if (ret)
+ *ret = v;
+ return 0;
+}
+
_public_ int sd_device_get_trigger_uuid(sd_device *device, sd_id128_t *ret) {
const char *s;
sd_id128_t id;

@ -0,0 +1,32 @@
From 42a11f89c8836493847a69906ef2765e2e984dbf Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 9 Jan 2023 16:11:04 +0900
Subject: [PATCH] core/device: downgrade log level for ignored errors
(cherry picked from commit 58b0a3e5112a27daa181383458f68955eb081551)
Related: RHEL-5988
---
src/core/device.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/core/device.c b/src/core/device.c
index 224fc90835..09b7d56e1e 100644
--- a/src/core/device.c
+++ b/src/core/device.c
@@ -1095,13 +1095,13 @@ static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *
r = sd_device_get_syspath(dev, &sysfs);
if (r < 0) {
- log_device_error_errno(dev, r, "Failed to get device syspath, ignoring: %m");
+ log_device_warning_errno(dev, r, "Failed to get device syspath, ignoring: %m");
return 0;
}
r = sd_device_get_action(dev, &action);
if (r < 0) {
- log_device_error_errno(dev, r, "Failed to get udev action, ignoring: %m");
+ log_device_warning_errno(dev, r, "Failed to get udev action, ignoring: %m");
return 0;
}

@ -0,0 +1,45 @@
From b59fda96b0e24b93dcdb061da24c42a924ae0b20 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 9 Jan 2023 16:11:52 +0900
Subject: [PATCH] core/device: ignore failed uevents
When udevd failed to process the device, SYSTEMD_ALIAS or any other
properties may contain invalid values. Let's refuse to handle the uevent.
(cherry picked from commit e9336d6ac346df38d96c91ba0447b3c76ee6697b)
Related: RHEL-5988
---
src/core/device.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/src/core/device.c b/src/core/device.c
index 09b7d56e1e..f007bdfd9b 100644
--- a/src/core/device.c
+++ b/src/core/device.c
@@ -1108,6 +1108,25 @@ static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *
if (action == SD_DEVICE_MOVE)
device_remove_old_on_move(m, dev);
+ /* When udevd failed to process the device, SYSTEMD_ALIAS or any other properties may contain invalid
+ * values. Let's refuse to handle the uevent. */
+ if (sd_device_get_property_value(dev, "UDEV_WORKER_FAILED", NULL) >= 0) {
+ int v;
+
+ if (device_get_property_int(dev, "UDEV_WORKER_ERRNO", &v) >= 0)
+ log_device_warning_errno(dev, v, "systemd-udevd failed to process the device, ignoring: %m");
+ else if (device_get_property_int(dev, "UDEV_WORKER_EXIT_STATUS", &v) >= 0)
+ log_device_warning(dev, "systemd-udevd failed to process the device with exit status %i, ignoring.", v);
+ else if (device_get_property_int(dev, "UDEV_WORKER_SIGNAL", &v) >= 0) {
+ const char *s;
+ (void) sd_device_get_property_value(dev, "UDEV_WORKER_SIGNAL_NAME", &s);
+ log_device_warning(dev, "systemd-udevd failed to process the device with signal %i(%s), ignoring.", v, strna(s));
+ } else
+ log_device_warning(dev, "systemd-udevd failed to process the device with unknown result, ignoring.");
+
+ return 0;
+ }
+
/* A change event can signal that a device is becoming ready, in particular if the device is using
* the SYSTEMD_READY logic in udev so we need to reach the else block of the following if, even for
* change events */

@ -0,0 +1,99 @@
From 9e9f53612dc2356796cffb25826008944aede0e3 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 9 Jan 2023 16:02:09 +0900
Subject: [PATCH] test: add tests for failure in renaming network interface
(cherry picked from commit 2d0d75b279924934c4c8e9acbc48456b01b71f00)
Related: RHEL-5988
---
test/units/testsuite-17.02.sh | 78 +++++++++++++++++++++++++++++++++++
1 file changed, 78 insertions(+)
diff --git a/test/units/testsuite-17.02.sh b/test/units/testsuite-17.02.sh
index 7abbce7747..ed3b39d074 100755
--- a/test/units/testsuite-17.02.sh
+++ b/test/units/testsuite-17.02.sh
@@ -102,4 +102,82 @@ timeout 30 bash -c 'while [[ "$(systemctl show --property=ActiveState --value /s
# cleanup
ip link del hoge
+teardown_netif_renaming_conflict() {
+ set +ex
+
+ if [[ -n "$KILL_PID" ]]; then
+ kill "$KILL_PID"
+ fi
+
+ rm -rf "$TMPDIR"
+
+ rm -f /run/udev/rules.d/50-testsuite.rules
+ udevadm control --reload --timeout=30
+
+ ip link del hoge
+ ip link del foobar
+}
+
+test_netif_renaming_conflict() {
+ local since found=
+
+ trap teardown_netif_renaming_conflict RETURN
+
+ cat >/run/udev/rules.d/50-testsuite.rules <<EOF
+ACTION!="add", GOTO="hoge_end"
+SUBSYSTEM!="net", GOTO="hoge_end"
+
+OPTIONS="log_level=debug"
+
+KERNEL=="foobar", NAME="hoge"
+
+LABEL="hoge_end"
+EOF
+
+ udevadm control --log-priority=debug --reload --timeout=30
+
+ ip link add hoge type dummy
+ udevadm wait --timeout=30 --settle /sys/devices/virtual/net/hoge
+
+ TMPDIR=$(mktemp -d -p /tmp udev-tests.XXXXXX)
+ udevadm monitor --udev --property --subsystem-match=net >"$TMPDIR"/monitor.txt &
+ KILL_PID="$!"
+
+ # make sure that 'udevadm monitor' actually monitor uevents
+ sleep 1
+
+ since="$(date '+%H:%M:%S')"
+
+ # add another interface which will conflict with an existing interface
+ ip link add foobar type dummy
+
+ for _ in {1..40}; do
+ if (
+ grep -q 'ACTION=add' "$TMPDIR"/monitor.txt
+ grep -q 'DEVPATH=/devices/virtual/net/foobar' "$TMPDIR"/monitor.txt
+ grep -q 'SUBSYSTEM=net' "$TMPDIR"/monitor.txt
+ grep -q 'INTERFACE=foobar' "$TMPDIR"/monitor.txt
+ grep -q 'ID_NET_DRIVER=dummy' "$TMPDIR"/monitor.txt
+ grep -q 'ID_NET_NAME=foobar' "$TMPDIR"/monitor.txt
+ # Even when network interface renaming is failed, SYSTEMD_ALIAS with the conflicting name will be broadcast.
+ grep -q 'SYSTEMD_ALIAS=/sys/subsystem/net/devices/hoge' "$TMPDIR"/monitor.txt
+ grep -q 'UDEV_WORKER_FAILED=1' "$TMPDIR"/monitor.txt
+ grep -q 'UDEV_WORKER_ERRNO=17' "$TMPDIR"/monitor.txt
+ grep -q 'UDEV_WORKER_ERRNO_NAME=EEXIST' "$TMPDIR"/monitor.txt
+ ); then
+ cat "$TMPDIR"/monitor.txt
+ found=1
+ break
+ fi
+ sleep .5
+ done
+ test -n "$found"
+
+ timeout 30 bash -c "while ! journalctl _PID=1 _COMM=systemd --since $since | grep -q 'foobar: systemd-udevd failed to process the device, ignoring: File exists'; do sleep 1; done"
+ # check if the invalid SYSTEMD_ALIAS property for the interface foobar is ignored by PID1
+ assert_eq "$(systemctl show --property=SysFSPath --value /sys/subsystem/net/devices/hoge)" "/sys/devices/virtual/net/hoge"
+}
+
+test_netif_renaming_conflict
+
exit 0

@ -0,0 +1,623 @@
From a3c14074e6cd91053ffafb0eb4b16054564e4239 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 9 Jan 2023 20:33:35 +0900
Subject: [PATCH] test: modernize test-netlink.c
(cherry picked from commit eafff21da2978bfa4c5c4171a595abaeb1d170dc)
Related: RHEL-5988
---
src/libsystemd/sd-netlink/test-netlink.c | 362 ++++++++---------------
1 file changed, 116 insertions(+), 246 deletions(-)
diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c
index 2d93f9eba0..f740035639 100644
--- a/src/libsystemd/sd-netlink/test-netlink.c
+++ b/src/libsystemd/sd-netlink/test-netlink.c
@@ -24,11 +24,12 @@
#include "strv.h"
#include "tests.h"
-static void test_message_link_bridge(sd_netlink *rtnl) {
+TEST(message_newlink_bridge) {
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
uint32_t cost;
- log_debug("/* %s */", __func__);
+ assert_se(sd_netlink_open(&rtnl) >= 0);
assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_NEWLINK, 1) >= 0);
assert_se(sd_rtnl_message_link_set_family(message, AF_BRIDGE) >= 0);
@@ -44,99 +45,81 @@ static void test_message_link_bridge(sd_netlink *rtnl) {
assert_se(sd_netlink_message_exit_container(message) >= 0);
}
-static void test_link_configure(sd_netlink *rtnl, int ifindex) {
+TEST(message_getlink) {
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL, *reply = NULL;
- uint32_t mtu_out;
- const char *name_out;
- struct ether_addr mac_out;
-
- log_debug("/* %s */", __func__);
-
- /* we'd really like to test NEWLINK, but let's not mess with the running kernel */
- assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_GETLINK, ifindex) >= 0);
-
- assert_se(sd_netlink_call(rtnl, message, 0, &reply) == 1);
-
- assert_se(sd_netlink_message_read_string(reply, IFLA_IFNAME, &name_out) >= 0);
- assert_se(sd_netlink_message_read_ether_addr(reply, IFLA_ADDRESS, &mac_out) >= 0);
- assert_se(sd_netlink_message_read_u32(reply, IFLA_MTU, &mtu_out) >= 0);
-}
-
-static void test_link_get(sd_netlink *rtnl, int ifindex) {
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *r = NULL;
- const char *str_data;
+ int ifindex;
uint8_t u8_data;
+ uint16_t u16_data;
uint32_t u32_data;
+ const char *str_data;
struct ether_addr eth_data;
- log_debug("/* %s */", __func__);
+ assert_se(sd_netlink_open(&rtnl) >= 0);
+ ifindex = (int) if_nametoindex("lo");
- assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
- assert_se(m);
+ /* we'd really like to test NEWLINK, but let's not mess with the running kernel */
+ assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_GETLINK, ifindex) >= 0);
+ assert_se(sd_netlink_call(rtnl, message, 0, &reply) == 1);
- assert_se(sd_netlink_call(rtnl, m, 0, &r) == 1);
+ /* u8 */
+ assert_se(sd_netlink_message_read_u8(reply, IFLA_CARRIER, &u8_data) >= 0);
+ assert_se(sd_netlink_message_read_u8(reply, IFLA_OPERSTATE, &u8_data) >= 0);
+ assert_se(sd_netlink_message_read_u8(reply, IFLA_LINKMODE, &u8_data) >= 0);
- assert_se(sd_netlink_message_read_string(r, IFLA_IFNAME, &str_data) == 0);
+ /* u16 */
+ assert_se(sd_netlink_message_get_type(reply, &u16_data) >= 0);
+ assert_se(u16_data == RTM_NEWLINK);
- assert_se(sd_netlink_message_read_u8(r, IFLA_CARRIER, &u8_data) == 0);
- assert_se(sd_netlink_message_read_u8(r, IFLA_OPERSTATE, &u8_data) == 0);
- assert_se(sd_netlink_message_read_u8(r, IFLA_LINKMODE, &u8_data) == 0);
+ /* u32 */
+ assert_se(sd_netlink_message_read_u32(reply, IFLA_MTU, &u32_data) >= 0);
+ assert_se(sd_netlink_message_read_u32(reply, IFLA_GROUP, &u32_data) >= 0);
+ assert_se(sd_netlink_message_read_u32(reply, IFLA_TXQLEN, &u32_data) >= 0);
+ assert_se(sd_netlink_message_read_u32(reply, IFLA_NUM_TX_QUEUES, &u32_data) >= 0);
+ assert_se(sd_netlink_message_read_u32(reply, IFLA_NUM_RX_QUEUES, &u32_data) >= 0);
- assert_se(sd_netlink_message_read_u32(r, IFLA_MTU, &u32_data) == 0);
- assert_se(sd_netlink_message_read_u32(r, IFLA_GROUP, &u32_data) == 0);
- assert_se(sd_netlink_message_read_u32(r, IFLA_TXQLEN, &u32_data) == 0);
- assert_se(sd_netlink_message_read_u32(r, IFLA_NUM_TX_QUEUES, &u32_data) == 0);
- assert_se(sd_netlink_message_read_u32(r, IFLA_NUM_RX_QUEUES, &u32_data) == 0);
+ /* string */
+ assert_se(sd_netlink_message_read_string(reply, IFLA_IFNAME, &str_data) >= 0);
- assert_se(sd_netlink_message_read_ether_addr(r, IFLA_ADDRESS, &eth_data) == 0);
+ /* ether_addr */
+ assert_se(sd_netlink_message_read_ether_addr(reply, IFLA_ADDRESS, &eth_data) >= 0);
}
-static void test_address_get(sd_netlink *rtnl, int ifindex) {
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *r = NULL;
+TEST(message_address) {
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL, *reply = NULL;
+ int ifindex;
struct in_addr in_data;
struct ifa_cacheinfo cache;
const char *label;
- log_debug("/* %s */", __func__);
+ assert_se(sd_netlink_open(&rtnl) >= 0);
+ ifindex = (int) if_nametoindex("lo");
- assert_se(sd_rtnl_message_new_addr(rtnl, &m, RTM_GETADDR, ifindex, AF_INET) >= 0);
- assert_se(m);
- assert_se(sd_netlink_message_set_request_dump(m, true) >= 0);
- assert_se(sd_netlink_call(rtnl, m, -1, &r) == 1);
+ assert_se(sd_rtnl_message_new_addr(rtnl, &message, RTM_GETADDR, ifindex, AF_INET) >= 0);
+ assert_se(sd_netlink_message_set_request_dump(message, true) >= 0);
+ assert_se(sd_netlink_call(rtnl, message, 0, &reply) == 1);
- assert_se(sd_netlink_message_read_in_addr(r, IFA_LOCAL, &in_data) == 0);
- assert_se(sd_netlink_message_read_in_addr(r, IFA_ADDRESS, &in_data) == 0);
- assert_se(sd_netlink_message_read_string(r, IFA_LABEL, &label) == 0);
- assert_se(sd_netlink_message_read_cache_info(r, IFA_CACHEINFO, &cache) == 0);
+ assert_se(sd_netlink_message_read_in_addr(reply, IFA_LOCAL, &in_data) >= 0);
+ assert_se(sd_netlink_message_read_in_addr(reply, IFA_ADDRESS, &in_data) >= 0);
+ assert_se(sd_netlink_message_read_string(reply, IFA_LABEL, &label) >= 0);
+ assert_se(sd_netlink_message_read_cache_info(reply, IFA_CACHEINFO, &cache) == 0);
}
-static void test_route(sd_netlink *rtnl) {
+TEST(message_route) {
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
struct in_addr addr, addr_data;
uint32_t index = 2, u32_data;
- int r;
- log_debug("/* %s */", __func__);
+ assert_se(sd_netlink_open(&rtnl) >= 0);
- r = sd_rtnl_message_new_route(rtnl, &req, RTM_NEWROUTE, AF_INET, RTPROT_STATIC);
- if (r < 0) {
- log_error_errno(r, "Could not create RTM_NEWROUTE message: %m");
- return;
- }
+ assert_se(sd_rtnl_message_new_route(rtnl, &req, RTM_NEWROUTE, AF_INET, RTPROT_STATIC) >= 0);
addr.s_addr = htobe32(INADDR_LOOPBACK);
- r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &addr);
- if (r < 0) {
- log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
- return;
- }
-
- r = sd_netlink_message_append_u32(req, RTA_OIF, index);
- if (r < 0) {
- log_error_errno(r, "Could not append RTA_OIF attribute: %m");
- return;
- }
+ assert_se(sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &addr) >= 0);
+ assert_se(sd_netlink_message_append_u32(req, RTA_OIF, index) >= 0);
assert_se(sd_netlink_message_rewind(req, rtnl) >= 0);
@@ -149,135 +132,94 @@ static void test_route(sd_netlink *rtnl) {
assert_se((req = sd_netlink_message_unref(req)) == NULL);
}
-static void test_multiple(void) {
- sd_netlink *rtnl1, *rtnl2;
-
- log_debug("/* %s */", __func__);
-
- assert_se(sd_netlink_open(&rtnl1) >= 0);
- assert_se(sd_netlink_open(&rtnl2) >= 0);
-
- rtnl1 = sd_netlink_unref(rtnl1);
- rtnl2 = sd_netlink_unref(rtnl2);
-}
-
static int link_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
- char *ifname = userdata;
const char *data;
assert_se(rtnl);
assert_se(m);
- assert_se(userdata);
- log_info("%s: got link info about %s", __func__, ifname);
- free(ifname);
+ assert_se(streq_ptr(userdata, "foo"));
assert_se(sd_netlink_message_read_string(m, IFLA_IFNAME, &data) >= 0);
assert_se(streq(data, "lo"));
+ log_info("%s: got link info about %s", __func__, data);
return 1;
}
-static void test_event_loop(int ifindex) {
+TEST(netlink_event_loop) {
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
- char *ifname;
-
- log_debug("/* %s */", __func__);
-
- ifname = strdup("lo2");
- assert_se(ifname);
+ _cleanup_free_ char *userdata = NULL;
+ int ifindex;
assert_se(sd_netlink_open(&rtnl) >= 0);
- assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
+ ifindex = (int) if_nametoindex("lo");
- assert_se(sd_netlink_call_async(rtnl, NULL, m, link_handler, NULL, ifname, 0, NULL) >= 0);
+ assert_se(userdata = strdup("foo"));
assert_se(sd_event_default(&event) >= 0);
-
assert_se(sd_netlink_attach_event(rtnl, event, 0) >= 0);
+ assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
+ assert_se(sd_netlink_call_async(rtnl, NULL, m, link_handler, NULL, userdata, 0, NULL) >= 0);
+
assert_se(sd_event_run(event, 0) >= 0);
assert_se(sd_netlink_detach_event(rtnl) >= 0);
-
assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
}
static void test_async_destroy(void *userdata) {
}
-static void test_async(int ifindex) {
+TEST(netlink_call_async) {
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *r = NULL;
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL;
_cleanup_(sd_netlink_slot_unrefp) sd_netlink_slot *slot = NULL;
+ _cleanup_free_ char *userdata = NULL;
sd_netlink_destroy_t destroy_callback;
const char *description;
- char *ifname;
-
- log_debug("/* %s */", __func__);
-
- ifname = strdup("lo");
- assert_se(ifname);
+ int ifindex;
assert_se(sd_netlink_open(&rtnl) >= 0);
+ ifindex = (int) if_nametoindex("lo");
- assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
+ assert_se(userdata = strdup("foo"));
- assert_se(sd_netlink_call_async(rtnl, &slot, m, link_handler, test_async_destroy, ifname, 0, "hogehoge") >= 0);
+ assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
+ assert_se(sd_netlink_call_async(rtnl, &slot, m, link_handler, test_async_destroy, userdata, 0, "hogehoge") >= 0);
assert_se(sd_netlink_slot_get_netlink(slot) == rtnl);
- assert_se(sd_netlink_slot_get_userdata(slot) == ifname);
- assert_se(sd_netlink_slot_get_destroy_callback(slot, &destroy_callback) == 1);
- assert_se(destroy_callback == test_async_destroy);
- assert_se(sd_netlink_slot_get_floating(slot) == 0);
- assert_se(sd_netlink_slot_get_description(slot, &description) == 1);
- assert_se(streq(description, "hogehoge"));
-
- assert_se(sd_netlink_wait(rtnl, 0) >= 0);
- assert_se(sd_netlink_process(rtnl, &r) >= 0);
-
- assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
-}
-static void test_slot_set(int ifindex) {
- _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *r = NULL;
- _cleanup_(sd_netlink_slot_unrefp) sd_netlink_slot *slot = NULL;
- sd_netlink_destroy_t destroy_callback;
- const char *description;
- char *ifname;
-
- log_debug("/* %s */", __func__);
-
- ifname = strdup("lo");
- assert_se(ifname);
-
- assert_se(sd_netlink_open(&rtnl) >= 0);
-
- assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
-
- assert_se(sd_netlink_call_async(rtnl, &slot, m, link_handler, NULL, NULL, 0, NULL) >= 0);
+ assert_se(sd_netlink_slot_get_userdata(slot) == userdata);
+ assert_se(sd_netlink_slot_set_userdata(slot, NULL) == userdata);
+ assert_se(sd_netlink_slot_get_userdata(slot) == NULL);
+ assert_se(sd_netlink_slot_set_userdata(slot, userdata) == NULL);
+ assert_se(sd_netlink_slot_get_userdata(slot) == userdata);
- assert_se(sd_netlink_slot_get_netlink(slot) == rtnl);
- assert_se(!sd_netlink_slot_get_userdata(slot));
- assert_se(!sd_netlink_slot_set_userdata(slot, ifname));
- assert_se(sd_netlink_slot_get_userdata(slot) == ifname);
- assert_se(sd_netlink_slot_get_destroy_callback(slot, NULL) == 0);
+ assert_se(sd_netlink_slot_get_destroy_callback(slot, &destroy_callback) == 1);
+ assert_se(destroy_callback == test_async_destroy);
+ assert_se(sd_netlink_slot_set_destroy_callback(slot, NULL) >= 0);
+ assert_se(sd_netlink_slot_get_destroy_callback(slot, &destroy_callback) == 0);
+ assert_se(destroy_callback == NULL);
assert_se(sd_netlink_slot_set_destroy_callback(slot, test_async_destroy) >= 0);
assert_se(sd_netlink_slot_get_destroy_callback(slot, &destroy_callback) == 1);
assert_se(destroy_callback == test_async_destroy);
+
assert_se(sd_netlink_slot_get_floating(slot) == 0);
assert_se(sd_netlink_slot_set_floating(slot, 1) == 1);
assert_se(sd_netlink_slot_get_floating(slot) == 1);
- assert_se(sd_netlink_slot_get_description(slot, NULL) == 0);
- assert_se(sd_netlink_slot_set_description(slot, "hogehoge") >= 0);
+
assert_se(sd_netlink_slot_get_description(slot, &description) == 1);
assert_se(streq(description, "hogehoge"));
+ assert_se(sd_netlink_slot_set_description(slot, NULL) >= 0);
+ assert_se(sd_netlink_slot_get_description(slot, &description) == 0);
+ assert_se(description == NULL);
assert_se(sd_netlink_wait(rtnl, 0) >= 0);
- assert_se(sd_netlink_process(rtnl, &r) >= 0);
+ assert_se(sd_netlink_process(rtnl, &reply) >= 0);
assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
}
@@ -322,23 +264,21 @@ static void test_async_object_destroy(void *userdata) {
test_async_object_unref(t);
}
-static void test_async_destroy_callback(int ifindex) {
+TEST(async_destroy_callback) {
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *r = NULL;
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL;
_cleanup_(test_async_object_unrefp) struct test_async_object *t = NULL;
_cleanup_(sd_netlink_slot_unrefp) sd_netlink_slot *slot = NULL;
- char *ifname;
+ int ifindex;
- log_debug("/* %s */", __func__);
+ assert_se(sd_netlink_open(&rtnl) >= 0);
+ ifindex = (int) if_nametoindex("lo");
assert_se(t = new(struct test_async_object, 1));
- assert_se(ifname = strdup("lo"));
*t = (struct test_async_object) {
.n_ref = 1,
- .ifname = ifname,
};
-
- assert_se(sd_netlink_open(&rtnl) >= 0);
+ assert_se(t->ifname = strdup("lo"));
/* destroy callback is called after processing message */
assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
@@ -349,7 +289,7 @@ static void test_async_destroy_callback(int ifindex) {
assert_se(t->n_ref == 2);
assert_se(sd_netlink_wait(rtnl, 0) >= 0);
- assert_se(sd_netlink_process(rtnl, &r) == 1);
+ assert_se(sd_netlink_process(rtnl, &reply) == 1);
assert_se(t->n_ref == 1);
assert_se(!sd_netlink_message_unref(m));
@@ -394,14 +334,13 @@ static int pipe_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata)
return 1;
}
-static void test_pipe(int ifindex) {
+TEST(pipe) {
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m1 = NULL, *m2 = NULL;
- int counter = 0;
-
- log_debug("/* %s */", __func__);
+ int ifindex, counter = 0;
assert_se(sd_netlink_open(&rtnl) >= 0);
+ ifindex = (int) if_nametoindex("lo");
assert_se(sd_rtnl_message_new_link(rtnl, &m1, RTM_GETLINK, ifindex) >= 0);
assert_se(sd_rtnl_message_new_link(rtnl, &m2, RTM_GETLINK, ifindex) >= 0);
@@ -420,13 +359,14 @@ static void test_pipe(int ifindex) {
assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
}
-static void test_container(sd_netlink *rtnl) {
+TEST(message_container) {
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
uint16_t u16_data;
uint32_t u32_data;
const char *string_data;
- log_debug("/* %s */", __func__);
+ assert_se(sd_netlink_open(&rtnl) >= 0);
assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0) >= 0);
@@ -434,9 +374,7 @@ static void test_container(sd_netlink *rtnl) {
assert_se(sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "vlan") >= 0);
assert_se(sd_netlink_message_append_u16(m, IFLA_VLAN_ID, 100) >= 0);
assert_se(sd_netlink_message_close_container(m) >= 0);
- assert_se(sd_netlink_message_append_string(m, IFLA_INFO_KIND, "vlan") >= 0);
assert_se(sd_netlink_message_close_container(m) >= 0);
- assert_se(sd_netlink_message_close_container(m) == -EINVAL);
assert_se(sd_netlink_message_rewind(m, rtnl) >= 0);
@@ -453,16 +391,12 @@ static void test_container(sd_netlink *rtnl) {
assert_se(sd_netlink_message_exit_container(m) >= 0);
assert_se(sd_netlink_message_read_u32(m, IFLA_LINKINFO, &u32_data) < 0);
-
- assert_se(sd_netlink_message_exit_container(m) == -EINVAL);
}
-static void test_match(void) {
+TEST(sd_netlink_add_match) {
_cleanup_(sd_netlink_slot_unrefp) sd_netlink_slot *s1 = NULL, *s2 = NULL;
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
- log_debug("/* %s */", __func__);
-
assert_se(sd_netlink_open(&rtnl) >= 0);
assert_se(sd_netlink_add_match(rtnl, &s1, RTM_NEWLINK, link_handler, NULL, NULL, NULL) >= 0);
@@ -475,17 +409,17 @@ static void test_match(void) {
assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
}
-static void test_get_addresses(sd_netlink *rtnl) {
+TEST(dump_addresses) {
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
- sd_netlink_message *m;
- log_debug("/* %s */", __func__);
+ assert_se(sd_netlink_open(&rtnl) >= 0);
assert_se(sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC) >= 0);
assert_se(sd_netlink_message_set_request_dump(req, true) >= 0);
assert_se(sd_netlink_call(rtnl, req, 0, &reply) >= 0);
- for (m = reply; m; m = sd_netlink_message_next(m)) {
+ for (sd_netlink_message *m = reply; m; m = sd_netlink_message_next(m)) {
uint16_t type;
unsigned char scope, flags;
int family, ifindex;
@@ -505,21 +439,20 @@ static void test_get_addresses(sd_netlink *rtnl) {
}
}
-static void test_message(sd_netlink *rtnl) {
+TEST(sd_netlink_message_get_errno) {
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
- log_debug("/* %s */", __func__);
+ assert_se(sd_netlink_open(&rtnl) >= 0);
assert_se(message_new_synthetic_error(rtnl, -ETIMEDOUT, 1, &m) >= 0);
assert_se(sd_netlink_message_get_errno(m) == -ETIMEDOUT);
}
-static void test_array(void) {
+TEST(message_array) {
_cleanup_(sd_netlink_unrefp) sd_netlink *genl = NULL;
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
- log_debug("/* %s */", __func__);
-
assert_se(sd_genl_socket_open(&genl) >= 0);
assert_se(sd_genl_message_new(genl, CTRL_GENL_NAME, CTRL_CMD_GETFAMILY, &m) >= 0);
@@ -557,12 +490,13 @@ static void test_array(void) {
assert_se(sd_netlink_message_exit_container(m) >= 0);
}
-static void test_strv(sd_netlink *rtnl) {
+TEST(message_strv) {
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
_cleanup_strv_free_ char **names_in = NULL, **names_out;
const char *p;
- log_debug("/* %s */", __func__);
+ assert_se(sd_netlink_open(&rtnl) >= 0);
assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINKPROP, 1) >= 0);
@@ -624,7 +558,7 @@ static int genl_ctrl_match_callback(sd_netlink *genl, sd_netlink_message *m, voi
return 0;
}
-static void test_genl(void) {
+TEST(genl) {
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
_cleanup_(sd_netlink_unrefp) sd_netlink *genl = NULL;
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
@@ -632,8 +566,6 @@ static void test_genl(void) {
uint8_t cmd;
int r;
- log_debug("/* %s */", __func__);
-
assert_se(sd_genl_socket_open(&genl) >= 0);
assert_se(sd_event_default(&event) >= 0);
assert_se(sd_netlink_attach_event(genl, event, 0) >= 0);
@@ -669,15 +601,17 @@ static void test_genl(void) {
}
}
-static void test_rtnl_set_link_name(sd_netlink *rtnl, int ifindex) {
+TEST(rtnl_set_link_name) {
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
_cleanup_strv_free_ char **alternative_names = NULL;
- int r;
-
- log_debug("/* %s */", __func__);
+ int ifindex, r;
if (geteuid() != 0)
return (void) log_tests_skipped("not root");
+ assert_se(sd_netlink_open(&rtnl) >= 0);
+ ifindex = (int) if_nametoindex("lo");
+
/* Test that the new name (which is currently an alternative name) is
* restored as an alternative name on error. Create an error by using
* an invalid device name, namely one that exceeds IFNAMSIZ
@@ -693,68 +627,4 @@ static void test_rtnl_set_link_name(sd_netlink *rtnl, int ifindex) {
assert_se(rtnl_delete_link_alternative_names(&rtnl, ifindex, STRV_MAKE("testlongalternativename")) >= 0);
}
-int main(void) {
- sd_netlink *rtnl;
- sd_netlink_message *m;
- sd_netlink_message *r;
- const char *string_data;
- int if_loopback;
- uint16_t type;
-
- test_setup_logging(LOG_DEBUG);
-
- test_match();
- test_multiple();
-
- assert_se(sd_netlink_open(&rtnl) >= 0);
- assert_se(rtnl);
-
- test_route(rtnl);
- test_message(rtnl);
- test_container(rtnl);
- test_array();
- test_strv(rtnl);
-
- if_loopback = (int) if_nametoindex("lo");
- assert_se(if_loopback > 0);
-
- test_async(if_loopback);
- test_slot_set(if_loopback);
- test_async_destroy_callback(if_loopback);
- test_pipe(if_loopback);
- test_event_loop(if_loopback);
- test_link_configure(rtnl, if_loopback);
- test_rtnl_set_link_name(rtnl, if_loopback);
-
- test_get_addresses(rtnl);
- test_message_link_bridge(rtnl);
-
- assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, if_loopback) >= 0);
- assert_se(m);
-
- assert_se(sd_netlink_message_get_type(m, &type) >= 0);
- assert_se(type == RTM_GETLINK);
-
- assert_se(sd_netlink_message_read_string(m, IFLA_IFNAME, &string_data) == -EPERM);
-
- assert_se(sd_netlink_call(rtnl, m, 0, &r) == 1);
- assert_se(sd_netlink_message_get_type(r, &type) >= 0);
- assert_se(type == RTM_NEWLINK);
-
- assert_se((r = sd_netlink_message_unref(r)) == NULL);
-
- assert_se(sd_netlink_call(rtnl, m, -1, &r) == -EPERM);
- assert_se((m = sd_netlink_message_unref(m)) == NULL);
- assert_se((r = sd_netlink_message_unref(r)) == NULL);
-
- test_link_get(rtnl, if_loopback);
- test_address_get(rtnl, if_loopback);
-
- assert_se((m = sd_netlink_message_unref(m)) == NULL);
- assert_se((r = sd_netlink_message_unref(r)) == NULL);
- assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
-
- test_genl();
-
- return EXIT_SUCCESS;
-}
+DEFINE_TEST_MAIN(LOG_DEBUG);

@ -0,0 +1,105 @@
From 49fa9a23e444f864a4f06fb0c7b1f54ff0513206 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 9 Jan 2023 21:00:53 +0900
Subject: [PATCH] test-netlink: use dummy interface to test assigning new
interface name
Fixes #25981.
(cherry picked from commit 5ccbe7fb197b01e0cf1f1ab523703274ef552555)
Related: RHEL-5988
---
src/libsystemd/sd-netlink/test-netlink.c | 59 ++++++++++++++++++++++--
1 file changed, 55 insertions(+), 4 deletions(-)
diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c
index f740035639..9ad8ecf320 100644
--- a/src/libsystemd/sd-netlink/test-netlink.c
+++ b/src/libsystemd/sd-netlink/test-netlink.c
@@ -601,30 +601,81 @@ TEST(genl) {
}
}
+static void remove_dummy_interfacep(int *ifindex) {
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
+
+ if (!ifindex || *ifindex <= 0)
+ return;
+
+ assert_se(sd_netlink_open(&rtnl) >= 0);
+
+ assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_DELLINK, *ifindex) >= 0);
+ assert_se(sd_netlink_call(rtnl, message, 0, NULL) == 1);
+}
+
TEST(rtnl_set_link_name) {
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL, *reply = NULL;
+ _cleanup_(remove_dummy_interfacep) int ifindex = 0;
_cleanup_strv_free_ char **alternative_names = NULL;
- int ifindex, r;
+ int r;
if (geteuid() != 0)
return (void) log_tests_skipped("not root");
assert_se(sd_netlink_open(&rtnl) >= 0);
- ifindex = (int) if_nametoindex("lo");
+
+ assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_NEWLINK, 0) >= 0);
+ assert_se(sd_netlink_message_append_string(message, IFLA_IFNAME, "test-netlink") >= 0);
+ assert_se(sd_netlink_message_open_container(message, IFLA_LINKINFO) >= 0);
+ assert_se(sd_netlink_message_append_string(message, IFLA_INFO_KIND, "dummy") >= 0);
+ r = sd_netlink_call(rtnl, message, 0, &reply);
+ if (r == -EPERM)
+ return (void) log_tests_skipped("missing required capabilities");
+ if (r == -EOPNOTSUPP)
+ return (void) log_tests_skipped("dummy network interface is not supported");
+ assert_se(r >= 0);
+
+ message = sd_netlink_message_unref(message);
+ reply = sd_netlink_message_unref(reply);
+
+ assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_GETLINK, 0) >= 0);
+ assert_se(sd_netlink_message_append_string(message, IFLA_IFNAME, "test-netlink") >= 0);
+ assert_se(sd_netlink_call(rtnl, message, 0, &reply) == 1);
+
+ assert_se(sd_rtnl_message_link_get_ifindex(reply, &ifindex) >= 0);
+ assert_se(ifindex > 0);
/* Test that the new name (which is currently an alternative name) is
* restored as an alternative name on error. Create an error by using
* an invalid device name, namely one that exceeds IFNAMSIZ
* (alternative names can exceed IFNAMSIZ, but not regular names). */
- r = rtnl_set_link_alternative_names(&rtnl, ifindex, STRV_MAKE("testlongalternativename"));
+ r = rtnl_set_link_alternative_names(&rtnl, ifindex, STRV_MAKE("testlongalternativename", "test-shortname"));
if (r == -EPERM)
return (void) log_tests_skipped("missing required capabilities");
-
+ if (r == -EOPNOTSUPP)
+ return (void) log_tests_skipped("alternative name is not supported");
assert_se(r >= 0);
+
+ assert_se(rtnl_get_link_alternative_names(&rtnl, ifindex, &alternative_names) >= 0);
+ assert_se(strv_contains(alternative_names, "testlongalternativename"));
+ assert_se(strv_contains(alternative_names, "test-shortname"));
+
assert_se(rtnl_set_link_name(&rtnl, ifindex, "testlongalternativename") == -EINVAL);
+ assert_se(rtnl_set_link_name(&rtnl, ifindex, "test-shortname") >= 0);
+
+ alternative_names = strv_free(alternative_names);
assert_se(rtnl_get_link_alternative_names(&rtnl, ifindex, &alternative_names) >= 0);
assert_se(strv_contains(alternative_names, "testlongalternativename"));
+ assert_se(!strv_contains(alternative_names, "test-shortname"));
+
assert_se(rtnl_delete_link_alternative_names(&rtnl, ifindex, STRV_MAKE("testlongalternativename")) >= 0);
+
+ alternative_names = strv_free(alternative_names);
+ assert_se(rtnl_get_link_alternative_names(&rtnl, ifindex, &alternative_names) >= 0);
+ assert_se(!strv_contains(alternative_names, "testlongalternativename"));
+ assert_se(!strv_contains(alternative_names, "test-shortname"));
}
DEFINE_TEST_MAIN(LOG_DEBUG);

@ -0,0 +1,26 @@
From 2deb458c5fd4ac318018b8464fa677dc4570ba61 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 16 May 2023 16:34:31 +0900
Subject: [PATCH] udev: use SYNTHETIC_ERRNO() at one more place
(cherry picked from commit b3cfe5900108df81fbf547b297d51ac8c7359a9b)
Related: RHEL-5988
---
src/udev/udevadm-test-builtin.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/udev/udevadm-test-builtin.c b/src/udev/udevadm-test-builtin.c
index 81b633611e..5570eec789 100644
--- a/src/udev/udevadm-test-builtin.c
+++ b/src/udev/udevadm-test-builtin.c
@@ -87,8 +87,7 @@ int builtin_main(int argc, char *argv[], void *userdata) {
cmd = udev_builtin_lookup(arg_command);
if (cmd < 0) {
- log_error("Unknown command '%s'", arg_command);
- r = -EINVAL;
+ r = log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown command '%s'", arg_command);
goto finish;
}

@ -0,0 +1,351 @@
From 09bc1c97130c4e646233ee3ea27ba03c226117d7 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 16 May 2023 11:29:49 +0900
Subject: [PATCH] udev: make udev_builtin_run() take UdevEvent*
No functional change, preparation for later commits.
(cherry picked from commit 5668f3a7cfccca704ea8e8bdc84ca7e17a5f101e)
Related: RHEL-5988
---
src/udev/udev-builtin-blkid.c | 3 ++-
src/udev/udev-builtin-btrfs.c | 3 ++-
src/udev/udev-builtin-hwdb.c | 3 ++-
src/udev/udev-builtin-input_id.c | 6 ++----
src/udev/udev-builtin-keyboard.c | 3 ++-
src/udev/udev-builtin-kmod.c | 5 ++---
src/udev/udev-builtin-net_id.c | 3 ++-
src/udev/udev-builtin-net_setup_link.c | 7 ++++---
src/udev/udev-builtin-path_id.c | 5 ++---
src/udev/udev-builtin-uaccess.c | 3 ++-
src/udev/udev-builtin-usb_id.c | 5 ++---
src/udev/udev-builtin.c | 7 ++++---
src/udev/udev-builtin.h | 6 ++++--
src/udev/udev-event.c | 2 +-
src/udev/udev-rules.c | 2 +-
src/udev/udevadm-test-builtin.c | 10 ++++++++--
16 files changed, 42 insertions(+), 31 deletions(-)
diff --git a/src/udev/udev-builtin-blkid.c b/src/udev/udev-builtin-blkid.c
index 9f5646ffdd..63d1bd579d 100644
--- a/src/udev/udev-builtin-blkid.c
+++ b/src/udev/udev-builtin-blkid.c
@@ -237,7 +237,8 @@ static int probe_superblocks(blkid_probe pr) {
return blkid_do_safeprobe(pr);
}
-static int builtin_blkid(sd_device *dev, sd_netlink **rtnl, int argc, char *argv[], bool test) {
+static int builtin_blkid(UdevEvent *event, int argc, char *argv[], bool test) {
+ sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
const char *devnode, *root_partition = NULL, *data, *name;
_cleanup_(blkid_free_probep) blkid_probe pr = NULL;
bool noraid = false, is_gpt = false;
diff --git a/src/udev/udev-builtin-btrfs.c b/src/udev/udev-builtin-btrfs.c
index 8cd627807f..b36eadb47a 100644
--- a/src/udev/udev-builtin-btrfs.c
+++ b/src/udev/udev-builtin-btrfs.c
@@ -13,7 +13,8 @@
#include "udev-builtin.h"
#include "util.h"
-static int builtin_btrfs(sd_device *dev, sd_netlink **rtnl, int argc, char *argv[], bool test) {
+static int builtin_btrfs(UdevEvent *event, int argc, char *argv[], bool test) {
+ sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
struct btrfs_ioctl_vol_args args = {};
_cleanup_close_ int fd = -1;
int r;
diff --git a/src/udev/udev-builtin-hwdb.c b/src/udev/udev-builtin-hwdb.c
index 8d652e46fe..19e07e734f 100644
--- a/src/udev/udev-builtin-hwdb.c
+++ b/src/udev/udev-builtin-hwdb.c
@@ -118,7 +118,7 @@ next:
return r;
}
-static int builtin_hwdb(sd_device *dev, sd_netlink **rtnl, int argc, char *argv[], bool test) {
+static int builtin_hwdb(UdevEvent *event, int argc, char *argv[], bool test) {
static const struct option options[] = {
{ "filter", required_argument, NULL, 'f' },
{ "device", required_argument, NULL, 'd' },
@@ -131,6 +131,7 @@ static int builtin_hwdb(sd_device *dev, sd_netlink **rtnl, int argc, char *argv[
const char *subsystem = NULL;
const char *prefix = NULL;
_cleanup_(sd_device_unrefp) sd_device *srcdev = NULL;
+ sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
int r;
if (!hwdb)
diff --git a/src/udev/udev-builtin-input_id.c b/src/udev/udev-builtin-input_id.c
index 0742120248..4322ce04b3 100644
--- a/src/udev/udev-builtin-input_id.c
+++ b/src/udev/udev-builtin-input_id.c
@@ -356,8 +356,8 @@ static bool test_key(sd_device *dev,
return found;
}
-static int builtin_input_id(sd_device *dev, sd_netlink **rtnl, int argc, char *argv[], bool test) {
- sd_device *pdev;
+static int builtin_input_id(UdevEvent *event, int argc, char *argv[], bool test) {
+ sd_device *pdev, *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
unsigned long bitmask_ev[NBITS(EV_MAX)];
unsigned long bitmask_abs[NBITS(ABS_MAX)];
unsigned long bitmask_key[NBITS(KEY_MAX)];
@@ -367,8 +367,6 @@ static int builtin_input_id(sd_device *dev, sd_netlink **rtnl, int argc, char *a
bool is_pointer;
bool is_key;
- assert(dev);
-
/* walk up the parental chain until we find the real input device; the
* argument is very likely a subdevice of this, like eventN */
for (pdev = dev; pdev; ) {
diff --git a/src/udev/udev-builtin-keyboard.c b/src/udev/udev-builtin-keyboard.c
index 6dd9eebd93..dac087a9e6 100644
--- a/src/udev/udev-builtin-keyboard.c
+++ b/src/udev/udev-builtin-keyboard.c
@@ -159,7 +159,8 @@ static int set_trackpoint_sensitivity(sd_device *dev, const char *value) {
return 0;
}
-static int builtin_keyboard(sd_device *dev, sd_netlink **rtnl, int argc, char *argv[], bool test) {
+static int builtin_keyboard(UdevEvent *event, int argc, char *argv[], bool test) {
+ sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
unsigned release[1024];
unsigned release_count = 0;
_cleanup_close_ int fd = -1;
diff --git a/src/udev/udev-builtin-kmod.c b/src/udev/udev-builtin-kmod.c
index eade042f35..3ab5c485f8 100644
--- a/src/udev/udev-builtin-kmod.c
+++ b/src/udev/udev-builtin-kmod.c
@@ -22,11 +22,10 @@ _printf_(6,0) static void udev_kmod_log(void *data, int priority, const char *fi
log_internalv(priority, 0, file, line, fn, format, args);
}
-static int builtin_kmod(sd_device *dev, sd_netlink **rtnl, int argc, char *argv[], bool test) {
+static int builtin_kmod(UdevEvent *event, int argc, char *argv[], bool test) {
+ sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
int r;
- assert(dev);
-
if (!ctx)
return 0;
diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
index c57568f8cb..cecf854b98 100644
--- a/src/udev/udev-builtin-net_id.c
+++ b/src/udev/udev-builtin-net_id.c
@@ -1109,7 +1109,8 @@ static int get_link_info(sd_device *dev, LinkInfo *info) {
return 0;
}
-static int builtin_net_id(sd_device *dev, sd_netlink **rtnl, int argc, char *argv[], bool test) {
+static int builtin_net_id(UdevEvent *event, int argc, char *argv[], bool test) {
+ sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
const char *prefix;
NetNames names = {};
LinkInfo info = {
diff --git a/src/udev/udev-builtin-net_setup_link.c b/src/udev/udev-builtin-net_setup_link.c
index ea7b1c5f60..4bf42cd492 100644
--- a/src/udev/udev-builtin-net_setup_link.c
+++ b/src/udev/udev-builtin-net_setup_link.c
@@ -10,14 +10,15 @@
static LinkConfigContext *ctx = NULL;
-static int builtin_net_setup_link(sd_device *dev, sd_netlink **rtnl, int argc, char **argv, bool test) {
+static int builtin_net_setup_link(UdevEvent *event, int argc, char **argv, bool test) {
+ sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
_cleanup_(link_freep) Link *link = NULL;
int r;
if (argc > 1)
return log_device_error_errno(dev, SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments.");
- r = link_new(ctx, rtnl, dev, &link);
+ r = link_new(ctx, &event->rtnl, dev, &link);
if (r == -ENODEV) {
log_device_debug_errno(dev, r, "Link vanished while getting information, ignoring.");
return 0;
@@ -38,7 +39,7 @@ static int builtin_net_setup_link(sd_device *dev, sd_netlink **rtnl, int argc, c
return log_device_error_errno(dev, r, "Failed to get link config: %m");
}
- r = link_apply_config(ctx, rtnl, link);
+ r = link_apply_config(ctx, &event->rtnl, link);
if (r == -ENODEV)
log_device_debug_errno(dev, r, "Link vanished while applying configuration, ignoring.");
else if (r < 0)
diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c
index d58a3d5d60..6f4d7cbc5b 100644
--- a/src/udev/udev-builtin-path_id.c
+++ b/src/udev/udev-builtin-path_id.c
@@ -581,15 +581,14 @@ static int find_real_nvme_parent(sd_device *dev, sd_device **ret) {
return 0;
}
-static int builtin_path_id(sd_device *dev, sd_netlink **rtnl, int argc, char *argv[], bool test) {
+static int builtin_path_id(UdevEvent *event, int argc, char *argv[], bool test) {
+ sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
_cleanup_(sd_device_unrefp) sd_device *dev_other_branch = NULL;
_cleanup_free_ char *path = NULL, *compat_path = NULL;
bool supported_transport = false, supported_parent = false;
const char *subsystem;
int r;
- assert(dev);
-
/* walk up the chain of devices and compose path */
for (sd_device *parent = dev; parent; ) {
const char *subsys, *sysname;
diff --git a/src/udev/udev-builtin-uaccess.c b/src/udev/udev-builtin-uaccess.c
index 6e73d99375..36c993cbb0 100644
--- a/src/udev/udev-builtin-uaccess.c
+++ b/src/udev/udev-builtin-uaccess.c
@@ -16,7 +16,8 @@
#include "log.h"
#include "udev-builtin.h"
-static int builtin_uaccess(sd_device *dev, sd_netlink **rtnl, int argc, char *argv[], bool test) {
+static int builtin_uaccess(UdevEvent *event, int argc, char *argv[], bool test) {
+ sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
const char *path = NULL, *seat;
bool changed_acl = false;
uid_t uid;
diff --git a/src/udev/udev-builtin-usb_id.c b/src/udev/udev-builtin-usb_id.c
index 847c2b8316..f3fc3cfdb3 100644
--- a/src/udev/udev-builtin-usb_id.c
+++ b/src/udev/udev-builtin-usb_id.c
@@ -224,7 +224,8 @@ static int dev_if_packed_info(sd_device *dev, char *ifs_str, size_t len) {
* 6.) If the device supplies a serial number, this number
* is concatenated with the identification with an underscore '_'.
*/
-static int builtin_usb_id(sd_device *dev, sd_netlink **rtnl, int argc, char *argv[], bool test) {
+static int builtin_usb_id(UdevEvent *event, int argc, char *argv[], bool test) {
+ sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
char vendor_str[64] = "";
char vendor_str_enc[256];
const char *vendor_id;
@@ -250,8 +251,6 @@ static int builtin_usb_id(sd_device *dev, sd_netlink **rtnl, int argc, char *arg
const char *syspath, *sysname, *devtype, *interface_syspath;
int r;
- assert(dev);
-
r = sd_device_get_syspath(dev, &syspath);
if (r < 0)
return r;
diff --git a/src/udev/udev-builtin.c b/src/udev/udev-builtin.c
index c98c6fa714..c84db8855c 100644
--- a/src/udev/udev-builtin.c
+++ b/src/udev/udev-builtin.c
@@ -98,11 +98,12 @@ UdevBuiltinCommand udev_builtin_lookup(const char *command) {
return _UDEV_BUILTIN_INVALID;
}
-int udev_builtin_run(sd_device *dev, sd_netlink **rtnl, UdevBuiltinCommand cmd, const char *command, bool test) {
+int udev_builtin_run(UdevEvent *event, UdevBuiltinCommand cmd, const char *command, bool test) {
_cleanup_strv_free_ char **argv = NULL;
int r;
- assert(dev);
+ assert(event);
+ assert(event->dev);
assert(cmd >= 0 && cmd < _UDEV_BUILTIN_MAX);
assert(command);
@@ -115,7 +116,7 @@ int udev_builtin_run(sd_device *dev, sd_netlink **rtnl, UdevBuiltinCommand cmd,
/* we need '0' here to reset the internal state */
optind = 0;
- return builtins[cmd]->cmd(dev, rtnl, strv_length(argv), argv, test);
+ return builtins[cmd]->cmd(event, strv_length(argv), argv, test);
}
int udev_builtin_add_property(sd_device *dev, bool test, const char *key, const char *val) {
diff --git a/src/udev/udev-builtin.h b/src/udev/udev-builtin.h
index bcfec03aae..919d51e798 100644
--- a/src/udev/udev-builtin.h
+++ b/src/udev/udev-builtin.h
@@ -6,6 +6,8 @@
#include "sd-device.h"
#include "sd-netlink.h"
+#include "udev-event.h"
+
typedef enum UdevBuiltinCommand {
#if HAVE_BLKID
UDEV_BUILTIN_BLKID,
@@ -30,7 +32,7 @@ typedef enum UdevBuiltinCommand {
typedef struct UdevBuiltin {
const char *name;
- int (*cmd)(sd_device *dev, sd_netlink **rtnl, int argc, char *argv[], bool test);
+ int (*cmd)(UdevEvent *event, int argc, char *argv[], bool test);
const char *help;
int (*init)(void);
void (*exit)(void);
@@ -74,7 +76,7 @@ void udev_builtin_exit(void);
UdevBuiltinCommand udev_builtin_lookup(const char *command);
const char *udev_builtin_name(UdevBuiltinCommand cmd);
bool udev_builtin_run_once(UdevBuiltinCommand cmd);
-int udev_builtin_run(sd_device *dev, sd_netlink **rtnl, UdevBuiltinCommand cmd, const char *command, bool test);
+int udev_builtin_run(UdevEvent *event, UdevBuiltinCommand cmd, const char *command, bool test);
void udev_builtin_list(void);
bool udev_builtin_should_reload(void);
int udev_builtin_add_property(sd_device *dev, bool test, const char *key, const char *val);
diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
index fab454ae37..cf90d6f205 100644
--- a/src/udev/udev-event.c
+++ b/src/udev/udev-event.c
@@ -1200,7 +1200,7 @@ void udev_event_execute_run(UdevEvent *event, usec_t timeout_usec, int timeout_s
if (builtin_cmd != _UDEV_BUILTIN_INVALID) {
log_device_debug(event->dev, "Running built-in command \"%s\"", command);
- r = udev_builtin_run(event->dev, &event->rtnl, builtin_cmd, command, false);
+ r = udev_builtin_run(event, builtin_cmd, command, false);
if (r < 0)
log_device_debug_errno(event->dev, r, "Failed to run built-in command \"%s\", ignoring: %m", command);
} else {
diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c
index a8473041c3..9336ce1cd3 100644
--- a/src/udev/udev-rules.c
+++ b/src/udev/udev-rules.c
@@ -1972,7 +1972,7 @@ static int udev_rule_apply_token_to_event(
log_rule_debug(dev, rules, "Importing properties from results of builtin command '%s'", buf);
- r = udev_builtin_run(dev, &event->rtnl, cmd, buf, false);
+ r = udev_builtin_run(event, cmd, buf, false);
if (r < 0) {
/* remember failure */
log_rule_debug_errno(dev, rules, r, "Failed to run builtin '%s': %m", buf);
diff --git a/src/udev/udevadm-test-builtin.c b/src/udev/udevadm-test-builtin.c
index 5570eec789..5d1fafbd03 100644
--- a/src/udev/udevadm-test-builtin.c
+++ b/src/udev/udevadm-test-builtin.c
@@ -72,7 +72,7 @@ static int parse_argv(int argc, char *argv[]) {
}
int builtin_main(int argc, char *argv[], void *userdata) {
- _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
+ _cleanup_(udev_event_freep) UdevEvent *event = NULL;
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
UdevBuiltinCommand cmd;
int r;
@@ -97,7 +97,13 @@ int builtin_main(int argc, char *argv[], void *userdata) {
goto finish;
}
- r = udev_builtin_run(dev, &rtnl, cmd, arg_command, true);
+ event = udev_event_new(dev, 0, NULL, LOG_DEBUG);
+ if (!event) {
+ r = log_oom();
+ goto finish;
+ }
+
+ r = udev_builtin_run(event, cmd, arg_command, true);
if (r < 0)
log_debug_errno(r, "Builtin command '%s' fails: %m", arg_command);

@ -0,0 +1,26 @@
From 87a2e6ccd7989f2b271f557c6303a4eb412a03cb Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 16 May 2023 11:46:11 +0900
Subject: [PATCH] udev/net: verify ID_NET_XYZ before trying to assign it as an
alternative name
(cherry picked from commit e65c6c1baa8ea905f7e5bad3b8486d509775ec6a)
Related: RHEL-5988
---
src/udev/net/link-config.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
index 5d28526527..4fcf373f8e 100644
--- a/src/udev/net/link-config.c
+++ b/src/udev/net/link-config.c
@@ -834,7 +834,7 @@ static int link_apply_alternative_names(Link *link, sd_netlink **rtnl) {
default:
assert_not_reached();
}
- if (!isempty(n)) {
+ if (ifname_valid_full(n, IFNAME_VALID_ALTERNATIVE)) {
r = strv_extend(&altnames, n);
if (r < 0)
return log_oom();

@ -0,0 +1,29 @@
From dd4c492721ed4be1b4c26cd937566dac2e97ba19 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 16 May 2023 13:05:09 +0900
Subject: [PATCH] udev/net: generate new network interface name only on add
uevent
On other uevents, the name will be anyway ignored in rename_netif() in
udev-event.c.
(cherry picked from commit cd941e6596adba6bb139c387ae596f26b35701f7)
Related: RHEL-5988
---
src/udev/net/link-config.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
index 4fcf373f8e..c9789bcb7c 100644
--- a/src/udev/net/link-config.c
+++ b/src/udev/net/link-config.c
@@ -722,7 +722,7 @@ static int link_generate_new_name(Link *link) {
config = link->config;
device = link->device;
- if (link->action == SD_DEVICE_MOVE) {
+ if (link->action != SD_DEVICE_ADD) {
log_link_debug(link, "Skipping to apply Name= and NamePolicy= on '%s' uevent.",
device_action_to_string(link->action));
goto no_rename;

@ -0,0 +1,191 @@
From ea5725b1e621c2733c28f818c3a58615a385337e Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 16 May 2023 13:29:37 +0900
Subject: [PATCH] sd-netlink: make rtnl_set_link_name() optionally append
alternative names
(cherry picked from commit 81824455008070253c62bf5c27187028ba8e7e99)
Related: RHEL-5988
---
src/libsystemd/sd-netlink/netlink-util.c | 89 ++++++++++++++++++------
src/libsystemd/sd-netlink/netlink-util.h | 5 +-
src/libsystemd/sd-netlink/test-netlink.c | 6 +-
src/udev/udev-event.c | 2 +-
4 files changed, 78 insertions(+), 24 deletions(-)
diff --git a/src/libsystemd/sd-netlink/netlink-util.c b/src/libsystemd/sd-netlink/netlink-util.c
index cfcf2578d6..5438737b42 100644
--- a/src/libsystemd/sd-netlink/netlink-util.c
+++ b/src/libsystemd/sd-netlink/netlink-util.c
@@ -11,44 +11,93 @@
#include "process-util.h"
#include "strv.h"
-int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
+static int set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
- _cleanup_strv_free_ char **alternative_names = NULL;
- bool altname_deleted = false;
int r;
assert(rtnl);
assert(ifindex > 0);
assert(name);
- if (!ifname_valid(name))
+ /* Assign the requested name. */
+ r = sd_rtnl_message_new_link(*rtnl, &message, RTM_SETLINK, ifindex);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_append_string(message, IFLA_IFNAME, name);
+ if (r < 0)
+ return r;
+
+ return sd_netlink_call(*rtnl, message, 0, NULL);
+}
+
+int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name, char* const *alternative_names) {
+ _cleanup_strv_free_ char **original_altnames = NULL, **new_altnames = NULL;
+ bool altname_deleted = false;
+ int r;
+
+ assert(rtnl);
+ assert(ifindex > 0);
+
+ if (isempty(name) && strv_isempty(alternative_names))
+ return 0;
+
+ if (name && !ifname_valid(name))
return -EINVAL;
- r = rtnl_get_link_alternative_names(rtnl, ifindex, &alternative_names);
+ /* If the requested name is already assigned as an alternative name, then first drop it. */
+ r = rtnl_get_link_alternative_names(rtnl, ifindex, &original_altnames);
if (r < 0)
log_debug_errno(r, "Failed to get alternative names on network interface %i, ignoring: %m",
ifindex);
- if (strv_contains(alternative_names, name)) {
- r = rtnl_delete_link_alternative_names(rtnl, ifindex, STRV_MAKE(name));
- if (r < 0)
- return log_debug_errno(r, "Failed to remove '%s' from alternative names on network interface %i: %m",
- name, ifindex);
+ if (name) {
+ if (strv_contains(original_altnames, name)) {
+ r = rtnl_delete_link_alternative_names(rtnl, ifindex, STRV_MAKE(name));
+ if (r < 0)
+ return log_debug_errno(r, "Failed to remove '%s' from alternative names on network interface %i: %m",
+ name, ifindex);
+
+ altname_deleted = true;
+ }
- altname_deleted = true;
+ r = set_link_name(rtnl, ifindex, name);
+ if (r < 0)
+ goto fail;
}
- r = sd_rtnl_message_new_link(*rtnl, &message, RTM_SETLINK, ifindex);
- if (r < 0)
- goto fail;
+ /* Filter out already assigned names from requested alternative names. Also, dedup the request. */
+ STRV_FOREACH(a, alternative_names) {
+ if (streq_ptr(name, *a))
+ continue;
- r = sd_netlink_message_append_string(message, IFLA_IFNAME, name);
- if (r < 0)
- goto fail;
+ if (strv_contains(original_altnames, *a))
+ continue;
- r = sd_netlink_call(*rtnl, message, 0, NULL);
- if (r < 0)
- goto fail;
+ if (strv_contains(new_altnames, *a))
+ continue;
+
+ if (!ifname_valid_full(*a, IFNAME_VALID_ALTERNATIVE))
+ continue;
+
+ r = strv_extend(&new_altnames, *a);
+ if (r < 0)
+ return r;
+ }
+
+ strv_sort(new_altnames);
+
+ /* Finally, assign alternative names. */
+ r = rtnl_set_link_alternative_names(rtnl, ifindex, new_altnames);
+ if (r == -EEXIST) /* Already assigned to another interface? */
+ STRV_FOREACH(a, new_altnames) {
+ r = rtnl_set_link_alternative_names(rtnl, ifindex, STRV_MAKE(*a));
+ if (r < 0)
+ log_debug_errno(r, "Failed to assign '%s' as an alternative name on network interface %i, ignoring: %m",
+ *a, ifindex);
+ }
+ else if (r < 0)
+ log_debug_errno(r, "Failed to assign alternative names on network interface %i, ignoring: %m", ifindex);
return 0;
diff --git a/src/libsystemd/sd-netlink/netlink-util.h b/src/libsystemd/sd-netlink/netlink-util.h
index d14392a018..888e28642d 100644
--- a/src/libsystemd/sd-netlink/netlink-util.h
+++ b/src/libsystemd/sd-netlink/netlink-util.h
@@ -29,7 +29,10 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(MultipathRoute*, multipath_route_free);
int multipath_route_dup(const MultipathRoute *m, MultipathRoute **ret);
-int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name);
+int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name, char* const* alternative_names);
+static inline int rtnl_append_link_alternative_names(sd_netlink **rtnl, int ifindex, char* const *alternative_names) {
+ return rtnl_set_link_name(rtnl, ifindex, NULL, alternative_names);
+}
int rtnl_set_link_properties(
sd_netlink **rtnl,
int ifindex,
diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c
index 9ad8ecf320..43124b99ae 100644
--- a/src/libsystemd/sd-netlink/test-netlink.c
+++ b/src/libsystemd/sd-netlink/test-netlink.c
@@ -662,12 +662,13 @@ TEST(rtnl_set_link_name) {
assert_se(strv_contains(alternative_names, "testlongalternativename"));
assert_se(strv_contains(alternative_names, "test-shortname"));
- assert_se(rtnl_set_link_name(&rtnl, ifindex, "testlongalternativename") == -EINVAL);
- assert_se(rtnl_set_link_name(&rtnl, ifindex, "test-shortname") >= 0);
+ assert_se(rtnl_set_link_name(&rtnl, ifindex, "testlongalternativename", NULL) == -EINVAL);
+ assert_se(rtnl_set_link_name(&rtnl, ifindex, "test-shortname", STRV_MAKE("testlongalternativename", "test-shortname", "test-additional-name")) >= 0);
alternative_names = strv_free(alternative_names);
assert_se(rtnl_get_link_alternative_names(&rtnl, ifindex, &alternative_names) >= 0);
assert_se(strv_contains(alternative_names, "testlongalternativename"));
+ assert_se(strv_contains(alternative_names, "test-additional-name"));
assert_se(!strv_contains(alternative_names, "test-shortname"));
assert_se(rtnl_delete_link_alternative_names(&rtnl, ifindex, STRV_MAKE("testlongalternativename")) >= 0);
@@ -675,6 +676,7 @@ TEST(rtnl_set_link_name) {
alternative_names = strv_free(alternative_names);
assert_se(rtnl_get_link_alternative_names(&rtnl, ifindex, &alternative_names) >= 0);
assert_se(!strv_contains(alternative_names, "testlongalternativename"));
+ assert_se(strv_contains(alternative_names, "test-additional-name"));
assert_se(!strv_contains(alternative_names, "test-shortname"));
}
diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
index cf90d6f205..2662806d61 100644
--- a/src/udev/udev-event.c
+++ b/src/udev/udev-event.c
@@ -980,7 +980,7 @@ static int rename_netif(UdevEvent *event) {
goto revert;
}
- r = rtnl_set_link_name(&event->rtnl, ifindex, event->name);
+ r = rtnl_set_link_name(&event->rtnl, ifindex, event->name, NULL);
if (r < 0) {
if (r == -EBUSY) {
log_device_info(dev, "Network interface '%s' is already up, cannot rename to '%s'.",

@ -0,0 +1,233 @@
From 11f76dbf187708c3eda4a4daeb058f544ea28af5 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 16 May 2023 12:28:23 +0900
Subject: [PATCH] udev/net: assign alternative names only on add uevent
Previously, we first assign alternative names to a network interface,
then later change its main name if requested. So, we could not assign
the name that currently assigned as the main name of an interface as an
alternative name. So, we retry to assign the previous main name as an
alternative name on later move uevent.
However, that causes some confusing situation. E.g. if a .link file has
```
Name=foo
AlternativeNames=foo baz
```
then even if the interface is renamed by a user e.g. by invoking 'ip link'
command manually, the interface can be still referenced as 'foo', as the
name is now assigned as an alternative name.
This makes the order of name assignment inverse: the main name is first
changed, and then the requested alternative names are assigned. And
udevd do not assign alternative names on move uevent.
Replaces #27506.
(cherry picked from commit 9094ae52caca0c19ff6abdbd95d17d8e401ea3b1)
Resolves: RHEL-5988
---
src/udev/net/link-config.c | 37 ++++++++-------------
src/udev/net/link-config.h | 1 +
src/udev/udev-builtin-net_setup_link.c | 2 ++
src/udev/udev-event.c | 45 ++++++++++++++++++++++----
src/udev/udev-event.h | 1 +
5 files changed, 55 insertions(+), 31 deletions(-)
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
index c9789bcb7c..2d8c902fd3 100644
--- a/src/udev/net/link-config.c
+++ b/src/udev/net/link-config.c
@@ -363,6 +363,7 @@ Link *link_free(Link *link) {
sd_device_unref(link->device);
free(link->kind);
free(link->driver);
+ strv_free(link->altnames);
return mfree(link);
}
@@ -791,19 +792,22 @@ no_rename:
return 0;
}
-static int link_apply_alternative_names(Link *link, sd_netlink **rtnl) {
- _cleanup_strv_free_ char **altnames = NULL, **current_altnames = NULL;
+static int link_generate_alternative_names(Link *link) {
+ _cleanup_strv_free_ char **altnames = NULL;
LinkConfig *config;
sd_device *device;
int r;
assert(link);
- assert(link->config);
- assert(link->device);
- assert(rtnl);
+ config = ASSERT_PTR(link->config);
+ device = ASSERT_PTR(link->device);
+ assert(!link->altnames);
- config = link->config;
- device = link->device;
+ if (link->action != SD_DEVICE_ADD) {
+ log_link_debug(link, "Skipping to apply AlternativeNames= and AlternativeNamesPolicy= on '%s' uevent.",
+ device_action_to_string(link->action));
+ return 0;
+ }
if (config->alternative_names) {
altnames = strv_copy(config->alternative_names);
@@ -841,22 +845,7 @@ static int link_apply_alternative_names(Link *link, sd_netlink **rtnl) {
}
}
- strv_remove(altnames, link->ifname);
-
- r = rtnl_get_link_alternative_names(rtnl, link->ifindex, &current_altnames);
- if (r < 0)
- log_link_debug_errno(link, r, "Failed to get alternative names, ignoring: %m");
-
- STRV_FOREACH(p, current_altnames)
- strv_remove(altnames, *p);
-
- strv_uniq(altnames);
- strv_sort(altnames);
- r = rtnl_set_link_alternative_names(rtnl, link->ifindex, altnames);
- if (r < 0)
- log_link_full_errno(link, r == -EOPNOTSUPP ? LOG_DEBUG : LOG_WARNING, r,
- "Could not set AlternativeName= or apply AlternativeNamesPolicy=, ignoring: %m");
-
+ link->altnames = TAKE_PTR(altnames);
return 0;
}
@@ -958,7 +947,7 @@ int link_apply_config(LinkConfigContext *ctx, sd_netlink **rtnl, Link *link) {
if (r < 0)
return r;
- r = link_apply_alternative_names(link, rtnl);
+ r = link_generate_alternative_names(link);
if (r < 0)
return r;
diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h
index ea9f560f45..874a391543 100644
--- a/src/udev/net/link-config.h
+++ b/src/udev/net/link-config.h
@@ -27,6 +27,7 @@ typedef struct Link {
int ifindex;
const char *ifname;
const char *new_name;
+ char **altnames;
LinkConfig *config;
sd_device *device;
diff --git a/src/udev/udev-builtin-net_setup_link.c b/src/udev/udev-builtin-net_setup_link.c
index 4bf42cd492..e964bf7bf4 100644
--- a/src/udev/udev-builtin-net_setup_link.c
+++ b/src/udev/udev-builtin-net_setup_link.c
@@ -49,6 +49,8 @@ static int builtin_net_setup_link(UdevEvent *event, int argc, char **argv, bool
if (link->new_name)
udev_builtin_add_property(dev, test, "ID_NET_NAME", link->new_name);
+ event->altnames = TAKE_PTR(link->altnames);
+
return 0;
}
diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
index 2662806d61..3315d34eff 100644
--- a/src/udev/udev-event.c
+++ b/src/udev/udev-event.c
@@ -88,6 +88,7 @@ UdevEvent *udev_event_free(UdevEvent *event) {
ordered_hashmap_free_free_free(event->seclabel_list);
free(event->program_result);
free(event->name);
+ strv_free(event->altnames);
return mfree(event);
}
@@ -918,9 +919,6 @@ static int rename_netif(UdevEvent *event) {
dev = ASSERT_PTR(event->dev);
- if (!device_for_action(dev, SD_DEVICE_ADD))
- return 0; /* Rename the interface only when it is added. */
-
r = sd_device_get_ifindex(dev, &ifindex);
if (r == -ENOENT)
return 0; /* Device is not a network interface. */
@@ -980,7 +978,7 @@ static int rename_netif(UdevEvent *event) {
goto revert;
}
- r = rtnl_set_link_name(&event->rtnl, ifindex, event->name, NULL);
+ r = rtnl_set_link_name(&event->rtnl, ifindex, event->name, event->altnames);
if (r < 0) {
if (r == -EBUSY) {
log_device_info(dev, "Network interface '%s' is already up, cannot rename to '%s'.",
@@ -1011,6 +1009,35 @@ revert:
return r;
}
+static int assign_altnames(UdevEvent *event) {
+ sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
+ int ifindex, r;
+ const char *s;
+
+ if (strv_isempty(event->altnames))
+ return 0;
+
+ r = sd_device_get_ifindex(dev, &ifindex);
+ if (r == -ENOENT)
+ return 0; /* Device is not a network interface. */
+ if (r < 0)
+ return log_device_warning_errno(dev, r, "Failed to get ifindex: %m");
+
+ r = sd_device_get_sysname(dev, &s);
+ if (r < 0)
+ return log_device_warning_errno(dev, r, "Failed to get sysname: %m");
+
+ /* Filter out the current interface name. */
+ strv_remove(event->altnames, s);
+
+ r = rtnl_append_link_alternative_names(&event->rtnl, ifindex, event->altnames);
+ if (r < 0)
+ log_device_full_errno(dev, r == -EOPNOTSUPP ? LOG_DEBUG : LOG_WARNING, r,
+ "Could not set AlternativeName= or apply AlternativeNamesPolicy=, ignoring: %m");
+
+ return 0;
+}
+
static int update_devnode(UdevEvent *event) {
sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
int r;
@@ -1163,9 +1190,13 @@ int udev_event_execute_rules(
DEVICE_TRACE_POINT(rules_finished, dev);
- r = rename_netif(event);
- if (r < 0)
- return r;
+ if (action == SD_DEVICE_ADD) {
+ r = rename_netif(event);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ (void) assign_altnames(event);
+ }
r = update_devnode(event);
if (r < 0)
diff --git a/src/udev/udev-event.h b/src/udev/udev-event.h
index 74d065ce23..13bd85dcf7 100644
--- a/src/udev/udev-event.h
+++ b/src/udev/udev-event.h
@@ -23,6 +23,7 @@ typedef struct UdevEvent {
sd_device *dev_parent;
sd_device *dev_db_clone;
char *name;
+ char **altnames;
char *program_result;
mode_t mode;
uid_t uid;

@ -0,0 +1,105 @@
From dec129d192c7815bdfbb71c88a1d7cdc3092f11f Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 16 May 2023 16:28:54 +0900
Subject: [PATCH] test: add tests for renaming network interface
(cherry picked from commit 40b6b448bda5294582e685091123952fbcd43502)
Related: RHEL-5988
---
test/units/testsuite-17.12.sh | 86 +++++++++++++++++++++++++++++++++++
1 file changed, 86 insertions(+)
create mode 100755 test/units/testsuite-17.12.sh
diff --git a/test/units/testsuite-17.12.sh b/test/units/testsuite-17.12.sh
new file mode 100755
index 0000000000..df74d356ee
--- /dev/null
+++ b/test/units/testsuite-17.12.sh
@@ -0,0 +1,86 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -ex
+set -o pipefail
+
+# shellcheck source=test/units/assert.sh
+. "$(dirname "$0")"/assert.sh
+
+create_link_file() {
+ name=${1?}
+
+ mkdir -p /run/systemd/network/
+ cat >/run/systemd/network/10-test.link <<EOF
+[Match]
+Kind=dummy
+MACAddress=00:50:56:c0:00:18
+
+[Link]
+Name=$name
+AlternativeName=test1 test2 test3 test4
+EOF
+ udevadm control --reload
+}
+
+udevadm control --log-level=debug
+
+create_link_file test1
+ip link add address 00:50:56:c0:00:18 type dummy
+udevadm wait --settle --timeout=30 /sys/class/net/test1
+output=$(ip link show dev test1)
+if ! [[ "$output" =~ altname ]]; then
+ echo "alternative name for network interface not supported, skipping test."
+ exit 0
+fi
+assert_not_in "altname test1" "$output"
+assert_in "altname test2" "$output"
+assert_in "altname test3" "$output"
+assert_in "altname test4" "$output"
+
+# By triggering add event, Name= and AlternativeNames= are re-applied
+create_link_file test2
+udevadm trigger --action add --settle /sys/class/net/test1
+udevadm wait --settle --timeout=30 /sys/class/net/test2
+output=$(ip link show dev test2)
+assert_in "altname test1" "$output"
+assert_not_in "altname test2" "$output"
+assert_in "altname test3" "$output"
+assert_in "altname test4" "$output"
+
+# Name= and AlternativeNames= are not applied on move event
+create_link_file test3
+udevadm trigger --action move --settle /sys/class/net/test2
+udevadm wait --settle --timeout=30 /sys/class/net/test2
+output=$(ip link show dev test2)
+assert_in "altname test1" "$output"
+assert_not_in "altname test2" "$output"
+assert_in "altname test3" "$output"
+assert_in "altname test4" "$output"
+
+# Test move event triggered by manual renaming
+ip link set dev test2 name hoge
+udevadm wait --settle --timeout=30 /sys/class/net/hoge
+output=$(ip link show dev hoge)
+assert_in "altname test1" "$output"
+assert_not_in "altname test2" "$output"
+assert_in "altname test3" "$output"
+assert_in "altname test4" "$output"
+assert_not_in "altname hoge" "$output"
+
+# Re-test add event
+udevadm trigger --action add --settle /sys/class/net/hoge
+udevadm wait --settle --timeout=30 /sys/class/net/test3
+output=$(ip link show dev test3)
+assert_in "altname test1" "$output"
+assert_in "altname test2" "$output"
+assert_not_in "altname test3" "$output"
+assert_in "altname test4" "$output"
+assert_not_in "altname hoge" "$output"
+
+# cleanup
+ip link del dev test3
+
+rm -f /run/systemd/network/10-test.link
+udevadm control --reload --log-level=info
+
+exit 0

File diff suppressed because it is too large Load Diff

@ -0,0 +1,54 @@
From 27e95f2513e24a6abc26c56f05c67c34492442d7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 15 Nov 2022 15:00:57 +0100
Subject: [PATCH] bootctl: make --json output normal json
We would output a sequence of concatenated JSON strings. 'jq' accepts such
output without fuss, and can even automatically build an array with --slurp/-s.
Nevertheless, parsing this format is more effort for the reader, since it's not
"standard JSON". E.g. Python's json module cannot do this out-of-the-box, but
needs some loop with json.JSONDecoder.raw_decode() and then collecting the
objects into an array. Such streaming output make sense in case of logs, where
we stream the output and it has no predefined length. But here we expect at
most a few dozen entries, so it's nicer to write normal JSON that is trivial to
parse.
I'm treating this is a bugfix and not attempting to provide compatibility
backwards. I don't think the previous format was seeing much use, and it's
trivial to adapt to the new one.
(cherry picked from commit b570204a97bccfbfce8fc4ffa65306f8a06fe16e)
Related: RHEL-13199
---
src/shared/bootspec.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c
index d3cfb41a12..fe44b5e9d2 100644
--- a/src/shared/bootspec.c
+++ b/src/shared/bootspec.c
@@ -1408,6 +1408,8 @@ int show_boot_entries(const BootConfig *config, JsonFormatFlags json_format) {
assert(config);
if (!FLAGS_SET(json_format, JSON_FORMAT_OFF)) {
+ _cleanup_(json_variant_unrefp) JsonVariant *array = NULL;
+
for (size_t i = 0; i < config->n_entries; i++) {
_cleanup_free_ char *opts = NULL;
const BootEntry *e = config->entries + i;
@@ -1447,9 +1449,13 @@ int show_boot_entries(const BootConfig *config, JsonFormatFlags json_format) {
if (r < 0)
return log_oom();
- json_variant_dump(v, json_format, stdout, NULL);
+ r = json_variant_append_array(&array, v);
+ if (r < 0)
+ return log_oom();
}
+ json_variant_dump(array, json_format, NULL, NULL);
+
} else {
for (size_t n = 0; n < config->n_entries; n++) {
r = show_boot_entry(

@ -0,0 +1,28 @@
From 8fced1b2ed30b9cda338c35946d8dcc3820ac25a Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Wed, 5 Jul 2023 19:43:43 +0200
Subject: [PATCH] test: replace readfp() with read_file()
ConfigParser.readfp() has been deprecated since Python 3.2 and was
dropped completely in Python 3.11.
(cherry picked from commit ba4a1cd8a863f65ff016be72e520c323aa1e1a6f)
Related: RHEL-13199
---
test/sysv-generator-test.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/sysv-generator-test.py b/test/sysv-generator-test.py
index 484b610a02..84237bab61 100755
--- a/test/sysv-generator-test.py
+++ b/test/sysv-generator-test.py
@@ -80,7 +80,7 @@ class SysvGeneratorTest(unittest.TestCase):
cp = RawConfigParser(dict_type=MultiDict)
cp.optionxform = lambda o: o # don't lower-case option names
with open(service) as f:
- cp.readfp(f)
+ cp.read_file(f)
results[os.path.basename(service)] = cp
return (err, results)

@ -0,0 +1,81 @@
From fe66c5955044cf2b93fa788ae7bdfe3a07f11449 Mon Sep 17 00:00:00 2001
From: Luca Boccassi <bluca@debian.org>
Date: Sun, 21 May 2023 14:32:09 +0100
Subject: [PATCH] stub/measure: document and measure .uname UKI section
(cherry picked from commit b6f2e6860220aa89550f690b12246c4e8eb6e908)
Resolves: RHEL-13199
---
man/systemd-stub.xml | 3 +++
src/boot/measure.c | 3 +++
src/fundamental/tpm-pcr.c | 1 +
src/fundamental/tpm-pcr.h | 1 +
4 files changed, 8 insertions(+)
diff --git a/man/systemd-stub.xml b/man/systemd-stub.xml
index 415d663f53..85d30129d6 100644
--- a/man/systemd-stub.xml
+++ b/man/systemd-stub.xml
@@ -57,6 +57,9 @@
<citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry> file of
the OS the kernel belongs to, in the <literal>.osrel</literal> PE section.</para></listitem>
+ <listitem><para>Kernel version information, i.e. the output of <command>uname -r</command> for the
+ kernel included in the UKI, in the <literal>.uname</literal> PE section.</para></listitem>
+
<listitem><para>The initrd will be loaded from the <literal>.initrd</literal> PE section.
</para></listitem>
diff --git a/src/boot/measure.c b/src/boot/measure.c
index 0bbd386449..67ab84753e 100644
--- a/src/boot/measure.c
+++ b/src/boot/measure.c
@@ -79,6 +79,7 @@ static int help(int argc, char *argv[], void *userdata) {
" --initrd=PATH Path to initrd image file %7$s .initrd\n"
" --splash=PATH Path to splash bitmap file %7$s .splash\n"
" --dtb=PATH Path to Devicetree file %7$s .dtb\n"
+ " --uname=PATH Path to 'uname -r' file %7$s .uname\n"
" --pcrpkey=PATH Path to public key for PCR signatures %7$s .pcrpkey\n"
"\nSee the %2$s for details.\n",
program_invocation_short_name,
@@ -118,6 +119,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_INITRD,
ARG_SPLASH,
ARG_DTB,
+ ARG_UNAME,
_ARG_PCRSIG, /* the .pcrsig section is not input for signing, hence not actually an argument here */
_ARG_SECTION_LAST,
ARG_PCRPKEY = _ARG_SECTION_LAST,
@@ -139,6 +141,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "initrd", required_argument, NULL, ARG_INITRD },
{ "splash", required_argument, NULL, ARG_SPLASH },
{ "dtb", required_argument, NULL, ARG_DTB },
+ { "uname", required_argument, NULL, ARG_UNAME },
{ "pcrpkey", required_argument, NULL, ARG_PCRPKEY },
{ "current", no_argument, NULL, 'c' },
{ "bank", required_argument, NULL, ARG_BANK },
diff --git a/src/fundamental/tpm-pcr.c b/src/fundamental/tpm-pcr.c
index 7609d83c2e..0685d37b05 100644
--- a/src/fundamental/tpm-pcr.c
+++ b/src/fundamental/tpm-pcr.c
@@ -11,6 +11,7 @@ const char* const unified_sections[_UNIFIED_SECTION_MAX + 1] = {
[UNIFIED_SECTION_INITRD] = ".initrd",
[UNIFIED_SECTION_SPLASH] = ".splash",
[UNIFIED_SECTION_DTB] = ".dtb",
+ [UNIFIED_SECTION_UNAME] = ".uname",
[UNIFIED_SECTION_PCRSIG] = ".pcrsig",
[UNIFIED_SECTION_PCRPKEY] = ".pcrpkey",
NULL,
diff --git a/src/fundamental/tpm-pcr.h b/src/fundamental/tpm-pcr.h
index 235d4841b0..24240b82ed 100644
--- a/src/fundamental/tpm-pcr.h
+++ b/src/fundamental/tpm-pcr.h
@@ -34,6 +34,7 @@ typedef enum UnifiedSection {
UNIFIED_SECTION_INITRD,
UNIFIED_SECTION_SPLASH,
UNIFIED_SECTION_DTB,
+ UNIFIED_SECTION_UNAME,
UNIFIED_SECTION_PCRSIG,
UNIFIED_SECTION_PCRPKEY,
_UNIFIED_SECTION_MAX,

@ -0,0 +1,96 @@
From 16b3bb1a1bb8a0a42ad6eb56fd33dcb800c8af04 Mon Sep 17 00:00:00 2001
From: Luca Boccassi <bluca@debian.org>
Date: Thu, 29 Jun 2023 23:41:48 +0100
Subject: [PATCH] boot: measure .sbat section
We are now merging .sbat sections from sd-stub and kernel image, so
measure it in PCR11.
(cherry picked from commit d5f91cf79361cab58e32bf7b76c41ba244add75f)
Resolves: RHEL-13199
---
man/systemd-measure.xml | 8 +++++---
src/boot/measure.c | 3 +++
src/fundamental/tpm-pcr.c | 1 +
src/fundamental/tpm-pcr.h | 1 +
4 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/man/systemd-measure.xml b/man/systemd-measure.xml
index 46fc979654..e08dbcdac9 100644
--- a/man/systemd-measure.xml
+++ b/man/systemd-measure.xml
@@ -66,9 +66,10 @@
<listitem><para>Pre-calculate the expected values seen in PCR register 11 after boot-up of a unified
kernel image consisting of the components specified with <option>--linux=</option>,
<option>--osrel=</option>, <option>--cmdline=</option>, <option>--initrd=</option>,
- <option>--splash=</option>, <option>--dtb=</option>, <option>--pcrpkey=</option> see below. Only
- <option>--linux=</option> is mandatory. (Alternatively, specify <option>--current</option> to use the
- current values of PCR register 11 instead.)</para></listitem>
+ <option>--splash=</option>, <option>--dtb=</option>, <option>--sbat=</option>,
+ <option>--pcrpkey=</option> see below. Only <option>--linux=</option> is mandatory. (Alternatively,
+ specify <option>--current</option> to use the current values of PCR register 11 instead.)</para>
+ </listitem>
</varlistentry>
<varlistentry>
@@ -104,6 +105,7 @@
<term><option>--initrd=PATH</option></term>
<term><option>--splash=PATH</option></term>
<term><option>--dtb=PATH</option></term>
+ <term><option>--sbat=PATH</option></term>
<term><option>--pcrpkey=PATH</option></term>
<listitem><para>When used with the <command>calculate</command> or <command>sign</command> verb,
diff --git a/src/boot/measure.c b/src/boot/measure.c
index 67ab84753e..84a7c357a4 100644
--- a/src/boot/measure.c
+++ b/src/boot/measure.c
@@ -80,6 +80,7 @@ static int help(int argc, char *argv[], void *userdata) {
" --splash=PATH Path to splash bitmap file %7$s .splash\n"
" --dtb=PATH Path to Devicetree file %7$s .dtb\n"
" --uname=PATH Path to 'uname -r' file %7$s .uname\n"
+ " --sbat=PATH Path to SBAT file %7$s .sbat\n"
" --pcrpkey=PATH Path to public key for PCR signatures %7$s .pcrpkey\n"
"\nSee the %2$s for details.\n",
program_invocation_short_name,
@@ -120,6 +121,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_SPLASH,
ARG_DTB,
ARG_UNAME,
+ ARG_SBAT,
_ARG_PCRSIG, /* the .pcrsig section is not input for signing, hence not actually an argument here */
_ARG_SECTION_LAST,
ARG_PCRPKEY = _ARG_SECTION_LAST,
@@ -142,6 +144,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "splash", required_argument, NULL, ARG_SPLASH },
{ "dtb", required_argument, NULL, ARG_DTB },
{ "uname", required_argument, NULL, ARG_UNAME },
+ { "sbat", required_argument, NULL, ARG_SBAT },
{ "pcrpkey", required_argument, NULL, ARG_PCRPKEY },
{ "current", no_argument, NULL, 'c' },
{ "bank", required_argument, NULL, ARG_BANK },
diff --git a/src/fundamental/tpm-pcr.c b/src/fundamental/tpm-pcr.c
index 0685d37b05..2f7e9b428d 100644
--- a/src/fundamental/tpm-pcr.c
+++ b/src/fundamental/tpm-pcr.c
@@ -12,6 +12,7 @@ const char* const unified_sections[_UNIFIED_SECTION_MAX + 1] = {
[UNIFIED_SECTION_SPLASH] = ".splash",
[UNIFIED_SECTION_DTB] = ".dtb",
[UNIFIED_SECTION_UNAME] = ".uname",
+ [UNIFIED_SECTION_SBAT] = ".sbat",
[UNIFIED_SECTION_PCRSIG] = ".pcrsig",
[UNIFIED_SECTION_PCRPKEY] = ".pcrpkey",
NULL,
diff --git a/src/fundamental/tpm-pcr.h b/src/fundamental/tpm-pcr.h
index 24240b82ed..794d593825 100644
--- a/src/fundamental/tpm-pcr.h
+++ b/src/fundamental/tpm-pcr.h
@@ -35,6 +35,7 @@ typedef enum UnifiedSection {
UNIFIED_SECTION_SPLASH,
UNIFIED_SECTION_DTB,
UNIFIED_SECTION_UNAME,
+ UNIFIED_SECTION_SBAT,
UNIFIED_SECTION_PCRSIG,
UNIFIED_SECTION_PCRPKEY,
_UNIFIED_SECTION_MAX,

@ -0,0 +1,42 @@
From 3c235c8d26813ae428053c284b67ddfe70d9caed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Wed, 22 Nov 2023 15:38:47 +0100
Subject: [PATCH] Revert "test_ukify: no stinky root needed for signing"
This reverts commit 0d66468243d888dd721ba0072cbad742ab6fc690.
There was a huge rewrite of the tpm2 code that removed the requirement for
device access, but backporting that would be a huge effort. Let's instead skip
the tests for now. (They pass under root.)
Related: RHEL-13199
---
src/ukify/test/test_ukify.py | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/src/ukify/test/test_ukify.py b/src/ukify/test/test_ukify.py
index b12c09d4bf..5a42a94799 100755
--- a/src/ukify/test/test_ukify.py
+++ b/src/ukify/test/test_ukify.py
@@ -661,6 +661,10 @@ def test_pcr_signing(kernel_initrd, tmpdir):
pytest.skip('linux+initrd not found')
if systemd_measure() is None:
pytest.skip('systemd-measure not found')
+ if os.getuid() != 0:
+ pytest.skip('must be root to access tpm2')
+ if subprocess.call(['systemd-creds', 'has-tpm2', '-q']) != 0:
+ pytest.skip('tpm2 is not available')
ourdir = pathlib.Path(__file__).parent
pub = unbase64(ourdir / 'example.tpm2-pcr-public.pem.base64')
@@ -724,6 +728,10 @@ def test_pcr_signing2(kernel_initrd, tmpdir):
pytest.skip('linux+initrd not found')
if systemd_measure() is None:
pytest.skip('systemd-measure not found')
+ if os.getuid() != 0:
+ pytest.skip('must be root to access tpm2')
+ if subprocess.call(['systemd-creds', 'has-tpm2', '-q']) != 0:
+ pytest.skip('tpm2 is not available')
ourdir = pathlib.Path(__file__).parent
pub = unbase64(ourdir / 'example.tpm2-pcr-public.pem.base64')

@ -0,0 +1,36 @@
From 2adec0d845e6d00a604ddaa5639759896b78728f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Mon, 28 Aug 2023 18:22:43 +0300
Subject: [PATCH] ukify: move to /usr/bin and mark as non non-experimental
The tool is moved into the $PATH and a compat symlink is provided.
It is fairly widely used now, and realistically we need to keep backwards
compat or people will be very unhappy.
(cherry picked from commit f65aa477d90ab7fbbc50ba05c55180213d5992e0)
Related: RHEL-13199
---
meson.build | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/meson.build b/meson.build
index b874c2f9b4..e0495ed36a 100644
--- a/meson.build
+++ b/meson.build
@@ -3861,9 +3861,13 @@ ukify = custom_target(
command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
install : want_ukify,
install_mode : 'rwxr-xr-x',
- install_dir : rootlibexecdir)
+ install_dir : bindir)
if want_ukify
public_programs += ukify
+
+ meson.add_install_script(sh, '-c',
+ ln_s.format(bindir / 'ukify',
+ rootlibexecdir / 'ukify'))
endif
if want_tests != 'false' and want_kernel_install

@ -0,0 +1,221 @@
From 90f26ba66f256fd65c6e7c38ed6f2138fed6b3ed Mon Sep 17 00:00:00 2001
From: Joerg Behrmann <behrmann@physik.fu-berlin.de>
Date: Wed, 23 Nov 2022 16:43:19 +0100
Subject: [PATCH] kernel-install: Add uki layout
Currently the kernel-install man page only documents the bls layout for use
with the boot loader spec type #1. 90-loaderentry.install uses this layout to
generate loader entries and copy the kernel image and initrd to $BOOT.
This commit documents a second layout "uki" and adds 90-uki-copy.install,
which copies a UKI "uki.efi" from the staging area or any file with the .efi
extension given on the command line to
$BOOT/EFI/Linux/$ENTRY_TOKEN-$KERNEl_VERSION(+$TRIES).efi
This allows for both locally generated and distro-provided UKIs to be handled
by kernel-install.
(cherry picked from commit 0ccfd3564b2532a4da6526a9e030362c4a142b77)
Resolves: RHEL-16354
---
man/kernel-install.xml | 38 ++++++++--
src/kernel-install/90-uki-copy.install | 97 ++++++++++++++++++++++++++
src/kernel-install/meson.build | 2 +
3 files changed, 131 insertions(+), 6 deletions(-)
create mode 100755 src/kernel-install/90-uki-copy.install
diff --git a/man/kernel-install.xml b/man/kernel-install.xml
index b8ea2b16b2..b1822a8847 100644
--- a/man/kernel-install.xml
+++ b/man/kernel-install.xml
@@ -108,6 +108,14 @@
is missing), or "Linux <replaceable>KERNEL-VERSION</replaceable>", if unset.</para>
<para>If <varname>$KERNEL_INSTALL_LAYOUT</varname> is not "bls", this plugin does nothing.</para></listitem>
+
+ <listitem><para><filename>90-uki-copy.install</filename> copies a file
+ <filename>uki.efi</filename> from <varname>$KERNEL_INSTALL_STAGING_AREA</varname> or if it does
+ not exist the <replaceable>KERNEL-IMAGE</replaceable> argument, iff it has a
+ <literal>.efi</literal> extension, to
+ <filename>$BOOT/EFI/Linux/<replaceable>ENTRY-TOKEN</replaceable>-<replaceable>KERNEL-VERSION</replaceable>.efi</filename>.</para>
+
+ <para>If <varname>$KERNEL_INSTALL_LAYOUT</varname> is not "uki", this plugin does nothing.</para></listitem>
</itemizedlist>
</listitem>
</varlistentry>
@@ -132,6 +140,9 @@
<listitem><para><filename>90-loaderentry.install</filename> removes the file
<filename>$BOOT/loader/entries/<replaceable>ENTRY-TOKEN</replaceable>-<replaceable>KERNEL-VERSION</replaceable>.conf</filename>.</para></listitem>
+
+ <listitem><para><filename>90-uki-copy.install</filename> removes the file
+ <filename>$BOOT/EFI/Linux/<replaceable>ENTRY-TOKEN</replaceable>-<replaceable>KERNEL-VERSION</replaceable>.efi</filename>.</para></listitem>
</itemizedlist>
</listitem>
</varlistentry>
@@ -213,7 +224,7 @@
(EFI System Partition) are mounted, and also conceptually referred to as <varname>$BOOT</varname>. Can
be overridden by setting <varname>$BOOT_ROOT</varname> (see below).</para>
- <para><varname>$KERNEL_INSTALL_LAYOUT=bls|other|...</varname> is set for the plugins to specify the
+ <para><varname>$KERNEL_INSTALL_LAYOUT=bls|uki|other|...</varname> is set for the plugins to specify the
installation layout. Defaults to <option>bls</option> if
<filename>$BOOT/<replaceable>ENTRY-TOKEN</replaceable></filename> exists, or <option>other</option>
otherwise. Additional layout names may be defined by convention. If a plugin uses a special layout,
@@ -235,6 +246,18 @@
<para>Implemented by <filename>90-loaderentry.install</filename>.</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>uki</term>
+ <listitem>
+ <para>Standard <ulink
+ url="https://uapi-group.org/specifications/specs/boot_loader_specification">Boot Loader
+ Specification</ulink> Type #2 layout, compatible with
+ <citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry>:
+ unified kernel images under <filename>$BOOT/EFI/Linux</filename> as
+ <filename>$BOOT/EFI/Linux/<replaceable>ENTRY-TOKEN</replaceable>-<replaceable>KERNEL-VERSION</replaceable>[+<replaceable>TRIES</replaceable>].efi</filename>.</para>
+ <para>Implemented by <filename>90-uki-copy.install</filename>.</para>
+ </listitem>
+ </varlistentry>
<varlistentry>
<term>other</term>
<listitem>
@@ -312,12 +335,15 @@
<filename>/etc/kernel/tries</filename>
</term>
<listitem>
- <para>Read by <filename>90-loaderentry.install</filename>. If this file exists a numeric value is read from
- it and the naming of the generated entry file is slightly altered to include it as
- <filename>$BOOT/loader/entries/<replaceable>MACHINE-ID</replaceable>-<replaceable>KERNEL-VERSION</replaceable>+<replaceable>TRIES</replaceable>.conf</filename>. This
+ <para>Read by <filename>90-loaderentry.install</filename> and
+ <filename>90-uki-copy.install</filename>. If this file exists a numeric value is read from it
+ and the naming of the generated entry file or UKI is slightly altered to include it as
+ <filename>$BOOT/loader/entries/<replaceable>ENTRY-TOKEN</replaceable>-<replaceable>KERNEL-VERSION</replaceable>+<replaceable>TRIES</replaceable>.conf</filename>
+ or
+ <filename>$BOOT/EFI/Linux/<replaceable>ENTRY-TOKEN</replaceable>-<replaceable>KERNEL-VERSION</replaceable>+<replaceable>TRIES</replaceable>.conf</filename>, respectively. This
is useful for boot loaders such as
- <citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry> which
- implement boot attempt counting with a counter embedded in the entry file name.
+ <citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ which implement boot attempt counting with a counter embedded in the entry file name.
<varname>$KERNEL_INSTALL_CONF_ROOT</varname> may be used to override the path.</para>
</listitem>
</varlistentry>
diff --git a/src/kernel-install/90-uki-copy.install b/src/kernel-install/90-uki-copy.install
new file mode 100755
index 0000000000..d6e3deb723
--- /dev/null
+++ b/src/kernel-install/90-uki-copy.install
@@ -0,0 +1,97 @@
+#!/bin/sh
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# systemd is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with systemd; If not, see <https://www.gnu.org/licenses/>.
+
+set -e
+
+COMMAND="${1:?}"
+KERNEL_VERSION="${2:?}"
+# shellcheck disable=SC2034
+ENTRY_DIR_ABS="$3"
+KERNEL_IMAGE="$4"
+
+[ "$KERNEL_INSTALL_LAYOUT" = "uki" ] || exit 0
+
+ENTRY_TOKEN="$KERNEL_INSTALL_ENTRY_TOKEN"
+BOOT_ROOT="$KERNEL_INSTALL_BOOT_ROOT"
+
+UKI_DIR="$BOOT_ROOT/EFI/Linux"
+
+case "$COMMAND" in
+ remove)
+ [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \
+ echo "Removing $UKI_DIR/$ENTRY_TOKEN-$KERNEL_VERSION*.efi"
+ exec rm -f \
+ "$UKI_DIR/$ENTRY_TOKEN-$KERNEL_VERSION.efi" \
+ "$UKI_DIR/$ENTRY_TOKEN-$KERNEL_VERSION+"*".efi"
+ ;;
+ add)
+ ;;
+ *)
+ exit 0
+ ;;
+esac
+
+if ! [ -d "$UKI_DIR" ]; then
+ echo "Error: entry directory '$UKI_DIR' does not exist" >&2
+ exit 1
+fi
+
+TRIES_FILE="${KERNEL_INSTALL_CONF_ROOT:-/etc/kernel}/tries"
+
+if [ -f "$TRIES_FILE" ]; then
+ read -r TRIES <"$TRIES_FILE"
+ if ! echo "$TRIES" | grep -q '^[0-9][0-9]*$'; then
+ echo "$TRIES_FILE does not contain an integer." >&2
+ exit 1
+ fi
+ UKI_FILE="$UKI_DIR/$ENTRY_TOKEN-$KERNEL_VERSION+$TRIES.efi"
+else
+ UKI_FILE="$UKI_DIR/$ENTRY_TOKEN-$KERNEL_VERSION.efi"
+fi
+
+# If there is a UKI named uki.efi on the staging area use that, if not use what
+# was passed in as $KERNEL_IMAGE but insist it has a .efi extension
+if [ -f "$KERNEL_INSTALL_STAGING_AREA/uki.efi" ]; then
+ [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "Installing $KERNEL_INSTALL_STAGING_AREA/uki.efi"
+ install -m 0644 "$KERNEL_INSTALL_STAGING_AREA/uki.efi" "$UKI_FILE" || {
+ echo "Error: could not copy '$KERNEL_INSTALL_STAGING_AREA/uki.efi' to '$UKI_FILE'." >&2
+ exit 1
+ }
+elif [ -n "$KERNEL_IMAGE" ]; then
+ [ -f "$KERNEL_IMAGE" ] || {
+ echo "Error: UKI '$KERNEL_IMAGE' not a file." >&2
+ exit 1
+ }
+ [ "$KERNEL_IMAGE" != "${KERNEL_IMAGE%*.efi}.efi" ] && {
+ echo "Error: $KERNEL_IMAGE is missing .efi suffix." >&2
+ exit 1
+ }
+ [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "Installing $KERNEL_IMAGE"
+ install -m 0644 "$KERNEL_IMAGE" "$UKI_FILE" || {
+ echo "Error: could not copy '$KERNEL_IMAGE' to '$UKI_FILE'." >&2
+ exit 1
+ }
+else
+ [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "No UKI available. Nothing to do."
+ exit 0
+fi
+chown root:root "$UKI_FILE" || :
+
+exit 0
diff --git a/src/kernel-install/meson.build b/src/kernel-install/meson.build
index 90a0e3ae49..68a4d43862 100644
--- a/src/kernel-install/meson.build
+++ b/src/kernel-install/meson.build
@@ -3,6 +3,8 @@
kernel_install_in = files('kernel-install.in')
loaderentry_install = files('90-loaderentry.install')
+uki_copy_install = files('90-uki-copy.install')
+
if want_kernel_install
install_data('50-depmod.install',
loaderentry_install,

@ -0,0 +1,25 @@
From 5d3d683fd54100fea2a355b0ebc8b03d9b6c964b Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 25 Jan 2023 13:57:09 +0100
Subject: [PATCH] kernel-install: remove math slang from man page
(cherry picked from commit 642617f431457382ec2140a52ee08bfbb3e5e1db)
Related: RHEL-16354
---
man/kernel-install.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/man/kernel-install.xml b/man/kernel-install.xml
index b1822a8847..1bc6e7aa05 100644
--- a/man/kernel-install.xml
+++ b/man/kernel-install.xml
@@ -111,7 +111,7 @@
<listitem><para><filename>90-uki-copy.install</filename> copies a file
<filename>uki.efi</filename> from <varname>$KERNEL_INSTALL_STAGING_AREA</varname> or if it does
- not exist the <replaceable>KERNEL-IMAGE</replaceable> argument, iff it has a
+ not exist the <replaceable>KERNEL-IMAGE</replaceable> argument, only if it has a
<literal>.efi</literal> extension, to
<filename>$BOOT/EFI/Linux/<replaceable>ENTRY-TOKEN</replaceable>-<replaceable>KERNEL-VERSION</replaceable>.efi</filename>.</para>

@ -0,0 +1,80 @@
From 4f3593718196c007838eebf5d9b42f09318bd4e6 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Fri, 20 Jan 2023 09:05:18 +0100
Subject: [PATCH] kernel-install: handle uki installs automatically
Detect image type using "bootctl kernel-identify $kernel",
store result in KERNEL_INSTALL_IMAGE_TYPE.
Extend layout autodetection to check the kernel image type
and pick layout=uki for UKIs.
Resolves: https://github.com/systemd/systemd/issues/25822
(cherry picked from commit 3d5f0bfe4e72fdc4d8f8d65f96dc5501dfed8a64)
Related: RHEL-16354
---
man/kernel-install.xml | 17 +++++++++++++----
src/kernel-install/kernel-install.in | 12 ++++++++++--
2 files changed, 23 insertions(+), 6 deletions(-)
diff --git a/man/kernel-install.xml b/man/kernel-install.xml
index 1bc6e7aa05..4d91b7b20b 100644
--- a/man/kernel-install.xml
+++ b/man/kernel-install.xml
@@ -224,10 +224,8 @@
(EFI System Partition) are mounted, and also conceptually referred to as <varname>$BOOT</varname>. Can
be overridden by setting <varname>$BOOT_ROOT</varname> (see below).</para>
- <para><varname>$KERNEL_INSTALL_LAYOUT=bls|uki|other|...</varname> is set for the plugins to specify the
- installation layout. Defaults to <option>bls</option> if
- <filename>$BOOT/<replaceable>ENTRY-TOKEN</replaceable></filename> exists, or <option>other</option>
- otherwise. Additional layout names may be defined by convention. If a plugin uses a special layout,
+ <para><varname>$KERNEL_INSTALL_LAYOUT=auto|bls|uki|other|...</varname> is set for the plugins to specify the
+ installation layout. Additional layout names may be defined by convention. If a plugin uses a special layout,
it's encouraged to declare its own layout name and configure <varname>layout=</varname> in
<filename>install.conf</filename> upon initial installation. The following values are currently
understood:</para>
@@ -264,6 +262,17 @@
<para>Some other layout not understood natively by <command>kernel-install</command>.</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>auto</term>
+ <listitem>
+ <para>Pick the layout automatically. If the kernel is a UKI set layout to
+ <option>uki</option>. If not default to <option>bls</option> if
+ <filename>$BOOT/loader/entries.srel</filename> with content <literal>type1</literal> or
+ <filename>$BOOT/<replaceable>ENTRY-TOKEN</replaceable></filename> exists, or
+ <option>other</option> otherwise.</para>
+ <para>Leaving layout blank has the same effect. This is the default.</para>
+ </listitem>
+ </varlistentry>
</variablelist>
<para><varname>$KERNEL_INSTALL_INITRD_GENERATOR</varname> is set for plugins to select the initrd
diff --git a/src/kernel-install/kernel-install.in b/src/kernel-install/kernel-install.in
index fa2c0d5276..25884fc0e2 100755
--- a/src/kernel-install/kernel-install.in
+++ b/src/kernel-install/kernel-install.in
@@ -250,10 +250,18 @@ if [ -z "$ENTRY_TOKEN" ]; then
echo "No entry-token candidate matched, using \"$ENTRY_TOKEN\" from machine-id"
fi
-if [ -z "$layout" ]; then
+export KERNEL_INSTALL_IMAGE_TYPE=""
+if [ -f "$1" ]; then
+ KERNEL_INSTALL_IMAGE_TYPE="$(bootctl kernel-identify "$1" 2>/dev/null || echo "unknown")"
+fi
+
+if [ "$layout" = "auto" ] || [ -z "$layout" ]; then
# No layout configured by the administrator. Let's try to figure it out
# automatically from metadata already contained in $BOOT_ROOT.
- if [ -e "$BOOT_ROOT/loader/entries.srel" ]; then
+ if [ "$KERNEL_INSTALL_IMAGE_TYPE" = "uki" ]; then
+ layout="uki"
+ log_verbose "Kernel image is UKI, using layout=$layout"
+ elif [ -e "$BOOT_ROOT/loader/entries.srel" ]; then
read -r ENTRIES_SREL <"$BOOT_ROOT/loader/entries.srel"
if [ "$ENTRIES_SREL" = "type1" ]; then
# The loader/entries.srel file clearly indicates that the installed

@ -0,0 +1,31 @@
From cb2ead4b9fc17554a8694fd213bfb100d9c15678 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Fri, 20 Jan 2023 12:59:33 +0100
Subject: [PATCH] 90-uki-copy.install: create $BOOT/EFI/Linux directory if
needed
Do not consider a missing 'Linux' subdirectory an error.
Just create it instead.
(cherry picked from commit c7314ee7e290b3978e2f2d7726d07656eda071f9)
Related: RHEL-16354
---
src/kernel-install/90-uki-copy.install | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/kernel-install/90-uki-copy.install b/src/kernel-install/90-uki-copy.install
index d6e3deb723..6c71b211d7 100755
--- a/src/kernel-install/90-uki-copy.install
+++ b/src/kernel-install/90-uki-copy.install
@@ -49,8 +49,8 @@ case "$COMMAND" in
esac
if ! [ -d "$UKI_DIR" ]; then
- echo "Error: entry directory '$UKI_DIR' does not exist" >&2
- exit 1
+ [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "creating $UKI_DIR"
+ mkdir -p "$UKI_DIR"
fi
TRIES_FILE="${KERNEL_INSTALL_CONF_ROOT:-/etc/kernel}/tries"

@ -0,0 +1,36 @@
From d0b5386bde65b8c488d23f16ec4049d1e6378c25 Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Sun, 5 Nov 2023 13:50:25 +0100
Subject: [PATCH] kernel-install: Log location that uki is installed in
Let's log where we install a UKI when running in verbose mode.
(cherry picked from commit 4f5278eead35bc66cc943a493eab8a8b78174400)
Related: RHEL-16354
---
src/kernel-install/90-uki-copy.install | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/kernel-install/90-uki-copy.install b/src/kernel-install/90-uki-copy.install
index 6c71b211d7..c66c09719c 100755
--- a/src/kernel-install/90-uki-copy.install
+++ b/src/kernel-install/90-uki-copy.install
@@ -69,7 +69,7 @@ fi
# If there is a UKI named uki.efi on the staging area use that, if not use what
# was passed in as $KERNEL_IMAGE but insist it has a .efi extension
if [ -f "$KERNEL_INSTALL_STAGING_AREA/uki.efi" ]; then
- [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "Installing $KERNEL_INSTALL_STAGING_AREA/uki.efi"
+ [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "Installing $KERNEL_INSTALL_STAGING_AREA/uki.efi as $UKI_FILE"
install -m 0644 "$KERNEL_INSTALL_STAGING_AREA/uki.efi" "$UKI_FILE" || {
echo "Error: could not copy '$KERNEL_INSTALL_STAGING_AREA/uki.efi' to '$UKI_FILE'." >&2
exit 1
@@ -83,7 +83,7 @@ elif [ -n "$KERNEL_IMAGE" ]; then
echo "Error: $KERNEL_IMAGE is missing .efi suffix." >&2
exit 1
}
- [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "Installing $KERNEL_IMAGE"
+ [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "Installing $KERNEL_IMAGE as $UKI_FILE"
install -m 0644 "$KERNEL_IMAGE" "$UKI_FILE" || {
echo "Error: could not copy '$KERNEL_IMAGE' to '$UKI_FILE'." >&2
exit 1

@ -0,0 +1,25 @@
From f0ab67eb46103c68a1fc708b45e2fa6b93780efb Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 19 Dec 2022 22:25:28 +0100
Subject: [PATCH] bootctl: fix errno logging
(cherry picked from commit e425849e995e448f529d3c106bf1e3de2ca23a35)
Related: RHEL-16354
---
src/boot/bootctl.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index 7da48b4ca4..67fcbcc8cd 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -2028,7 +2028,7 @@ static int install_random_seed(const char *esp) {
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short write while writing random seed file.");
if (rename(tmp, path) < 0)
- return log_error_errno(r, "Failed to move random seed file into place: %m");
+ return log_error_errno(errno, "Failed to move random seed file into place: %m");
tmp = mfree(tmp);

@ -0,0 +1,214 @@
From ca716a0fdfd434e52384dd74ff4c909aa95b6c81 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Mon, 16 Jan 2023 18:58:21 +0100
Subject: [PATCH] bootctl: add kernel-identity command
The command takes a kernel as argument and checks what kind of kernel
the image is. Returns one of uki, pe or unknown.
(cherry picked from commit 53c368d71ba43da7414ac86c58291a11da05ba84)
Resolves: RHEL-16354
---
man/bootctl.xml | 13 +++++
meson.build | 5 +-
src/boot/bootctl-uki.c | 109 +++++++++++++++++++++++++++++++++++++++++
src/boot/bootctl-uki.h | 3 ++
src/boot/bootctl.c | 4 ++
5 files changed, 133 insertions(+), 1 deletion(-)
create mode 100644 src/boot/bootctl-uki.c
create mode 100644 src/boot/bootctl-uki.h
diff --git a/man/bootctl.xml b/man/bootctl.xml
index dfc56d6125..0f992ec383 100644
--- a/man/bootctl.xml
+++ b/man/bootctl.xml
@@ -217,6 +217,19 @@
</variablelist>
</refsect1>
+ <refsect1>
+ <title><command>kernel</command> Commands</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><option>kernel-identify</option> <replaceable>kernel</replaceable></term>
+
+ <listitem><para>Takes a kernel image as argument. Checks what kind of kernel the image is. Returns
+ one of uki, pe or unknown.</para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
<refsect1>
<title>Options</title>
<para>The following options are understood:</para>
diff --git a/meson.build b/meson.build
index e0495ed36a..936e612a01 100644
--- a/meson.build
+++ b/meson.build
@@ -2566,7 +2566,10 @@ if conf.get('HAVE_BLKID') == 1 and conf.get('HAVE_GNU_EFI') == 1
public_programs += executable(
'bootctl',
- 'src/boot/bootctl.c',
+ ['src/boot/bootctl.c',
+ 'src/boot/bootctl-uki.c',
+ 'src/boot/bootctl-uki.h',
+ ],
include_directories : includes,
link_with : [boot_link_with],
dependencies : [libblkid],
diff --git a/src/boot/bootctl-uki.c b/src/boot/bootctl-uki.c
new file mode 100644
index 0000000000..7e8e8a570b
--- /dev/null
+++ b/src/boot/bootctl-uki.c
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "bootctl-uki.h"
+#include "fd-util.h"
+#include "parse-util.h"
+#include "pe-header.h"
+
+#define MAX_SECTIONS 96
+
+static const uint8_t dos_file_magic[2] = "MZ";
+static const uint8_t pe_file_magic[4] = "PE\0\0";
+
+static const uint8_t name_osrel[8] = ".osrel";
+static const uint8_t name_linux[8] = ".linux";
+static const uint8_t name_initrd[8] = ".initrd";
+
+static int pe_sections(FILE *uki, struct PeSectionHeader **ret, size_t *ret_n) {
+ _cleanup_free_ struct PeSectionHeader *sections = NULL;
+ struct DosFileHeader dos;
+ struct PeHeader pe;
+ size_t scount;
+ uint64_t soff, items;
+ int rc;
+
+ items = fread(&dos, 1, sizeof(dos), uki);
+ if (items != sizeof(dos))
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "DOS header read error");
+ if (memcmp(dos.Magic, dos_file_magic, sizeof(dos_file_magic)) != 0)
+ goto no_sections;
+
+ rc = fseek(uki, le32toh(dos.ExeHeader), SEEK_SET);
+ if (rc < 0)
+ return log_error_errno(errno, "seek to PE header");
+ items = fread(&pe, 1, sizeof(pe), uki);
+ if (items != sizeof(pe))
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "PE header read error");
+ if (memcmp(pe.Magic, pe_file_magic, sizeof(pe_file_magic)) != 0)
+ goto no_sections;
+
+ soff = le32toh(dos.ExeHeader) + sizeof(pe) + le16toh(pe.FileHeader.SizeOfOptionalHeader);
+ rc = fseek(uki, soff, SEEK_SET);
+ if (rc < 0)
+ return log_error_errno(errno, "seek to PE section headers");
+
+ scount = le16toh(pe.FileHeader.NumberOfSections);
+ if (scount > MAX_SECTIONS)
+ goto no_sections;
+ sections = new(struct PeSectionHeader, scount);
+ if (!sections)
+ return log_oom();
+ items = fread(sections, sizeof(*sections), scount, uki);
+ if (items != scount)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "PE section header read error");
+
+ *ret = TAKE_PTR(sections);
+ *ret_n = scount;
+ return 0;
+
+no_sections:
+ *ret = NULL;
+ *ret_n = 0;
+ return 0;
+}
+
+static int find_pe_section(struct PeSectionHeader *sections, size_t scount,
+ const uint8_t *name, size_t namelen, size_t *ret) {
+ for (size_t s = 0; s < scount; s++) {
+ if (memcmp_nn(sections[s].Name, sizeof(sections[s].Name),
+ name, namelen) == 0) {
+ if (ret)
+ *ret = s;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static bool is_uki(struct PeSectionHeader *sections, size_t scount) {
+ return (find_pe_section(sections, scount, name_osrel, sizeof(name_osrel), NULL) &&
+ find_pe_section(sections, scount, name_linux, sizeof(name_linux), NULL) &&
+ find_pe_section(sections, scount, name_initrd, sizeof(name_initrd), NULL));
+}
+
+int verb_kernel_identify(int argc, char *argv[], void *userdata) {
+ _cleanup_fclose_ FILE *uki = NULL;
+ _cleanup_free_ struct PeSectionHeader *sections = NULL;
+ size_t scount;
+ int rc;
+
+ uki = fopen(argv[1], "re");
+ if (!uki)
+ return log_error_errno(errno, "Failed to open UKI file '%s': %m", argv[1]);
+
+ rc = pe_sections(uki, &sections, &scount);
+ if (rc < 0)
+ return EXIT_FAILURE;
+
+ if (sections) {
+ if (is_uki(sections, scount)) {
+ puts("uki");
+ return EXIT_SUCCESS;
+ }
+ puts("pe");
+ return EXIT_SUCCESS;
+ }
+
+ puts("unknown");
+ return EXIT_SUCCESS;
+}
diff --git a/src/boot/bootctl-uki.h b/src/boot/bootctl-uki.h
new file mode 100644
index 0000000000..3c1fb5bc6a
--- /dev/null
+++ b/src/boot/bootctl-uki.h
@@ -0,0 +1,3 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+int verb_kernel_identify(int argc, char *argv[], void *userdata);
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index 67fcbcc8cd..58e4af85f8 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -14,6 +14,7 @@
#include "alloc-util.h"
#include "blkid-util.h"
+#include "bootctl-uki.h"
#include "bootspec.h"
#include "chase-symlinks.h"
#include "copy.h"
@@ -1453,6 +1454,8 @@ static int help(int argc, char *argv[], void *userdata) {
" remove Remove systemd-boot from the ESP and EFI variables\n"
" is-installed Test whether systemd-boot is installed in the ESP\n"
" random-seed Initialize random seed in ESP and EFI variables\n"
+ "\n%3$skernel Commands:%4$s\n"
+ " kernel-identify Identify kernel image type.\n"
"\n%3$sOptions:%4$s\n"
" -h --help Show this help\n"
" --version Print version\n"
@@ -2567,6 +2570,7 @@ static int bootctl_main(int argc, char *argv[]) {
{ "update", VERB_ANY, 1, 0, verb_install },
{ "remove", VERB_ANY, 1, 0, verb_remove },
{ "is-installed", VERB_ANY, 1, 0, verb_is_installed },
+ { "kernel-identify", 2, 2, 0, verb_kernel_identify },
{ "list", VERB_ANY, 1, 0, verb_list },
{ "set-default", 2, 2, 0, verb_set_efivar },
{ "set-oneshot", 2, 2, 0, verb_set_efivar },

@ -0,0 +1,150 @@
From 3012047a48f67f6cceba50ce326497aa647074ea Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 17 Jan 2023 22:06:06 +0100
Subject: [PATCH] bootctl: add kernel-inspect command
Takes a kernel image as argument. Prints details about the kernel.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit a05255981ba5b04f1cf54ea656fbce1dfd9c3a68)
Resolves: RHEL-16354
---
man/bootctl.xml | 6 ++++
src/boot/bootctl-uki.c | 79 ++++++++++++++++++++++++++++++++++++++++++
src/boot/bootctl-uki.h | 1 +
src/boot/bootctl.c | 1 +
4 files changed, 87 insertions(+)
diff --git a/man/bootctl.xml b/man/bootctl.xml
index 0f992ec383..c12fe93214 100644
--- a/man/bootctl.xml
+++ b/man/bootctl.xml
@@ -227,6 +227,12 @@
<listitem><para>Takes a kernel image as argument. Checks what kind of kernel the image is. Returns
one of uki, pe or unknown.</para></listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><option>kernel-inspect</option> <replaceable>kernel</replaceable></term>
+
+ <listitem><para>Takes a kernel image as argument. Prints details about the kernel.</para></listitem>
+ </varlistentry>
</variablelist>
</refsect1>
diff --git a/src/boot/bootctl-uki.c b/src/boot/bootctl-uki.c
index 7e8e8a570b..3085f703a8 100644
--- a/src/boot/bootctl-uki.c
+++ b/src/boot/bootctl-uki.c
@@ -13,6 +13,8 @@ static const uint8_t pe_file_magic[4] = "PE\0\0";
static const uint8_t name_osrel[8] = ".osrel";
static const uint8_t name_linux[8] = ".linux";
static const uint8_t name_initrd[8] = ".initrd";
+static const uint8_t name_cmdline[8] = ".cmdline";
+static const uint8_t name_uname[8] = ".uname";
static int pe_sections(FILE *uki, struct PeSectionHeader **ret, size_t *ret_n) {
_cleanup_free_ struct PeSectionHeader *sections = NULL;
@@ -107,3 +109,80 @@ int verb_kernel_identify(int argc, char *argv[], void *userdata) {
puts("unknown");
return EXIT_SUCCESS;
}
+
+static int read_pe_section(FILE *uki, const struct PeSectionHeader *section,
+ void **ret, size_t *ret_n) {
+ _cleanup_free_ void *data = NULL;
+ uint32_t size, bytes;
+ uint64_t soff;
+ int rc;
+
+ soff = le32toh(section->PointerToRawData);
+ size = le32toh(section->VirtualSize);
+
+ if (size > 16 * 1024)
+ return log_error_errno(SYNTHETIC_ERRNO(E2BIG), "PE section too big");
+
+ rc = fseek(uki, soff, SEEK_SET);
+ if (rc < 0)
+ return log_error_errno(errno, "seek to PE section");
+
+ data = malloc(size+1);
+ if (!data)
+ return log_oom();
+ ((uint8_t*) data)[size] = 0; /* safety NUL byte */
+
+ bytes = fread(data, 1, size, uki);
+ if (bytes != size)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "PE section read error");
+
+ *ret = TAKE_PTR(data);
+ if (ret_n)
+ *ret_n = size;
+ return 0;
+}
+
+static void inspect_uki(FILE *uki, struct PeSectionHeader *sections, size_t scount) {
+ _cleanup_free_ char *cmdline = NULL;
+ _cleanup_free_ char *uname = NULL;
+ size_t idx;
+
+ if (find_pe_section(sections, scount, name_cmdline, sizeof(name_cmdline), &idx))
+ read_pe_section(uki, sections + idx, (void**)&cmdline, NULL);
+
+ if (find_pe_section(sections, scount, name_uname, sizeof(name_uname), &idx))
+ read_pe_section(uki, sections + idx, (void**)&uname, NULL);
+
+ if (cmdline)
+ printf(" Cmdline: %s\n", cmdline);
+ if (uname)
+ printf(" Version: %s\n", uname);
+}
+
+int verb_kernel_inspect(int argc, char *argv[], void *userdata) {
+ _cleanup_fclose_ FILE *uki = NULL;
+ _cleanup_free_ struct PeSectionHeader *sections = NULL;
+ size_t scount;
+ int rc;
+
+ uki = fopen(argv[1], "re");
+ if (!uki)
+ return log_error_errno(errno, "Failed to open UKI file '%s': %m", argv[1]);
+
+ rc = pe_sections(uki, &sections, &scount);
+ if (rc < 0)
+ return EXIT_FAILURE;
+
+ if (sections) {
+ if (is_uki(sections, scount)) {
+ puts("Kernel Type: uki");
+ inspect_uki(uki, sections, scount);
+ return EXIT_SUCCESS;
+ }
+ puts("Kernel Type: pe");
+ return EXIT_SUCCESS;
+ }
+
+ puts("Kernel Type: unknown");
+ return EXIT_SUCCESS;
+}
diff --git a/src/boot/bootctl-uki.h b/src/boot/bootctl-uki.h
index 3c1fb5bc6a..effb984d80 100644
--- a/src/boot/bootctl-uki.h
+++ b/src/boot/bootctl-uki.h
@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
int verb_kernel_identify(int argc, char *argv[], void *userdata);
+int verb_kernel_inspect(int argc, char *argv[], void *userdata);
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index 58e4af85f8..b98673cd11 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -2571,6 +2571,7 @@ static int bootctl_main(int argc, char *argv[]) {
{ "remove", VERB_ANY, 1, 0, verb_remove },
{ "is-installed", VERB_ANY, 1, 0, verb_is_installed },
{ "kernel-identify", 2, 2, 0, verb_kernel_identify },
+ { "kernel-inspect", 2, 2, 0, verb_kernel_inspect },
{ "list", VERB_ANY, 1, 0, verb_list },
{ "set-default", 2, 2, 0, verb_set_efivar },
{ "set-oneshot", 2, 2, 0, verb_set_efivar },

@ -0,0 +1,24 @@
From c1736cd4c9d0cb7b39333280bd30657e68481436 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Fri, 20 Jan 2023 13:30:48 +0100
Subject: [PATCH] bootctl: add kernel-inspect to --help text
(cherry picked from commit 24a3b37f12a1a752e5a1379cadc15031b04c3fba)
Related: RHEL-16354
---
src/boot/bootctl.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index b98673cd11..cc35147376 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -1456,6 +1456,7 @@ static int help(int argc, char *argv[], void *userdata) {
" random-seed Initialize random seed in ESP and EFI variables\n"
"\n%3$skernel Commands:%4$s\n"
" kernel-identify Identify kernel image type.\n"
+ " kernel-inspect Prints details about the kernel.\n"
"\n%3$sOptions:%4$s\n"
" -h --help Show this help\n"
" --version Print version\n"

@ -0,0 +1,29 @@
From d5d960b0b8db73ffe4cff9d156b0883876d722ac Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Fri, 20 Jan 2023 18:29:13 +0100
Subject: [PATCH] bootctl: drop full stop at end of --help texts
We never do that, don't do so here either.
(cherry picked from commit 2b197967bf251ecf58b93fed0f51b9d4cd83fda4)
Related: RHEL-16354
---
src/boot/bootctl.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index cc35147376..681c5bd44f 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -1455,8 +1455,8 @@ static int help(int argc, char *argv[], void *userdata) {
" is-installed Test whether systemd-boot is installed in the ESP\n"
" random-seed Initialize random seed in ESP and EFI variables\n"
"\n%3$skernel Commands:%4$s\n"
- " kernel-identify Identify kernel image type.\n"
- " kernel-inspect Prints details about the kernel.\n"
+ " kernel-identify Identify kernel image type\n"
+ " kernel-inspect Prints details about the kernel\n"
"\n%3$sOptions:%4$s\n"
" -h --help Show this help\n"
" --version Print version\n"

@ -0,0 +1,44 @@
From 6ee66a4736bde681956ef8ab601a72a5cb7b19ed Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Fri, 20 Jan 2023 18:30:06 +0100
Subject: [PATCH] bootctl: change section title for kernel image commands
Let's call them kernel *images*, not just *kernels*.
(cherry picked from commit 1e7d6cc07211de425bcc5c408c1f4376d6717305)
Related: RHEL-16354
---
man/bootctl.xml | 2 +-
src/boot/bootctl.c | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/man/bootctl.xml b/man/bootctl.xml
index c12fe93214..d82f12d5bb 100644
--- a/man/bootctl.xml
+++ b/man/bootctl.xml
@@ -218,7 +218,7 @@
</refsect1>
<refsect1>
- <title><command>kernel</command> Commands</title>
+ <title>Kernel Image Commands</title>
<variablelist>
<varlistentry>
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index 681c5bd44f..4f2a6288fb 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -1454,9 +1454,9 @@ static int help(int argc, char *argv[], void *userdata) {
" remove Remove systemd-boot from the ESP and EFI variables\n"
" is-installed Test whether systemd-boot is installed in the ESP\n"
" random-seed Initialize random seed in ESP and EFI variables\n"
- "\n%3$skernel Commands:%4$s\n"
+ "\n%3$sKernel Image Commands:%4$s\n"
" kernel-identify Identify kernel image type\n"
- " kernel-inspect Prints details about the kernel\n"
+ " kernel-inspect Prints details about the kernel image\n"
"\n%3$sOptions:%4$s\n"
" -h --help Show this help\n"
" --version Print version\n"

@ -0,0 +1,25 @@
From 2eae3094d018587e2550aaf895a7cbdeaea679bd Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Fri, 20 Jan 2023 18:40:57 +0100
Subject: [PATCH] bootctl: remove space that should not be there
(cherry picked from commit e684d2d5f85a82ed47eb063809145540df01ae1a)
Related: RHEL-16354
---
src/boot/bootctl.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index 4f2a6288fb..3044f67b5a 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -1433,7 +1433,7 @@ static int help(int argc, char *argv[], void *userdata) {
if (r < 0)
return log_oom();
- printf("%1$s [OPTIONS...] COMMAND ...\n"
+ printf("%1$s [OPTIONS...] COMMAND ...\n"
"\n%5$sControl EFI firmware boot settings and manage boot loader.%6$s\n"
"\n%3$sGeneric EFI Firmware/Boot Loader Commands:%4$s\n"
" status Show status of installed boot loader and EFI variables\n"

@ -0,0 +1,73 @@
From 6204aa43883fdf02d72bd0db6d3cfbfa7c075213 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Fri, 20 Jan 2023 15:40:36 +0100
Subject: [PATCH] bootctl: kernel-inspect: print os info
(cherry picked from commit 2d4260482cb8463f4de9502efd26bf8c64262669)
Related: RHEL-16354
---
src/boot/bootctl-uki.c | 29 ++++++++++++++++++++++++++++-
1 file changed, 28 insertions(+), 1 deletion(-)
diff --git a/src/boot/bootctl-uki.c b/src/boot/bootctl-uki.c
index 3085f703a8..6bdf926350 100644
--- a/src/boot/bootctl-uki.c
+++ b/src/boot/bootctl-uki.c
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "bootctl-uki.h"
+#include "env-file.h"
#include "fd-util.h"
#include "parse-util.h"
#include "pe-header.h"
@@ -142,10 +143,31 @@ static int read_pe_section(FILE *uki, const struct PeSectionHeader *section,
return 0;
}
+static void inspect_osrel(char *osrel, size_t osrel_size) {
+ _cleanup_fclose_ FILE *s = NULL;
+ _cleanup_free_ char *pname = NULL, *name = NULL;
+ int r;
+
+ assert(osrel);
+ s = fmemopen(osrel, osrel_size, "r");
+ if (!s)
+ return (void) log_warning_errno(errno, "Failed to open embedded os-release file, ignoring: %m");
+
+ r = parse_env_file(s, NULL,
+ "PRETTY_NAME", &pname,
+ "NAME", &name);
+ if (r < 0)
+ return (void) log_warning_errno(r, "Failed to parse embedded os-release file, ignoring: %m");
+
+ if (pname || name)
+ printf(" OS: %s\n", pname ?: name);
+}
+
static void inspect_uki(FILE *uki, struct PeSectionHeader *sections, size_t scount) {
_cleanup_free_ char *cmdline = NULL;
_cleanup_free_ char *uname = NULL;
- size_t idx;
+ _cleanup_free_ char *osrel = NULL;
+ size_t osrel_size, idx;
if (find_pe_section(sections, scount, name_cmdline, sizeof(name_cmdline), &idx))
read_pe_section(uki, sections + idx, (void**)&cmdline, NULL);
@@ -153,10 +175,15 @@ static void inspect_uki(FILE *uki, struct PeSectionHeader *sections, size_t scou
if (find_pe_section(sections, scount, name_uname, sizeof(name_uname), &idx))
read_pe_section(uki, sections + idx, (void**)&uname, NULL);
+ if (find_pe_section(sections, scount, name_osrel, sizeof(name_osrel), &idx))
+ read_pe_section(uki, sections + idx, (void**)&osrel, &osrel_size);
+
if (cmdline)
printf(" Cmdline: %s\n", cmdline);
if (uname)
printf(" Version: %s\n", uname);
+ if (osrel)
+ inspect_osrel(osrel, osrel_size);
}
int verb_kernel_inspect(int argc, char *argv[], void *userdata) {

@ -0,0 +1,207 @@
From a9c7fe86260ca906c7378503e059eca0ad014947 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 24 Jan 2023 22:59:59 +0900
Subject: [PATCH] bootctl-uki: several coding style fixlets
Mostly follow-ups for #26082.
(cherry picked from commit 5b532e14e3ac1d8f8cef90fd8c5b1ce277458ae7)
Related: RHEL-16354
---
src/boot/bootctl-uki.c | 105 +++++++++++++++++++++++------------------
1 file changed, 60 insertions(+), 45 deletions(-)
diff --git a/src/boot/bootctl-uki.c b/src/boot/bootctl-uki.c
index 6bdf926350..3492fa548f 100644
--- a/src/boot/bootctl-uki.c
+++ b/src/boot/bootctl-uki.c
@@ -23,7 +23,10 @@ static int pe_sections(FILE *uki, struct PeSectionHeader **ret, size_t *ret_n) {
struct PeHeader pe;
size_t scount;
uint64_t soff, items;
- int rc;
+
+ assert(uki);
+ assert(ret);
+ assert(ret_n);
items = fread(&dos, 1, sizeof(dos), uki);
if (items != sizeof(dos))
@@ -31,9 +34,9 @@ static int pe_sections(FILE *uki, struct PeSectionHeader **ret, size_t *ret_n) {
if (memcmp(dos.Magic, dos_file_magic, sizeof(dos_file_magic)) != 0)
goto no_sections;
- rc = fseek(uki, le32toh(dos.ExeHeader), SEEK_SET);
- if (rc < 0)
+ if (fseek(uki, le32toh(dos.ExeHeader), SEEK_SET) < 0)
return log_error_errno(errno, "seek to PE header");
+
items = fread(&pe, 1, sizeof(pe), uki);
if (items != sizeof(pe))
return log_error_errno(SYNTHETIC_ERRNO(EIO), "PE header read error");
@@ -41,8 +44,7 @@ static int pe_sections(FILE *uki, struct PeSectionHeader **ret, size_t *ret_n) {
goto no_sections;
soff = le32toh(dos.ExeHeader) + sizeof(pe) + le16toh(pe.FileHeader.SizeOfOptionalHeader);
- rc = fseek(uki, soff, SEEK_SET);
- if (rc < 0)
+ if (fseek(uki, soff, SEEK_SET) < 0)
return log_error_errno(errno, "seek to PE section headers");
scount = le16toh(pe.FileHeader.NumberOfSections);
@@ -65,58 +67,72 @@ no_sections:
return 0;
}
-static int find_pe_section(struct PeSectionHeader *sections, size_t scount,
- const uint8_t *name, size_t namelen, size_t *ret) {
- for (size_t s = 0; s < scount; s++) {
- if (memcmp_nn(sections[s].Name, sizeof(sections[s].Name),
- name, namelen) == 0) {
+static bool find_pe_section(
+ struct PeSectionHeader *sections,
+ size_t scount,
+ const uint8_t *name,
+ size_t namelen,
+ size_t *ret) {
+
+ assert(sections || scount == 0);
+ assert(name || namelen == 0);
+
+ for (size_t s = 0; s < scount; s++)
+ if (memcmp_nn(sections[s].Name, sizeof(sections[s].Name), name, namelen) == 0) {
if (ret)
*ret = s;
- return 1;
+ return true;
}
- }
- return 0;
+
+ return false;
}
static bool is_uki(struct PeSectionHeader *sections, size_t scount) {
- return (find_pe_section(sections, scount, name_osrel, sizeof(name_osrel), NULL) &&
+ assert(sections || scount == 0);
+
+ return
+ find_pe_section(sections, scount, name_osrel, sizeof(name_osrel), NULL) &&
find_pe_section(sections, scount, name_linux, sizeof(name_linux), NULL) &&
- find_pe_section(sections, scount, name_initrd, sizeof(name_initrd), NULL));
+ find_pe_section(sections, scount, name_initrd, sizeof(name_initrd), NULL);
}
int verb_kernel_identify(int argc, char *argv[], void *userdata) {
_cleanup_fclose_ FILE *uki = NULL;
_cleanup_free_ struct PeSectionHeader *sections = NULL;
size_t scount;
- int rc;
+ int r;
uki = fopen(argv[1], "re");
if (!uki)
return log_error_errno(errno, "Failed to open UKI file '%s': %m", argv[1]);
- rc = pe_sections(uki, &sections, &scount);
- if (rc < 0)
- return EXIT_FAILURE;
+ r = pe_sections(uki, &sections, &scount);
+ if (r < 0)
+ return r;
- if (sections) {
- if (is_uki(sections, scount)) {
- puts("uki");
- return EXIT_SUCCESS;
- }
+ if (!sections)
+ puts("unknown");
+ else if (is_uki(sections, scount))
+ puts("uki");
+ else
puts("pe");
- return EXIT_SUCCESS;
- }
- puts("unknown");
return EXIT_SUCCESS;
}
-static int read_pe_section(FILE *uki, const struct PeSectionHeader *section,
- void **ret, size_t *ret_n) {
+static int read_pe_section(
+ FILE *uki,
+ const struct PeSectionHeader *section,
+ void **ret,
+ size_t *ret_n) {
+
_cleanup_free_ void *data = NULL;
uint32_t size, bytes;
uint64_t soff;
- int rc;
+
+ assert(uki);
+ assert(section);
+ assert(ret);
soff = le32toh(section->PointerToRawData);
size = le32toh(section->VirtualSize);
@@ -124,8 +140,7 @@ static int read_pe_section(FILE *uki, const struct PeSectionHeader *section,
if (size > 16 * 1024)
return log_error_errno(SYNTHETIC_ERRNO(E2BIG), "PE section too big");
- rc = fseek(uki, soff, SEEK_SET);
- if (rc < 0)
+ if (fseek(uki, soff, SEEK_SET) < 0)
return log_error_errno(errno, "seek to PE section");
data = malloc(size+1);
@@ -169,6 +184,9 @@ static void inspect_uki(FILE *uki, struct PeSectionHeader *sections, size_t scou
_cleanup_free_ char *osrel = NULL;
size_t osrel_size, idx;
+ assert(uki);
+ assert(sections || scount == 0);
+
if (find_pe_section(sections, scount, name_cmdline, sizeof(name_cmdline), &idx))
read_pe_section(uki, sections + idx, (void**)&cmdline, NULL);
@@ -190,26 +208,23 @@ int verb_kernel_inspect(int argc, char *argv[], void *userdata) {
_cleanup_fclose_ FILE *uki = NULL;
_cleanup_free_ struct PeSectionHeader *sections = NULL;
size_t scount;
- int rc;
+ int r;
uki = fopen(argv[1], "re");
if (!uki)
return log_error_errno(errno, "Failed to open UKI file '%s': %m", argv[1]);
- rc = pe_sections(uki, &sections, &scount);
- if (rc < 0)
- return EXIT_FAILURE;
+ r = pe_sections(uki, &sections, &scount);
+ if (r < 0)
+ return r;
- if (sections) {
- if (is_uki(sections, scount)) {
- puts("Kernel Type: uki");
- inspect_uki(uki, sections, scount);
- return EXIT_SUCCESS;
- }
+ if (!sections)
+ puts("Kernel Type: unknown");
+ else if (is_uki(sections, scount)) {
+ puts("Kernel Type: uki");
+ inspect_uki(uki, sections, scount);
+ } else
puts("Kernel Type: pe");
- return EXIT_SUCCESS;
- }
- puts("Kernel Type: unknown");
return EXIT_SUCCESS;
}

@ -0,0 +1,171 @@
From a83545ba5d0cc1b29f2bb4e2b794ce14b138e3fe Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 23 Jan 2023 12:28:38 +0100
Subject: [PATCH] tree-wide: unify how we pick OS pretty name to display
(cherry picked from commit 02b7005e38db756711cd6463bda34e93cf304c3c)
Related: RHEL-16354
---
src/analyze/analyze-plot.c | 3 ++-
src/basic/os-util.c | 9 +++++++++
src/basic/os-util.h | 2 ++
src/core/main.c | 2 +-
src/firstboot/firstboot.c | 5 +++--
src/hostname/hostnamed.c | 7 ++++++-
src/journal-remote/journal-gatewayd.c | 9 ++++++---
7 files changed, 29 insertions(+), 8 deletions(-)
diff --git a/src/analyze/analyze-plot.c b/src/analyze/analyze-plot.c
index 24f4add099..8aca691b3d 100644
--- a/src/analyze/analyze-plot.c
+++ b/src/analyze/analyze-plot.c
@@ -6,6 +6,7 @@
#include "bus-error.h"
#include "bus-map-properties.h"
#include "format-table.h"
+#include "os-util.h"
#include "sort-util.h"
#include "version.h"
@@ -283,7 +284,7 @@ static int produce_plot_as_svg(
svg("<text x=\"20\" y=\"50\">%s</text>", pretty_times);
if (host)
svg("<text x=\"20\" y=\"30\">%s %s (%s %s %s) %s %s</text>",
- isempty(host->os_pretty_name) ? "Linux" : host->os_pretty_name,
+ os_release_pretty_name(host->os_pretty_name, NULL),
strempty(host->hostname),
strempty(host->kernel_name),
strempty(host->kernel_release),
diff --git a/src/basic/os-util.c b/src/basic/os-util.c
index 8f8bb0881e..66cbfc76a5 100644
--- a/src/basic/os-util.c
+++ b/src/basic/os-util.c
@@ -370,3 +370,12 @@ int os_release_support_ended(const char *support_end, bool quiet) {
usec_t ts = now(CLOCK_REALTIME);
return DIV_ROUND_UP(ts, USEC_PER_SEC) > (usec_t) eol;
}
+
+const char *os_release_pretty_name(const char *pretty_name, const char *name) {
+ /* Distills a "pretty" name to show from os-release data. First argument is supposed to be the
+ * PRETTY_NAME= field, the second one the NAME= field. This function is trivial, of course, and
+ * exists mostly to ensure we use the same logic wherever possible. */
+
+ return empty_to_null(pretty_name) ?:
+ empty_to_null(name) ?: "Linux";
+}
diff --git a/src/basic/os-util.h b/src/basic/os-util.h
index d22f5ab8e7..1239f6f6b7 100644
--- a/src/basic/os-util.h
+++ b/src/basic/os-util.h
@@ -33,3 +33,5 @@ int load_os_release_pairs(const char *root, char ***ret);
int load_os_release_pairs_with_prefix(const char *root, const char *prefix, char ***ret);
int os_release_support_ended(const char *support_end, bool quiet);
+
+const char *os_release_pretty_name(const char *pretty_name, const char *name);
diff --git a/src/core/main.c b/src/core/main.c
index d3ec526e7e..0e2e5448bb 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -1339,7 +1339,7 @@ static int os_release_status(void) {
return log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
"Failed to read os-release file, ignoring: %m");
- const char *label = empty_to_null(pretty_name) ?: empty_to_null(name) ?: "Linux";
+ const char *label = os_release_pretty_name(pretty_name, name);
if (show_status_on(arg_show_status)) {
if (log_get_show_color())
diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c
index 63db78b52d..10eda1d302 100644
--- a/src/firstboot/firstboot.c
+++ b/src/firstboot/firstboot.c
@@ -96,7 +96,7 @@ static bool press_any_key(void) {
}
static void print_welcome(void) {
- _cleanup_free_ char *pretty_name = NULL, *ansi_color = NULL;
+ _cleanup_free_ char *pretty_name = NULL, *os_name = NULL, *ansi_color = NULL;
static bool done = false;
const char *pn, *ac;
int r;
@@ -110,12 +110,13 @@ static void print_welcome(void) {
r = parse_os_release(
arg_root,
"PRETTY_NAME", &pretty_name,
+ "NAME", &os_name,
"ANSI_COLOR", &ansi_color);
if (r < 0)
log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
"Failed to read os-release file, ignoring: %m");
- pn = isempty(pretty_name) ? "Linux" : pretty_name;
+ pn = os_release_pretty_name(pretty_name, os_name);
ac = isempty(ansi_color) ? "0" : ansi_color;
if (colors_enabled())
diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c
index 486b093062..2a675caada 100644
--- a/src/hostname/hostnamed.c
+++ b/src/hostname/hostnamed.c
@@ -147,6 +147,7 @@ static void context_read_machine_info(Context *c) {
}
static void context_read_os_release(Context *c) {
+ _cleanup_free_ char *os_name = NULL, *os_pretty_name = NULL;
struct stat current_stat = {};
int r;
@@ -163,12 +164,16 @@ static void context_read_os_release(Context *c) {
(UINT64_C(1) << PROP_OS_HOME_URL));
r = parse_os_release(NULL,
- "PRETTY_NAME", &c->data[PROP_OS_PRETTY_NAME],
+ "PRETTY_NAME", &os_pretty_name,
+ "NAME", &os_name,
"CPE_NAME", &c->data[PROP_OS_CPE_NAME],
"HOME_URL", &c->data[PROP_OS_HOME_URL]);
if (r < 0 && r != -ENOENT)
log_warning_errno(r, "Failed to read os-release file, ignoring: %m");
+ if (free_and_strdup(&c->data[PROP_OS_PRETTY_NAME], os_release_pretty_name(os_pretty_name, os_name)) < 0)
+ log_oom();
+
c->etc_os_release_stat = current_stat;
}
diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c
index 34def4670e..e848ae5026 100644
--- a/src/journal-remote/journal-gatewayd.c
+++ b/src/journal-remote/journal-gatewayd.c
@@ -732,7 +732,7 @@ static int request_handler_machine(
_cleanup_(MHD_destroy_responsep) struct MHD_Response *response = NULL;
RequestMeta *m = ASSERT_PTR(connection_cls);
int r;
- _cleanup_free_ char* hostname = NULL, *os_name = NULL;
+ _cleanup_free_ char* hostname = NULL, *pretty_name = NULL, *os_name = NULL;
uint64_t cutoff_from = 0, cutoff_to = 0, usage = 0;
sd_id128_t mid, bid;
_cleanup_free_ char *v = NULL, *json = NULL;
@@ -763,7 +763,10 @@ static int request_handler_machine(
if (r < 0)
return mhd_respondf(connection, r, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to determine disk usage: %m");
- (void) parse_os_release(NULL, "PRETTY_NAME", &os_name);
+ (void) parse_os_release(
+ NULL,
+ "PRETTY_NAME", &pretty_name,
+ "NAME=", &os_name);
(void) get_virtualization(&v);
r = asprintf(&json,
@@ -778,7 +781,7 @@ static int request_handler_machine(
SD_ID128_FORMAT_VAL(mid),
SD_ID128_FORMAT_VAL(bid),
hostname_cleanup(hostname),
- os_name ? os_name : "Linux",
+ os_release_pretty_name(pretty_name, os_name),
v ? v : "bare",
usage,
cutoff_from,

@ -0,0 +1,102 @@
From 5374c8fb7c32e79f9dcd24333e5c117bd8963a1a Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Wed, 25 Jan 2023 11:05:46 +0900
Subject: [PATCH] bootctl-uki: several follow-ups for inspect_osrel()
Follow-ups for #26124 and #26158.
- use os_release_pretty_name(),
- constify the buffer passed to inspect_osrel(),
- propagate errors in inspect_osrele(), and ignore them in the caller
side,
- and several coding style fixlets.
(cherry picked from commit 1b7586df976d7b033b4901a099337d83578bb8f1)
Related: RHEL-16354
---
src/boot/bootctl-uki.c | 36 ++++++++++++++++++++----------------
1 file changed, 20 insertions(+), 16 deletions(-)
diff --git a/src/boot/bootctl-uki.c b/src/boot/bootctl-uki.c
index 3492fa548f..fd249c43fb 100644
--- a/src/boot/bootctl-uki.c
+++ b/src/boot/bootctl-uki.c
@@ -3,6 +3,7 @@
#include "bootctl-uki.h"
#include "env-file.h"
#include "fd-util.h"
+#include "os-util.h"
#include "parse-util.h"
#include "pe-header.h"
@@ -158,50 +159,53 @@ static int read_pe_section(
return 0;
}
-static void inspect_osrel(char *osrel, size_t osrel_size) {
+static int inspect_osrel(const void *osrel, size_t osrel_size) {
_cleanup_fclose_ FILE *s = NULL;
_cleanup_free_ char *pname = NULL, *name = NULL;
int r;
- assert(osrel);
- s = fmemopen(osrel, osrel_size, "r");
+ assert(osrel || osrel_size == 0);
+
+ if (!osrel)
+ return 0;
+
+ s = fmemopen((void*) osrel, osrel_size, "r");
if (!s)
- return (void) log_warning_errno(errno, "Failed to open embedded os-release file, ignoring: %m");
+ return log_warning_errno(errno, "Failed to open embedded os-release file, ignoring: %m");
r = parse_env_file(s, NULL,
"PRETTY_NAME", &pname,
"NAME", &name);
if (r < 0)
- return (void) log_warning_errno(r, "Failed to parse embedded os-release file, ignoring: %m");
+ return log_warning_errno(r, "Failed to parse embedded os-release file, ignoring: %m");
- if (pname || name)
- printf(" OS: %s\n", pname ?: name);
+ printf(" OS: %s\n", os_release_pretty_name(pname, name));
+ return 0;
}
static void inspect_uki(FILE *uki, struct PeSectionHeader *sections, size_t scount) {
- _cleanup_free_ char *cmdline = NULL;
- _cleanup_free_ char *uname = NULL;
- _cleanup_free_ char *osrel = NULL;
- size_t osrel_size, idx;
+ _cleanup_free_ char *cmdline = NULL, *uname = NULL;
+ _cleanup_free_ void *osrel = NULL;
+ size_t osrel_size = 0, idx;
assert(uki);
assert(sections || scount == 0);
if (find_pe_section(sections, scount, name_cmdline, sizeof(name_cmdline), &idx))
- read_pe_section(uki, sections + idx, (void**)&cmdline, NULL);
+ read_pe_section(uki, sections + idx, (void**) &cmdline, NULL);
if (find_pe_section(sections, scount, name_uname, sizeof(name_uname), &idx))
- read_pe_section(uki, sections + idx, (void**)&uname, NULL);
+ read_pe_section(uki, sections + idx, (void**) &uname, NULL);
if (find_pe_section(sections, scount, name_osrel, sizeof(name_osrel), &idx))
- read_pe_section(uki, sections + idx, (void**)&osrel, &osrel_size);
+ read_pe_section(uki, sections + idx, &osrel, &osrel_size);
if (cmdline)
printf(" Cmdline: %s\n", cmdline);
if (uname)
printf(" Version: %s\n", uname);
- if (osrel)
- inspect_osrel(osrel, osrel_size);
+
+ (void) inspect_osrel(osrel, osrel_size);
}
int verb_kernel_inspect(int argc, char *argv[], void *userdata) {

@ -0,0 +1,25 @@
From 47a9030cad80a684b9affcc2c35ef264e7a8b145 Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Thu, 9 Feb 2023 10:44:35 +0100
Subject: [PATCH] bootctl: Add missing %m
(cherry picked from commit 3b42ffe590c5728af50feb138890a44264c4b02e)
Related: RHEL-16354
---
src/boot/bootctl.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index 3044f67b5a..a0ca2afec2 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -1420,7 +1420,7 @@ static int install_entry_token(void) {
r = write_string_file("/etc/kernel/entry-token", arg_entry_token, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_MKDIR_0755);
if (r < 0)
- return log_error_errno(r, "Failed to write entry token '%s' to /etc/kernel/entry-token", arg_entry_token);
+ return log_error_errno(r, "Failed to write entry token '%s' to /etc/kernel/entry-token: %m", arg_entry_token);
return 0;
}

@ -0,0 +1,41 @@
From 618e38b8b775f45c0a18975ae33753b92c954092 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 24 Jan 2023 10:28:25 +0100
Subject: [PATCH] bootctl: tweak DOS header magic check
Read the magic first, try reading the full DOS exe header only in case
the magic check succeeds.
This avoids throwing an header read error on small dummy files as used
by test-kernel-install.
(cherry picked from commit 78088b8f43717a43661cd2c1627a9860904c4794)
Related: RHEL-16354
---
src/boot/bootctl-uki.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/src/boot/bootctl-uki.c b/src/boot/bootctl-uki.c
index fd249c43fb..d90a850b1c 100644
--- a/src/boot/bootctl-uki.c
+++ b/src/boot/bootctl-uki.c
@@ -30,11 +30,16 @@ static int pe_sections(FILE *uki, struct PeSectionHeader **ret, size_t *ret_n) {
assert(ret_n);
items = fread(&dos, 1, sizeof(dos), uki);
- if (items != sizeof(dos))
- return log_error_errno(SYNTHETIC_ERRNO(EIO), "DOS header read error");
+ if (items < sizeof(dos.Magic))
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "File is smaller than DOS magic (got %"PRIu64" of %zu bytes)",
+ items, sizeof(dos.Magic));
if (memcmp(dos.Magic, dos_file_magic, sizeof(dos_file_magic)) != 0)
goto no_sections;
+ if (items != sizeof(dos))
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "File is smaller than DOS header (got %"PRIu64" of %zu bytes)",
+ items, sizeof(dos));
+
if (fseek(uki, le32toh(dos.ExeHeader), SEEK_SET) < 0)
return log_error_errno(errno, "seek to PE header");

@ -0,0 +1,30 @@
From a1bd733809ff01c64a8a304a45e57277a5a98463 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Fri, 8 Dec 2023 19:35:37 +0100
Subject: [PATCH] meson: fix installation of ukify
ln_s was added in upstream later on. It's not present in this branch.
Fixup for b98da2d9e7.
Related: RHEL-13199
---
meson.build | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/meson.build b/meson.build
index 936e612a01..e09c426a72 100644
--- a/meson.build
+++ b/meson.build
@@ -3868,9 +3868,9 @@ ukify = custom_target(
if want_ukify
public_programs += ukify
- meson.add_install_script(sh, '-c',
- ln_s.format(bindir / 'ukify',
- rootlibexecdir / 'ukify'))
+ meson.add_install_script(meson_make_symlink,
+ bindir / 'ukify',
+ rootlibexecdir / 'ukify')
endif
if want_tests != 'false' and want_kernel_install

@ -0,0 +1,37 @@
From 81802cf297a05d202aae5de21673fcc7064f9b7d Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Fri, 28 Oct 2022 09:08:09 +0900
Subject: [PATCH] sd-id128: introduce id128_hash_ops_free
(cherry picked from commit 3e61656fab869bb40f019c38c3347885238294de)
Related: RHEL-5988
---
src/libsystemd/sd-id128/id128-util.c | 1 +
src/libsystemd/sd-id128/id128-util.h | 1 +
2 files changed, 2 insertions(+)
diff --git a/src/libsystemd/sd-id128/id128-util.c b/src/libsystemd/sd-id128/id128-util.c
index 4f52c14f64..cef340f3bc 100644
--- a/src/libsystemd/sd-id128/id128-util.c
+++ b/src/libsystemd/sd-id128/id128-util.c
@@ -184,6 +184,7 @@ sd_id128_t id128_make_v4_uuid(sd_id128_t id) {
}
DEFINE_HASH_OPS(id128_hash_ops, sd_id128_t, id128_hash_func, id128_compare_func);
+DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(id128_hash_ops_free, sd_id128_t, id128_hash_func, id128_compare_func, free);
int id128_get_product(sd_id128_t *ret) {
sd_id128_t uuid;
diff --git a/src/libsystemd/sd-id128/id128-util.h b/src/libsystemd/sd-id128/id128-util.h
index 17b180c10c..9d8fe93641 100644
--- a/src/libsystemd/sd-id128/id128-util.h
+++ b/src/libsystemd/sd-id128/id128-util.h
@@ -30,6 +30,7 @@ int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync);
void id128_hash_func(const sd_id128_t *p, struct siphash *state);
int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) _pure_;
extern const struct hash_ops id128_hash_ops;
+extern const struct hash_ops id128_hash_ops_free;
sd_id128_t id128_make_v4_uuid(sd_id128_t id);

@ -0,0 +1,104 @@
From 597c41edd3e94f2c16209359fbd8de7ed44225d7 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Fri, 28 Oct 2022 10:14:09 +0900
Subject: [PATCH] udevadm-trigger: allow to fallback without synthetic UUID
only first time
If a device is successfully triggered with synthetic UUID, then that means
the kernel support it. Hence, it is not necessary to fallback without UUID
for later devices.
(cherry picked from commit b15039425feba8f316fb306b75d96e2f0f0b82fa)
Related: RHEL-5988
---
src/udev/udevadm-trigger.c | 22 ++++++++++++++--------
1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c
index 1d421064d7..cda31edd75 100644
--- a/src/udev/udevadm-trigger.c
+++ b/src/udev/udevadm-trigger.c
@@ -26,17 +26,20 @@ static bool arg_verbose = false;
static bool arg_dry_run = false;
static bool arg_quiet = false;
static bool arg_uuid = false;
+static bool arg_settle = false;
static int exec_list(
sd_device_enumerator *e,
sd_device_action_t action,
Hashmap *settle_hashmap) {
- bool skip_uuid_logic = false;
+ int uuid_supported = -1;
const char *action_str;
sd_device *d;
int r, ret = 0;
+ assert(e);
+
action_str = device_action_to_string(action);
FOREACH_DEVICE_AND_SUBSYSTEM(e, d) {
@@ -57,14 +60,14 @@ static int exec_list(
/* Use the UUID mode if the user explicitly asked for it, or if --settle has been specified,
* so that we can recognize our own uevent. */
- r = sd_device_trigger_with_uuid(d, action, (arg_uuid || settle_hashmap) && !skip_uuid_logic ? &id : NULL);
- if (r == -EINVAL && !arg_uuid && settle_hashmap && !skip_uuid_logic) {
+ r = sd_device_trigger_with_uuid(d, action, (arg_uuid || arg_settle) && uuid_supported != 0 ? &id : NULL);
+ if (r == -EINVAL && !arg_uuid && arg_settle && uuid_supported < 0) {
/* If we specified a UUID because of the settling logic, and we got EINVAL this might
* be caused by an old kernel which doesn't know the UUID logic (pre-4.13). Let's try
* if it works without the UUID logic then. */
r = sd_device_trigger(d, action);
if (r != -EINVAL)
- skip_uuid_logic = true; /* dropping the uuid stuff changed the return code,
+ uuid_supported = false; /* dropping the uuid stuff changed the return code,
* hence don't bother next time */
}
if (r < 0) {
@@ -108,11 +111,14 @@ static int exec_list(
continue;
}
+ if (uuid_supported < 0)
+ uuid_supported = true;
+
/* If the user asked for it, write event UUID to stdout */
if (arg_uuid)
printf(SD_ID128_UUID_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(id));
- if (settle_hashmap) {
+ if (arg_settle) {
_cleanup_free_ sd_id128_t *mid = NULL;
_cleanup_free_ char *sp = NULL;
@@ -285,7 +291,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
_cleanup_hashmap_free_ Hashmap *settle_hashmap = NULL;
usec_t ping_timeout_usec = 5 * USEC_PER_SEC;
- bool settle = false, ping = false;
+ bool ping = false;
int c, r;
if (running_in_chroot() > 0) {
@@ -389,7 +395,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
break;
}
case 'w':
- settle = true;
+ arg_settle = true;
break;
case ARG_NAME: {
@@ -477,7 +483,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
return log_error_errno(r, "Failed to add parent match '%s': %m", argv[optind]);
}
- if (settle) {
+ if (arg_settle) {
settle_hashmap = hashmap_new(&path_hash_ops_free_free);
if (!settle_hashmap)
return log_oom();

@ -0,0 +1,196 @@
From 73dbfdaab1d633e3a1ae96cc15c551eaa2fd4243 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Fri, 28 Oct 2022 10:21:57 +0900
Subject: [PATCH] udevadm-trigger: settle with synthetic UUID if the kernel
support it
If the kernel support synthetic UUID in uevent, then let's assume that
the UUID is unique, and check only if the received UUID matches we
specified.
Partially fixes #25115.
(cherry picked from commit dfbd824a0b780310d7f865a6ea0d60434d924683)
Related: RHEL-5988
---
src/udev/udevadm-trigger.c | 82 +++++++++++++++++++-------------------
1 file changed, 40 insertions(+), 42 deletions(-)
diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c
index cda31edd75..3909fa237c 100644
--- a/src/udev/udevadm-trigger.c
+++ b/src/udev/udevadm-trigger.c
@@ -11,10 +11,12 @@
#include "device-util.h"
#include "fd-util.h"
#include "fileio.h"
+#include "id128-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
#include "set.h"
+#include "static-destruct.h"
#include "string-util.h"
#include "strv.h"
#include "udevadm.h"
@@ -31,8 +33,9 @@ static bool arg_settle = false;
static int exec_list(
sd_device_enumerator *e,
sd_device_action_t action,
- Hashmap *settle_hashmap) {
+ Set **ret_settle_path_or_ids) {
+ _cleanup_set_free_ Set *settle_path_or_ids = NULL;
int uuid_supported = -1;
const char *action_str;
sd_device *d;
@@ -119,60 +122,62 @@ static int exec_list(
printf(SD_ID128_UUID_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(id));
if (arg_settle) {
- _cleanup_free_ sd_id128_t *mid = NULL;
- _cleanup_free_ char *sp = NULL;
+ if (uuid_supported) {
+ sd_id128_t *dup;
- sp = strdup(syspath);
- if (!sp)
- return log_oom();
+ dup = newdup(sd_id128_t, &id, 1);
+ if (!dup)
+ return log_oom();
- mid = newdup(sd_id128_t, &id, 1);
- if (!d)
- return log_oom();
+ r = set_ensure_consume(&settle_path_or_ids, &id128_hash_ops_free, dup);
+ } else {
+ char *dup;
+
+ dup = strdup(syspath);
+ if (!dup)
+ return log_oom();
- r = hashmap_put(settle_hashmap, sp, mid);
+ r = set_ensure_consume(&settle_path_or_ids, &path_hash_ops_free, dup);
+ }
if (r < 0)
return log_oom();
-
- TAKE_PTR(sp);
- TAKE_PTR(mid);
}
}
+ if (ret_settle_path_or_ids)
+ *ret_settle_path_or_ids = TAKE_PTR(settle_path_or_ids);
+
return ret;
}
static int device_monitor_handler(sd_device_monitor *m, sd_device *dev, void *userdata) {
- Hashmap *settle_hashmap = ASSERT_PTR(userdata);
- sd_id128_t *settle_id;
+ Set *settle_path_or_ids = * (Set**) ASSERT_PTR(userdata);
const char *syspath;
- char *k;
+ sd_id128_t id;
int r;
assert(dev);
r = sd_device_get_syspath(dev, &syspath);
if (r < 0) {
- log_debug_errno(r, "Failed to get syspath of device event, ignoring: %m");
+ log_device_debug_errno(dev, r, "Failed to get syspath of device event, ignoring: %m");
return 0;
}
- settle_id = hashmap_get2(settle_hashmap, syspath, (void**) &k);
- if (!settle_id) {
- log_debug("Got uevent for unexpected device '%s', ignoring.", syspath);
- return 0;
- }
- if (!sd_id128_is_null(*settle_id)) { /* If this is SD_ID128_NULL then we are on pre-4.13 and have no UUID to check, hence don't */
- sd_id128_t event_id;
+ if (sd_device_get_trigger_uuid(dev, &id) >= 0) {
+ _cleanup_free_ sd_id128_t *saved = NULL;
- r = sd_device_get_trigger_uuid(dev, &event_id);
- if (r < 0) {
- log_debug_errno(r, "Got uevent without synthetic UUID for device '%s', ignoring: %m", syspath);
+ saved = set_remove(settle_path_or_ids, &id);
+ if (!saved) {
+ log_device_debug(dev, "Got uevent not matching expected UUID, ignoring.");
return 0;
}
+ } else {
+ _cleanup_free_ char *saved = NULL;
- if (!sd_id128_equal(event_id, *settle_id)) {
- log_debug("Got uevent not matching expected UUID for device '%s', ignoring.", syspath);
+ saved = set_remove(settle_path_or_ids, syspath);
+ if (!saved) {
+ log_device_debug(dev, "Got uevent for unexpected device, ignoring.");
return 0;
}
}
@@ -181,12 +186,9 @@ static int device_monitor_handler(sd_device_monitor *m, sd_device *dev, void *us
printf("settle %s\n", syspath);
if (arg_uuid)
- printf("settle " SD_ID128_UUID_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(*settle_id));
+ printf("settle " SD_ID128_UUID_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(id));
- free(hashmap_remove(settle_hashmap, syspath));
- free(k);
-
- if (hashmap_isempty(settle_hashmap))
+ if (set_isempty(settle_path_or_ids))
return sd_event_exit(sd_device_monitor_get_event(m), 0);
return 0;
@@ -289,7 +291,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *m = NULL;
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
- _cleanup_hashmap_free_ Hashmap *settle_hashmap = NULL;
+ _cleanup_set_free_ Set *settle_path_or_ids = NULL;
usec_t ping_timeout_usec = 5 * USEC_PER_SEC;
bool ping = false;
int c, r;
@@ -484,10 +486,6 @@ int trigger_main(int argc, char *argv[], void *userdata) {
}
if (arg_settle) {
- settle_hashmap = hashmap_new(&path_hash_ops_free_free);
- if (!settle_hashmap)
- return log_oom();
-
r = sd_event_default(&event);
if (r < 0)
return log_error_errno(r, "Failed to get default event: %m");
@@ -500,7 +498,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
if (r < 0)
return log_error_errno(r, "Failed to attach event to device monitor: %m");
- r = sd_device_monitor_start(m, device_monitor_handler, settle_hashmap);
+ r = sd_device_monitor_start(m, device_monitor_handler, &settle_path_or_ids);
if (r < 0)
return log_error_errno(r, "Failed to start device monitor: %m");
}
@@ -525,11 +523,11 @@ int trigger_main(int argc, char *argv[], void *userdata) {
assert_not_reached();
}
- r = exec_list(e, action, settle_hashmap);
+ r = exec_list(e, action, arg_settle ? &settle_path_or_ids : NULL);
if (r < 0)
return r;
- if (event && !hashmap_isempty(settle_hashmap)) {
+ if (!set_isempty(settle_path_or_ids)) {
r = sd_event_loop(event);
if (r < 0)
return log_error_errno(r, "Event loop failed: %m");

@ -0,0 +1,56 @@
From 4007f494b2e4c45f2d59948af3f4053258d3f127 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Fri, 28 Oct 2022 09:06:02 +0900
Subject: [PATCH] udevadm-trigger: also check with the original syspath if
device is renamed
For older kernels that synthetic UUID is not supported, we need to also
check the original device name, as udevd broadcasts uevent with new
sysname.
Fixes #25115.
(cherry picked from commit 1193448cb68e5a90cab027e16a093bbd367e9494)
Related: RHEL-5988
---
src/udev/udevadm-trigger.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c
index 3909fa237c..40ee5085a0 100644
--- a/src/udev/udevadm-trigger.c
+++ b/src/udev/udevadm-trigger.c
@@ -176,6 +176,32 @@ static int device_monitor_handler(sd_device_monitor *m, sd_device *dev, void *us
_cleanup_free_ char *saved = NULL;
saved = set_remove(settle_path_or_ids, syspath);
+ if (!saved) {
+ const char *old_sysname;
+
+ /* When the device is renamed, the new name is broadcast, and the old name is saved
+ * in INTERFACE_OLD. */
+
+ if (sd_device_get_property_value(dev, "INTERFACE_OLD", &old_sysname) >= 0) {
+ _cleanup_free_ char *dir = NULL, *old_syspath = NULL;
+
+ r = path_extract_directory(syspath, &dir);
+ if (r < 0) {
+ log_device_debug_errno(dev, r,
+ "Failed to extract directory from '%s', ignoring: %m",
+ syspath);
+ return 0;
+ }
+
+ old_syspath = path_join(dir, old_sysname);
+ if (!old_syspath) {
+ log_oom_debug();
+ return 0;
+ }
+
+ saved = set_remove(settle_path_or_ids, old_syspath);
+ }
+ }
if (!saved) {
log_device_debug(dev, "Got uevent for unexpected device, ignoring.");
return 0;

@ -0,0 +1,37 @@
From ff755f035485eab0317d1320caa2748d5d4a2d78 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Thu, 27 Oct 2022 05:48:05 +0900
Subject: [PATCH] test: use 'udevadm trigger --settle' even if device is
renamed
(cherry picked from commit ff4d2a09fd141474cb552d4b5bd5a53d9748a1b4)
Related: RHEL-5988
---
test/units/testsuite-17.02.sh | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/test/units/testsuite-17.02.sh b/test/units/testsuite-17.02.sh
index ed3b39d074..82f9fd1f62 100755
--- a/test/units/testsuite-17.02.sh
+++ b/test/units/testsuite-17.02.sh
@@ -61,9 +61,7 @@ EOF
udevadm control --log-priority=debug --reload --timeout=30
-# FIXME(?): the 'add' uevent is broadcast as for 'foobar', instead of 'hoge'. Hence, we cannot use --settle here.
-# See issue #25115.
-udevadm trigger --action=add /sys/devices/virtual/net/hoge
+udevadm trigger --action=add --settle /sys/devices/virtual/net/hoge
udevadm wait --timeout=30 --settle /sys/devices/virtual/net/foobar
assert_not_in "ID_RENAMING=" "$(udevadm info /sys/devices/virtual/net/foobar)"
timeout 30 bash -c 'while [[ "$(systemctl show --property=ActiveState --value /sys/devices/virtual/net/hoge)" != "inactive" ]]; do sleep .5; done'
@@ -71,7 +69,7 @@ timeout 30 bash -c 'while [[ "$(systemctl show --property=ActiveState --value /s
timeout 30 bash -c 'while [[ "$(systemctl show --property=ActiveState --value /sys/devices/virtual/net/foobar)" != "active" ]]; do sleep .5; done'
timeout 30 bash -c 'while [[ "$(systemctl show --property=ActiveState --value /sys/subsystem/net/devices/foobar)" != "active" ]]; do sleep .5; done'
-udevadm trigger --action=add /sys/devices/virtual/net/foobar
+udevadm trigger --action=add --settle /sys/devices/virtual/net/foobar
udevadm wait --timeout=30 --settle /sys/devices/virtual/net/hoge
assert_not_in "ID_RENAMING=" "$(udevadm info /sys/devices/virtual/net/hoge)"
timeout 30 bash -c 'while [[ "$(systemctl show --property=ActiveState --value /sys/devices/virtual/net/hoge)" != "active" ]]; do sleep .5; done'

@ -0,0 +1,33 @@
From e92c85b68932845c908cb3f38b2130c57065e263 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Fri, 6 Jan 2023 11:27:17 +0100
Subject: [PATCH] sd-event: don't mistake USEC_INFINITY passed in for overflow
Let's pass USEC_INFINITY from sd_event_source_set_time_relative() to
sd_event_source_set_time() instead of raising EOVERFLOW.
We should raise EOVERFLOW only if your addition fails, but not if the
input already is USEC_INFINITY, since it's an entirely valid operation
to have an infinite time-out, and we should support that.
(cherry picked from commit ef8591951aefccb668201f24aa481aa6cda834da)
Related: RHEL-6090
---
src/libsystemd/sd-event/sd-event.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index 778070a5fb..cd73cd8bfd 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -2723,6 +2723,9 @@ _public_ int sd_event_source_set_time_relative(sd_event_source *s, uint64_t usec
assert_return(s, -EINVAL);
assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM);
+ if (usec == USEC_INFINITY)
+ return sd_event_source_set_time(s, USEC_INFINITY);
+
r = sd_event_now(s->event, event_source_type_to_clock(s->type), &t);
if (r < 0)
return r;

@ -0,0 +1,118 @@
From 917b03f2b5ccdd668a49da7df72baaddd338c071 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 2 Jan 2023 15:06:10 +0100
Subject: [PATCH] pid1: rework service_arm_timer() to optionally take a
relative time value
In most cases this is actually what we want, hence simplify this case.
(cherry picked from commit e5d6dcce7f852b978251d062afb2fcba16714eb9)
Related: RHEL-6090
---
src/core/service.c | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/src/core/service.c b/src/core/service.c
index 1e14cdc6ca..aa76b4ad9a 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -530,13 +530,13 @@ static usec_t service_running_timeout(Service *s) {
delta);
}
-static int service_arm_timer(Service *s, usec_t usec) {
+static int service_arm_timer(Service *s, bool relative, usec_t usec) {
int r;
assert(s);
if (s->timer_event_source) {
- r = sd_event_source_set_time(s->timer_event_source, usec);
+ r = (relative ? sd_event_source_set_time_relative : sd_event_source_set_time)(s->timer_event_source, usec);
if (r < 0)
return r;
@@ -546,7 +546,7 @@ static int service_arm_timer(Service *s, usec_t usec) {
if (usec == USEC_INFINITY)
return 0;
- r = sd_event_add_time(
+ r = (relative ? sd_event_add_time_relative : sd_event_add_time)(
UNIT(s)->manager->event,
&s->timer_event_source,
CLOCK_MONOTONIC,
@@ -1195,7 +1195,7 @@ static int service_coldplug(Unit *u) {
if (s->deserialized_state == s->state)
return 0;
- r = service_arm_timer(s, service_coldplug_timeout(s));
+ r = service_arm_timer(s, /* relative= */ false, service_coldplug_timeout(s));
if (r < 0)
return r;
@@ -1538,7 +1538,7 @@ static int service_spawn_internal(
return r;
}
- r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), timeout));
+ r = service_arm_timer(s, /* relative= */ true, timeout);
if (r < 0)
return r;
@@ -1857,7 +1857,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
if (s->will_auto_restart) {
s->will_auto_restart = false;
- r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->restart_usec));
+ r = service_arm_timer(s, /* relative= */ true, s->restart_usec);
if (r < 0) {
s->n_keep_fd_store--;
goto fail;
@@ -1989,8 +1989,8 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
goto fail;
if (r > 0) {
- r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC),
- kill_operation == KILL_WATCHDOG ? service_timeout_abort_usec(s) : s->timeout_stop_usec));
+ r = service_arm_timer(s, /* relative= */ true,
+ kill_operation == KILL_WATCHDOG ? service_timeout_abort_usec(s) : s->timeout_stop_usec);
if (r < 0)
goto fail;
@@ -2020,7 +2020,7 @@ static void service_enter_stop_by_notify(Service *s) {
(void) unit_enqueue_rewatch_pids(UNIT(s));
- service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_stop_usec));
+ service_arm_timer(s, /* relative= */ true, s->timeout_stop_usec);
/* The service told us it's stopping, so it's as if we SIGTERM'd it. */
service_set_state(s, SERVICE_STOP_SIGTERM);
@@ -2099,7 +2099,7 @@ static void service_enter_running(Service *s, ServiceResult f) {
service_enter_stop_by_notify(s);
else {
service_set_state(s, SERVICE_RUNNING);
- service_arm_timer(s, service_running_timeout(s));
+ service_arm_timer(s, /* relative= */ false, service_running_timeout(s));
}
} else if (s->remain_after_exit)
@@ -2398,7 +2398,7 @@ static void service_enter_reload_by_notify(Service *s) {
assert(s);
- service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_start_usec));
+ service_arm_timer(s, /* relative= */ true, s->timeout_start_usec);
service_set_state(s, SERVICE_RELOAD);
/* service_enter_reload_by_notify is never called during a reload, thus no loops are possible. */
@@ -4570,7 +4570,7 @@ static int service_clean(Unit *u, ExecCleanMask mask) {
s->control_command = NULL;
s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
- r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->exec_context.timeout_clean_usec));
+ r = service_arm_timer(s, /* relative= */ true, s->exec_context.timeout_clean_usec);
if (r < 0)
goto fail;

@ -0,0 +1,25 @@
From efe1737efae0950b7ded32d9c5e1a9cfaea7296b Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 2 Jan 2023 15:00:05 +0100
Subject: [PATCH] manager: add one more assert()
(cherry picked from commit 7fa49280bc33ba5135228401fb24dce0de5f9195)
Related: RHEL-6090
---
src/core/manager.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/core/manager.c b/src/core/manager.c
index 657263eb73..6371810ce3 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -806,6 +806,8 @@ static int manager_find_credentials_dirs(Manager *m) {
}
void manager_set_switching_root(Manager *m, bool switching_root) {
+ assert(m);
+
m->switching_root = MANAGER_IS_SYSTEM(m) && switching_root;
}

@ -0,0 +1,688 @@
From f64d331351e33199c4096b2ae4a4b9d24d127661 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 2 Jan 2023 16:49:23 +0100
Subject: [PATCH] pid1: add new Type=notify-reload service type
Fixes: #6162
(cherry picked from commit 3bd28bf721dc70722ff1c675026ed0b44ad968a3)
Resolves: RHEL-6090
---
man/org.freedesktop.systemd1.xml | 6 +
src/basic/unit-def.c | 2 +
src/basic/unit-def.h | 4 +-
src/core/dbus-service.c | 5 +
src/core/load-fragment-gperf.gperf.in | 1 +
src/core/service.c | 226 ++++++++++++++++++--------
src/core/service.h | 18 +-
src/shared/bus-unit-util.c | 3 +-
8 files changed, 189 insertions(+), 76 deletions(-)
diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml
index 13a84af747..c18428a092 100644
--- a/man/org.freedesktop.systemd1.xml
+++ b/man/org.freedesktop.systemd1.xml
@@ -2570,6 +2570,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
readonly u NRestarts = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s OOMPolicy = '...';
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly i ReloadSignal = ...;
readonly t ExecMainStartTimestamp = ...;
readonly t ExecMainStartTimestampMonotonic = ...;
readonly t ExecMainExitTimestamp = ...;
@@ -3163,6 +3165,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
<!--property OOMPolicy is not documented!-->
+ <!--property ReloadSignal is not documented!-->
+
<!--property ExecCondition is not documented!-->
<!--property ExecConditionEx is not documented!-->
@@ -3715,6 +3719,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
<variablelist class="dbus-property" generated="True" extra-ref="OOMPolicy"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="ReloadSignal"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="ExecMainStartTimestamp"/>
<variablelist class="dbus-property" generated="True" extra-ref="ExecMainStartTimestampMonotonic"/>
diff --git a/src/basic/unit-def.c b/src/basic/unit-def.c
index 94cd603e32..bdb1860246 100644
--- a/src/basic/unit-def.c
+++ b/src/basic/unit-def.c
@@ -188,6 +188,8 @@ static const char* const service_state_table[_SERVICE_STATE_MAX] = {
[SERVICE_RUNNING] = "running",
[SERVICE_EXITED] = "exited",
[SERVICE_RELOAD] = "reload",
+ [SERVICE_RELOAD_SIGNAL] = "reload-signal",
+ [SERVICE_RELOAD_NOTIFY] = "reload-notify",
[SERVICE_STOP] = "stop",
[SERVICE_STOP_WATCHDOG] = "stop-watchdog",
[SERVICE_STOP_SIGTERM] = "stop-sigterm",
diff --git a/src/basic/unit-def.h b/src/basic/unit-def.h
index 5fcd51c095..bae132ea09 100644
--- a/src/basic/unit-def.h
+++ b/src/basic/unit-def.h
@@ -132,7 +132,9 @@ typedef enum ServiceState {
SERVICE_START_POST,
SERVICE_RUNNING,
SERVICE_EXITED, /* Nothing is running anymore, but RemainAfterExit is true hence this is OK */
- SERVICE_RELOAD,
+ SERVICE_RELOAD, /* Reloading via ExecReload= */
+ SERVICE_RELOAD_SIGNAL, /* Reloading via SIGHUP requested */
+ SERVICE_RELOAD_NOTIFY, /* Waiting for READY=1 after RELOADING=1 notify */
SERVICE_STOP, /* No STOP_PRE state, instead just register multiple STOP executables */
SERVICE_STOP_WATCHDOG,
SERVICE_STOP_SIGTERM,
diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c
index 6e4bc0bd1a..3d130db66a 100644
--- a/src/core/dbus-service.c
+++ b/src/core/dbus-service.c
@@ -228,6 +228,7 @@ const sd_bus_vtable bus_service_vtable[] = {
SD_BUS_PROPERTY("GID", "u", bus_property_get_gid, offsetof(Unit, ref_gid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("NRestarts", "u", bus_property_get_unsigned, offsetof(Service, n_restarts), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("OOMPolicy", "s", bus_property_get_oom_policy, offsetof(Service, oom_policy), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("ReloadSignal", "i", bus_property_get_int, offsetof(Service, reload_signal), SD_BUS_VTABLE_PROPERTY_CONST),
BUS_EXEC_STATUS_VTABLE("ExecMain", offsetof(Service, main_exec_status), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecCondition", offsetof(Service, exec_command[SERVICE_EXEC_CONDITION]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
@@ -374,6 +375,7 @@ static BUS_DEFINE_SET_TRANSIENT_PARSE(service_restart, ServiceRestart, service_r
static BUS_DEFINE_SET_TRANSIENT_PARSE(oom_policy, OOMPolicy, oom_policy_from_string);
static BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(bus_name, sd_bus_service_name_is_valid);
static BUS_DEFINE_SET_TRANSIENT_PARSE(timeout_failure_mode, ServiceTimeoutFailureMode, service_timeout_failure_mode_from_string);
+static BUS_DEFINE_SET_TRANSIENT_TO_STRING(reload_signal, "i", int32_t, int, "%" PRIi32, signal_to_string_with_check);
static int bus_service_set_transient_property(
Service *s,
@@ -532,6 +534,9 @@ static int bus_service_set_transient_property(
if (streq(name, "StandardErrorFileDescriptor"))
return bus_set_transient_std_fd(u, name, &s->stderr_fd, &s->exec_context.stdio_as_fds, message, flags, error);
+ if (streq(name, "ReloadSignal"))
+ return bus_set_transient_reload_signal(u, name, &s->reload_signal, message, flags, error);
+
return 0;
}
diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in
index 81a5971339..53089d5590 100644
--- a/src/core/load-fragment-gperf.gperf.in
+++ b/src/core/load-fragment-gperf.gperf.in
@@ -424,6 +424,7 @@ Service.BusPolicy, config_parse_warn_compat,
Service.USBFunctionDescriptors, config_parse_unit_path_printf, 0, offsetof(Service, usb_function_descriptors)
Service.USBFunctionStrings, config_parse_unit_path_printf, 0, offsetof(Service, usb_function_strings)
Service.OOMPolicy, config_parse_oom_policy, 0, offsetof(Service, oom_policy)
+Service.ReloadSignal, config_parse_signal, 0, offsetof(Service, reload_signal)
{{ EXEC_CONTEXT_CONFIG_ITEMS('Service') }}
{{ CGROUP_CONTEXT_CONFIG_ITEMS('Service') }}
{{ KILL_CONTEXT_CONFIG_ITEMS('Service') }}
diff --git a/src/core/service.c b/src/core/service.c
index aa76b4ad9a..902948905f 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -54,6 +54,8 @@ static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
[SERVICE_RUNNING] = UNIT_ACTIVE,
[SERVICE_EXITED] = UNIT_ACTIVE,
[SERVICE_RELOAD] = UNIT_RELOADING,
+ [SERVICE_RELOAD_SIGNAL] = UNIT_RELOADING,
+ [SERVICE_RELOAD_NOTIFY] = UNIT_RELOADING,
[SERVICE_STOP] = UNIT_DEACTIVATING,
[SERVICE_STOP_WATCHDOG] = UNIT_DEACTIVATING,
[SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING,
@@ -78,6 +80,8 @@ static const UnitActiveState state_translation_table_idle[_SERVICE_STATE_MAX] =
[SERVICE_RUNNING] = UNIT_ACTIVE,
[SERVICE_EXITED] = UNIT_ACTIVE,
[SERVICE_RELOAD] = UNIT_RELOADING,
+ [SERVICE_RELOAD_SIGNAL] = UNIT_RELOADING,
+ [SERVICE_RELOAD_NOTIFY] = UNIT_RELOADING,
[SERVICE_STOP] = UNIT_DEACTIVATING,
[SERVICE_STOP_WATCHDOG] = UNIT_DEACTIVATING,
[SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING,
@@ -124,6 +128,8 @@ static void service_init(Unit *u) {
s->watchdog_original_usec = USEC_INFINITY;
s->oom_policy = _OOM_POLICY_INVALID;
+ s->reload_begin_usec = USEC_INFINITY;
+ s->reload_signal = SIGHUP;
}
static void service_unwatch_control_pid(Service *s) {
@@ -765,7 +771,7 @@ static int service_add_extras(Service *s) {
/* If the service needs the notify socket, let's enable it automatically. */
if (s->notify_access == NOTIFY_NONE &&
- (s->type == SERVICE_NOTIFY || s->watchdog_usec > 0 || s->n_fd_store_max > 0))
+ (IN_SET(s->type, SERVICE_NOTIFY, SERVICE_NOTIFY_RELOAD) || s->watchdog_usec > 0 || s->n_fd_store_max > 0))
s->notify_access = NOTIFY_MAIN;
/* If no OOM policy was explicitly set, then default to the configure default OOM policy. Except when
@@ -830,7 +836,8 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
"%sRestart: %s\n"
"%sNotifyAccess: %s\n"
"%sNotifyState: %s\n"
- "%sOOMPolicy: %s\n",
+ "%sOOMPolicy: %s\n"
+ "%sReloadSignal: %s\n",
prefix, service_state_to_string(s->state),
prefix, service_result_to_string(s->result),
prefix, service_result_to_string(s->reload_result),
@@ -843,7 +850,8 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
prefix, service_restart_to_string(s->restart),
prefix, notify_access_to_string(s->notify_access),
prefix, notify_state_to_string(s->notify_state),
- prefix, oom_policy_to_string(s->oom_policy));
+ prefix, oom_policy_to_string(s->oom_policy),
+ prefix, signal_to_string(s->reload_signal));
if (s->control_pid > 0)
fprintf(f,
@@ -1088,7 +1096,7 @@ static void service_set_state(Service *s, ServiceState state) {
if (!IN_SET(state,
SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_RUNNING,
- SERVICE_RELOAD,
+ SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
SERVICE_AUTO_RESTART,
@@ -1097,7 +1105,8 @@ static void service_set_state(Service *s, ServiceState state) {
if (!IN_SET(state,
SERVICE_START, SERVICE_START_POST,
- SERVICE_RUNNING, SERVICE_RELOAD,
+ SERVICE_RUNNING,
+ SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
service_unwatch_main_pid(s);
@@ -1106,7 +1115,7 @@ static void service_set_state(Service *s, ServiceState state) {
if (!IN_SET(state,
SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
- SERVICE_RELOAD,
+ SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
SERVICE_CLEANING)) {
@@ -1122,7 +1131,8 @@ static void service_set_state(Service *s, ServiceState state) {
if (!IN_SET(state,
SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
- SERVICE_RUNNING, SERVICE_RELOAD,
+ SERVICE_RUNNING,
+ SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL) &&
!(state == SERVICE_DEAD && UNIT(s)->job))
@@ -1131,7 +1141,7 @@ static void service_set_state(Service *s, ServiceState state) {
if (state != SERVICE_START)
s->exec_fd_event_source = sd_event_source_disable_unref(s->exec_fd_event_source);
- if (!IN_SET(state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
+ if (!IN_SET(state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY))
service_stop_watchdog(s);
/* For the inactive states unit_notify() will trim the cgroup,
@@ -1157,6 +1167,8 @@ static usec_t service_coldplug_timeout(Service *s) {
case SERVICE_START:
case SERVICE_START_POST:
case SERVICE_RELOAD:
+ case SERVICE_RELOAD_SIGNAL:
+ case SERVICE_RELOAD_NOTIFY:
return usec_add(UNIT(s)->state_change_timestamp.monotonic, s->timeout_start_usec);
case SERVICE_RUNNING:
@@ -1203,7 +1215,8 @@ static int service_coldplug(Unit *u) {
pid_is_unwaited(s->main_pid) &&
(IN_SET(s->deserialized_state,
SERVICE_START, SERVICE_START_POST,
- SERVICE_RUNNING, SERVICE_RELOAD,
+ SERVICE_RUNNING,
+ SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) {
r = unit_watch_pid(UNIT(s), s->main_pid, false);
@@ -1215,7 +1228,7 @@ static int service_coldplug(Unit *u) {
pid_is_unwaited(s->control_pid) &&
IN_SET(s->deserialized_state,
SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
- SERVICE_RELOAD,
+ SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
SERVICE_CLEANING)) {
@@ -1230,7 +1243,7 @@ static int service_coldplug(Unit *u) {
(void) unit_setup_exec_runtime(u);
}
- if (IN_SET(s->deserialized_state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
+ if (IN_SET(s->deserialized_state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY))
service_start_watchdog(s);
if (UNIT_ISSET(s->accept_socket)) {
@@ -2255,7 +2268,7 @@ static void service_enter_start(Service *s) {
s->control_pid = pid;
service_set_state(s, SERVICE_START);
- } else if (IN_SET(s->type, SERVICE_ONESHOT, SERVICE_DBUS, SERVICE_NOTIFY, SERVICE_EXEC)) {
+ } else if (IN_SET(s->type, SERVICE_ONESHOT, SERVICE_DBUS, SERVICE_NOTIFY, SERVICE_NOTIFY_RELOAD, SERVICE_EXEC)) {
/* For oneshot services we wait until the start process exited, too, but it is our main process. */
@@ -2399,7 +2412,7 @@ static void service_enter_reload_by_notify(Service *s) {
assert(s);
service_arm_timer(s, /* relative= */ true, s->timeout_start_usec);
- service_set_state(s, SERVICE_RELOAD);
+ service_set_state(s, SERVICE_RELOAD_NOTIFY);
/* service_enter_reload_by_notify is never called during a reload, thus no loops are possible. */
r = manager_propagate_reload(UNIT(s)->manager, UNIT(s), JOB_FAIL, &error);
@@ -2408,6 +2421,7 @@ static void service_enter_reload_by_notify(Service *s) {
}
static void service_enter_reload(Service *s) {
+ bool killed = false;
int r;
assert(s);
@@ -2415,6 +2429,18 @@ static void service_enter_reload(Service *s) {
service_unwatch_control_pid(s);
s->reload_result = SERVICE_SUCCESS;
+ usec_t ts = now(CLOCK_MONOTONIC);
+
+ if (s->type == SERVICE_NOTIFY_RELOAD && s->main_pid > 0) {
+ r = kill_and_sigcont(s->main_pid, s->reload_signal);
+ if (r < 0) {
+ log_unit_warning_errno(UNIT(s), r, "Failed to send reload signal: %m");
+ goto fail;
+ }
+
+ killed = true;
+ }
+
s->control_command = s->exec_command[SERVICE_EXEC_RELOAD];
if (s->control_command) {
s->control_command_id = SERVICE_EXEC_RELOAD;
@@ -2424,17 +2450,28 @@ static void service_enter_reload(Service *s) {
s->timeout_start_usec,
EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_CONTROL_CGROUP,
&s->control_pid);
- if (r < 0)
+ if (r < 0) {
+ log_unit_warning_errno(UNIT(s), r, "Failed to run 'reload' task: %m");
goto fail;
+ }
service_set_state(s, SERVICE_RELOAD);
- } else
+ } else if (killed) {
+ service_arm_timer(s, /* relative= */ true, s->timeout_start_usec);
+ service_set_state(s, SERVICE_RELOAD_SIGNAL);
+ } else {
service_enter_running(s, SERVICE_SUCCESS);
+ return;
+ }
+ /* Store the timestamp when we started reloading: when reloading via SIGHUP we won't leave the reload
+ * state until we received both RELOADING=1 and READY=1 with MONOTONIC_USEC= set to a value above
+ * this. Thus we know for sure the reload cycle was executed *after* we requested it, and is not one
+ * that was already in progress before. */
+ s->reload_begin_usec = ts;
return;
fail:
- log_unit_warning_errno(UNIT(s), r, "Failed to run 'reload' task: %m");
s->reload_result = SERVICE_FAILURE_RESOURCES;
service_enter_running(s, SERVICE_SUCCESS);
}
@@ -2597,9 +2634,8 @@ static int service_stop(Unit *u) {
return 0;
}
- /* If there's already something running we go directly into
- * kill mode. */
- if (IN_SET(s->state, SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD, SERVICE_STOP_WATCHDOG)) {
+ /* If there's already something running we go directly into kill mode. */
+ if (IN_SET(s->state, SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY, SERVICE_STOP_WATCHDOG)) {
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_SUCCESS);
return 0;
}
@@ -2632,7 +2668,8 @@ _pure_ static bool service_can_reload(Unit *u) {
assert(s);
- return !!s->exec_command[SERVICE_EXEC_RELOAD];
+ return s->exec_command[SERVICE_EXEC_RELOAD] ||
+ s->type == SERVICE_NOTIFY_RELOAD;
}
static unsigned service_exec_command_index(Unit *u, ServiceExecCommand id, ExecCommand *current) {
@@ -2808,6 +2845,9 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
if (s->watchdog_original_usec != USEC_INFINITY)
(void) serialize_item_format(f, "watchdog-original-usec", USEC_FMT, s->watchdog_original_usec);
+ if (s->reload_begin_usec != USEC_INFINITY)
+ (void) serialize_item_format(f, "reload-begin-usec", USEC_FMT, s->reload_begin_usec);
+
return 0;
}
@@ -3146,6 +3186,10 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
log_unit_debug_errno(u, r, "Failed to parse serialized flush restart counter setting '%s': %m", value);
else
s->flush_n_restarts = r;
+ } else if (streq(key, "reload-begin-usec")) {
+ r = deserialize_usec(value, &s->reload_begin_usec);
+ if (r < 0)
+ log_unit_debug_errno(u, r, "Failed to parse serialized reload begin timestamp '%s', ignoring: %m", value);
} else
log_unit_debug(u, "Unknown serialization key: %s", key);
@@ -3349,7 +3393,7 @@ static void service_notify_cgroup_empty_event(Unit *u) {
* SIGCHLD for. */
case SERVICE_START:
- if (s->type == SERVICE_NOTIFY &&
+ if (IN_SET(s->type, SERVICE_NOTIFY, SERVICE_NOTIFY_RELOAD) &&
main_pid_good(s) == 0 &&
control_pid_good(s) == 0) {
/* No chance of getting a ready notification anymore */
@@ -3553,17 +3597,19 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
} else {
s->main_command = NULL;
- /* Services with ExitType=cgroup do not act on main PID exiting,
- * unless the cgroup is already empty */
+ /* Services with ExitType=cgroup do not act on main PID exiting, unless the cgroup is
+ * already empty */
if (s->exit_type == SERVICE_EXIT_MAIN || cgroup_good(s) <= 0) {
/* The service exited, so the service is officially gone. */
switch (s->state) {
case SERVICE_START_POST:
case SERVICE_RELOAD:
- /* If neither main nor control processes are running then
- * the current state can never exit cleanly, hence immediately
- * terminate the service. */
+ case SERVICE_RELOAD_SIGNAL:
+ case SERVICE_RELOAD_NOTIFY:
+ /* If neither main nor control processes are running then the current
+ * state can never exit cleanly, hence immediately terminate the
+ * service. */
if (control_pid_good(s) <= 0)
service_enter_stop(s, f);
@@ -3582,7 +3628,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
else
service_enter_signal(s, SERVICE_STOP_SIGTERM, f);
break;
- } else if (s->type == SERVICE_NOTIFY) {
+ } else if (IN_SET(s->type, SERVICE_NOTIFY, SERVICE_NOTIFY_RELOAD)) {
/* Only enter running through a notification, so that the
* SERVICE_START state signifies that no ready notification
* has been received */
@@ -3675,15 +3721,13 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
s->control_command->command_next &&
f == SERVICE_SUCCESS) {
- /* There is another command to *
- * execute, so let's do that. */
+ /* There is another command to * execute, so let's do that. */
log_unit_debug(u, "Running next control command for state %s.", service_state_to_string(s->state));
service_run_next_control(s);
} else {
- /* No further commands for this step, so let's
- * figure out what to do next */
+ /* No further commands for this step, so let's figure out what to do next */
s->control_command = NULL;
s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
@@ -3761,12 +3805,22 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
break;
case SERVICE_RELOAD:
+ case SERVICE_RELOAD_SIGNAL:
+ case SERVICE_RELOAD_NOTIFY:
if (f == SERVICE_SUCCESS)
if (service_load_pid_file(s, true) < 0)
service_search_main_pid(s);
s->reload_result = f;
- service_enter_running(s, SERVICE_SUCCESS);
+
+ /* If the last notification we received from the service process indiciates
+ * we are still reloading, then don't leave reloading state just yet, just
+ * transition into SERVICE_RELOAD_NOTIFY, to wait for the READY=1 coming,
+ * too. */
+ if (s->notify_state == NOTIFY_RELOADING)
+ service_set_state(s, SERVICE_RELOAD_NOTIFY);
+ else
+ service_enter_running(s, SERVICE_SUCCESS);
break;
case SERVICE_STOP:
@@ -3869,6 +3923,8 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us
break;
case SERVICE_RELOAD:
+ case SERVICE_RELOAD_SIGNAL:
+ case SERVICE_RELOAD_NOTIFY:
log_unit_warning(UNIT(s), "Reload operation timed out. Killing reload process.");
service_kill_control_process(s);
s->reload_result = SERVICE_FAILURE_TIMEOUT;
@@ -4094,6 +4150,7 @@ static void service_notify_message(
Service *s = SERVICE(u);
bool notify_dbus = false;
+ usec_t monotonic_usec = USEC_INFINITY;
const char *e;
int r;
@@ -4112,7 +4169,7 @@ static void service_notify_message(
/* Interpret MAINPID= */
e = strv_find_startswith(tags, "MAINPID=");
- if (e && IN_SET(s->state, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD)) {
+ if (e && IN_SET(s->state, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY)) {
pid_t new_main_pid;
if (parse_pid(e, &new_main_pid) < 0)
@@ -4141,43 +4198,73 @@ static void service_notify_message(
}
}
- /* Interpret READY=/STOPPING=/RELOADING=. Last one wins. */
- STRV_FOREACH_BACKWARDS(i, tags) {
+ /* Parse MONOTONIC_USEC= */
+ e = strv_find_startswith(tags, "MONOTONIC_USEC=");
+ if (e) {
+ r = safe_atou64(e, &monotonic_usec);
+ if (r < 0)
+ log_unit_warning_errno(u, r, "Failed to parse MONOTONIC_USEC= field in notification message, ignoring: %s", e);
+ }
- if (streq(*i, "READY=1")) {
- s->notify_state = NOTIFY_READY;
+ /* Interpret READY=/STOPPING=/RELOADING=. STOPPING= wins over the others, and READY= over RELOADING= */
+ if (strv_contains(tags, "STOPPING=1")) {
+ s->notify_state = NOTIFY_STOPPING;
- /* Type=notify services inform us about completed
- * initialization with READY=1 */
- if (s->type == SERVICE_NOTIFY && s->state == SERVICE_START)
- service_enter_start_post(s);
+ if (IN_SET(s->state, SERVICE_RUNNING, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY))
+ service_enter_stop_by_notify(s);
- /* Sending READY=1 while we are reloading informs us
- * that the reloading is complete */
- if (s->state == SERVICE_RELOAD && s->control_pid == 0)
- service_enter_running(s, SERVICE_SUCCESS);
+ notify_dbus = true;
- notify_dbus = true;
- break;
+ } else if (strv_contains(tags, "READY=1")) {
- } else if (streq(*i, "RELOADING=1")) {
- s->notify_state = NOTIFY_RELOADING;
+ s->notify_state = NOTIFY_READY;
- if (s->state == SERVICE_RUNNING)
- service_enter_reload_by_notify(s);
+ /* Type=notify services inform us about completed initialization with READY=1 */
+ if (IN_SET(s->type, SERVICE_NOTIFY, SERVICE_NOTIFY_RELOAD) &&
+ s->state == SERVICE_START)
+ service_enter_start_post(s);
- notify_dbus = true;
- break;
+ /* Sending READY=1 while we are reloading informs us that the reloading is complete. */
+ if (s->state == SERVICE_RELOAD_NOTIFY)
+ service_enter_running(s, SERVICE_SUCCESS);
- } else if (streq(*i, "STOPPING=1")) {
- s->notify_state = NOTIFY_STOPPING;
+ /* Combined RELOADING=1 and READY=1? Then this is indication that the service started and
+ * immediately finished reloading. */
+ if (s->state == SERVICE_RELOAD_SIGNAL &&
+ strv_contains(tags, "RELOADING=1") &&
+ monotonic_usec != USEC_INFINITY &&
+ monotonic_usec >= s->reload_begin_usec) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- if (s->state == SERVICE_RUNNING)
- service_enter_stop_by_notify(s);
+ /* Propagate a reload explicitly */
+ r = manager_propagate_reload(UNIT(s)->manager, UNIT(s), JOB_FAIL, &error);
+ if (r < 0)
+ log_unit_warning(UNIT(s), "Failed to schedule propagation of reload, ignoring: %s", bus_error_message(&error, r));
- notify_dbus = true;
- break;
+ service_enter_running(s, SERVICE_SUCCESS);
}
+
+ notify_dbus = true;
+
+ } else if (strv_contains(tags, "RELOADING=1")) {
+
+ s->notify_state = NOTIFY_RELOADING;
+
+ /* Sending RELOADING=1 after we send SIGHUP to request a reload will transition
+ * things to "reload-notify" state, where we'll wait for READY=1 to let us know the
+ * reload is done. Note that we insist on a timestamp being sent along here, so that
+ * we know for sure this is a reload cycle initiated *after* we sent the signal */
+ if (s->state == SERVICE_RELOAD_SIGNAL &&
+ monotonic_usec != USEC_INFINITY &&
+ monotonic_usec >= s->reload_begin_usec)
+ /* Note, we don't call service_enter_reload_by_notify() here, because we
+ * don't need reload propagation nor do we want to restart the time-out. */
+ service_set_state(s, SERVICE_RELOAD_NOTIFY);
+
+ if (s->state == SERVICE_RUNNING)
+ service_enter_reload_by_notify(s);
+
+ notify_dbus = true;
}
/* Interpret STATUS= */
@@ -4307,7 +4394,9 @@ static bool pick_up_pid_from_bus_name(Service *s) {
SERVICE_START,
SERVICE_START_POST,
SERVICE_RUNNING,
- SERVICE_RELOAD);
+ SERVICE_RELOAD,
+ SERVICE_RELOAD_SIGNAL,
+ SERVICE_RELOAD_NOTIFY);
}
static int bus_name_pid_lookup_callback(sd_bus_message *reply, void *userdata, sd_bus_error *ret_error) {
@@ -4514,6 +4603,8 @@ static bool service_needs_console(Unit *u) {
SERVICE_START_POST,
SERVICE_RUNNING,
SERVICE_RELOAD,
+ SERVICE_RELOAD_SIGNAL,
+ SERVICE_RELOAD_NOTIFY,
SERVICE_STOP,
SERVICE_STOP_WATCHDOG,
SERVICE_STOP_SIGTERM,
@@ -4636,13 +4727,14 @@ static const char* const service_restart_table[_SERVICE_RESTART_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(service_restart, ServiceRestart);
static const char* const service_type_table[_SERVICE_TYPE_MAX] = {
- [SERVICE_SIMPLE] = "simple",
- [SERVICE_FORKING] = "forking",
- [SERVICE_ONESHOT] = "oneshot",
- [SERVICE_DBUS] = "dbus",
- [SERVICE_NOTIFY] = "notify",
- [SERVICE_IDLE] = "idle",
- [SERVICE_EXEC] = "exec",
+ [SERVICE_SIMPLE] = "simple",
+ [SERVICE_FORKING] = "forking",
+ [SERVICE_ONESHOT] = "oneshot",
+ [SERVICE_DBUS] = "dbus",
+ [SERVICE_NOTIFY] = "notify",
+ [SERVICE_NOTIFY_RELOAD] = "notify-reload",
+ [SERVICE_IDLE] = "idle",
+ [SERVICE_EXEC] = "exec",
};
DEFINE_STRING_TABLE_LOOKUP(service_type, ServiceType);
diff --git a/src/core/service.h b/src/core/service.h
index 91e02e6d7e..194067f0e1 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -24,13 +24,14 @@ typedef enum ServiceRestart {
} ServiceRestart;
typedef enum ServiceType {
- SERVICE_SIMPLE, /* we fork and go on right-away (i.e. modern socket activated daemons) */
- SERVICE_FORKING, /* forks by itself (i.e. traditional daemons) */
- SERVICE_ONESHOT, /* we fork and wait until the program finishes (i.e. programs like fsck which run and need to finish before we continue) */
- SERVICE_DBUS, /* we fork and wait until a specific D-Bus name appears on the bus */
- SERVICE_NOTIFY, /* we fork and wait until a daemon sends us a ready message with sd_notify() */
- SERVICE_IDLE, /* much like simple, but delay exec() until all jobs are dispatched. */
- SERVICE_EXEC, /* we fork and wait until we execute exec() (this means our own setup is waited for) */
+ SERVICE_SIMPLE, /* we fork and go on right-away (i.e. modern socket activated daemons) */
+ SERVICE_FORKING, /* forks by itself (i.e. traditional daemons) */
+ SERVICE_ONESHOT, /* we fork and wait until the program finishes (i.e. programs like fsck which run and need to finish before we continue) */
+ SERVICE_DBUS, /* we fork and wait until a specific D-Bus name appears on the bus */
+ SERVICE_NOTIFY, /* we fork and wait until a daemon sends us a ready message with sd_notify() */
+ SERVICE_NOTIFY_RELOAD, /* just like SERVICE_NOTIFY, but also implements a reload protocol via SIGHUP */
+ SERVICE_IDLE, /* much like simple, but delay exec() until all jobs are dispatched. */
+ SERVICE_EXEC, /* we fork and wait until we execute exec() (this means our own setup is waited for) */
_SERVICE_TYPE_MAX,
_SERVICE_TYPE_INVALID = -EINVAL,
} ServiceType;
@@ -215,6 +216,9 @@ struct Service {
bool flush_n_restarts;
OOMPolicy oom_policy;
+
+ int reload_signal;
+ usec_t reload_begin_usec;
};
static inline usec_t service_timeout_abort_usec(Service *s) {
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 922011eccd..a9844e1cc3 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -2065,7 +2065,8 @@ static int bus_append_kill_property(sd_bus_message *m, const char *field, const
if (STR_IN_SET(field, "KillSignal",
"RestartKillSignal",
"FinalKillSignal",
- "WatchdogSignal"))
+ "WatchdogSignal",
+ "ReloadSignal"))
return bus_append_signal_from_string(m, field, eq);
return 0;

@ -0,0 +1,420 @@
From e8de964c146f67c91acdaff076420282c2d1b217 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 2 Jan 2023 18:13:27 +0100
Subject: [PATCH] man: document Type=notify-reload
(cherry picked from commit 81e19b6f6585d656e972efad73781e184ca0e7a0)
Related: RHEL-6090
---
man/sd_notify.xml | 36 ++++--
man/systemd.service.xml | 248 ++++++++++++++++++++++------------------
2 files changed, 162 insertions(+), 122 deletions(-)
diff --git a/man/sd_notify.xml b/man/sd_notify.xml
index de402950bb..d2dba00004 100644
--- a/man/sd_notify.xml
+++ b/man/sd_notify.xml
@@ -102,23 +102,35 @@
<varlistentry>
<term>READY=1</term>
- <listitem><para>Tells the service manager that service startup is finished, or the service finished loading its
- configuration. This is only used by systemd if the service definition file has <varname>Type=notify</varname>
- set. Since there is little value in signaling non-readiness, the only value services should send is
- <literal>READY=1</literal> (i.e. <literal>READY=0</literal> is not defined).</para></listitem>
+ <listitem><para>Tells the service manager that service startup is finished, or the service finished
+ re-loading its configuration. This is only used by systemd if the service definition file has
+ <varname>Type=notify</varname> or <varname>Type=notify-reload</varname> set. Since there is little
+ value in signaling non-readiness, the only value services should send is <literal>READY=1</literal>
+ (i.e. <literal>READY=0</literal> is not defined).</para></listitem>
</varlistentry>
<varlistentry>
<term>RELOADING=1</term>
- <listitem><para>Tells the service manager that the service is
- reloading its configuration. This is useful to allow the
- service manager to track the service's internal state, and
- present it to the user. Note that a service that sends this
- notification must also send a <literal>READY=1</literal>
- notification when it completed reloading its
- configuration. Reloads are propagated in the same way as they
- are when initiated by the user.</para></listitem>
+ <listitem><para>Tells the service manager that the service is beginning to reload its
+ configuration. This is useful to allow the service manager to track the service's internal state, and
+ present it to the user. Note that a service that sends this notification must also send a
+ <literal>READY=1</literal> notification when it completed reloading its configuration. Reloads the
+ service manager is notified about with this mechanisms are propagated in the same way as they are
+ when originally initiated through the service manager. This message is particularly relevant for
+ <varname>Type=notify-reload</varname> services, to inform the service manager that the request to
+ reload the service has been received and is now being processed.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>MONOTONIC_USEC=…</term>
+
+ <listitem><para>A field carrying the monotonic timestamp (as per
+ <constant>CLOCK_MONOTONIC</constant>) formatted in decimal in µs, when the notification message was
+ generated by the client. This is typically used in combination with <literal>RELOADING=1</literal>,
+ to allow the service manager to properly synchronize reload cycles. See
+ <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ for details, specifically <literal>Type=notify-reload</literal>.</para></listitem>
</varlistentry>
<varlistentry>
diff --git a/man/systemd.service.xml b/man/systemd.service.xml
index 1c9e59f722..ae54332440 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -157,7 +157,7 @@
<listitem>
<para>Configures the process start-up type for this service unit. One of <option>simple</option>,
<option>exec</option>, <option>forking</option>, <option>oneshot</option>, <option>dbus</option>,
- <option>notify</option> or <option>idle</option>:</para>
+ <option>notify</option>, <option>notify-reload</option> or <option>idle</option>:</para>
<itemizedlist>
<listitem><para>If set to <option>simple</option> (the default if <varname>ExecStart=</varname> is
@@ -216,14 +216,30 @@
logic thus should be prepared to receive a <constant>SIGTERM</constant> (or whichever signal is
configured in <varname>KillSignal=</varname>) as result.</para></listitem>
- <listitem><para>Behavior of <option>notify</option> is similar to <option>exec</option>; however, it is
- expected that the service sends a notification message via
- <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry> or an
- equivalent call when it has finished starting up. systemd will proceed with starting follow-up units after
- this notification message has been sent. If this option is used, <varname>NotifyAccess=</varname> (see
- below) should be set to open access to the notification socket provided by systemd. If
- <varname>NotifyAccess=</varname> is missing or set to <option>none</option>, it will be forcibly set to
- <option>main</option>.</para></listitem>
+ <listitem><para>Behavior of <option>notify</option> is similar to <option>exec</option>; however,
+ it is expected that the service sends a <literal>READY=1</literal> notification message via
+ <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry> or
+ an equivalent call when it has finished starting up. systemd will proceed with starting follow-up
+ units after this notification message has been sent. If this option is used,
+ <varname>NotifyAccess=</varname> (see below) should be set to open access to the notification
+ socket provided by systemd. If <varname>NotifyAccess=</varname> is missing or set to
+ <option>none</option>, it will be forcibly set to <option>main</option>.</para></listitem>
+
+ <listitem><para>Behavior of <option>notify-reload</option> is identical to
+ <option>notify</option>. However, it extends the logic in one way: the
+ <constant>SIGHUP</constant> UNIX process signal is sent to the service's main process when the
+ service is asked to reload. (The signal to send can be tweaked via
+ <varname>ReloadSignal=</varname>, see below.). When
+ initiating the reload process the service is then expected to reply with a notification message
+ via <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ that contains the <literal>RELOADING=1</literal> field in combination with
+ <literal>MONOTONIC_USEC=</literal> set to the current monotonic time
+ (i.e. <constant>CLOCK_MONOTONIC</constant> in
+ <citerefentry><refentrytitle>clock_gettime</refentrytitle><manvolnum>2</manvolnum></citerefentry>)
+ in µs, formatted as decimal string. Once reloading is complete another notification message must
+ be sent, containing <literal>READY=1</literal>. Using this service type and implementing this
+ reload protocol is an efficient alternative to providing an <varname>ExecReload=</varname>
+ command for reloading of the service's configuration.</para></listitem>
<listitem><para>Behavior of <option>idle</option> is very similar to <option>simple</option>; however,
actual execution of the service program is delayed until all active jobs are dispatched. This may be used
@@ -233,25 +249,27 @@
anyway.</para></listitem>
</itemizedlist>
- <para>It is generally recommended to use <varname>Type=</varname><option>simple</option> for long-running
- services whenever possible, as it is the simplest and fastest option. However, as this service type won't
- propagate service start-up failures and doesn't allow ordering of other units against completion of
- initialization of the service (which for example is useful if clients need to connect to the service through
- some form of IPC, and the IPC channel is only established by the service itself — in contrast to doing this
- ahead of time through socket or bus activation or similar), it might not be sufficient for many cases. If so,
- <option>notify</option> or <option>dbus</option> (the latter only in case the service provides a D-Bus
- interface) are the preferred options as they allow service program code to precisely schedule when to
- consider the service started up successfully and when to proceed with follow-up units. The
- <option>notify</option> service type requires explicit support in the service codebase (as
- <function>sd_notify()</function> or an equivalent API needs to be invoked by the service at the appropriate
- time) — if it's not supported, then <option>forking</option> is an alternative: it supports the traditional
- UNIX service start-up protocol. Finally, <option>exec</option> might be an option for cases where it is
- enough to ensure the service binary is invoked, and where the service binary itself executes no or little
- initialization on its own (and its initialization is unlikely to fail). Note that using any type other than
- <option>simple</option> possibly delays the boot process, as the service manager needs to wait for service
- initialization to complete. It is hence recommended not to needlessly use any types other than
- <option>simple</option>. (Also note it is generally not recommended to use <option>idle</option> or
- <option>oneshot</option> for long-running services.)</para>
+ <para>It is generally recommended to use <varname>Type=</varname><option>simple</option> for
+ long-running services whenever possible, as it is the simplest and fastest option. However, as this
+ service type won't propagate service start-up failures and doesn't allow ordering of other units
+ against completion of initialization of the service (which for example is useful if clients need to
+ connect to the service through some form of IPC, and the IPC channel is only established by the
+ service itself — in contrast to doing this ahead of time through socket or bus activation or
+ similar), it might not be sufficient for many cases. If so, <option>notify</option>,
+ <option>notify-reload</option> or <option>dbus</option> (the latter only in case the service
+ provides a D-Bus interface) are the preferred options as they allow service program code to
+ precisely schedule when to consider the service started up successfully and when to proceed with
+ follow-up units. The <option>notify</option>/<option>notify-reload</option> service types require
+ explicit support in the service codebase (as <function>sd_notify()</function> or an equivalent API
+ needs to be invoked by the service at the appropriate time) — if it's not supported, then
+ <option>forking</option> is an alternative: it supports the traditional UNIX service start-up
+ protocol. Finally, <option>exec</option> might be an option for cases where it is enough to ensure
+ the service binary is invoked, and where the service binary itself executes no or little
+ initialization on its own (and its initialization is unlikely to fail). Note that using any type
+ other than <option>simple</option> possibly delays the boot process, as the service manager needs
+ to wait for service initialization to complete. It is hence recommended not to needlessly use any
+ types other than <option>simple</option>. (Also note it is generally not recommended to use
+ <option>idle</option> or <option>oneshot</option> for long-running services.)</para>
</listitem>
</varlistentry>
@@ -319,9 +337,10 @@
the file may not be a symlink to a file owned by a different user (neither directly nor indirectly), and the
PID file must refer to a process already belonging to the service.</para>
- <para>Note that PID files should be avoided in modern projects. Use <option>Type=notify</option> or
- <option>Type=simple</option> where possible, which does not require use of PID files to determine the
- main process of a service and avoids needless forking.</para></listitem>
+ <para>Note that PID files should be avoided in modern projects. Use <option>Type=notify</option>,
+ <option>Type=notify-reload</option> or <option>Type=simple</option> where possible, which does not
+ require use of PID files to determine the main process of a service and avoids needless
+ forking.</para></listitem>
</varlistentry>
<varlistentry>
@@ -443,12 +462,13 @@
with a <literal>-</literal> exit successfully.</para>
<para><varname>ExecStartPost=</varname> commands are only run after the commands specified in
- <varname>ExecStart=</varname> have been invoked successfully, as determined by <varname>Type=</varname>
- (i.e. the process has been started for <varname>Type=simple</varname> or <varname>Type=idle</varname>, the last
- <varname>ExecStart=</varname> process exited successfully for <varname>Type=oneshot</varname>, the initial
- process exited successfully for <varname>Type=forking</varname>, <literal>READY=1</literal> is sent for
- <varname>Type=notify</varname>, or the <varname>BusName=</varname> has been taken for
- <varname>Type=dbus</varname>).</para>
+ <varname>ExecStart=</varname> have been invoked successfully, as determined by
+ <varname>Type=</varname> (i.e. the process has been started for <varname>Type=simple</varname> or
+ <varname>Type=idle</varname>, the last <varname>ExecStart=</varname> process exited successfully for
+ <varname>Type=oneshot</varname>, the initial process exited successfully for
+ <varname>Type=forking</varname>, <literal>READY=1</literal> is sent for
+ <varname>Type=notify</varname>/<varname>Type=notify-reload</varname>, or the
+ <varname>BusName=</varname> has been taken for <varname>Type=dbus</varname>).</para>
<para>Note that <varname>ExecStartPre=</varname> may not be
used to start long-running processes. All processes forked
@@ -487,30 +507,26 @@
<varlistentry>
<term><varname>ExecReload=</varname></term>
- <listitem><para>Commands to execute to trigger a configuration
- reload in the service. This argument takes multiple command
- lines, following the same scheme as described for
- <varname>ExecStart=</varname> above. Use of this setting is
- optional. Specifier and environment variable substitution is
- supported here following the same scheme as for
+
+ <listitem><para>Commands to execute to trigger a configuration reload in the service. This argument
+ takes multiple command lines, following the same scheme as described for
+ <varname>ExecStart=</varname> above. Use of this setting is optional. Specifier and environment
+ variable substitution is supported here following the same scheme as for
<varname>ExecStart=</varname>.</para>
- <para>One additional, special environment variable is set: if
- known, <varname>$MAINPID</varname> is set to the main process
- of the daemon, and may be used for command lines like the
- following:</para>
+ <para>One additional, special environment variable is set: if known, <varname>$MAINPID</varname> is
+ set to the main process of the daemon, and may be used for command lines like the following:</para>
<programlisting>ExecReload=kill -HUP $MAINPID</programlisting>
- <para>Note however that reloading a daemon by sending a signal
- (as with the example line above) is usually not a good choice,
- because this is an asynchronous operation and hence not
- suitable to order reloads of multiple services against each
- other. It is strongly recommended to set
- <varname>ExecReload=</varname> to a command that not only
- triggers a configuration reload of the daemon, but also
- synchronously waits for it to complete. For example,
- <citerefentry project='mankier'><refentrytitle>dbus-broker</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ <para>Note however that reloading a daemon by enqueing a signal (as with the example line above) is
+ usually not a good choice, because this is an asynchronous operation and hence not suitable when
+ ordering reloads of multiple services against each other. It is thus strongly recommended to either
+ use <varname>Type=</varname><option>notify-reload</option> in place of
+ <varname>ExecReload=</varname>, or to set <varname>ExecReload=</varname> to a command that not only
+ triggers a configuration reload of the daemon, but also synchronously waits for it to complete. For
+ example, <citerefentry
+ project='mankier'><refentrytitle>dbus-broker</refentrytitle><manvolnum>1</manvolnum></citerefentry>
uses the following:</para>
<programlisting>ExecReload=busctl call org.freedesktop.DBus \
@@ -605,12 +621,13 @@
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
</para>
- <para>If a service of <varname>Type=notify</varname> sends <literal>EXTEND_TIMEOUT_USEC=…</literal>, this may cause
- the start time to be extended beyond <varname>TimeoutStartSec=</varname>. The first receipt of this message
- must occur before <varname>TimeoutStartSec=</varname> is exceeded, and once the start time has extended beyond
- <varname>TimeoutStartSec=</varname>, the service manager will allow the service to continue to start, provided
- the service repeats <literal>EXTEND_TIMEOUT_USEC=…</literal> within the interval specified until the service
- startup status is finished by <literal>READY=1</literal>. (see
+ <para>If a service of <varname>Type=notify</varname>/<varname>Type=notify-reload</varname> sends
+ <literal>EXTEND_TIMEOUT_USEC=…</literal>, this may cause the start time to be extended beyond
+ <varname>TimeoutStartSec=</varname>. The first receipt of this message must occur before
+ <varname>TimeoutStartSec=</varname> is exceeded, and once the start time has extended beyond
+ <varname>TimeoutStartSec=</varname>, the service manager will allow the service to continue to start,
+ provided the service repeats <literal>EXTEND_TIMEOUT_USEC=…</literal> within the interval specified
+ until the service startup status is finished by <literal>READY=1</literal>. (see
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>).
</para></listitem>
</varlistentry>
@@ -633,12 +650,14 @@
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
</para>
- <para>If a service of <varname>Type=notify</varname> sends <literal>EXTEND_TIMEOUT_USEC=…</literal>, this may cause
- the stop time to be extended beyond <varname>TimeoutStopSec=</varname>. The first receipt of this message
- must occur before <varname>TimeoutStopSec=</varname> is exceeded, and once the stop time has extended beyond
- <varname>TimeoutStopSec=</varname>, the service manager will allow the service to continue to stop, provided
- the service repeats <literal>EXTEND_TIMEOUT_USEC=…</literal> within the interval specified, or terminates itself
- (see <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>).
+ <para>If a service of <varname>Type=notify</varname>/<varname>Type=notify-reload</varname> sends
+ <literal>EXTEND_TIMEOUT_USEC=…</literal>, this may cause the stop time to be extended beyond
+ <varname>TimeoutStopSec=</varname>. The first receipt of this message must occur before
+ <varname>TimeoutStopSec=</varname> is exceeded, and once the stop time has extended beyond
+ <varname>TimeoutStopSec=</varname>, the service manager will allow the service to continue to stop,
+ provided the service repeats <literal>EXTEND_TIMEOUT_USEC=…</literal> within the interval specified,
+ or terminates itself (see
+ <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>).
</para></listitem>
</varlistentry>
@@ -661,13 +680,15 @@
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
</para>
- <para>If a service of <varname>Type=notify</varname> handles <constant>SIGABRT</constant> itself (instead of relying
- on the kernel to write a core dump) it can send <literal>EXTEND_TIMEOUT_USEC=…</literal> to
- extended the abort time beyond <varname>TimeoutAbortSec=</varname>. The first receipt of this message
- must occur before <varname>TimeoutAbortSec=</varname> is exceeded, and once the abort time has extended beyond
- <varname>TimeoutAbortSec=</varname>, the service manager will allow the service to continue to abort, provided
- the service repeats <literal>EXTEND_TIMEOUT_USEC=…</literal> within the interval specified, or terminates itself
- (see <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>).
+ <para>If a service of <varname>Type=notify</varname>/<varname>Type=notify-reload</varname> handles
+ <constant>SIGABRT</constant> itself (instead of relying on the kernel to write a core dump) it can
+ send <literal>EXTEND_TIMEOUT_USEC=…</literal> to extended the abort time beyond
+ <varname>TimeoutAbortSec=</varname>. The first receipt of this message must occur before
+ <varname>TimeoutAbortSec=</varname> is exceeded, and once the abort time has extended beyond
+ <varname>TimeoutAbortSec=</varname>, the service manager will allow the service to continue to abort,
+ provided the service repeats <literal>EXTEND_TIMEOUT_USEC=…</literal> within the interval specified,
+ or terminates itself (see
+ <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>).
</para></listitem>
</varlistentry>
@@ -710,12 +731,13 @@
activation completed. Pass <literal>infinity</literal> (the default) to configure no runtime
limit.</para>
- <para>If a service of <varname>Type=notify</varname> sends <literal>EXTEND_TIMEOUT_USEC=…</literal>, this may cause
- the runtime to be extended beyond <varname>RuntimeMaxSec=</varname>. The first receipt of this message
- must occur before <varname>RuntimeMaxSec=</varname> is exceeded, and once the runtime has extended beyond
- <varname>RuntimeMaxSec=</varname>, the service manager will allow the service to continue to run, provided
- the service repeats <literal>EXTEND_TIMEOUT_USEC=…</literal> within the interval specified until the service
- shutdown is achieved by <literal>STOPPING=1</literal> (or termination). (see
+ <para>If a service of <varname>Type=notify</varname>/<varname>Type=notify-reload</varname> sends
+ <literal>EXTEND_TIMEOUT_USEC=…</literal>, this may cause the runtime to be extended beyond
+ <varname>RuntimeMaxSec=</varname>. The first receipt of this message must occur before
+ <varname>RuntimeMaxSec=</varname> is exceeded, and once the runtime has extended beyond
+ <varname>RuntimeMaxSec=</varname>, the service manager will allow the service to continue to run,
+ provided the service repeats <literal>EXTEND_TIMEOUT_USEC=…</literal> within the interval specified
+ until the service shutdown is achieved by <literal>STOPPING=1</literal> (or termination). (see
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>).
</para></listitem>
</varlistentry>
@@ -1023,16 +1045,19 @@
<varlistentry>
<term><varname>NotifyAccess=</varname></term>
<listitem><para>Controls access to the service status notification socket, as accessible via the
- <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry> call. Takes one
- of <option>none</option> (the default), <option>main</option>, <option>exec</option> or
- <option>all</option>. If <option>none</option>, no daemon status updates are accepted from the service
- processes, all status update messages are ignored. If <option>main</option>, only service updates sent from the
- main process of the service are accepted. If <option>exec</option>, only service updates sent from any of the
- main or control processes originating from one of the <varname>Exec*=</varname> commands are accepted. If
- <option>all</option>, all services updates from all members of the service's control group are accepted. This
- option should be set to open access to the notification socket when using <varname>Type=notify</varname> or
- <varname>WatchdogSec=</varname> (see above). If those options are used but <varname>NotifyAccess=</varname> is
- not configured, it will be implicitly set to <option>main</option>.</para>
+ <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ call. Takes one of <option>none</option> (the default), <option>main</option>, <option>exec</option>
+ or <option>all</option>. If <option>none</option>, no daemon status updates are accepted from the
+ service processes, all status update messages are ignored. If <option>main</option>, only service
+ updates sent from the main process of the service are accepted. If <option>exec</option>, only
+ service updates sent from any of the main or control processes originating from one of the
+ <varname>Exec*=</varname> commands are accepted. If <option>all</option>, all services updates from
+ all members of the service's control group are accepted. This option should be set to open access to
+ the notification socket when using
+ <varname>Type=notify</varname>/<varname>Type=notify-reload</varname> or
+ <varname>WatchdogSec=</varname> (see above). If those options are used but
+ <varname>NotifyAccess=</varname> is not configured, it will be implicitly set to
+ <option>main</option>.</para>
<para>Note that <function>sd_notify()</function> notifications may be attributed to units correctly only if
either the sending process is still around at the time PID 1 processes the message, or if the sending process
@@ -1156,6 +1181,15 @@
kills, this setting determines the state of the unit after <command>systemd-oomd</command> kills a
cgroup associated with it.</para></listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><varname>ReloadSignal=</varname></term>
+ <listitem><para>Configures the UNIX process signal to send to the service's main process when asked
+ to reload the service's configuration. Defaults to <constant>SIGHUP</constant>. This option has no
+ effect unless <varname>Type=</varname><option>notify-reload</option> is used, see
+ above.</para></listitem>
+ </varlistentry>
+
</variablelist>
<para id='shared-unit-options'>Check
@@ -1319,16 +1353,13 @@ WantedBy=multi-user.target</programlisting>
<citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details.</para>
- <para>Note that this unit type does not include any type of
- notification when a service has completed initialization. For
- this, you should use other unit types, such as
- <varname>Type=</varname><option>notify</option> if the service
- understands systemd's notification protocol,
- <varname>Type=</varname><option>forking</option> if the service
- can background itself or
- <varname>Type=</varname><option>dbus</option> if the unit
- acquires a DBus name once initialization is complete. See
- below.</para>
+ <para>Note that this unit type does not include any type of notification when a service has completed
+ initialization. For this, you should use other unit types, such as
+ <varname>Type=</varname><option>notify</option>/<varname>Type=</varname><option>notify-reload</option>
+ if the service understands systemd's notification protocol,
+ <varname>Type=</varname><option>forking</option> if the service can background itself or
+ <varname>Type=</varname><option>dbus</option> if the unit acquires a DBus name once initialization is
+ complete. See below.</para>
</example>
<example>
@@ -1505,15 +1536,12 @@ SystemdService=simple-dbus-service.service</programlisting>
<example>
<title>Services that notify systemd about their initialization</title>
- <para><varname>Type=</varname><option>simple</option> services
- are really easy to write, but have the major disadvantage of
- systemd not being able to tell when initialization of the given
- service is complete. For this reason, systemd supports a simple
- notification protocol that allows daemons to make systemd aware
- that they are done initializing. Use
- <varname>Type=</varname><option>notify</option> for this. A
- typical service file for such a daemon would look like
- this:</para>
+ <para><varname>Type=</varname><option>simple</option> services are really easy to write, but have the
+ major disadvantage of systemd not being able to tell when initialization of the given service is
+ complete. For this reason, systemd supports a simple notification protocol that allows daemons to make
+ systemd aware that they are done initializing. Use <varname>Type=</varname><option>notify</option> or
+ <varname>Type=</varname><option>notify-reload</option> for this. A typical service file for such a
+ daemon would look like this:</para>
<programlisting>[Unit]
Description=Simple notifying service

@ -0,0 +1,105 @@
From 567b6dcd4ff8e4a9c9b0b1629fa8c015d5e6a724 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 2 Jan 2023 15:01:56 +0100
Subject: [PATCH] pid1: make sure we send our calling service manager
RELOADING=1 when reloading
And send READY=1 again when we are done with it.
We do this not only for "daemon-reload" but also for "daemon-reexec" and
"switch-root", since from the perspective of an encapsulating service
manager these three operations are not that different.
(cherry picked from commit dd0ab174c36492cdcb92cf46844fb0905b1d4a7e)
Related: RHEL-6090
---
src/core/main.c | 10 ++++++++++
src/core/manager.c | 12 ++++++++++++
src/core/manager.h | 1 +
units/user@.service.in | 2 +-
4 files changed, 24 insertions(+), 1 deletion(-)
diff --git a/src/core/main.c b/src/core/main.c
index 0e2e5448bb..126a4bce8c 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -1925,6 +1925,8 @@ static int invoke_main_loop(
LogTarget saved_log_target;
int saved_log_level;
+ manager_send_reloading(m);
+
log_info("Reloading.");
/* First, save any overridden log level/target, then parse the configuration file,
@@ -1955,6 +1957,10 @@ static int invoke_main_loop(
}
case MANAGER_REEXECUTE:
+
+ manager_send_reloading(m); /* From the perspective of the manager calling us this is
+ * pretty much the same as a reload */
+
r = prepare_reexecute(m, &arg_serialization, ret_fds, false);
if (r < 0) {
*ret_error_message = "Failed to prepare for reexecution";
@@ -1970,6 +1976,10 @@ static int invoke_main_loop(
return objective;
case MANAGER_SWITCH_ROOT:
+
+ manager_send_reloading(m); /* From the perspective of the manager calling us this is
+ * pretty much the same as a reload */
+
manager_set_switching_root(m, true);
if (!m->switch_root_init) {
diff --git a/src/core/manager.c b/src/core/manager.c
index 6371810ce3..b34103d7d3 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -3641,6 +3641,18 @@ void manager_check_finished(Manager *m) {
manager_invalidate_startup_units(m);
}
+void manager_send_reloading(Manager *m) {
+ assert(m);
+
+ /* Let whoever invoked us know that we are now reloading */
+ (void) sd_notifyf(/* unset= */ false,
+ "RELOADING=1\n"
+ "MONOTONIC_USEC=" USEC_FMT "\n", now(CLOCK_MONOTONIC));
+
+ /* And ensure that we'll send READY=1 again as soon as we are ready again */
+ m->ready_sent = false;
+}
+
static bool generator_path_any(const char* const* paths) {
bool found = false;
diff --git a/src/core/manager.h b/src/core/manager.h
index 75c16d6e26..87e63c3b68 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -535,6 +535,7 @@ void manager_send_unit_plymouth(Manager *m, Unit *u);
bool manager_unit_inactive_or_pending(Manager *m, const char *name);
void manager_check_finished(Manager *m);
+void manager_send_reloading(Manager *m);
void disable_printk_ratelimit(void);
void manager_recheck_dbus(Manager *m);
diff --git a/units/user@.service.in b/units/user@.service.in
index efbd5dfbc8..2c99f50905 100644
--- a/units/user@.service.in
+++ b/units/user@.service.in
@@ -17,7 +17,7 @@ IgnoreOnIsolate=yes
[Service]
User=%i
PAMName=systemd-user
-Type=notify
+Type=notify-reload
ExecStart={{ROOTLIBEXECDIR}}/systemd --user
Slice=user-%i.slice
KillMode=mixed

@ -0,0 +1,166 @@
From fef242735b987c1870bcd0460cc0c802e78a3cde Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 2 Jan 2023 17:25:46 +0100
Subject: [PATCH] networkd: implement Type=notify-reload protocol
(cherry picked from commit 0e07cdb0e77d0322bc866b5e13abbe38e988059d)
Related: RHEL-6090
---
src/network/networkd-manager-bus.c | 13 +-------
src/network/networkd-manager.c | 48 ++++++++++++++++++++++++++----
src/network/networkd-manager.h | 2 ++
src/network/networkd.c | 2 --
units/systemd-networkd.service.in | 3 +-
5 files changed, 47 insertions(+), 21 deletions(-)
diff --git a/src/network/networkd-manager-bus.c b/src/network/networkd-manager-bus.c
index 2ab3aaadc2..67f951df69 100644
--- a/src/network/networkd-manager-bus.c
+++ b/src/network/networkd-manager-bus.c
@@ -197,7 +197,6 @@ static int bus_method_reconfigure_link(sd_bus_message *message, void *userdata,
static int bus_method_reload(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *manager = userdata;
- Link *link;
int r;
r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
@@ -209,20 +208,10 @@ static int bus_method_reload(sd_bus_message *message, void *userdata, sd_bus_err
if (r == 0)
return 1; /* Polkit will call us back */
- r = netdev_load(manager, true);
+ r = manager_reload(manager);
if (r < 0)
return r;
- r = network_reload(manager);
- if (r < 0)
- return r;
-
- HASHMAP_FOREACH(link, manager->links_by_index) {
- r = link_reconfigure(link, /* force = */ false);
- if (r < 0)
- return r;
- }
-
return sd_bus_reply_method_return(message, NULL);
}
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index cdfd29bc0e..362ee84b09 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -483,6 +483,14 @@ static int signal_restart_callback(sd_event_source *s, const struct signalfd_sig
return sd_event_exit(sd_event_source_get_event(s), 0);
}
+static int signal_reload_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
+ Manager *m = ASSERT_PTR(userdata);
+
+ manager_reload(m);
+
+ return 0;
+}
+
static int manager_set_keep_configuration(Manager *m) {
int r;
@@ -517,12 +525,11 @@ int manager_setup(Manager *m) {
if (r < 0)
return r;
- assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR2, -1) >= 0);
-
(void) sd_event_set_watchdog(m->event, true);
- (void) sd_event_add_signal(m->event, NULL, SIGTERM, signal_terminate_callback, m);
- (void) sd_event_add_signal(m->event, NULL, SIGINT, signal_terminate_callback, m);
- (void) sd_event_add_signal(m->event, NULL, SIGUSR2, signal_restart_callback, m);
+ (void) sd_event_add_signal(m->event, NULL, SIGTERM | SD_EVENT_SIGNAL_PROCMASK, signal_terminate_callback, m);
+ (void) sd_event_add_signal(m->event, NULL, SIGINT | SD_EVENT_SIGNAL_PROCMASK, signal_terminate_callback, m);
+ (void) sd_event_add_signal(m->event, NULL, SIGUSR2 | SD_EVENT_SIGNAL_PROCMASK, signal_restart_callback, m);
+ (void) sd_event_add_signal(m->event, NULL, SIGHUP | SD_EVENT_SIGNAL_PROCMASK, signal_reload_callback, m);
r = sd_event_add_post(m->event, NULL, manager_dirty_handler, m);
if (r < 0)
@@ -1078,3 +1085,34 @@ int manager_set_timezone(Manager *m, const char *tz) {
return 0;
}
+
+int manager_reload(Manager *m) {
+ Link *link;
+ int r;
+
+ assert(m);
+
+ (void) sd_notifyf(/* unset= */ false,
+ "RELOADING=1\n"
+ "STATUS=Reloading configuration...\n"
+ "MONOTONIC_USEC=" USEC_FMT, now(CLOCK_MONOTONIC));
+
+ r = netdev_load(m, /* reload= */ true);
+ if (r < 0)
+ goto finish;
+
+ r = network_reload(m);
+ if (r < 0)
+ goto finish;
+
+ HASHMAP_FOREACH(link, m->links_by_index) {
+ r = link_reconfigure(link, /* force = */ false);
+ if (r < 0)
+ goto finish;
+ }
+
+ r = 0;
+finish:
+ (void) sd_notify(/* unset= */ false, NOTIFY_READY);
+ return r;
+}
diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h
index 40e6092f85..e6183af0e4 100644
--- a/src/network/networkd-manager.h
+++ b/src/network/networkd-manager.h
@@ -115,4 +115,6 @@ int manager_enumerate(Manager *m);
int manager_set_hostname(Manager *m, const char *hostname);
int manager_set_timezone(Manager *m, const char *timezone);
+int manager_reload(Manager *m);
+
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
diff --git a/src/network/networkd.c b/src/network/networkd.c
index d61769d9f3..68760e8ff4 100644
--- a/src/network/networkd.c
+++ b/src/network/networkd.c
@@ -81,8 +81,6 @@ static int run(int argc, char *argv[]) {
if (r < 0)
log_warning_errno(r, "Could not create runtime directory 'lldp': %m");
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
-
r = manager_new(&m, /* test_mode = */ false);
if (r < 0)
return log_error_errno(r, "Could not create manager: %m");
diff --git a/units/systemd-networkd.service.in b/units/systemd-networkd.service.in
index d15129e7f0..d8b935a358 100644
--- a/units/systemd-networkd.service.in
+++ b/units/systemd-networkd.service.in
@@ -24,7 +24,6 @@ BusName=org.freedesktop.network1
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_NET_RAW
DeviceAllow=char-* rw
ExecStart=!!{{ROOTLIBEXECDIR}}/systemd-networkd
-ExecReload=networkctl reload
FileDescriptorStoreMax=512
LockPersonality=yes
MemoryDenyWriteExecute=yes
@@ -48,7 +47,7 @@ RuntimeDirectoryPreserve=yes
SystemCallArchitectures=native
SystemCallErrorNumber=EPERM
SystemCallFilter=@system-service
-Type=notify
+Type=notify-reload
User=systemd-network
{{SERVICE_WATCHDOG}}

@ -0,0 +1,127 @@
From daa0a0268e9ed03b8e3c39f003266d0b14cae120 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 2 Jan 2023 17:21:16 +0100
Subject: [PATCH] udevd: implement the full Type=notify-reload protocol
We are basically already there, just need to add MONOTONIC_USEC= to the
RELOADING=1 message, and make sure the message is generated in really
all cases.
(cherry picked from commit f84331539deae28fbeb42d45ad0c8d583b3372a3)
Related: RHEL-6090
---
src/udev/udevd.c | 47 +++++++++++++++++++---------------
units/systemd-udevd.service.in | 3 +--
2 files changed, 28 insertions(+), 22 deletions(-)
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index ccc3c0eece..6d82a6eff2 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -32,6 +32,7 @@
#include "cgroup-setup.h"
#include "cgroup-util.h"
#include "cpu-set-util.h"
+#include "daemon-util.h"
#include "dev-setup.h"
#include "device-monitor-private.h"
#include "device-private.h"
@@ -331,9 +332,7 @@ static void manager_exit(Manager *manager) {
manager->exit = true;
- sd_notify(false,
- "STOPPING=1\n"
- "STATUS=Starting shutdown...");
+ (void) sd_notify(/* unset= */ false, NOTIFY_STOPPING);
/* close sources of new events and discard buffered events */
manager->ctrl = udev_ctrl_unref(manager->ctrl);
@@ -351,7 +350,7 @@ static void manager_exit(Manager *manager) {
static void notify_ready(void) {
int r;
- r = sd_notifyf(false,
+ r = sd_notifyf(/* unset= */ false,
"READY=1\n"
"STATUS=Processing with %u children at max", arg_children_max);
if (r < 0)
@@ -376,23 +375,33 @@ static void manager_reload(Manager *manager, bool force) {
mac_selinux_maybe_reload();
/* Nothing changed. It is not necessary to reload. */
- if (!udev_rules_should_reload(manager->rules) && !udev_builtin_should_reload())
- return;
+ if (!udev_rules_should_reload(manager->rules) && !udev_builtin_should_reload()) {
- sd_notify(false,
- "RELOADING=1\n"
- "STATUS=Flushing configuration...");
+ if (!force)
+ return;
- manager_kill_workers(manager, false);
+ /* If we eat this up, then tell our service manager to just continue */
+ (void) sd_notifyf(/* unset= */ false,
+ "RELOADING=1\n"
+ "STATUS=Skipping configuration reloading, nothing changed.\n"
+ "MONOTONIC_USEC=" USEC_FMT, now(CLOCK_MONOTONIC));
+ } else {
+ (void) sd_notifyf(/* unset= */ false,
+ "RELOADING=1\n"
+ "STATUS=Flushing configuration...\n"
+ "MONOTONIC_USEC=" USEC_FMT, now(CLOCK_MONOTONIC));
- udev_builtin_exit();
- udev_builtin_init();
+ manager_kill_workers(manager, false);
- r = udev_rules_load(&rules, arg_resolve_name_timing);
- if (r < 0)
- log_warning_errno(r, "Failed to read udev rules, using the previously loaded rules, ignoring: %m");
- else
- udev_rules_free_and_replace(manager->rules, rules);
+ udev_builtin_exit();
+ udev_builtin_init();
+
+ r = udev_rules_load(&rules, arg_resolve_name_timing);
+ if (r < 0)
+ log_warning_errno(r, "Failed to read udev rules, using the previously loaded rules, ignoring: %m");
+ else
+ udev_rules_free_and_replace(manager->rules, rules);
+ }
notify_ready();
}
@@ -1982,9 +1991,7 @@ static int main_loop(Manager *manager) {
if (r < 0)
log_error_errno(r, "Event loop failed: %m");
- sd_notify(false,
- "STOPPING=1\n"
- "STATUS=Shutting down...");
+ (void) sd_notify(/* unset= */ false, NOTIFY_STOPPING);
return r;
}
diff --git a/units/systemd-udevd.service.in b/units/systemd-udevd.service.in
index e9dbe85ef4..dfc2a0e341 100644
--- a/units/systemd-udevd.service.in
+++ b/units/systemd-udevd.service.in
@@ -18,14 +18,13 @@ ConditionPathIsReadWrite=/sys
[Service]
CapabilityBoundingSet=~CAP_SYS_TIME CAP_WAKE_ALARM
Delegate=pids
-Type=notify
+Type=notify-reload
# Note that udev will reset the value internally for its workers
OOMScoreAdjust=-1000
Sockets=systemd-udevd-control.socket systemd-udevd-kernel.socket
Restart=always
RestartSec=0
ExecStart={{ROOTLIBEXECDIR}}/systemd-udevd
-ExecReload=udevadm control --reload --timeout 0
KillMode=mixed
TasksMax=infinity
PrivateMounts=yes

@ -0,0 +1,52 @@
From dd9aa5ffe940ac6d5204a04fce5faafc3fc01924 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 2 Jan 2023 17:35:23 +0100
Subject: [PATCH] logind: implement Type=notify-reload protocol properly
So close already. Let's add the two missing notifications too.
Fixes: #18484
(cherry picked from commit 5d71e463f49518c7702467f6145484afa31bf8ba)
Related: RHEL-6090
---
src/login/logind.c | 6 ++++++
units/systemd-logind.service.in | 1 +
2 files changed, 7 insertions(+)
diff --git a/src/login/logind.c b/src/login/logind.c
index cdca5ca58c..0348b19c05 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -1014,6 +1014,11 @@ static int manager_dispatch_reload_signal(sd_event_source *s, const struct signa
Manager *m = userdata;
int r;
+ (void) sd_notifyf(/* unset= */ false,
+ "RELOADING=1\n"
+ "STATUS=Reloading configuration...\n"
+ "MONOTONIC_USEC=" USEC_FMT, now(CLOCK_MONOTONIC));
+
manager_reset_config(m);
r = manager_parse_config_file(m);
if (r < 0)
@@ -1021,6 +1026,7 @@ static int manager_dispatch_reload_signal(sd_event_source *s, const struct signa
else
log_info("Config file reloaded.");
+ (void) sd_notify(/* unset= */ false, NOTIFY_READY);
return 0;
}
diff --git a/units/systemd-logind.service.in b/units/systemd-logind.service.in
index 042ea75d7a..24f5ddaa17 100644
--- a/units/systemd-logind.service.in
+++ b/units/systemd-logind.service.in
@@ -58,6 +58,7 @@ StateDirectory=systemd/linger
SystemCallArchitectures=native
SystemCallErrorNumber=EPERM
SystemCallFilter=@system-service
+Type=notify-reload
{{SERVICE_WATCHDOG}}
# Increase the default a bit in order to allow many simultaneous logins since

@ -0,0 +1,297 @@
From 2b5c9fceaaa30ec9c2d031c9ca32b71c43f22f98 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 3 Jan 2023 12:55:50 +0100
Subject: [PATCH] notify: add --stopping + --reloading switches
These wrap RELOADING=1 and STOPPING=1 messages. The former is
particularly useful, since we want to insert the MONOTONIC_USEC= field
into the message automatically, which is easy from C but harder from
shell.
(cherry picked from commit fd0f4da5457fbf7136f2d1888142d5fea75fd45a)
Related: RHEL-6090
---
man/systemd-notify.xml | 107 ++++++++++++++++++++++++-----------------
src/notify/notify.c | 39 +++++++++++++--
2 files changed, 97 insertions(+), 49 deletions(-)
diff --git a/man/systemd-notify.xml b/man/systemd-notify.xml
index 1327d23155..a275123d40 100644
--- a/man/systemd-notify.xml
+++ b/man/systemd-notify.xml
@@ -30,34 +30,35 @@
<refsect1>
<title>Description</title>
- <para><command>systemd-notify</command> may be called by daemon
- scripts to notify the init system about status changes. It can be
- used to send arbitrary information, encoded in an
- environment-block-like list of strings. Most importantly, it can be
- used for start-up completion notification.</para>
-
- <para>This is mostly just a wrapper around
- <function>sd_notify()</function> and makes this functionality
+ <para><command>systemd-notify</command> may be called by service scripts to notify the invoking service
+ manager about status changes. It can be used to send arbitrary information, encoded in an
+ environment-block-like list of strings. Most importantly, it can be used for start-up completion
+ notification.</para>
+
+ <para>This is mostly just a wrapper around <function>sd_notify()</function> and makes this functionality
available to shell scripts. For details see
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
</para>
- <para>The command line may carry a list of environment variables
- to send as part of the status update.</para>
+ <para>The command line may carry a list of environment variables to send as part of the status
+ update.</para>
<para>Note that systemd will refuse reception of status updates from this command unless
<varname>NotifyAccess=</varname> is set for the service unit this command is called from.</para>
- <para>Note that <function>sd_notify()</function> notifications may be attributed to units correctly only if either
- the sending process is still around at the time PID 1 processes the message, or if the sending process is
- explicitly runtime-tracked by the service manager. The latter is the case if the service manager originally forked
- off the process, i.e. on all processes that match <varname>NotifyAccess=</varname><option>main</option> or
- <varname>NotifyAccess=</varname><option>exec</option>. Conversely, if an auxiliary process of the unit sends an
- <function>sd_notify()</function> message and immediately exits, the service manager might not be able to properly
- attribute the message to the unit, and thus will ignore it, even if <varname>NotifyAccess=</varname><option>all
- </option> is set for it. When <option>--no-block</option> is used, all synchronization for reception of notifications
- is disabled, and hence the aforementioned race may occur if the invoking process is not the service manager or spawned
- by the service manager.</para>
+ <para>Note that <function>sd_notify()</function> notifications may be attributed to units correctly only
+ if either the sending process is still around at the time the service manager processes the message, or
+ if the sending process is explicitly runtime-tracked by the service manager. The latter is the case if
+ the service manager originally forked off the process, i.e. on all processes that match
+ <varname>NotifyAccess=</varname><option>main</option> or
+ <varname>NotifyAccess=</varname><option>exec</option>. Conversely, if an auxiliary process of the unit
+ sends an <function>sd_notify()</function> message and immediately exits, the service manager might not be
+ able to properly attribute the message to the unit, and thus will ignore it, even if
+ <varname>NotifyAccess=</varname><option>all</option> is set for it. To address this
+ <command>systemd-notify</command> will wait until the notification message has been processed by the
+ service manager. When <option>--no-block</option> is used, this synchronization for reception of
+ notifications is disabled, and hence the aforementioned race may occur if the invoking process is not the
+ service manager or spawned by the service manager.</para>
<para>Hence, <command>systemd-notify</command> will first attempt to invoke <function>sd_notify()</function>
pretending to have the PID of the invoking process. This will only succeed when invoked with sufficient privileges.
@@ -66,7 +67,6 @@
— appears as sender of the message, which in turn is helpful if the shell process is the main process of a service,
due to the limitations of <varname>NotifyAccess=</varname><option>all</option>. Use the <option>--pid=</option>
switch to tweak this behaviour.</para>
-
</refsect1>
<refsect1>
@@ -78,22 +78,42 @@
<varlistentry>
<term><option>--ready</option></term>
- <listitem><para>Inform the init system about service start-up
- completion. This is equivalent to <command>systemd-notify
- READY=1</command>. For details about the semantics of this
- option see
+ <listitem><para>Inform the invoking service manager about service start-up or configuration reload
+ completion. This is equivalent to <command>systemd-notify READY=1</command>. For details about the
+ semantics of this option see
+ <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--reloading</option></term>
+
+ <listitem><para>Inform the invoking service manager about the beginning of a configuration reload
+ cycle. This is equivalent to <command>systemd-notify RELOADING=1</command> (but implicitly also sets
+ a <varname>MONOTONIC_USEC=</varname> field as required for <varname>Type=notify-reload</varname>
+ services, see
+ <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ for details). For details about the semantics of this option see
+ <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--stopping</option></term>
+
+ <listitem><para>Inform the invoking service manager about the beginning of the shutdown phase of the
+ service. This is equivalent to <command>systemd-notify STOPPING=1</command>. For details about the
+ semantics of this option see
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--pid=</option></term>
- <listitem><para>Inform the service manager about the main PID of the daemon. Takes a PID as
+ <listitem><para>Inform the service manager about the main PID of the service. Takes a PID as
argument. If the argument is specified as <literal>auto</literal> or omitted, the PID of the process
that invoked <command>systemd-notify</command> is used, except if that's the service manager. If the
argument is specified as <literal>self</literal>, the PID of the <command>systemd-notify</command>
command itself is used, and if <literal>parent</literal> is specified the calling process' PID is
- used — even if it is the service manager. This is equivalent to <command>systemd-notify
+ used — even if it is the service manager. The latter is equivalent to <command>systemd-notify
MAINPID=$PID</command>. For details about the semantics of this option see
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
</varlistentry>
@@ -110,27 +130,26 @@
<varlistentry>
<term><option>--status=</option></term>
- <listitem><para>Send a free-form status string for the daemon
- to the init systemd. This option takes the status string as
- argument. This is equivalent to <command>systemd-notify
- STATUS=…</command>. For details about the semantics of this
- option see
- <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
+ <listitem><para>Send a free-form human readable status string for the daemon to the service
+ manager. This option takes the status string as argument. This is equivalent to
+ <command>systemd-notify STATUS=…</command>. For details about the semantics of this option see
+ <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>. This
+ information is shown in
+ <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
+ <command>status</command> output, among other places.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--booted</option></term>
- <listitem><para>Returns 0 if the system was booted up with
- systemd, non-zero otherwise. If this option is passed, no
- message is sent. This option is hence unrelated to the other
- options. For details about the semantics of this option, see
+ <listitem><para>Returns 0 if the system was booted up with systemd, non-zero otherwise. If this
+ option is passed, no message is sent. This option is hence unrelated to the other options. For
+ details about the semantics of this option, see
<citerefentry><refentrytitle>sd_booted</refentrytitle><manvolnum>3</manvolnum></citerefentry>. An
alternate way to check for this state is to call
- <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
- with the <command>is-system-running</command> command. It will
- return <literal>offline</literal> if the system was not booted
- with systemd. </para></listitem>
+ <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> with
+ the <command>is-system-running</command> command. It will return <literal>offline</literal> if the
+ system was not booted with systemd. </para></listitem>
</varlistentry>
<varlistentry>
@@ -162,9 +181,8 @@
<example>
<title>Start-up Notification and Status Updates</title>
- <para>A simple shell daemon that sends start-up notifications
- after having set up its communication channel. During runtime it
- sends further status updates to the init system:</para>
+ <para>A simple shell daemon that sends start-up notifications after having set up its communication
+ channel. During runtime it sends further status updates to the init system:</para>
<programlisting>#!/bin/sh
@@ -192,5 +210,4 @@ done</programlisting>
<citerefentry><refentrytitle>sd_booted</refentrytitle><manvolnum>3</manvolnum></citerefentry>
</para>
</refsect1>
-
</refentry>
diff --git a/src/notify/notify.c b/src/notify/notify.c
index 7b23e7bdb0..2d4900a110 100644
--- a/src/notify/notify.c
+++ b/src/notify/notify.c
@@ -23,6 +23,8 @@
#include "util.h"
static bool arg_ready = false;
+static bool arg_reloading = false;
+static bool arg_stopping = false;
static pid_t arg_pid = 0;
static const char *arg_status = NULL;
static bool arg_booted = false;
@@ -42,7 +44,10 @@ static int help(void) {
"\n%sNotify the init system about service status updates.%s\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
- " --ready Inform the init system about service start-up completion\n"
+ " --ready Inform the service manager about service start-up/reload\n"
+ " completion\n"
+ " --reloading Inform the service manager about configuration reloading\n"
+ " --stopping Inform the service manager about service shutdown\n"
" --pid[=PID] Set main PID of daemon\n"
" --uid=USER Set user to send from\n"
" --status=TEXT Set status text\n"
@@ -81,6 +86,8 @@ static int parse_argv(int argc, char *argv[]) {
enum {
ARG_READY = 0x100,
+ ARG_RELOADING,
+ ARG_STOPPING,
ARG_VERSION,
ARG_PID,
ARG_STATUS,
@@ -93,6 +100,8 @@ static int parse_argv(int argc, char *argv[]) {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "ready", no_argument, NULL, ARG_READY },
+ { "reloading", no_argument, NULL, ARG_RELOADING },
+ { "stopping", no_argument, NULL, ARG_STOPPING },
{ "pid", optional_argument, NULL, ARG_PID },
{ "status", required_argument, NULL, ARG_STATUS },
{ "booted", no_argument, NULL, ARG_BOOTED },
@@ -120,6 +129,14 @@ static int parse_argv(int argc, char *argv[]) {
arg_ready = true;
break;
+ case ARG_RELOADING:
+ arg_reloading = true;
+ break;
+
+ case ARG_STOPPING:
+ arg_stopping = true;
+ break;
+
case ARG_PID:
if (isempty(optarg) || streq(optarg, "auto")) {
arg_pid = getppid();
@@ -176,6 +193,8 @@ static int parse_argv(int argc, char *argv[]) {
if (optind >= argc &&
!arg_ready &&
+ !arg_stopping &&
+ !arg_reloading &&
!arg_status &&
!arg_pid &&
!arg_booted) {
@@ -187,10 +206,10 @@ static int parse_argv(int argc, char *argv[]) {
}
static int run(int argc, char* argv[]) {
- _cleanup_free_ char *status = NULL, *cpid = NULL, *n = NULL;
+ _cleanup_free_ char *status = NULL, *cpid = NULL, *n = NULL, *monotonic_usec = NULL;
_cleanup_strv_free_ char **final_env = NULL;
- char* our_env[4];
- unsigned i = 0;
+ char* our_env[7];
+ size_t i = 0;
pid_t source_pid;
int r;
@@ -212,9 +231,21 @@ static int run(int argc, char* argv[]) {
return r <= 0;
}
+ if (arg_reloading) {
+ our_env[i++] = (char*) "RELOADING=1";
+
+ if (asprintf(&monotonic_usec, "MONOTONIC_USEC=" USEC_FMT, now(CLOCK_MONOTONIC)) < 0)
+ return log_oom();
+
+ our_env[i++] = monotonic_usec;
+ }
+
if (arg_ready)
our_env[i++] = (char*) "READY=1";
+ if (arg_stopping)
+ our_env[i++] = (char*) "STOPPING=1";
+
if (arg_status) {
status = strjoin("STATUS=", arg_status);
if (!status)

@ -0,0 +1,74 @@
From 3a2cb37fdbe4e761ae649716f6f8f71feffdd608 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 3 Jan 2023 12:56:53 +0100
Subject: [PATCH] test: add Type=notify-reload testcase
(cherry picked from commit ee52bbc68f129cfed833990906c0a0a77ee12c42)
Related: RHEL-6090
---
test/units/testsuite-59.sh | 51 ++++++++++++++++++++++++++++++++++++++
1 file changed, 51 insertions(+)
diff --git a/test/units/testsuite-59.sh b/test/units/testsuite-59.sh
index 83db053107..475766a851 100755
--- a/test/units/testsuite-59.sh
+++ b/test/units/testsuite-59.sh
@@ -83,6 +83,57 @@ systemctl start testservice-abort-restart-59.service
systemctl --signal=SIGABRT kill testservice-abort-restart-59.service
wait_on_state_or_fail "testservice-abort-restart-59.service" "failed" "30"
+# Let's now test the notify-reload logic
+
+cat >/run/notify-reload-test.sh <<EOF
+#!/usr/bin/env bash
+set -eux
+set -o pipefail
+
+EXIT_STATUS=88
+LEAVE=0
+
+function reload() {
+ systemd-notify --reloading --status="Adding 11 to exit status"
+ EXIT_STATUS=\$((\$EXIT_STATUS + 11))
+ systemd-notify --ready --status="Back running"
+}
+
+function leave() {
+ systemd-notify --stopping --status="Adding 7 to exit status"
+ EXIT_STATUS=\$((\$EXIT_STATUS + 7))
+ LEAVE=1
+ return 0
+}
+
+trap reload SIGHUP
+trap leave SIGTERM
+
+systemd-notify --ready
+systemd-notify --status="Running now"
+
+while [ \$LEAVE = 0 ] ; do
+ sleep 1
+done
+
+systemd-notify --status="Adding 3 to exit status"
+EXIT_STATUS=\$((\$EXIT_STATUS + 3))
+exit \$EXIT_STATUS
+EOF
+
+chmod +x /run/notify-reload-test.sh
+
+systemd-analyze log-level debug
+
+systemd-run --unit notify-reload-test -p Type=notify-reload -p KillMode=process /run/notify-reload-test.sh
+systemctl reload notify-reload-test
+systemctl stop notify-reload-test
+
+test "$(systemctl show -p ExecMainStatus --value notify-reload-test)" = 109
+
+systemctl reset-failed notify-reload-test
+rm /run/notify-reload-test.sh
+
systemd-analyze log-level info
echo OK >/testok

@ -0,0 +1,45 @@
From 3fa498dba2e67c1c97f25b093ec6c36e55023259 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 2 Jan 2023 16:48:51 +0100
Subject: [PATCH] update TODO
(cherry picked from commit 6fee784964b2763bd4307181335a433078ba977c)
Related: RHEL-6090
---
TODO | 15 +++------------
1 file changed, 3 insertions(+), 12 deletions(-)
diff --git a/TODO b/TODO
index 66c008bff3..8c67f93f35 100644
--- a/TODO
+++ b/TODO
@@ -700,17 +700,9 @@ Features:
and synthesize initrd from it, and measure it. Signing is not necessary, as
microcode does that on its own. Pass as first initrd to kernel.
-* Add a new service type very similar to Type=notify, that goes one step
- further and extends the protocol to cover reloads. Specifically, SIGHUP will
- become the official way to reload, and daemon has to respond with sd_notify()
- to report when it starts reloading, and when it is complete reloading. Care
- must be taken to remove races from this model. I.e. PID 1 needs to take
- CLOCK_MONOTONIC, then send SIGHUP, then wait for at least one RELOADING=1
- message that comes with a newer timestamp, then wait for a READY=1 message.
- while we are at it, also maybe extend the logic to require handling of some
- specific SIGRT signal for setting debug log level, that carries the level via
- the sigqueue() data parameter. With that we extended with minimal logic the
- service runtime logic quite substantially.
+* Maybe extend the service protocol to support handling of some specific SIGRT
+ signal for setting service log level, that carries the level via the
+ sigqueue() data parameter. Enable this via unit file setting.
* firstboot: maybe just default to C.UTF-8 locale if nothing is set, so that we
don't query this unnecessarily in entirely uninitialized
@@ -1738,7 +1730,6 @@ Features:
* unit files:
- allow port=0 in .socket units
- maybe introduce ExecRestartPre=
- - add ReloadSignal= for configuring a reload signal to use
- implement Register= switch in .socket units to enable registration
in Avahi, RPC and other socket registration services.
- allow Type=simple with PIDFile=

@ -0,0 +1,40 @@
From 036f0593b33ddc0f40a333d790a276c3cffe862e Mon Sep 17 00:00:00 2001
From: msizanoen1 <msizanoen@qtmlabs.xyz>
Date: Tue, 2 May 2023 16:59:07 +0700
Subject: [PATCH] core: check for SERVICE_RELOAD_NOTIFY in
manager_dbus_is_running
This ensures that systemd won't erronously disconnect from the system
bus in case a bus recheck is triggered immediately after the bus service
emits `RELOADING=1`.
This fixes an issue where systemd-logind sometimes randomly stops
receiving `UnitRemoved` after a system update.
This also handles SERVICE_RELOAD_SIGNAL just in case somebody ever
creates a D-Bus broker implementation that uses `Type=notify-reload`.
(cherry picked from commit 845824acddf2e7e08c94afe7cfee6e50a682c947)
Related: RHEL-6090
---
src/core/manager.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/core/manager.c b/src/core/manager.c
index b34103d7d3..eeee395b90 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -1696,7 +1696,11 @@ static bool manager_dbus_is_running(Manager *m, bool deserialized) {
u = manager_get_unit(m, SPECIAL_DBUS_SERVICE);
if (!u)
return false;
- if (!IN_SET((deserialized ? SERVICE(u)->deserialized_state : SERVICE(u)->state), SERVICE_RUNNING, SERVICE_RELOAD))
+ if (!IN_SET((deserialized ? SERVICE(u)->deserialized_state : SERVICE(u)->state),
+ SERVICE_RUNNING,
+ SERVICE_RELOAD,
+ SERVICE_RELOAD_NOTIFY,
+ SERVICE_RELOAD_SIGNAL))
return false;
return true;

@ -0,0 +1,37 @@
From 4b2fb9adb3cd46cf6fe9b7e093d3f513a44f8e14 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <fsumsal@redhat.com>
Date: Thu, 14 Dec 2023 10:54:38 +0100
Subject: [PATCH] Revert "man: mention System Administrator's Guide in
systemctl manpage"
This reverts commit 5b2c931fb85d79db5a369a46eaeaf4ba297cbeef.
Related: RHEL-19436
rhel-only
---
man/systemctl.xml | 11 -----------
1 file changed, 11 deletions(-)
diff --git a/man/systemctl.xml b/man/systemctl.xml
index b73d4ac048..55310c974e 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -2518,17 +2518,6 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
<xi:include href="common-variables.xml" xpointer="urlify"/>
</refsect1>
- <refsect1>
- <title>Examples</title>
- <para>
- For examples how to use systemctl in comparsion
- with old service and chkconfig command please see:
- <ulink url="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html/configuring_basic_system_settings/managing-system-services-with-systemctl_configuring-basic-system-settings">
- Managing System Services
- </ulink>
- </para>
- </refsect1>
-
<refsect1>
<title>See Also</title>
<para>

@ -0,0 +1,33 @@
From 024e4e1989e8e1a8d67429ab7f36dcca5734f81b Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <fsumsal@redhat.com>
Date: Thu, 14 Dec 2023 10:56:51 +0100
Subject: [PATCH] man: mention RHEL documentation in systemctl's man page
Resolves: RHEL-19436
rhel-only
---
man/systemctl.xml | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/man/systemctl.xml b/man/systemctl.xml
index 55310c974e..1df0b158bd 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -2518,6 +2518,16 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
<xi:include href="common-variables.xml" xpointer="urlify"/>
</refsect1>
+ <refsect1>
+ <title>Examples</title>
+ <para>
+ For examples how to use systemctl in comparison with old service and chkconfig commands please see:
+ <ulink url="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html/configuring_basic_system_settings/managing-systemd_configuring-basic-system-settings#managing-system-services-with-systemctl_managing-systemd">
+ Managing System Services
+ </ulink>
+ </para>
+ </refsect1>
+
<refsect1>
<title>See Also</title>
<para>

@ -0,0 +1,37 @@
From 92ca40483db514bac34d8cd29438f48a794fae91 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Wed, 20 Dec 2023 16:44:14 +0100
Subject: [PATCH] resolved: actually check authenticated flag of SOA
transaction
Fixes #25676
(cherry picked from commit 3b4cc1437b51fcc0b08da8cc3f5d1175eed25eb1)
Resolves: RHEL-6216
---
src/resolve/resolved-dns-transaction.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index 0212569fb0..0306af84a2 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -2800,7 +2800,7 @@ static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord *
if (r == 0)
continue;
- return FLAGS_SET(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED);
+ return FLAGS_SET(dt->answer_query_flags, SD_RESOLVED_AUTHENTICATED);
}
return true;
@@ -2827,7 +2827,7 @@ static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord *
/* We found the transaction that was supposed to find the SOA RR for us. It was
* successful, but found no RR for us. This means we are not at a zone cut. In this
* case, we require authentication if the SOA lookup was authenticated too. */
- return FLAGS_SET(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED);
+ return FLAGS_SET(dt->answer_query_flags, SD_RESOLVED_AUTHENTICATED);
}
return true;

@ -0,0 +1,404 @@
From 9cd7868bc7cb5bda25c0470a9b4e349d4f2004fe Mon Sep 17 00:00:00 2001
From: Lukas Nykryn <lnykryn@redhat.com>
Date: Fri, 8 Dec 2023 12:33:06 +0100
Subject: [PATCH] udev: allow/denylist for reading sysfs attributes when
composing a NIC name
Users can currently pick specific versions of NIC naming, but that
does not guarantee that NIC names won't change after the kernel adds
a new sysfs attribute.
This patch allows for an allow/deny list of sysfs attributes
that could be used when composing the name.
These lists can be supplied as an hwdb entry in the form of
/etc/udev/hwdb.d/50-net-naming-allowlist.hwdb
net:naming:drvirtio_net
ID_NET_NAME_ALLOW=0
ID_NET_NAME_ALLOW_ACPI_INDEX=1
ID_NET_NAME_ALLOW_ADDR_ASSIGN_TYPE=1
ID_NET_NAME_ALLOW_ADDRESS=1
ID_NET_NAME_ALLOW_ARI_ENABLED=1
ID_NET_NAME_ALLOW_DEV_PORT=1
ID_NET_NAME_ALLOW_FUNCTION_ID=1
ID_NET_NAME_ALLOW_IFLINK=1
ID_NET_NAME_ALLOW_INDEX=1
ID_NET_NAME_ALLOW_LABEL=1
ID_NET_NAME_ALLOW_PHYS_PORT_NAME=1
ID_NET_NAME_ALLOW_TYPE=1
(cherry picked from commit 3b2e7dc5a285edbbb1bf6aed2d88b889d801613f)
Resolves: RHEL-1317
---
man/systemd.net-naming-scheme.xml | 69 ++++++++++++++++++++++++++
rules.d/75-net-description.rules | 2 +
src/shared/netif-naming-scheme.c | 81 +++++++++++++++++++++++++++++++
src/shared/netif-naming-scheme.h | 7 +++
src/udev/udev-builtin-net_id.c | 34 ++++++-------
5 files changed, 176 insertions(+), 17 deletions(-)
diff --git a/man/systemd.net-naming-scheme.xml b/man/systemd.net-naming-scheme.xml
index c6ab86906a..ec9f3da437 100644
--- a/man/systemd.net-naming-scheme.xml
+++ b/man/systemd.net-naming-scheme.xml
@@ -588,6 +588,45 @@
particular version of systemd).</para>
</refsect1>
+ <refsect1>
+ <title>Limiting the use of specific sysfs attributes</title>
+
+ <para>When creating names for network cards, some naming schemes use data from sysfs populated
+ by the kernel. This means that although a specific naming scheme in udev is picked,
+ the network card's name can still change when a new kernel version adds a new sysfs attribute.
+ For example if kernel starts setting the <constant>phys_port_name</constant>, udev will append the
+ "<constant>n</constant><replaceable>phys_port_name</replaceable>" suffix to the device name.</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><varname>ID_NET_NAME_ALLOW=<replaceable>BOOL</replaceable></varname></term>
+
+ <listitem><para>This evironment value sets a fallback policy for reading a sysfs attribute.
+ If set to <constant>0</constant> udev will not read any sysfs attribute by default, unless it is
+ explicitly allowlisted, see below. If set to <constant>1</constant> udev can use any sysfs attribute
+ unless it is explicitly forbidden. The default value is <constant>1</constant>.</para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>ID_NET_NAME_ALLOW_<replaceable>sysfsattr</replaceable>=<replaceable>BOOL</replaceable></varname></term>
+
+ <listitem><para>This evironment value explicitly states if udev shall use the specified
+ <replaceable>sysfsattr</replaceable>, when composing the device name.</para>
+
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>With these options, users can set an allowlist or denylist for sysfs attributes. To create
+ an allowlist, the user needs to set <varname>ID_NET_NAME_ALLOW=0</varname> for the device and then list
+ the allowed attributes with the
+ <varname>ID_NET_NAME_ALLOW_<replaceable>sysfsattr</replaceable>=1</varname>
+ options. In case of a denylist, the user needs to provide the list of denied attributes with
+ the <varname>ID_NET_NAME_ALLOW_<replaceable>sysfsattr</replaceable>=0</varname> options.</para>
+ </refsect1>
+
<refsect1>
<title>Examples</title>
@@ -674,6 +713,36 @@ ID_NET_NAME_PATH=enp0s29u1u2</programlisting>
ID_NET_NAME_MAC=enx026d3c00000a
ID_NET_NAME_PATH=encf5f0</programlisting>
</example>
+
+ <example>
+ <title>Set an allowlist for reading sysfs attributes for network card naming</title>
+
+ <programlisting><filename>/etc/udev/hwdb.d/50-net-naming-allowlist.hwdb</filename>
+net:naming:drvirtio_net:*
+ ID_NET_NAME_ALLOW=0
+ ID_NET_NAME_ALLOW_ACPI_INDEX=1
+ ID_NET_NAME_ALLOW_ADDR_ASSIGN_TYPE=1
+ ID_NET_NAME_ALLOW_ADDRESS=1
+ ID_NET_NAME_ALLOW_ARI_ENABLED=1
+ ID_NET_NAME_ALLOW_DEV_PORT=1
+ ID_NET_NAME_ALLOW_FUNCTION_ID=1
+ ID_NET_NAME_ALLOW_IFLINK=1
+ ID_NET_NAME_ALLOW_INDEX=1
+ ID_NET_NAME_ALLOW_LABEL=1
+ ID_NET_NAME_ALLOW_PHYS_PORT_NAME=1
+ ID_NET_NAME_ALLOW_TYPE=1</programlisting>
+ </example>
+
+ <example>
+ <title>Set a denylist so that specified sysfs attribute are ignored</title>
+
+ <programlisting><filename>/etc/udev/hwdb.d/50-net-naming-denylist.hwdb</filename>
+net:naming:drvirtio_net:*
+ ID_NET_NAME_ALLOW=1
+ ID_NET_NAME_ALLOW_DEV_PORT=0
+ ID_NET_NAME_ALLOW_PHYS_PORT_NAME=0
+ </programlisting>
+ </example>
</refsect1>
<refsect1>
diff --git a/rules.d/75-net-description.rules b/rules.d/75-net-description.rules
index 7e62f8b26b..5ba70a6545 100644
--- a/rules.d/75-net-description.rules
+++ b/rules.d/75-net-description.rules
@@ -3,6 +3,8 @@
ACTION=="remove", GOTO="net_end"
SUBSYSTEM!="net", GOTO="net_end"
+IMPORT{builtin}="hwdb 'net:naming:dr$env{ID_NET_DRIVER}:'"
+
IMPORT{builtin}="net_id"
SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id", IMPORT{builtin}="hwdb --subsystem=usb"
diff --git a/src/shared/netif-naming-scheme.c b/src/shared/netif-naming-scheme.c
index 9cfa5ca8e6..e73c265371 100644
--- a/src/shared/netif-naming-scheme.c
+++ b/src/shared/netif-naming-scheme.c
@@ -1,6 +1,9 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#include "sd-device.h"
+
#include "alloc-util.h"
+#include "device-private.h"
#include "netif-naming-scheme.h"
#include "proc-cmdline.h"
#include "string-util.h"
@@ -119,3 +122,81 @@ static const char* const alternative_names_policy_table[_NAMEPOLICY_MAX] = {
};
DEFINE_STRING_TABLE_LOOKUP(alternative_names_policy, NamePolicy);
+
+static int naming_sysattr_allowed_by_default(sd_device *dev) {
+ int r;
+
+ assert(dev);
+
+ r = device_get_property_bool(dev, "ID_NET_NAME_ALLOW");
+ if (r == -ENOENT)
+ return true;
+
+ return r;
+}
+
+static int naming_sysattr_allowed(sd_device *dev, const char *sysattr) {
+ char *sysattr_property;
+ int r;
+
+ assert(dev);
+ assert(sysattr);
+
+ sysattr_property = strjoina("ID_NET_NAME_ALLOW_", sysattr);
+ ascii_strupper(sysattr_property);
+
+ r = device_get_property_bool(dev, sysattr_property);
+ if (r == -ENOENT)
+ /* If ID_NET_NAME_ALLOW is not set or set to 1 default is to allow */
+ return naming_sysattr_allowed_by_default(dev);
+
+ return r;
+}
+
+int device_get_sysattr_int_filtered(sd_device *device, const char *sysattr, int *ret_value) {
+ int r;
+
+ r = naming_sysattr_allowed(device, sysattr);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -ENOENT;
+
+ return device_get_sysattr_int(device, sysattr, ret_value);
+}
+
+int device_get_sysattr_unsigned_filtered(sd_device *device, const char *sysattr, unsigned *ret_value) {
+ int r;
+
+ r = naming_sysattr_allowed(device, sysattr);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -ENOENT;
+
+ return device_get_sysattr_unsigned(device, sysattr, ret_value);
+}
+
+int device_get_sysattr_bool_filtered(sd_device *device, const char *sysattr) {
+ int r;
+
+ r = naming_sysattr_allowed(device, sysattr);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -ENOENT;
+
+ return device_get_sysattr_bool(device, sysattr);
+}
+
+int device_get_sysattr_value_filtered(sd_device *device, const char *sysattr, const char **ret_value) {
+ int r;
+
+ r = naming_sysattr_allowed(device, sysattr);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -ENOENT;
+
+ return sd_device_get_sysattr_value(device, sysattr, ret_value);
+}
diff --git a/src/shared/netif-naming-scheme.h b/src/shared/netif-naming-scheme.h
index ed45536f65..3baa7d5e72 100644
--- a/src/shared/netif-naming-scheme.h
+++ b/src/shared/netif-naming-scheme.h
@@ -3,6 +3,8 @@
#include <stdbool.h>
+#include "sd-device.h"
+
#include "macro.h"
/* So here's the deal: net_id is supposed to be an exercise in providing stable names for network devices. However, we
@@ -103,3 +105,8 @@ NamePolicy name_policy_from_string(const char *p) _pure_;
const char *alternative_names_policy_to_string(NamePolicy p) _const_;
NamePolicy alternative_names_policy_from_string(const char *p) _pure_;
+
+int device_get_sysattr_int_filtered(sd_device *device, const char *sysattr, int *ret_value);
+int device_get_sysattr_unsigned_filtered(sd_device *device, const char *sysattr, unsigned *ret_value);
+int device_get_sysattr_bool_filtered(sd_device *device, const char *sysattr);
+int device_get_sysattr_value_filtered(sd_device *device, const char *sysattr, const char **ret_value);
diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
index cecf854b98..c20df41c37 100644
--- a/src/udev/udev-builtin-net_id.c
+++ b/src/udev/udev-builtin-net_id.c
@@ -177,11 +177,11 @@ static int dev_pci_onboard(sd_device *dev, const LinkInfo *info, NetNames *names
assert(names);
/* ACPI _DSM — device specific method for naming a PCI or PCI Express device */
- if (sd_device_get_sysattr_value(names->pcidev, "acpi_index", &attr) >= 0)
+ if (device_get_sysattr_value_filtered(names->pcidev, "acpi_index", &attr) >= 0)
log_device_debug(names->pcidev, "acpi_index=%s", attr);
else {
/* SMBIOS type 41 — Onboard Devices Extended Information */
- r = sd_device_get_sysattr_value(names->pcidev, "index", &attr);
+ r = device_get_sysattr_value_filtered(names->pcidev, "index", &attr);
if (r < 0)
return r;
log_device_debug(names->pcidev, "index=%s", attr);
@@ -199,7 +199,7 @@ static int dev_pci_onboard(sd_device *dev, const LinkInfo *info, NetNames *names
"Not a valid onboard index: %lu", idx);
/* kernel provided port index for multiple ports on a single PCI function */
- if (sd_device_get_sysattr_value(dev, "dev_port", &attr) >= 0) {
+ if (device_get_sysattr_value_filtered(dev, "dev_port", &attr) >= 0) {
r = safe_atolu_full(attr, 10, &dev_port);
if (r < 0)
log_device_debug_errno(dev, r, "Failed to parse dev_port, ignoring: %m");
@@ -223,7 +223,7 @@ static int dev_pci_onboard(sd_device *dev, const LinkInfo *info, NetNames *names
idx, strempty(info->phys_port_name), dev_port,
special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), empty_to_na(names->pci_onboard));
- if (sd_device_get_sysattr_value(names->pcidev, "label", &names->pci_onboard_label) >= 0)
+ if (device_get_sysattr_value_filtered(names->pcidev, "label", &names->pci_onboard_label) >= 0)
log_device_debug(dev, "Onboard label from PCI device: %s", names->pci_onboard_label);
else
names->pci_onboard_label = NULL;
@@ -260,7 +260,7 @@ static int is_pci_multifunction(sd_device *dev) {
static bool is_pci_ari_enabled(sd_device *dev) {
const char *a;
- if (sd_device_get_sysattr_value(dev, "ari_enabled", &a) < 0)
+ if (device_get_sysattr_value_filtered(dev, "ari_enabled", &a) < 0)
return false;
return streq(a, "1");
@@ -269,7 +269,7 @@ static bool is_pci_ari_enabled(sd_device *dev) {
static bool is_pci_bridge(sd_device *dev) {
const char *v, *p;
- if (sd_device_get_sysattr_value(dev, "modalias", &v) < 0)
+ if (device_get_sysattr_value_filtered(dev, "modalias", &v) < 0)
return false;
if (!startswith(v, "pci:"))
@@ -309,7 +309,7 @@ static int parse_hotplug_slot_from_function_id(sd_device *dev, int slots_dirfd,
if (!naming_scheme_has(NAMING_SLOT_FUNCTION_ID))
return 0;
- if (sd_device_get_sysattr_value(dev, "function_id", &attr) < 0)
+ if (device_get_sysattr_value_filtered(dev, "function_id", &attr) < 0)
return 0;
r = safe_atou64(attr, &function_id);
@@ -366,7 +366,7 @@ static int dev_pci_slot(sd_device *dev, const LinkInfo *info, NetNames *names) {
func += slot * 8;
/* kernel provided port index for multiple ports on a single PCI function */
- if (sd_device_get_sysattr_value(dev, "dev_port", &attr) >= 0) {
+ if (device_get_sysattr_value_filtered(dev, "dev_port", &attr) >= 0) {
log_device_debug(dev, "dev_port=%s", attr);
r = safe_atolu_full(attr, 10, &dev_port);
@@ -378,7 +378,7 @@ static int dev_pci_slot(sd_device *dev, const LinkInfo *info, NetNames *names) {
* which thus stays initialized as 0. */
if (dev_port == 0 &&
info->iftype == ARPHRD_INFINIBAND &&
- sd_device_get_sysattr_value(dev, "dev_id", &attr) >= 0) {
+ device_get_sysattr_value_filtered(dev, "dev_id", &attr) >= 0) {
log_device_debug(dev, "dev_id=%s", attr);
r = safe_atolu_full(attr, 10, &dev_port);
@@ -449,7 +449,7 @@ static int dev_pci_slot(sd_device *dev, const LinkInfo *info, NetNames *names) {
if (!path)
return -ENOMEM;
- if (sd_device_get_sysattr_value(pci, path, &address) < 0)
+ if (device_get_sysattr_value_filtered(pci, path, &address) < 0)
continue;
/* match slot address with device by stripping the function */
@@ -674,7 +674,7 @@ static int dev_devicetree_onboard(sd_device *dev, NetNames *names) {
if (!alias_index)
continue;
- if (sd_device_get_sysattr_value(aliases_dev, alias, &alias_path) < 0)
+ if (device_get_sysattr_value_filtered(aliases_dev, alias, &alias_path) < 0)
continue;
if (!path_equal(ofnode_path, alias_path))
@@ -693,7 +693,7 @@ static int dev_devicetree_onboard(sd_device *dev, NetNames *names) {
}
/* ...but make sure we don't have an alias conflict */
- if (i == 0 && sd_device_get_sysattr_value(aliases_dev, conflict, NULL) >= 0)
+ if (i == 0 && device_get_sysattr_value_filtered(aliases_dev, conflict, NULL) >= 0)
return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EEXIST),
"Ethernet alias conflict: ethernet and ethernet0 both exist");
@@ -944,7 +944,7 @@ static int names_mac(sd_device *dev, const LinkInfo *info) {
info->hw_addr.length);
/* check for NET_ADDR_PERM, skip random MAC addresses */
- r = sd_device_get_sysattr_value(dev, "addr_assign_type", &s);
+ r = device_get_sysattr_value_filtered(dev, "addr_assign_type", &s);
if (r < 0)
return log_device_debug_errno(dev, r, "Failed to read addr_assign_type: %m");
r = safe_atou(s, &i);
@@ -1080,11 +1080,11 @@ static int get_link_info(sd_device *dev, LinkInfo *info) {
if (r < 0)
return r;
- r = device_get_sysattr_int(dev, "iflink", &info->iflink);
+ r = device_get_sysattr_int_filtered(dev, "iflink", &info->iflink);
if (r < 0)
return r;
- r = device_get_sysattr_int(dev, "type", &info->iftype);
+ r = device_get_sysattr_int_filtered(dev, "type", &info->iftype);
if (r < 0)
return r;
@@ -1092,12 +1092,12 @@ static int get_link_info(sd_device *dev, LinkInfo *info) {
if (r < 0 && r != -ENOENT)
return r;
- r = sd_device_get_sysattr_value(dev, "phys_port_name", &info->phys_port_name);
+ r = device_get_sysattr_value_filtered(dev, "phys_port_name", &info->phys_port_name);
if (r >= 0)
/* Check if phys_port_name indicates virtual device representor */
(void) sscanf(info->phys_port_name, "pf%*uvf%d", &info->vf_representor_id);
- r = sd_device_get_sysattr_value(dev, "address", &s);
+ r = device_get_sysattr_value_filtered(dev, "address", &s);
if (r < 0 && r != -ENOENT)
return r;
if (r >= 0) {

@ -0,0 +1,38 @@
From c5e8c8163c5063d7cc0a376022380f46a9d18ab0 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Wed, 20 Dec 2023 15:08:49 +0900
Subject: [PATCH] man: environment value -> udev property
These are not environment variables, but udev properties.
Follow-up for 3b2e7dc5a285edbbb1bf6aed2d88b889d801613f.
(cherry picked from commit 044149e6152db7a8bb293aac19e84b3b06566d63)
Resolves: RHEL-1317
---
man/systemd.net-naming-scheme.xml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/man/systemd.net-naming-scheme.xml b/man/systemd.net-naming-scheme.xml
index ec9f3da437..639c03262f 100644
--- a/man/systemd.net-naming-scheme.xml
+++ b/man/systemd.net-naming-scheme.xml
@@ -601,7 +601,7 @@
<varlistentry>
<term><varname>ID_NET_NAME_ALLOW=<replaceable>BOOL</replaceable></varname></term>
- <listitem><para>This evironment value sets a fallback policy for reading a sysfs attribute.
+ <listitem><para>This udev property sets a fallback policy for reading a sysfs attribute.
If set to <constant>0</constant> udev will not read any sysfs attribute by default, unless it is
explicitly allowlisted, see below. If set to <constant>1</constant> udev can use any sysfs attribute
unless it is explicitly forbidden. The default value is <constant>1</constant>.</para>
@@ -612,7 +612,7 @@
<varlistentry>
<term><varname>ID_NET_NAME_ALLOW_<replaceable>sysfsattr</replaceable>=<replaceable>BOOL</replaceable></varname></term>
- <listitem><para>This evironment value explicitly states if udev shall use the specified
+ <listitem><para>This udev property explicitly states if udev shall use the specified
<replaceable>sysfsattr</replaceable>, when composing the device name.</para>
</listitem>

@ -0,0 +1,50 @@
From 58b968fc319f227fde22725f862063010c1c4138 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Tue, 12 Dec 2023 19:03:39 +0100
Subject: [PATCH] logind: don't setup idle session watch for lock-screen and
greeter
Reason to skip the idle session logic for these session classes is that
they are idle by default.
(cherry picked from commit 508b4786e8592e82eb4832549f74aaa54335d14c)
Related: RHEL-20757
---
man/logind.conf.xml | 9 +++++----
src/login/logind-session.c | 2 +-
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/man/logind.conf.xml b/man/logind.conf.xml
index 1a87cf6baf..55cbabaafb 100644
--- a/man/logind.conf.xml
+++ b/man/logind.conf.xml
@@ -348,10 +348,11 @@
<term><varname>StopIdleSessionSec=</varname></term>
<listitem><para>Specifies a timeout in seconds, or a time span value after which
- <filename>systemd-logind</filename> checks the idle state of all sessions. Every session that is idle for
- longer then the timeout will be stopped. Defaults to <literal>infinity</literal>
- (<filename>systemd-logind</filename> is not checking the idle state of sessions). For details about the syntax
- of time spans, see
+ <filename>systemd-logind</filename> checks the idle state of all sessions. Every session that is idle
+ for longer than the timeout will be stopped. Note that this option doesn't apply to
+ <literal>greeter</literal> or <literal>lock-screen</literal> sessions. Defaults to
+ <literal>infinity</literal> (<filename>systemd-logind</filename> is not checking the idle state
+ of sessions). For details about the syntax of time spans, see
<citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
</para></listitem>
</varlistentry>
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index 709a585013..68c2aa9670 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -735,7 +735,7 @@ static int session_setup_stop_on_idle_timer(Session *s) {
assert(s);
- if (s->manager->stop_idle_session_usec == USEC_INFINITY)
+ if (s->manager->stop_idle_session_usec == USEC_INFINITY || IN_SET(s->class, SESSION_GREETER, SESSION_LOCK_SCREEN))
return 0;
r = sd_event_add_time_relative(

@ -0,0 +1,33 @@
From 51dba4b4c93298e32442c88cd0bce7715eea289d Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 29 Nov 2023 11:07:08 +0100
Subject: [PATCH] logind: don't make idle action timer accuracy more coarse
than timeout
If we allow the timer accuracy to grow larger then the timeout itself
things are very confusing, because people might set a 1s time-out and we
turn that into 30s.
Hence, let's just cut off the 30s accuracy to the time-out itself, so
that we stay close to what users configured.
(cherry picked from commit e20bfa5005ab5458837bb62cb35bc1687f25124f)
Related: RHEL-20757
---
src/login/logind.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/login/logind.c b/src/login/logind.c
index 0348b19c05..70f72387c5 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -989,7 +989,7 @@ static int manager_dispatch_idle_action(sd_event_source *s, uint64_t t, void *us
m->event,
&m->idle_action_event_source,
CLOCK_MONOTONIC,
- elapse, USEC_PER_SEC*30,
+ elapse, MIN(USEC_PER_SEC*30, m->idle_action_usec), /* accuracy of 30s, but don't have an accuracy lower than the idle action timeout */
manager_dispatch_idle_action, m);
if (r < 0)
return log_error_errno(r, "Failed to add idle event source: %m");

@ -0,0 +1,58 @@
From 468acdce5f4c6e5eaca7f348280e2491130e8d6d Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 29 Nov 2023 11:09:20 +0100
Subject: [PATCH] logind: do TTY idle logic only for sessions marked as "tty"
Otherwise things might be weird, because background sessions might
become "idle", wich doesn#t really make much sense.
This shouldn't change much in 99% of the cases, but slightly corrects
behaviour as it ensures only "primary"/"foreground" sessions get the
idle logic, i.e. where a user exists that could actually make it
non-idle.
(cherry picked from commit 20604ff219cf4027f4ee9ca9ba7c0b9e72aec448)
Related: RHEL-20757
---
src/login/logind-session.c | 26 ++++++++++++++------------
1 file changed, 14 insertions(+), 12 deletions(-)
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index 68c2aa9670..af5817e2b6 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -1029,19 +1029,21 @@ int session_get_idle_hint(Session *s, dual_timestamp *t) {
return s->idle_hint;
}
- /* For sessions with an explicitly configured tty, let's check its atime */
- if (s->tty) {
- r = get_tty_atime(s->tty, &atime);
- if (r >= 0)
- goto found_atime;
- }
+ if (s->type == SESSION_TTY) {
+ /* For sessions with an explicitly configured tty, let's check its atime */
+ if (s->tty) {
+ r = get_tty_atime(s->tty, &atime);
+ if (r >= 0)
+ goto found_atime;
+ }
- /* For sessions with a leader but no explicitly configured tty, let's check the controlling tty of
- * the leader */
- if (pid_is_valid(s->leader)) {
- r = get_process_ctty_atime(s->leader, &atime);
- if (r >= 0)
- goto found_atime;
+ /* For sessions with a leader but no explicitly configured tty, let's check the controlling tty of
+ * the leader */
+ if (pid_is_valid(s->leader)) {
+ r = get_process_ctty_atime(s->leader, &atime);
+ if (r >= 0)
+ goto found_atime;
+ }
}
if (t)

@ -0,0 +1,32 @@
From f36dfb7ec1c780bdb74a4879fcce4be63adbaa6e Mon Sep 17 00:00:00 2001
From: Jan Janssen <medhefgo@web.de>
Date: Fri, 27 Jan 2023 14:28:58 +0100
Subject: [PATCH] meson: Properly install 90-uki-copy.install
(cherry picked from commit 4c181c1a33ef4de0130a131a2b332348dda672ed)
Resolves: RHEL-16354
---
src/kernel-install/meson.build | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/kernel-install/meson.build b/src/kernel-install/meson.build
index 68a4d43862..2ff62d5935 100644
--- a/src/kernel-install/meson.build
+++ b/src/kernel-install/meson.build
@@ -3,10 +3,13 @@
kernel_install_in = files('kernel-install.in')
loaderentry_install = files('90-loaderentry.install')
-uki_copy_install = files('90-uki-copy.install')
+kernel_install_files = files(
+ '50-depmod.install',
+ '90-uki-copy.install',
+)
if want_kernel_install
- install_data('50-depmod.install',
+ install_data(kernel_install_files,
loaderentry_install,
install_mode : 'rwxr-xr-x',
install_dir : kernelinstalldir)

@ -0,0 +1,189 @@
From bf287f49fab60f47dd2547cdc3653fed53af3b21 Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Fri, 12 Jan 2024 15:25:14 +0100
Subject: [PATCH] ci: use source-git-automation composite Action
This will allow us maintain the source-git automation in separate repo
and reduce the duplication of the code and noise in the systemd repo.
rhel-only
Related: RHEL-1086
---
.../source-git-automation-on-demand.yml | 61 ++--------------
.github/workflows/source-git-automation.yml | 72 ++-----------------
2 files changed, 12 insertions(+), 121 deletions(-)
diff --git a/.github/workflows/source-git-automation-on-demand.yml b/.github/workflows/source-git-automation-on-demand.yml
index 3f3da959c4..90149e74bb 100644
--- a/.github/workflows/source-git-automation-on-demand.yml
+++ b/.github/workflows/source-git-automation-on-demand.yml
@@ -1,5 +1,3 @@
----
-
name: Source git Automation Scheduled/On Demand
on:
schedule:
@@ -59,62 +57,17 @@ jobs:
matrix:
pr-number: ${{ inputs.pr-number == 0 && fromJSON(needs.gather-pull-requests.outputs.pr-numbers) || fromJSON(needs.gather-pull-requests.outputs.pr-numbers-manual) }}
- permissions: write-all
- # contents: write
- # statuses: write
- # checks: write
- # pull-requests: write
+ permissions:
+ # required for merging PRs
+ contents: write
+ # required for PR comments and setting labels
+ pull-requests: write
steps:
- - name: Repository checkout
- uses: actions/checkout@v3
-
- - id: metadata
- name: Gather Pull Request Metadata
- uses: redhat-plumbers-in-action/gather-pull-request-metadata@v1
+ - name: Source-git Automation
+ uses: redhat-plumbers-in-action/source-git-automation@v1
with:
pr-number: ${{ matrix.pr-number }}
-
- - if: ${{ !cancelled() }}
- id: commit-linter
- name: Lint Commits
- uses: redhat-plumbers-in-action/advanced-commit-linter@v2
- with:
- pr-metadata: ${{ steps.metadata.outputs.metadata }}
- token: ${{ secrets.GITHUB_TOKEN }}
-
- # Validates tracker, changes tracker status, updates PR title
- - if: ${{ !cancelled() }}
- id: tracker-validator
- name: Validate Tracker
- uses: redhat-plumbers-in-action/tracker-validator@v1
- with:
- pr-metadata: ${{ steps.metadata.outputs.metadata }}
- component: systemd
- tracker: ${{ fromJSON(steps.commit-linter.outputs.validated-pr-metadata).validation.tracker.id }}
- tracker-type: ${{ fromJSON(steps.commit-linter.outputs.validated-pr-metadata).validation.tracker.type }}
- bugzilla-instance: https://bugzilla.redhat.com
- bugzilla-api-token: ${{ secrets.BUGZILLA_API_TOKEN }}
- jira-instance: https://issues.redhat.com
- jira-api-token: ${{ secrets.JIRA_API_TOKEN }}
- token: ${{ secrets.GITHUB_TOKEN }}
-
- - if: ${{ !cancelled() }}
- name: Pull Request Validator
- uses: redhat-plumbers-in-action/pull-request-validator@v1
- with:
- pr-metadata: ${{ steps.metadata.outputs.metadata }}
- token: ${{ secrets.GITHUB_TOKEN }}
-
- - id: auto-merge
- name: Auto Merge
- uses: redhat-plumbers-in-action/auto-merge@v1
- with:
- pr-metadata: ${{ steps.metadata.outputs.metadata }}
- tracker: ${{ fromJSON(steps.commit-linter.outputs.validated-pr-metadata).validation.tracker.id }}
- tracker-type: ${{ fromJSON(steps.commit-linter.outputs.validated-pr-metadata).validation.tracker.type }}
- bugzilla-instance: https://bugzilla.redhat.com
bugzilla-api-token: ${{ secrets.BUGZILLA_API_TOKEN }}
- jira-instance: https://issues.redhat.com
jira-api-token: ${{ secrets.JIRA_API_TOKEN }}
token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/source-git-automation.yml b/.github/workflows/source-git-automation.yml
index 17135b590f..776ac5b237 100644
--- a/.github/workflows/source-git-automation.yml
+++ b/.github/workflows/source-git-automation.yml
@@ -26,83 +26,21 @@ jobs:
with:
name: pr-metadata
- commit-linter:
+ source-git-automation:
needs: [ download-metadata ]
runs-on: ubuntu-latest
- outputs:
- validated-pr-metadata: ${{ steps.commit-linter.outputs.validated-pr-metadata }}
-
- permissions:
- statuses: write
- checks: write
- pull-requests: write
-
- steps:
- - id: commit-linter
- name: Lint Commits
- uses: redhat-plumbers-in-action/advanced-commit-linter@v2
- with:
- pr-metadata: ${{ needs.download-metadata.outputs.pr-metadata }}
- token: ${{ secrets.GITHUB_TOKEN }}
-
- # Validates tracker, changes tracker status, updates PR title
- tracker-validator:
- if: ${{ !cancelled() }}
- needs: [ download-metadata, commit-linter ]
- runs-on: ubuntu-latest
-
- permissions:
- checks: write
- pull-requests: write
-
- steps:
- - name: Validate Tracker
- uses: redhat-plumbers-in-action/tracker-validator@v1
- with:
- pr-metadata: ${{ needs.download-metadata.outputs.pr-metadata }}
- component: systemd
- tracker: ${{ fromJSON(needs.commit-linter.outputs.validated-pr-metadata).validation.tracker.id }}
- tracker-type: ${{ fromJSON(needs.commit-linter.outputs.validated-pr-metadata).validation.tracker.type }}
- bugzilla-instance: https://bugzilla.redhat.com
- bugzilla-api-token: ${{ secrets.BUGZILLA_API_TOKEN }}
- jira-instance: https://issues.redhat.com
- jira-api-token: ${{ secrets.JIRA_API_TOKEN }}
- token: ${{ secrets.GITHUB_TOKEN }}
-
- pull-request-validator:
- needs: [ download-metadata ]
- runs-on: ubuntu-latest
-
- permissions:
- checks: write
- pull-requests: write
-
- steps:
- - name: Pull Request Validator
- uses: redhat-plumbers-in-action/pull-request-validator@v1
- with:
- pr-metadata: ${{ needs.download-metadata.outputs.pr-metadata }}
- token: ${{ secrets.GITHUB_TOKEN }}
-
- auto-merge:
- needs: [ download-metadata, commit-linter, tracker-validator, pull-request-validator ]
- runs-on: ubuntu-latest
-
permissions:
+ # required for merging PRs
contents: write
- checks: write
+ # required for PR comments and setting labels
pull-requests: write
steps:
- - name: Auto Merge
- uses: redhat-plumbers-in-action/auto-merge@v1
+ - name: Source-git Automation
+ uses: redhat-plumbers-in-action/source-git-automation@v1
with:
pr-metadata: ${{ needs.download-metadata.outputs.pr-metadata }}
- tracker: ${{ fromJSON(needs.commit-linter.outputs.validated-pr-metadata).validation.tracker.id }}
- tracker-type: ${{ fromJSON(needs.commit-linter.outputs.validated-pr-metadata).validation.tracker.type }}
- bugzilla-instance: https://bugzilla.redhat.com
bugzilla-api-token: ${{ secrets.BUGZILLA_API_TOKEN }}
- jira-instance: https://issues.redhat.com
jira-api-token: ${{ secrets.JIRA_API_TOKEN }}
token: ${{ secrets.GITHUB_TOKEN }}

@ -0,0 +1,29 @@
From 5f98f309ccc71db57b93392c4f6427df620b8f53 Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Fri, 12 Jan 2024 15:27:56 +0100
Subject: [PATCH] ci: increase the cron interval to 45 minutes
This should help us to avoid hitting the rate limit on the GitHub API.
rhel-only
Related: RHEL-1086
---
.github/workflows/source-git-automation-on-demand.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/source-git-automation-on-demand.yml b/.github/workflows/source-git-automation-on-demand.yml
index 90149e74bb..b5ccb891d1 100644
--- a/.github/workflows/source-git-automation-on-demand.yml
+++ b/.github/workflows/source-git-automation-on-demand.yml
@@ -1,8 +1,8 @@
name: Source git Automation Scheduled/On Demand
on:
schedule:
- # Workflow runs every 15 minutes
- - cron: '*/15 * * * *'
+ # Workflow runs every 45 minutes
+ - cron: '*/45 * * * *'
workflow_dispatch:
inputs:
pr-number:

@ -0,0 +1,39 @@
From 5701905d024afc00a650ff2f2461570497694edb Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Fri, 12 Jan 2024 15:32:27 +0100
Subject: [PATCH] ci: add all Z-Stream versions to array of allowed versions
rhel-only
Related: RHEL-1086
---
.github/tracker-validator.yml | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/.github/tracker-validator.yml b/.github/tracker-validator.yml
index 9e43e4e7d5..f88cc0a572 100644
--- a/.github/tracker-validator.yml
+++ b/.github/tracker-validator.yml
@@ -7,12 +7,22 @@ products:
- Red Hat Enterprise Linux 9
- CentOS Stream 9
- rhel-9.0.0
+ - rhel-9.0.0.z
- rhel-9.2.0
+ - rhel-9.2.0.z
- rhel-9.3.0
+ - rhel-9.3.0.z
- rhel-9.4.0
+ - rhel-9.4.0.z
- rhel-9.5.0
+ - rhel-9.5.0.z
- rhel-9.6.0
+ - rhel-9.6.0.z
- rhel-9.7.0
+ - rhel-9.7.0.z
- rhel-9.8.0
+ - rhel-9.8.0.z
- rhel-9.9.0
+ - rhel-9.9.0.z
- rhel-9.10.0
+ - rhel-9.10.0.z

@ -0,0 +1,55 @@
From 63b7060ef28895ce56bb058912e8e81bd00b8395 Mon Sep 17 00:00:00 2001
From: Jan Macku <jamacku@redhat.com>
Date: Tue, 23 Jan 2024 15:23:05 +0100
Subject: [PATCH] udev/net_id: introduce naming scheme for RHEL-9.4
rhel-only
Resolves: RHEL-22427
---
man/systemd.net-naming-scheme.xml | 6 ++++++
src/shared/netif-naming-scheme.c | 1 +
src/shared/netif-naming-scheme.h | 1 +
3 files changed, 8 insertions(+)
diff --git a/man/systemd.net-naming-scheme.xml b/man/systemd.net-naming-scheme.xml
index 639c03262f..4f06587ec9 100644
--- a/man/systemd.net-naming-scheme.xml
+++ b/man/systemd.net-naming-scheme.xml
@@ -582,6 +582,12 @@
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><constant>rhel-9.4</constant></term>
+
+ <listitem><para>Same as naming scheme <constant>rhel-9.3</constant>.</para></listitem>
+ </varlistentry>
+
</variablelist>
<para>Note that <constant>latest</constant> may be used to denote the latest scheme known (to this
diff --git a/src/shared/netif-naming-scheme.c b/src/shared/netif-naming-scheme.c
index e73c265371..bf27f5571b 100644
--- a/src/shared/netif-naming-scheme.c
+++ b/src/shared/netif-naming-scheme.c
@@ -42,6 +42,7 @@ static const NamingScheme naming_schemes[] = {
{ "rhel-9.1", NAMING_RHEL_9_1 },
{ "rhel-9.2", NAMING_RHEL_9_2 },
{ "rhel-9.3", NAMING_RHEL_9_3 },
+ { "rhel-9.4", NAMING_RHEL_9_4 },
/* … add more schemes here, as the logic to name devices is updated … */
EXTRA_NET_NAMING_MAP
diff --git a/src/shared/netif-naming-scheme.h b/src/shared/netif-naming-scheme.h
index 3baa7d5e72..f39c75c64e 100644
--- a/src/shared/netif-naming-scheme.h
+++ b/src/shared/netif-naming-scheme.h
@@ -70,6 +70,7 @@ typedef enum NamingSchemeFlags {
NAMING_RHEL_9_1 = NAMING_RHEL_9_0,
NAMING_RHEL_9_2 = NAMING_RHEL_9_0,
NAMING_RHEL_9_3 = NAMING_RHEL_9_0 | NAMING_SR_IOV_R,
+ NAMING_RHEL_9_4 = NAMING_RHEL_9_3,
EXTRA_NET_NAMING_SCHEMES

@ -0,0 +1,204 @@
From 690c7cdadd1033bfb47e8de5cc9db781a6055e2a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Wed, 9 Aug 2023 16:36:38 +0200
Subject: [PATCH] basic/errno-util: add wrappers which only accept negative
errno
We do 'IN_SET(r, -CONST1, -CONST2)', instead of 'IN_SET(-r, CONST1, CONST2)'
because -r is undefined if r is the minimum value (i.e. INT_MIN). But we know
that the constants are small, so their negative values are fine.
(cherry picked from commit b0be985cdd5e51f5f16d6bf541435c225f7c0633)
Related: RHEL-22443
---
src/basic/errno-util.h | 129 +++++++++++++++++++++----------------
src/test/test-errno-util.c | 7 ++
2 files changed, 80 insertions(+), 56 deletions(-)
diff --git a/src/basic/errno-util.h b/src/basic/errno-util.h
index 091f99c590..be5c04e285 100644
--- a/src/basic/errno-util.h
+++ b/src/basic/errno-util.h
@@ -84,12 +84,21 @@ static inline int errno_or_else(int fallback) {
return -abs(fallback);
}
+/* abs(3) says: Trying to take the absolute value of the most negative integer is not defined. */
+#define _DEFINE_ABS_WRAPPER(name) \
+ static inline bool ERRNO_IS_##name(int r) { \
+ if (r == INT_MIN) \
+ return false; \
+ return ERRNO_IS_NEG_##name(-abs(r)); \
+ }
+
/* For send()/recv() or read()/write(). */
-static inline bool ERRNO_IS_TRANSIENT(int r) {
- return IN_SET(abs(r),
- EAGAIN,
- EINTR);
+static inline bool ERRNO_IS_NEG_TRANSIENT(int r) {
+ return IN_SET(r,
+ -EAGAIN,
+ -EINTR);
}
+_DEFINE_ABS_WRAPPER(TRANSIENT);
/* Hint #1: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5.
*
@@ -98,79 +107,87 @@ static inline bool ERRNO_IS_TRANSIENT(int r) {
*
* Hint #3: When asynchronous connect() on TCP fails because the host never acknowledges a single packet,
* kernel tells us that with ETIMEDOUT, see tcp(7). */
-static inline bool ERRNO_IS_DISCONNECT(int r) {
- return IN_SET(abs(r),
- ECONNABORTED,
- ECONNREFUSED,
- ECONNRESET,
- EHOSTDOWN,
- EHOSTUNREACH,
- ENETDOWN,
- ENETRESET,
- ENETUNREACH,
- ENONET,
- ENOPROTOOPT,
- ENOTCONN,
- EPIPE,
- EPROTO,
- ESHUTDOWN,
- ETIMEDOUT);
+static inline bool ERRNO_IS_NEG_DISCONNECT(int r) {
+ return IN_SET(r,
+ -ECONNABORTED,
+ -ECONNREFUSED,
+ -ECONNRESET,
+ -EHOSTDOWN,
+ -EHOSTUNREACH,
+ -ENETDOWN,
+ -ENETRESET,
+ -ENETUNREACH,
+ -ENONET,
+ -ENOPROTOOPT,
+ -ENOTCONN,
+ -EPIPE,
+ -EPROTO,
+ -ESHUTDOWN,
+ -ETIMEDOUT);
}
+_DEFINE_ABS_WRAPPER(DISCONNECT);
/* Transient errors we might get on accept() that we should ignore. As per error handling comment in
* the accept(2) man page. */
-static inline bool ERRNO_IS_ACCEPT_AGAIN(int r) {
- return ERRNO_IS_DISCONNECT(r) ||
- ERRNO_IS_TRANSIENT(r) ||
- abs(r) == EOPNOTSUPP;
+static inline bool ERRNO_IS_NEG_ACCEPT_AGAIN(int r) {
+ return ERRNO_IS_NEG_DISCONNECT(r) ||
+ ERRNO_IS_NEG_TRANSIENT(r) ||
+ r == -EOPNOTSUPP;
}
+_DEFINE_ABS_WRAPPER(ACCEPT_AGAIN);
/* Resource exhaustion, could be our fault or general system trouble */
-static inline bool ERRNO_IS_RESOURCE(int r) {
- return IN_SET(abs(r),
- EMFILE,
- ENFILE,
- ENOMEM);
+static inline bool ERRNO_IS_NEG_RESOURCE(int r) {
+ return IN_SET(r,
+ -EMFILE,
+ -ENFILE,
+ -ENOMEM);
}
+_DEFINE_ABS_WRAPPER(RESOURCE);
/* Seven different errors for "operation/system call/ioctl/socket feature not supported" */
-static inline bool ERRNO_IS_NOT_SUPPORTED(int r) {
- return IN_SET(abs(r),
- EOPNOTSUPP,
- ENOTTY,
- ENOSYS,
- EAFNOSUPPORT,
- EPFNOSUPPORT,
- EPROTONOSUPPORT,
- ESOCKTNOSUPPORT);
+static inline bool ERRNO_IS_NEG_NOT_SUPPORTED(int r) {
+ return IN_SET(r,
+ -EOPNOTSUPP,
+ -ENOTTY,
+ -ENOSYS,
+ -EAFNOSUPPORT,
+ -EPFNOSUPPORT,
+ -EPROTONOSUPPORT,
+ -ESOCKTNOSUPPORT);
}
+_DEFINE_ABS_WRAPPER(NOT_SUPPORTED);
/* Two different errors for access problems */
-static inline bool ERRNO_IS_PRIVILEGE(int r) {
- return IN_SET(abs(r),
- EACCES,
- EPERM);
+static inline bool ERRNO_IS_NEG_PRIVILEGE(int r) {
+ return IN_SET(r,
+ -EACCES,
+ -EPERM);
}
+_DEFINE_ABS_WRAPPER(PRIVILEGE);
/* Three different errors for "not enough disk space" */
-static inline bool ERRNO_IS_DISK_SPACE(int r) {
- return IN_SET(abs(r),
- ENOSPC,
- EDQUOT,
- EFBIG);
+static inline bool ERRNO_IS_NEG_DISK_SPACE(int r) {
+ return IN_SET(r,
+ -ENOSPC,
+ -EDQUOT,
+ -EFBIG);
}
+_DEFINE_ABS_WRAPPER(DISK_SPACE);
/* Three different errors for "this device does not quite exist" */
-static inline bool ERRNO_IS_DEVICE_ABSENT(int r) {
- return IN_SET(abs(r),
- ENODEV,
- ENXIO,
- ENOENT);
+static inline bool ERRNO_IS_NEG_DEVICE_ABSENT(int r) {
+ return IN_SET(r,
+ -ENODEV,
+ -ENXIO,
+ -ENOENT);
}
+_DEFINE_ABS_WRAPPER(DEVICE_ABSENT);
/* Quite often we want to handle cases where the backing FS doesn't support extended attributes at all and
* where it simply doesn't have the requested xattr the same way */
-static inline bool ERRNO_IS_XATTR_ABSENT(int r) {
- return abs(r) == ENODATA ||
- ERRNO_IS_NOT_SUPPORTED(r);
+static inline bool ERRNO_IS_NEG_XATTR_ABSENT(int r) {
+ return r == -ENODATA ||
+ ERRNO_IS_NEG_NOT_SUPPORTED(r);
}
+_DEFINE_ABS_WRAPPER(XATTR_ABSENT);
diff --git a/src/test/test-errno-util.c b/src/test/test-errno-util.c
index f858927c92..507d53df7a 100644
--- a/src/test/test-errno-util.c
+++ b/src/test/test-errno-util.c
@@ -47,4 +47,11 @@ TEST(STRERROR_OR_ELSE) {
log_info("STRERROR_OR_ELSE(-EPERM, \"EOF\") → %s", STRERROR_OR_EOF(-EPERM));
}
+TEST(ERRNO_IS_TRANSIENT) {
+ assert_se( ERRNO_IS_NEG_TRANSIENT(-EINTR));
+ assert_se(!ERRNO_IS_NEG_TRANSIENT(EINTR));
+ assert_se( ERRNO_IS_TRANSIENT(-EINTR));
+ assert_se( ERRNO_IS_TRANSIENT(EINTR));
+}
+
DEFINE_TEST_MAIN(LOG_INFO);

@ -0,0 +1,148 @@
From 7c5ece0b649ebea23ebb28eb3cafdb28ba49a9d0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Wed, 9 Aug 2023 18:21:13 +0200
Subject: [PATCH] errno-util: allow ERRNO_IS_* to accept types wider than int
This is useful if the variable is ssize_t and we don't want to trigger a
warning or truncation.
With gcc (gcc-13.2.1-1.fc38.x86_64), the resulting systemd binary is identical,
so I assume that the compiler is able to completely optimize away the type.
(cherry picked from commit fe0feacb9e9641874fde459af4067d9b7e9d7462)
Related: RHEL-22443
---
src/basic/errno-util.h | 27 +++++++++++++++------------
src/test/test-errno-util.c | 13 +++++++++++++
2 files changed, 28 insertions(+), 12 deletions(-)
diff --git a/src/basic/errno-util.h b/src/basic/errno-util.h
index be5c04e285..b10dd755c9 100644
--- a/src/basic/errno-util.h
+++ b/src/basic/errno-util.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
+#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
@@ -86,14 +87,16 @@ static inline int errno_or_else(int fallback) {
/* abs(3) says: Trying to take the absolute value of the most negative integer is not defined. */
#define _DEFINE_ABS_WRAPPER(name) \
- static inline bool ERRNO_IS_##name(int r) { \
- if (r == INT_MIN) \
+ static inline bool ERRNO_IS_##name(intmax_t r) { \
+ if (r == INTMAX_MIN) \
return false; \
- return ERRNO_IS_NEG_##name(-abs(r)); \
+ return ERRNO_IS_NEG_##name(-imaxabs(r)); \
}
+assert_cc(INT_MAX <= INTMAX_MAX);
+
/* For send()/recv() or read()/write(). */
-static inline bool ERRNO_IS_NEG_TRANSIENT(int r) {
+static inline bool ERRNO_IS_NEG_TRANSIENT(intmax_t r) {
return IN_SET(r,
-EAGAIN,
-EINTR);
@@ -107,7 +110,7 @@ _DEFINE_ABS_WRAPPER(TRANSIENT);
*
* Hint #3: When asynchronous connect() on TCP fails because the host never acknowledges a single packet,
* kernel tells us that with ETIMEDOUT, see tcp(7). */
-static inline bool ERRNO_IS_NEG_DISCONNECT(int r) {
+static inline bool ERRNO_IS_NEG_DISCONNECT(intmax_t r) {
return IN_SET(r,
-ECONNABORTED,
-ECONNREFUSED,
@@ -129,7 +132,7 @@ _DEFINE_ABS_WRAPPER(DISCONNECT);
/* Transient errors we might get on accept() that we should ignore. As per error handling comment in
* the accept(2) man page. */
-static inline bool ERRNO_IS_NEG_ACCEPT_AGAIN(int r) {
+static inline bool ERRNO_IS_NEG_ACCEPT_AGAIN(intmax_t r) {
return ERRNO_IS_NEG_DISCONNECT(r) ||
ERRNO_IS_NEG_TRANSIENT(r) ||
r == -EOPNOTSUPP;
@@ -137,7 +140,7 @@ static inline bool ERRNO_IS_NEG_ACCEPT_AGAIN(int r) {
_DEFINE_ABS_WRAPPER(ACCEPT_AGAIN);
/* Resource exhaustion, could be our fault or general system trouble */
-static inline bool ERRNO_IS_NEG_RESOURCE(int r) {
+static inline bool ERRNO_IS_NEG_RESOURCE(intmax_t r) {
return IN_SET(r,
-EMFILE,
-ENFILE,
@@ -146,7 +149,7 @@ static inline bool ERRNO_IS_NEG_RESOURCE(int r) {
_DEFINE_ABS_WRAPPER(RESOURCE);
/* Seven different errors for "operation/system call/ioctl/socket feature not supported" */
-static inline bool ERRNO_IS_NEG_NOT_SUPPORTED(int r) {
+static inline bool ERRNO_IS_NEG_NOT_SUPPORTED(intmax_t r) {
return IN_SET(r,
-EOPNOTSUPP,
-ENOTTY,
@@ -159,7 +162,7 @@ static inline bool ERRNO_IS_NEG_NOT_SUPPORTED(int r) {
_DEFINE_ABS_WRAPPER(NOT_SUPPORTED);
/* Two different errors for access problems */
-static inline bool ERRNO_IS_NEG_PRIVILEGE(int r) {
+static inline bool ERRNO_IS_NEG_PRIVILEGE(intmax_t r) {
return IN_SET(r,
-EACCES,
-EPERM);
@@ -167,7 +170,7 @@ static inline bool ERRNO_IS_NEG_PRIVILEGE(int r) {
_DEFINE_ABS_WRAPPER(PRIVILEGE);
/* Three different errors for "not enough disk space" */
-static inline bool ERRNO_IS_NEG_DISK_SPACE(int r) {
+static inline bool ERRNO_IS_NEG_DISK_SPACE(intmax_t r) {
return IN_SET(r,
-ENOSPC,
-EDQUOT,
@@ -176,7 +179,7 @@ static inline bool ERRNO_IS_NEG_DISK_SPACE(int r) {
_DEFINE_ABS_WRAPPER(DISK_SPACE);
/* Three different errors for "this device does not quite exist" */
-static inline bool ERRNO_IS_NEG_DEVICE_ABSENT(int r) {
+static inline bool ERRNO_IS_NEG_DEVICE_ABSENT(intmax_t r) {
return IN_SET(r,
-ENODEV,
-ENXIO,
@@ -186,7 +189,7 @@ _DEFINE_ABS_WRAPPER(DEVICE_ABSENT);
/* Quite often we want to handle cases where the backing FS doesn't support extended attributes at all and
* where it simply doesn't have the requested xattr the same way */
-static inline bool ERRNO_IS_NEG_XATTR_ABSENT(int r) {
+static inline bool ERRNO_IS_NEG_XATTR_ABSENT(intmax_t r) {
return r == -ENODATA ||
ERRNO_IS_NEG_NOT_SUPPORTED(r);
}
diff --git a/src/test/test-errno-util.c b/src/test/test-errno-util.c
index 507d53df7a..cac0d5402b 100644
--- a/src/test/test-errno-util.c
+++ b/src/test/test-errno-util.c
@@ -52,6 +52,19 @@ TEST(ERRNO_IS_TRANSIENT) {
assert_se(!ERRNO_IS_NEG_TRANSIENT(EINTR));
assert_se( ERRNO_IS_TRANSIENT(-EINTR));
assert_se( ERRNO_IS_TRANSIENT(EINTR));
+
+ /* Test with type wider than int */
+ ssize_t r = -EAGAIN;
+ assert_se( ERRNO_IS_NEG_TRANSIENT(r));
+
+ /* On 64-bit arches, now (int) r == EAGAIN */
+ r = SSIZE_MAX - EAGAIN + 1;
+ assert_se(!ERRNO_IS_NEG_TRANSIENT(r));
+
+ assert_se(!ERRNO_IS_NEG_TRANSIENT(INT_MAX));
+ assert_se(!ERRNO_IS_NEG_TRANSIENT(INT_MIN));
+ assert_se(!ERRNO_IS_NEG_TRANSIENT(INTMAX_MAX));
+ assert_se(!ERRNO_IS_NEG_TRANSIENT(INTMAX_MIN));
}
DEFINE_TEST_MAIN(LOG_INFO);

@ -0,0 +1,184 @@
From f2bf171137c348f6f976276504c8e8a54e33ff78 Mon Sep 17 00:00:00 2001
From: Lukas Nykryn <lnykryn@redhat.com>
Date: Thu, 19 Oct 2023 10:38:06 +0200
Subject: [PATCH] udev: add new builtin net_driver
Currently the ID_NET_DRIVER is set in net_setup_link builtin.
But this is called pretty late in the udev processing chain.
Right now in some custom rules it was workarounded by calling ethtool
binary directly, which is ugly.
So let's split this code to a separate builtin.
(cherry picked from commit 2b5b25f123ceb89b3ff45b2380db1c8a88b046d9)
Resolves: RHEL-22443
---
rules.d/50-udev-default.rules.in | 2 ++
src/udev/meson.build | 1 +
src/udev/net/link-config.c | 5 ++-
src/udev/net/link-config.h | 2 +-
src/udev/udev-builtin-net_driver.c | 43 ++++++++++++++++++++++++++
src/udev/udev-builtin-net_setup_link.c | 3 --
src/udev/udev-builtin.c | 1 +
src/udev/udev-builtin.h | 2 ++
8 files changed, 52 insertions(+), 7 deletions(-)
create mode 100644 src/udev/udev-builtin-net_driver.c
diff --git a/rules.d/50-udev-default.rules.in b/rules.d/50-udev-default.rules.in
index 843bdaf9ce..f670b51987 100644
--- a/rules.d/50-udev-default.rules.in
+++ b/rules.d/50-udev-default.rules.in
@@ -17,6 +17,8 @@ SUBSYSTEM=="rtc", KERNEL=="rtc0", SYMLINK+="rtc", OPTIONS+="link_priority=-100"
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", IMPORT{builtin}="usb_id", IMPORT{builtin}="hwdb --subsystem=usb"
ENV{MODALIAS}!="", IMPORT{builtin}="hwdb --subsystem=$env{SUBSYSTEM}"
+SUBSYSTEM=="net", IMPORT{builtin}="net_driver"
+
ACTION!="add", GOTO="default_end"
SUBSYSTEM=="tty", KERNEL=="ptmx", GROUP="tty", MODE="0666"
diff --git a/src/udev/meson.build b/src/udev/meson.build
index 08a1d97e81..564aa6de1b 100644
--- a/src/udev/meson.build
+++ b/src/udev/meson.build
@@ -35,6 +35,7 @@ libudevd_core_sources = files(
'udev-builtin-hwdb.c',
'udev-builtin-input_id.c',
'udev-builtin-keyboard.c',
+ 'udev-builtin-net_driver.c',
'udev-builtin-net_id.c',
'udev-builtin-net_setup_link.c',
'udev-builtin-path_id.c',
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
index 2d8c902fd3..80c64519ab 100644
--- a/src/udev/net/link-config.c
+++ b/src/udev/net/link-config.c
@@ -362,7 +362,6 @@ Link *link_free(Link *link) {
sd_device_unref(link->device);
free(link->kind);
- free(link->driver);
strv_free(link->altnames);
return mfree(link);
}
@@ -415,8 +414,8 @@ int link_new(LinkConfigContext *ctx, sd_netlink **rtnl, sd_device *device, Link
log_link_debug_errno(link, r, "Failed to get permanent hardware address, ignoring: %m");
}
- r = ethtool_get_driver(&ctx->ethtool_fd, link->ifname, &link->driver);
- if (r < 0)
+ r = sd_device_get_property_value(link->device, "ID_NET_DRIVER", &link->driver);
+ if (r < 0 && r != -ENOENT)
log_link_debug_errno(link, r, "Failed to get driver, ignoring: %m");
*ret = TAKE_PTR(link);
diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h
index 874a391543..8343783caf 100644
--- a/src/udev/net/link-config.h
+++ b/src/udev/net/link-config.h
@@ -34,7 +34,7 @@ typedef struct Link {
sd_device_action_t action;
char *kind;
- char *driver;
+ const char *driver;
uint16_t iftype;
uint32_t flags;
struct hw_addr_data hw_addr;
diff --git a/src/udev/udev-builtin-net_driver.c b/src/udev/udev-builtin-net_driver.c
new file mode 100644
index 0000000000..f1642a491d
--- /dev/null
+++ b/src/udev/udev-builtin-net_driver.c
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "alloc-util.h"
+#include "device-util.h"
+#include "errno-util.h"
+#include "ethtool-util.h"
+#include "fd-util.h"
+#include "log.h"
+#include "string-util.h"
+#include "udev-builtin.h"
+
+static int builtin_net_driver_set_driver(UdevEvent *event, int argc, char **argv, bool test) {
+ sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
+ _cleanup_close_ int ethtool_fd = -EBADF;
+ _cleanup_free_ char *driver = NULL;
+ const char *sysname;
+ int r;
+
+ r = sd_device_get_sysname(dev, &sysname);
+ if (r < 0)
+ return log_device_warning_errno(dev, r, "Failed to get sysname: %m");
+
+ r = ethtool_get_driver(&ethtool_fd, sysname, &driver);
+ if (ERRNO_IS_NEG_NOT_SUPPORTED(r)) {
+ log_device_debug_errno(dev, r, "Querying driver name via ethtool API is not supported by device '%s', ignoring: %m", sysname);
+ return 0;
+ }
+ if (r == -ENODEV) {
+ log_device_debug_errno(dev, r, "Device already vanished, ignoring.");
+ return 0;
+ }
+ if (r < 0)
+ return log_device_warning_errno(dev, r, "Failed to get driver for '%s': %m", sysname);
+
+ return udev_builtin_add_property(event->dev, test, "ID_NET_DRIVER", driver);
+}
+
+const UdevBuiltin udev_builtin_net_driver = {
+ .name = "net_driver",
+ .cmd = builtin_net_driver_set_driver,
+ .help = "Set driver for network device",
+ .run_once = true,
+};
diff --git a/src/udev/udev-builtin-net_setup_link.c b/src/udev/udev-builtin-net_setup_link.c
index e964bf7bf4..b0279a1814 100644
--- a/src/udev/udev-builtin-net_setup_link.c
+++ b/src/udev/udev-builtin-net_setup_link.c
@@ -26,9 +26,6 @@ static int builtin_net_setup_link(UdevEvent *event, int argc, char **argv, bool
if (r < 0)
return log_device_warning_errno(dev, r, "Failed to get link information: %m");
- if (link->driver)
- udev_builtin_add_property(dev, test, "ID_NET_DRIVER", link->driver);
-
r = link_get_config(ctx, link);
if (r < 0) {
if (r == -ENOENT) {
diff --git a/src/udev/udev-builtin.c b/src/udev/udev-builtin.c
index c84db8855c..d55dc3337d 100644
--- a/src/udev/udev-builtin.c
+++ b/src/udev/udev-builtin.c
@@ -22,6 +22,7 @@ static const UdevBuiltin *const builtins[_UDEV_BUILTIN_MAX] = {
#if HAVE_KMOD
[UDEV_BUILTIN_KMOD] = &udev_builtin_kmod,
#endif
+ [UDEV_BUILTIN_NET_DRIVER] = &udev_builtin_net_driver,
[UDEV_BUILTIN_NET_ID] = &udev_builtin_net_id,
[UDEV_BUILTIN_NET_LINK] = &udev_builtin_net_setup_link,
[UDEV_BUILTIN_PATH_ID] = &udev_builtin_path_id,
diff --git a/src/udev/udev-builtin.h b/src/udev/udev-builtin.h
index 919d51e798..c23f2d1613 100644
--- a/src/udev/udev-builtin.h
+++ b/src/udev/udev-builtin.h
@@ -19,6 +19,7 @@ typedef enum UdevBuiltinCommand {
#if HAVE_KMOD
UDEV_BUILTIN_KMOD,
#endif
+ UDEV_BUILTIN_NET_DRIVER,
UDEV_BUILTIN_NET_ID,
UDEV_BUILTIN_NET_LINK,
UDEV_BUILTIN_PATH_ID,
@@ -63,6 +64,7 @@ extern const UdevBuiltin udev_builtin_keyboard;
#if HAVE_KMOD
extern const UdevBuiltin udev_builtin_kmod;
#endif
+extern const UdevBuiltin udev_builtin_net_driver;
extern const UdevBuiltin udev_builtin_net_id;
extern const UdevBuiltin udev_builtin_net_setup_link;
extern const UdevBuiltin udev_builtin_path_id;

@ -0,0 +1,55 @@
From 9ff108d83a19557593c1d0f1687878377e898a54 Mon Sep 17 00:00:00 2001
From: Lukas Nykryn <lnykryn@redhat.com>
Date: Wed, 24 Jan 2024 13:49:21 +0100
Subject: [PATCH] udev/net_id: introduce naming scheme for RHEL-8.10
rhel-only
Resolves: RHEL-22427
---
man/systemd.net-naming-scheme.xml | 6 ++++++
src/shared/netif-naming-scheme.c | 1 +
src/shared/netif-naming-scheme.h | 1 +
3 files changed, 8 insertions(+)
diff --git a/man/systemd.net-naming-scheme.xml b/man/systemd.net-naming-scheme.xml
index 4f06587ec9..3bab402e98 100644
--- a/man/systemd.net-naming-scheme.xml
+++ b/man/systemd.net-naming-scheme.xml
@@ -547,6 +547,12 @@
<para>Same as naming scheme <constant>rhel-8.7</constant>.</para>
</varlistentry>
+ <varlistentry>
+ <term><constant>rhel-8.10</constant></term>
+
+ <para>Same as naming scheme <constant>rhel-8.7</constant>.</para>
+ </varlistentry>
+
<varlistentry>
<term><constant>rhel-9.0</constant></term>
diff --git a/src/shared/netif-naming-scheme.c b/src/shared/netif-naming-scheme.c
index bf27f5571b..536ed44b21 100644
--- a/src/shared/netif-naming-scheme.c
+++ b/src/shared/netif-naming-scheme.c
@@ -38,6 +38,7 @@ static const NamingScheme naming_schemes[] = {
{ "rhel-8.7", NAMING_RHEL_8_7 },
{ "rhel-8.8", NAMING_RHEL_8_8 },
{ "rhel-8.9", NAMING_RHEL_8_9 },
+ { "rhel-8.10", NAMING_RHEL_8_10 },
{ "rhel-9.0", NAMING_RHEL_9_0 },
{ "rhel-9.1", NAMING_RHEL_9_1 },
{ "rhel-9.2", NAMING_RHEL_9_2 },
diff --git a/src/shared/netif-naming-scheme.h b/src/shared/netif-naming-scheme.h
index f39c75c64e..5f49157aaa 100644
--- a/src/shared/netif-naming-scheme.h
+++ b/src/shared/netif-naming-scheme.h
@@ -65,6 +65,7 @@ typedef enum NamingSchemeFlags {
NAMING_RHEL_8_7 = NAMING_RHEL_8_4 | NAMING_SLOT_FUNCTION_ID | NAMING_16BIT_INDEX,
NAMING_RHEL_8_8 = NAMING_RHEL_8_7,
NAMING_RHEL_8_9 = NAMING_RHEL_8_7,
+ NAMING_RHEL_8_10 = NAMING_RHEL_8_7,
NAMING_RHEL_9_0 = NAMING_V250 | NAMING_BRIDGE_MULTIFUNCTION_SLOT,
NAMING_RHEL_9_1 = NAMING_RHEL_9_0,

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save