diff --git a/.semaphore/semaphore-runner.sh b/.semaphore/semaphore-runner.sh
index 4a37ee20149..87ba3a694d2 100755
--- a/.semaphore/semaphore-runner.sh
+++ b/.semaphore/semaphore-runner.sh
@@ -11,7 +11,8 @@ SALSA_URL="${SALSA_URL:-https://salsa.debian.org/systemd-team/systemd.git}"
BRANCH="${BRANCH:-upstream-ci}"
ARCH="${ARCH:-amd64}"
CONTAINER="${RELEASE}-${ARCH}"
-CACHE_DIR="${SEMAPHORE_CACHE_DIR:-/tmp}"
+CACHE_DIR=/var/tmp
+TMPDIR=/var/tmp
AUTOPKGTEST_DIR="${CACHE_DIR}/autopkgtest"
# semaphore cannot expose these, but useful for interactive/local runs
ARTIFACTS_DIR=/tmp/artifacts
@@ -64,7 +65,7 @@ for phase in "${PHASES[@]}"; do
sudo apt-get install -y -t "$UBUNTU_RELEASE-backports" lxc
sudo apt-get install -y python3-debian git dpkg-dev fakeroot python3-jinja2
- [ -d "$AUTOPKGTEST_DIR" ] || git clone --quiet --branch=debian/5.32 --depth=1 https://salsa.debian.org/ci-team/autopkgtest.git "$AUTOPKGTEST_DIR"
+ [ -d "$AUTOPKGTEST_DIR" ] || git clone --quiet --depth=1 https://salsa.debian.org/ci-team/autopkgtest.git "$AUTOPKGTEST_DIR"
create_container
;;
@@ -91,7 +92,7 @@ EOF
# disable autopkgtests which are not for upstream
sed -i '/# NOUPSTREAM/ q' debian/tests/control
# enable more unit tests
- sed -i '/^CONFFLAGS =/ s/=/= --werror -Dtests=unsafe -Dsplit-usr=true -Dslow-tests=true -Dfuzz-tests=true -Dman=true /' debian/rules
+ sed -i '/^CONFFLAGS =/ s/=/= --werror -Dsplit-usr=true /' debian/rules
# no orig tarball
echo '1.0' > debian/source/format
@@ -101,8 +102,11 @@ EOF
# now build the package and run the tests
rm -rf "$ARTIFACTS_DIR"
# autopkgtest exits with 2 for "some tests skipped", accept that
- sudo "$AUTOPKGTEST_DIR/runner/autopkgtest" --env DEB_BUILD_OPTIONS=noudeb \
- --env TEST_UPSTREAM=1 ../systemd_*.dsc \
+ sudo TMPDIR=/var/tmp "$AUTOPKGTEST_DIR/runner/autopkgtest" --env DEB_BUILD_OPTIONS="noudeb nostrip nodoc optimize=-lto" \
+ --env DPKG_DEB_COMPRESSOR_TYPE="none" \
+ --env DEB_BUILD_PROFILES="noudeb nodoc" \
+ --env TEST_UPSTREAM=1 \
+ ../systemd_*.dsc \
-o "$ARTIFACTS_DIR" \
-- lxc -s "$CONTAINER" \
|| [ $? -eq 2 ]
diff --git a/hwdb.d/60-evdev.hwdb b/hwdb.d/60-evdev.hwdb
index 0b70a82093c..372ae682ed7 100644
--- a/hwdb.d/60-evdev.hwdb
+++ b/hwdb.d/60-evdev.hwdb
@@ -255,6 +255,13 @@ evdev:input:b0003v0ED1p7821*
# Dell
#########################################
+# Dell AlpsPS/2 ALPS DualPoint TouchPad
+evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:*:svnDellInc.*:pnLatitudeE7440*:
+ EVDEV_ABS_00=:::28
+ EVDEV_ABS_01=:::28
+ EVDEV_ABS_35=:::28
+ EVDEV_ABS_36=:::28
+
# Dell Vostro 1510
evdev:name:AlpsPS/2 ALPS GlidePoint*:dmi:bvn*:bvr*:bd*:svnDellInc.:pnVostro1510:*
EVDEV_ABS_00=::14
diff --git a/hwdb.d/60-keyboard.hwdb b/hwdb.d/60-keyboard.hwdb
index 15c0d4ca31f..5a089316360 100644
--- a/hwdb.d/60-keyboard.hwdb
+++ b/hwdb.d/60-keyboard.hwdb
@@ -223,7 +223,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnPackard*Bell*:pn*:*
# Swift SF314-511
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnSwiftSF314-511:pvr*
- KEYBOARD_KEY_8a=f20 # Fn+F12, microphone mute
+ KEYBOARD_KEY_8a=f20 # Fn+F12, microphone mute
# Predator PHN16-71
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnPredatorPHN16-71:*
@@ -231,6 +231,10 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnPredatorPHN16-71:*
KEYBOARD_KEY_f5=prog1 # "predator sense" button
KEYBOARD_KEY_66=micmute # Microphone mute button
+# Predator PHN16-72
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnPredatorPHN16-72:*
+ KEYBOARD_KEY_66=micmute # Microphone mute button
+
# Nitro AN515-58
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnNitro*AN*515-58:pvr*
KEYBOARD_KEY_8a=f20 # Microphone mute button
@@ -259,7 +263,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAlienware*:pnM17xR3:*
# Aquarius Cmp NS483
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAquarius*:pnCmp*NS483*:*
KEYBOARD_KEY_56=backslash
- KEYBOARD_KEY_76=f21 # Touchpad Toggle
+ KEYBOARD_KEY_76=f21 # Touchpad Toggle
###########################################################
# Asus
@@ -341,6 +345,9 @@ evdev:atkbd:dmi:bvn*:bvr*:svnNotebook:pnV54x_6x_TU:*
KEYBOARD_KEY_f7=f21 # Touchpad Toggle
KEYBOARD_KEY_f8=f21 # Touchpad Toggle
+evdev:atkbd:dmi:bvn*:bvr*:svnNotebook:pnV5xTNC_TND_TNE:*
+ KEYBOARD_KEY_81=f20 # Fn+4; Mic Mute
+
###########################################################
# Compal
###########################################################
@@ -973,7 +980,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnJP-IK:pnLEAPW502:pvr*
# LE14U/LE15U
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnKVADRA*:pn*LE1*U*:*
- KEYBOARD_KEY_76=f21 # Fn+F1 Toggle touchpad, sends meta+ctrl+toggle
+ KEYBOARD_KEY_76=f21 # Fn+F1 Toggle touchpad, sends meta+ctrl+toggle
###########################################################
# Lenovo
@@ -1901,9 +1908,9 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*700T*:*
# Galaxy Book (2021) NP750XDA-KD4SE
evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn750XDA:pvr*
KEYBOARD_KEY_81=!esc
- KEYBOARD_KEY_ce=!prog1 # Fn+F1 launch settings
- KEYBOARD_KEY_ae=!volumedown # Fn+F7 volume down
- KEYBOARD_KEY_b0=!volumeup # Fn+F8 volume up
+ KEYBOARD_KEY_ce=!prog1 # Fn+F1 launch settings
+ KEYBOARD_KEY_ae=!volumedown # Fn+F7 volume down
+ KEYBOARD_KEY_b0=!volumeup # Fn+F8 volume up
###########################################################
@@ -2028,13 +2035,13 @@ evdev:name:Toshiba*input*device:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*P75-A:
# Portege Z830 ACPI quickstart buttons
evdev:name:Quickstart Button 1:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnPORTEGEZ830:*
- KEYBOARD_KEY_1=prog1 # TOSHIBA eco button
+ KEYBOARD_KEY_1=prog1 # TOSHIBA eco button
evdev:name:Quickstart Button 2:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnPORTEGEZ830:*
- KEYBOARD_KEY_1=prog2 # TOSHIBA Presentation button
+ KEYBOARD_KEY_1=prog2 # TOSHIBA Presentation button
evdev:name:Quickstart Button 3:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnPORTEGEZ830:*
- KEYBOARD_KEY_1=f21 # Touchpad toggle
+ KEYBOARD_KEY_1=f21 # Touchpad toggle
###########################################################
# VIA
@@ -2067,11 +2074,11 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnINET:pnP325J:*
# Home: LeftCtrl + Esc -> LeftMeta (ignore LeftCtrl, map Esc to LeftMeta)
# Back: Backspace -> back (map backspace to back)
evdev:name:FTSC1000:00 2808:509C Keyboard:dmi:*:svnXiaomiInc:pnMipad2:*
- KEYBOARD_KEY_700e0=unknown # LeftCtrl -> ignore
- KEYBOARD_KEY_700e3=unknown # LeftMeta -> ignore
- KEYBOARD_KEY_70016=menu # S -> menu
- KEYBOARD_KEY_70029=leftmeta # Esc -> LeftMeta (Windows key / Win8 tablets home)
- KEYBOARD_KEY_7002a=back # Backspace -> back
+ KEYBOARD_KEY_700e0=unknown # LeftCtrl -> ignore
+ KEYBOARD_KEY_700e3=unknown # LeftMeta -> ignore
+ KEYBOARD_KEY_70016=menu # S -> menu
+ KEYBOARD_KEY_70029=leftmeta # Esc -> LeftMeta (Windows key / Win8 tablets home)
+ KEYBOARD_KEY_7002a=back # Backspace -> back
###########################################################
# Zepto
@@ -2183,7 +2190,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnViewSonic:pnVPAD10:*
evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:bvr*:bd*:svnPositivoBahia-VAIO:pnVJPW1[12]F11X*:pvr*:*
# Vaio FE14 (VJFE41F11X, VJE42F11X, VJFE44F11X, VJFE54F11X)
evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:bvr*:bd*:svnPositivoBahia-VAIO:pnVJFE*:pvr*:*
- KEYBOARD_KEY_76=f21 # Fn+F1 toggle touchpad
+ KEYBOARD_KEY_76=f21 # Fn+F1 toggle touchpad
###########################################################
# Positivo
@@ -2288,6 +2295,18 @@ evdev:input:b0003v05FEp1010*
#
# Presence of a LED is implicit when the property is absent.
+# Apple Wireless keyboards
+evdev:input:b0005v05aCp022C*
+evdev:input:b0005v05aCp022D*
+evdev:input:b0005v05aCp022E*
+evdev:input:b0005v05aCp0239*
+evdev:input:b0005v05aCp023A*
+evdev:input:b0005v05aCp023B*
+evdev:input:b0005v05aCp0255*
+evdev:input:b0005v05aCp0256*
+evdev:input:b0005v05aCp0257*
+ KEYBOARD_LED_NUMLOCK=0
+
# Logitech K750
evdev:input:b0003v046Dp4002*
KEYBOARD_LED_NUMLOCK=0
diff --git a/hwdb.d/60-sensor.hwdb b/hwdb.d/60-sensor.hwdb
index 21f4380dd08..80547834d24 100644
--- a/hwdb.d/60-sensor.hwdb
+++ b/hwdb.d/60-sensor.hwdb
@@ -152,6 +152,7 @@ sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:*pnM80TA:*
sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:*pnT100TA:*
sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:*pnT100TAF:*
sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:*pnT100TAM:*
+sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:*pnT100TAS:*
sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:pnT200TA:*
ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
@@ -163,6 +164,7 @@ sensor:modalias:acpi:INVN6500*:dmi:*svn*ASUSTeK*:*pn*TP300LA:*
sensor:modalias:acpi:INVN6500*:dmi:*svn*ASUSTeK*:*pn*TP300LD:*
ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
+sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:*pn*Q551LB:*
sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:*pn*Q551LN:*
ACCEL_MOUNT_MATRIX=0, 1, 0; -1, 0, 0; 0, 0, 1
diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml
index 1e12e8f6827..5bd38134603 100644
--- a/man/org.freedesktop.systemd1.xml
+++ b/man/org.freedesktop.systemd1.xml
@@ -2344,18 +2344,9 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
was already active).
ActiveState contains a state value that reflects whether the unit is currently
- active or not. The following states are currently defined: active,
- reloading, inactive, failed,
- activating, and deactivating. active indicates
- that unit is active (obviously...). reloading indicates that the unit is active and
- currently reloading its configuration. inactive indicates that it is inactive and
- the previous run was successful or no previous run has taken place yet. failed
- indicates that it is inactive and the previous run was not successful (more information about the
- reason for this is available on the unit type specific interfaces, for example for services in the
- Result property, see below). activating indicates that the unit
- has previously been inactive but is currently in the process of entering an active state. Conversely
- deactivating indicates that the unit is currently in the process of
- deactivation.
+ active or not. The following states are currently defined:
+
+
SubState encodes states of the same state machine that
ActiveState covers, but knows more fine-grained states that are
diff --git a/man/sd_bus_message_append_array.xml b/man/sd_bus_message_append_array.xml
index da72b78cb07..94bbb8be774 100644
--- a/man/sd_bus_message_append_array.xml
+++ b/man/sd_bus_message_append_array.xml
@@ -34,7 +34,7 @@
int sd_bus_message_append_array
sd_bus_message *m
char type
- void *ptr
+ const void *ptr
size_t size
diff --git a/man/systemctl.xml b/man/systemctl.xml
index 862609fe5af..cfaf8a8cb59 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -96,12 +96,15 @@ To show all installed unit files use 'systemctl list-unit-files'.The LOAD column shows the load state, one of loaded,
not-found, bad-setting, error,
- masked. The ACTIVE columns shows the general unit state, one of
- active, reloading, inactive,
- failed, activating, deactivating. The SUB
- column shows the unit-type-specific detailed state of the unit, possible values vary by unit type. The list
- of possible LOAD, ACTIVE, and SUB states is not constant and new systemd releases may both add and remove
- values. systemctl --state=help command maybe be used to display the
+ masked. The ACTIVE columns shows the general unit state, one of the
+ following:
+
+
+
+ The SUB column shows the unit-type-specific detailed state of the unit, possible values
+ vary by unit type. The list of possible LOAD, ACTIVE, and SUB states is not constant and new
+ systemd releases may both add and remove values.
+ systemctl --state=help command may be used to display the
current set of possible values.
This is the default command.
diff --git a/man/systemd.special.xml b/man/systemd.special.xml
index 85eb8ad0762..46a148bc1ba 100644
--- a/man/systemd.special.xml
+++ b/man/systemd.special.xml
@@ -229,6 +229,11 @@
names like single, rescue, 1,
3, 5, …; see
systemd1.
+
+ For typical unit files please set WantedBy= to a regular target (like
+ multi-user.target or graphical.target),
+ instead of default.target, since such a service will also be run on special
+ boots like on system update, emergency boot…
diff --git a/man/systemd.xml b/man/systemd.xml
index d292ceb5ab7..126382c4b0e 100644
--- a/man/systemd.xml
+++ b/man/systemd.xml
@@ -74,21 +74,12 @@
configuration files, whose syntax and basic set of options is
described in
systemd.unit5,
- however some are created automatically from other configuration
- files, dynamically from system state or programmatically at runtime.
- Units may be "active" (meaning started, bound, plugged in, …,
- depending on the unit type, see below), or "inactive" (meaning
- stopped, unbound, unplugged, …), as well as in the process of
- being activated or deactivated, i.e. between the two states (these
- states are called "activating", "deactivating"). A special
- "failed" state is available as well, which is very similar to
- "inactive" and is entered when the service failed in some way
- (process returned error code on exit, or crashed, an operation
- timed out, or after too many restarts). If this state is entered,
- the cause will be logged, for later reference. Note that the
- various unit types may have a number of additional substates,
- which are mapped to the five generalized unit states described
- here.
+ however some are created automatically from other configuration files, dynamically from system state or
+ programmatically at runtime. Units may be in a number of states, described in the following table. Note
+ that the various unit types may have a number of additional substates, which are mapped to the
+ generalized unit states described here.
+
+
The following unit types are available:
diff --git a/man/unit-states.xml b/man/unit-states.xml
new file mode 100644
index 00000000000..b772c3f19a7
--- /dev/null
+++ b/man/unit-states.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+ Unit ACTIVE states
+
+
+
+
+
+ State
+ Description
+
+
+
+
+ active
+ Started, bound, plugged in, …, depending on the unit type.
+
+
+ inactive
+ Stopped, unbound, unplugged, …, depending on the unit type.
+
+
+ failed
+ Similar to inactive, but the unit failed in some way (process returned error code on exit, crashed, an operation timed out, or after too many restarts).
+
+
+
+ activating
+ Changing from inactive to active.
+
+
+ deactivating
+ Changing from active to inactive.
+
+
+ maintenance
+ Unit is inactive and a maintenance operation is in progress.
+
+
+ reloading
+ Unit is active and it is reloading its configuration.
+
+
+
+
+
+
diff --git a/src/basic/audit-util.c b/src/basic/audit-util.c
index f2dce206b37..fb72e4ce336 100644
--- a/src/basic/audit-util.c
+++ b/src/basic/audit-util.c
@@ -101,7 +101,7 @@ static int try_audit_request(int fd) {
n = recvmsg_safe(fd, &mh, 0);
if (n < 0)
- return -errno;
+ return n;
if (n != NLMSG_LENGTH(sizeof(struct nlmsgerr)))
return -EIO;
diff --git a/src/basic/missing_loop.h b/src/basic/missing_loop.h
index 24b3e0def9f..e9c8bae6622 100644
--- a/src/basic/missing_loop.h
+++ b/src/basic/missing_loop.h
@@ -22,3 +22,7 @@ struct loop_config {
#ifndef LOOP_SET_STATUS_SETTABLE_FLAGS
#define LOOP_SET_STATUS_SETTABLE_FLAGS (LO_FLAGS_AUTOCLEAR | LO_FLAGS_PARTSCAN)
#endif
+
+#ifndef LOOP_SET_BLOCK_SIZE
+# define LOOP_SET_BLOCK_SIZE 0x4C09
+#endif
diff --git a/src/basic/os-util.c b/src/basic/os-util.c
index 8f8bb0881e9..27faf0a6eea 100644
--- a/src/basic/os-util.c
+++ b/src/basic/os-util.c
@@ -44,8 +44,9 @@ int path_is_extension_tree(const char *path, const char *extension, bool relax_e
/* Does the path exist at all? If not, generate an error immediately. This is useful so that a missing root dir
* always results in -ENOENT, and we can properly distinguish the case where the whole root doesn't exist from
* the case where just the os-release file is missing. */
- if (laccess(path, F_OK) < 0)
- return -errno;
+ r = laccess(path, F_OK);
+ if (r < 0)
+ return r;
/* We use /usr/lib/extension-release.d/extension-release[.NAME] as flag for something being a system extension,
* and {/etc|/usr/lib}/os-release as a flag for something being an OS (when not an extension). */
diff --git a/src/basic/path-lookup.c b/src/basic/path-lookup.c
index 36f386254b7..1fe4bb5fbdd 100644
--- a/src/basic/path-lookup.c
+++ b/src/basic/path-lookup.c
@@ -881,6 +881,7 @@ char **env_generator_binary_paths(bool is_system) {
int find_portable_profile(const char *name, const char *unit, char **ret_path) {
const char *p, *dot;
+ int r;
assert(name);
assert(ret_path);
@@ -894,13 +895,13 @@ int find_portable_profile(const char *name, const char *unit, char **ret_path) {
if (!joined)
return -ENOMEM;
- if (laccess(joined, F_OK) >= 0) {
+ r = laccess(joined, F_OK);
+ if (r >= 0) {
*ret_path = TAKE_PTR(joined);
return 0;
}
-
- if (errno != ENOENT)
- return -errno;
+ if (r != -ENOENT)
+ return r;
}
return -ENOENT;
diff --git a/src/basic/unit-def.c b/src/basic/unit-def.c
index 94cd603e32c..31d4dc8b1e3 100644
--- a/src/basic/unit-def.c
+++ b/src/basic/unit-def.c
@@ -96,6 +96,7 @@ static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState);
+/* Keep in sync with man/unit-states.xml */
static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = {
[UNIT_ACTIVE] = "active",
[UNIT_RELOADING] = "reloading",
diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
index 2c1828c3908..4663ae16b9e 100644
--- a/src/boot/efi/boot.c
+++ b/src/boot/efi/boot.c
@@ -1506,7 +1506,7 @@ static void config_entry_add_type1(
if (streq8(key, "architecture")) {
/* do not add an entry for an EFI image of architecture not matching with that of the image */
- if (!streq8(value, EFI_MACHINE_TYPE_NAME)) {
+ if (!strcaseeq8(value, EFI_MACHINE_TYPE_NAME)) {
entry->type = LOADER_UNDEFINED;
break;
}
diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
index ee4002f7b46..3a88769b6dc 100644
--- a/src/core/dbus-cgroup.c
+++ b/src/core/dbus-cgroup.c
@@ -1259,7 +1259,7 @@ int bus_cgroup_set_property(
for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++)
a->limits[type] = cgroup_io_limit_defaults[type];
- LIST_PREPEND(device_limits, c->io_device_limits, a);
+ LIST_APPEND(device_limits, c->io_device_limits, a);
}
a->limits[iol_type] = u64;
@@ -1338,7 +1338,7 @@ int bus_cgroup_set_property(
free(a);
return -ENOMEM;
}
- LIST_PREPEND(device_weights, c->io_device_weights, a);
+ LIST_APPEND(device_weights, c->io_device_weights, a);
}
a->weight = weight;
@@ -1411,7 +1411,7 @@ int bus_cgroup_set_property(
free(a);
return -ENOMEM;
}
- LIST_PREPEND(device_latencies, c->io_device_latencies, a);
+ LIST_APPEND(device_latencies, c->io_device_latencies, a);
}
a->target_usec = target;
@@ -1491,7 +1491,7 @@ int bus_cgroup_set_property(
return -ENOMEM;
}
- LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a);
+ LIST_APPEND(device_bandwidths, c->blockio_device_bandwidths, a);
}
if (read)
@@ -1585,7 +1585,7 @@ int bus_cgroup_set_property(
free(a);
return -ENOMEM;
}
- LIST_PREPEND(device_weights, c->blockio_device_weights, a);
+ LIST_APPEND(device_weights, c->blockio_device_weights, a);
}
a->weight = weight;
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 11166f9509d..224e41873c0 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -4237,7 +4237,7 @@ int config_parse_io_device_weight(
w->path = TAKE_PTR(resolved);
w->weight = u;
- LIST_PREPEND(device_weights, c->io_device_weights, w);
+ LIST_APPEND(device_weights, c->io_device_weights, w);
return 0;
}
@@ -4308,7 +4308,7 @@ int config_parse_io_device_latency(
l->path = TAKE_PTR(resolved);
l->target_usec = usec;
- LIST_PREPEND(device_latencies, c->io_device_latencies, l);
+ LIST_APPEND(device_latencies, c->io_device_latencies, l);
return 0;
}
@@ -4396,7 +4396,7 @@ int config_parse_io_limit(
for (ttype = 0; ttype < _CGROUP_IO_LIMIT_TYPE_MAX; ttype++)
l->limits[ttype] = cgroup_io_limit_defaults[ttype];
- LIST_PREPEND(device_limits, c->io_device_limits, l);
+ LIST_APPEND(device_limits, c->io_device_limits, l);
}
l->limits[type] = num;
@@ -4477,7 +4477,7 @@ int config_parse_blockio_device_weight(
w->path = TAKE_PTR(resolved);
w->weight = u;
- LIST_PREPEND(device_weights, c->blockio_device_weights, w);
+ LIST_APPEND(device_weights, c->blockio_device_weights, w);
return 0;
}
@@ -4564,7 +4564,7 @@ int config_parse_blockio_bandwidth(
b->rbps = CGROUP_LIMIT_MAX;
b->wbps = CGROUP_LIMIT_MAX;
- LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
+ LIST_APPEND(device_bandwidths, c->blockio_device_bandwidths, b);
}
if (read)
diff --git a/src/home/homework-luks.c b/src/home/homework-luks.c
index 16616b8be37..33644303362 100644
--- a/src/home/homework-luks.c
+++ b/src/home/homework-luks.c
@@ -1986,11 +1986,11 @@ static int wait_for_devlink(const char *path) {
_cleanup_free_ char *dn = NULL;
usec_t w;
- if (laccess(path, F_OK) < 0) {
- if (errno != ENOENT)
- return log_error_errno(errno, "Failed to determine whether %s exists: %m", path);
- } else
+ r = laccess(path, F_OK);
+ if (r >= 0)
return 0; /* Found it */
+ if (r != -ENOENT)
+ return log_error_errno(r, "Failed to determine whether %s exists: %m", path);
if (inotify_fd < 0) {
/* We need to wait for the device symlink to show up, let's create an inotify watch for it */
diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c
index 9b11b2f1606..3e7d412d7e4 100644
--- a/src/libsystemd-network/sd-ipv4acd.c
+++ b/src/libsystemd-network/sd-ipv4acd.c
@@ -396,6 +396,7 @@ static int ipv4acd_on_packet(
}
break;
+ case IPV4ACD_STATE_STARTED:
case IPV4ACD_STATE_WAITING_PROBE:
case IPV4ACD_STATE_PROBING:
case IPV4ACD_STATE_WAITING_ANNOUNCE:
diff --git a/src/libsystemd-network/test-dhcp-server.c b/src/libsystemd-network/test-dhcp-server.c
index 763ecb93df9..074f08eaea9 100644
--- a/src/libsystemd-network/test-dhcp-server.c
+++ b/src/libsystemd-network/test-dhcp-server.c
@@ -119,6 +119,7 @@ static void test_message_handler(void) {
.s_addr = htobe32(INADDR_LOOPBACK + 42),
};
static uint8_t static_lease_client_id[7] = {0x01, 'A', 'B', 'C', 'D', 'E', 'G' };
+ int r;
log_debug("/* %s */", __func__);
@@ -129,7 +130,10 @@ static void test_message_handler(void) {
assert_se(sd_dhcp_server_attach_event(server, NULL, 0) >= 0);
assert_se(sd_dhcp_server_start(server) >= 0);
- assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
+ r = dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test));
+ if (r == -ENETDOWN)
+ return (void) log_tests_skipped("Network is not available");
+ assert_se(r == DHCP_OFFER);
test.end = 0;
/* TODO, shouldn't this fail? */
diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c
index 199d10a00ea..82836de66b5 100644
--- a/src/libsystemd/sd-daemon/sd-daemon.c
+++ b/src/libsystemd/sd-daemon/sd-daemon.c
@@ -616,17 +616,18 @@ _public_ int sd_notifyf(int unset_environment, const char *format, ...) {
}
_public_ int sd_booted(void) {
- /* We test whether the runtime unit file directory has been
- * created. This takes place in mount-setup.c, so is
- * guaranteed to happen very early during boot. */
+ int r;
- if (laccess("/run/systemd/system/", F_OK) >= 0)
- return true;
+ /* We test whether the runtime unit file directory has been created. This takes place in mount-setup.c,
+ * so is guaranteed to happen very early during boot. */
- if (errno == ENOENT)
+ r = laccess("/run/systemd/system/", F_OK);
+ if (r >= 0)
+ return true;
+ if (r == -ENOENT)
return false;
- return -errno;
+ return r;
}
_public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c
index df2e203abd8..71926100d00 100644
--- a/src/libsystemd/sd-netlink/test-netlink.c
+++ b/src/libsystemd/sd-netlink/test-netlink.c
@@ -95,18 +95,24 @@ static void test_address_get(sd_netlink *rtnl, int ifindex) {
struct in_addr in_data;
struct ifa_cacheinfo cache;
const char *label;
+ int ret;
log_debug("/* %s */", __func__);
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_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);
+ ret = sd_netlink_call(rtnl, m, -1, &r);
+ assert_se(ret >= 0);
+
+ /* If the loopback device is down we won't get any results. */
+ if (ret > 0) {
+ 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);
+ }
}
static void test_route(sd_netlink *rtnl) {
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index b3e6867887a..afc3835e911 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -2264,7 +2264,7 @@ static int copy_devnodes(const char *dest) {
/* Explicitly warn the user when /dev is already populated. */
if (errno == EEXIST)
log_notice("%s/dev is pre-mounted and pre-populated. If a pre-mounted /dev is provided it needs to be an unpopulated file system.", dest);
- if (errno != EPERM)
+ if (errno != EPERM || arg_uid_shift != 0)
return log_error_errno(errno, "mknod(%s) failed: %m", to);
/* Some systems abusively restrict mknod but allow bind mounts. */
@@ -2274,12 +2274,12 @@ static int copy_devnodes(const char *dest) {
r = mount_nofollow_verbose(LOG_DEBUG, from, to, NULL, MS_BIND, NULL);
if (r < 0)
return log_error_errno(r, "Both mknod and bind mount (%s) failed: %m", to);
+ } else {
+ r = userns_lchown(to, 0, 0);
+ if (r < 0)
+ return log_error_errno(r, "chown() of device node %s failed: %m", to);
}
- r = userns_lchown(to, 0, 0);
- if (r < 0)
- return log_error_errno(r, "chown() of device node %s failed: %m", to);
-
dn = path_join("/dev", S_ISCHR(st.st_mode) ? "char" : "block");
if (!dn)
return log_oom();
diff --git a/src/partition/repart.c b/src/partition/repart.c
index 9ccacc42a7d..f22b8c69986 100644
--- a/src/partition/repart.c
+++ b/src/partition/repart.c
@@ -3291,13 +3291,13 @@ static int do_copy_files(Partition *p, const char *root) {
sfd, ".",
pfd, fn,
UID_INVALID, GID_INVALID,
- COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS);
+ COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_RESTORE_DIRECTORY_TIMESTAMPS);
} else
r = copy_tree_at(
sfd, ".",
tfd, ".",
UID_INVALID, GID_INVALID,
- COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS);
+ COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_RESTORE_DIRECTORY_TIMESTAMPS);
if (r < 0)
return log_error_errno(r, "Failed to copy '%s' to '%s%s': %m", *source, strempty(arg_root), *target);
} else {
@@ -5862,6 +5862,10 @@ static int run(int argc, char *argv[]) {
if (!context)
return log_oom();
+ r = context_read_seed(context, arg_root);
+ if (r < 0)
+ return r;
+
strv_uniq(arg_definitions);
r = context_read_definitions(context, arg_definitions, arg_root);
@@ -5926,10 +5930,6 @@ static int run(int argc, char *argv[]) {
putchar('\n');
#endif
- r = context_read_seed(context, arg_root);
- if (r < 0)
- return r;
-
/* Open all files to copy blocks from now, since we want to take their size into consideration */
r = context_open_copy_block_paths(
context,
diff --git a/src/portable/portable.c b/src/portable/portable.c
index 70f9071b352..91c5fb2173d 100644
--- a/src/portable/portable.c
+++ b/src/portable/portable.c
@@ -1083,8 +1083,12 @@ static int install_profile_dropin(
return -ENOMEM;
if (flags & PORTABLE_PREFER_COPY) {
+ CopyFlags copy_flags = COPY_REFLINK|COPY_FSYNC;
- r = copy_file_atomic(from, dropin, 0644, 0, 0, COPY_REFLINK|COPY_FSYNC);
+ if (flags & PORTABLE_FORCE_ATTACH)
+ copy_flags |= COPY_REPLACE;
+
+ r = copy_file_atomic(from, dropin, 0644, 0, 0, copy_flags);
if (r < 0)
return log_debug_errno(r, "Failed to copy %s %s %s: %m", from, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), dropin);
@@ -1092,8 +1096,12 @@ static int install_profile_dropin(
} else {
- if (symlink(from, dropin) < 0)
- return log_debug_errno(errno, "Failed to link %s %s %s: %m", from, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), dropin);
+ if (flags & PORTABLE_FORCE_ATTACH)
+ r = symlink_atomic(from, dropin);
+ else
+ r = RET_NERRNO(symlink(from, dropin));
+ if (r < 0)
+ return log_debug_errno(r, "Failed to link %s %s %s: %m", from, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), dropin);
(void) portable_changes_add(changes, n_changes, PORTABLE_SYMLINK, dropin, from);
}
@@ -1177,8 +1185,12 @@ static int attach_unit_file(
if ((flags & PORTABLE_PREFER_SYMLINK) && m->source) {
- if (symlink(m->source, path) < 0)
- return log_debug_errno(errno, "Failed to symlink unit file '%s': %m", path);
+ if (flags & PORTABLE_FORCE_ATTACH)
+ r = symlink_atomic(m->source, path);
+ else
+ r = RET_NERRNO(symlink(m->source, path));
+ if (r < 0)
+ return log_debug_errno(r, "Failed to symlink unit file '%s': %m", path);
(void) portable_changes_add(changes, n_changes, PORTABLE_SYMLINK, path, m->source);
@@ -1200,6 +1212,9 @@ static int attach_unit_file(
if (fchmod(fd, 0644) < 0)
return log_debug_errno(errno, "Failed to change unit file access mode for '%s': %m", path);
+ if (flags & PORTABLE_FORCE_ATTACH)
+ (void) unlink(path);
+
r = link_tmpfile(fd, tmp, path);
if (r < 0)
return log_debug_errno(r, "Failed to install unit file '%s': %m", path);
diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h
index 4a34ec9b901..fde49694991 100644
--- a/src/resolve/resolved-dns-packet.h
+++ b/src/resolve/resolved-dns-packet.h
@@ -111,6 +111,7 @@ static inline uint8_t* DNS_PACKET_DATA(const DnsPacket *p) {
#define DNS_PACKET_AD(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 5) & 1)
#define DNS_PACKET_CD(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 4) & 1)
+#define DNS_PACKET_FLAG_AD (UINT16_C(1) << 5)
#define DNS_PACKET_FLAG_TC (UINT16_C(1) << 9)
static inline uint16_t DNS_PACKET_RCODE(DnsPacket *p) {
diff --git a/src/resolve/resolved-dns-stub.c b/src/resolve/resolved-dns-stub.c
index 4e903f13f97..ffbb27dd98c 100644
--- a/src/resolve/resolved-dns-stub.c
+++ b/src/resolve/resolved-dns-stub.c
@@ -685,7 +685,8 @@ static int dns_stub_send_failure(
static int dns_stub_patch_bypass_reply_packet(
DnsPacket **ret, /* Where to place the patched packet */
DnsPacket *original, /* The packet to patch */
- DnsPacket *request) { /* The packet the patched packet shall look like a reply to */
+ DnsPacket *request, /* The packet the patched packet shall look like a reply to */
+ bool authenticated) {
_cleanup_(dns_packet_unrefp) DnsPacket *c = NULL;
int r;
@@ -725,6 +726,10 @@ static int dns_stub_patch_bypass_reply_packet(
DNS_PACKET_HEADER(c)->flags = htobe16(be16toh(DNS_PACKET_HEADER(c)->flags) | DNS_PACKET_FLAG_TC);
}
+ /* Ensure we don't pass along an untrusted ad flag for bypass packets */
+ if (!authenticated)
+ DNS_PACKET_HEADER(c)->flags = htobe16(be16toh(DNS_PACKET_HEADER(c)->flags) & ~DNS_PACKET_FLAG_AD);
+
*ret = TAKE_PTR(c);
return 0;
}
@@ -745,7 +750,8 @@ static void dns_stub_query_complete(DnsQuery *query) {
q->answer_full_packet->protocol == DNS_PROTOCOL_DNS) {
_cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL;
- r = dns_stub_patch_bypass_reply_packet(&reply, q->answer_full_packet, q->request_packet);
+ r = dns_stub_patch_bypass_reply_packet(&reply, q->answer_full_packet, q->request_packet,
+ FLAGS_SET(q->answer_query_flags, SD_RESOLVED_AUTHENTICATED));
if (r < 0)
log_debug_errno(r, "Failed to patch bypass reply packet: %m");
else
diff --git a/src/shared/bpf-dlopen.c b/src/shared/bpf-dlopen.c
index 808f8c0bb7d..9243162b50e 100644
--- a/src/shared/bpf-dlopen.c
+++ b/src/shared/bpf-dlopen.c
@@ -49,13 +49,13 @@ int dlopen_bpf(void) {
void *dl;
int r;
- dl = dlopen("libbpf.so.1", RTLD_LAZY);
+ dl = dlopen("libbpf.so.1", RTLD_NOW|RTLD_NODELETE);
if (!dl) {
/* libbpf < 1.0.0 (we rely on 0.1.0+) provide most symbols we care about, but
* unfortunately not all until 0.7.0. See bpf-compat.h for more details.
* Once we consider we can assume 0.7+ is present we can just use the same symbol
* list for both files, and when we assume 1.0+ is present we can remove this dlopen */
- dl = dlopen("libbpf.so.0", RTLD_LAZY);
+ dl = dlopen("libbpf.so.0", RTLD_NOW|RTLD_NODELETE);
if (!dl)
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"neither libbpf.so.1 nor libbpf.so.0 are installed: %s", dlerror());
diff --git a/src/shared/condition.c b/src/shared/condition.c
index b624f2ee31b..18c97f0ab58 100644
--- a/src/shared/condition.c
+++ b/src/shared/condition.c
@@ -172,10 +172,11 @@ static int condition_test_credential(Condition *c, char **env) {
if (!j)
return -ENOMEM;
- if (laccess(j, F_OK) >= 0)
+ r = laccess(j, F_OK);
+ if (r >= 0)
return true; /* yay! */
- if (errno != ENOENT)
- return -errno;
+ if (r != -ENOENT)
+ return r;
/* not found in this dir */
}
diff --git a/src/shared/copy.c b/src/shared/copy.c
index 64c61e15ab2..dc18ea0e20b 100644
--- a/src/shared/copy.c
+++ b/src/shared/copy.c
@@ -908,6 +908,7 @@ static int fd_copy_directory(
_cleanup_close_ int fdf = -1, fdt = -1;
_cleanup_closedir_ DIR *d = NULL;
+ struct stat dt_st;
bool exists, created;
int r;
@@ -966,6 +967,9 @@ static int fd_copy_directory(
if (fdt < 0)
return -errno;
+ if (exists && FLAGS_SET(copy_flags, COPY_RESTORE_DIRECTORY_TIMESTAMPS) && fstat(fdt, &dt_st) < 0)
+ return -errno;
+
r = 0;
FOREACH_DIRENT_ALL(de, d, return -errno) {
@@ -1050,7 +1054,9 @@ static int fd_copy_directory(
(void) copy_xattr(dirfd(d), fdt, copy_flags);
(void) futimens(fdt, (struct timespec[]) { st->st_atim, st->st_mtim });
- }
+ } else if (FLAGS_SET(copy_flags, COPY_RESTORE_DIRECTORY_TIMESTAMPS))
+ /* If the directory already exists, make sure the timestamps stay the same as before. */
+ (void) futimens(fdt, (struct timespec[]) { dt_st.st_atim, dt_st.st_mtim });
if (copy_flags & COPY_FSYNC_FULL) {
if (fsync(fdt) < 0)
diff --git a/src/shared/copy.h b/src/shared/copy.h
index d755916bd98..bdbe8ccc9c4 100644
--- a/src/shared/copy.h
+++ b/src/shared/copy.h
@@ -25,6 +25,7 @@ typedef enum CopyFlags {
COPY_SYNCFS = 1 << 12, /* syncfs() the *top-level* dir after we are done */
COPY_ALL_XATTRS = 1 << 13, /* Preserve all xattrs when copying, not just those in the user namespace */
COPY_HOLES = 1 << 14, /* Copy holes */
+ COPY_RESTORE_DIRECTORY_TIMESTAMPS = 1 << 15, /* Make sure existing directory timestamps don't change during copying. */
} CopyFlags;
typedef int (*copy_progress_bytes_t)(uint64_t n_bytes, void *userdata);
diff --git a/src/shared/dlfcn-util.c b/src/shared/dlfcn-util.c
index 8022f552943..2ebb1463c20 100644
--- a/src/shared/dlfcn-util.c
+++ b/src/shared/dlfcn-util.c
@@ -44,7 +44,7 @@ int dlopen_many_sym_or_warn_sentinel(void **dlp, const char *filename, int log_l
if (*dlp)
return 0; /* Already loaded */
- dl = dlopen(filename, RTLD_LAZY);
+ dl = dlopen(filename, RTLD_NOW|RTLD_NODELETE);
if (!dl)
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"%s is not installed: %s", filename, dlerror());
diff --git a/src/shared/idn-util.c b/src/shared/idn-util.c
index d9e0cca433e..38ed6267021 100644
--- a/src/shared/idn-util.c
+++ b/src/shared/idn-util.c
@@ -42,11 +42,11 @@ int dlopen_idn(void) {
if (idn_dl)
return 0; /* Already loaded */
- dl = dlopen("libidn.so.12", RTLD_LAZY);
+ dl = dlopen("libidn.so.12", RTLD_NOW|RTLD_NODELETE);
if (!dl) {
/* libidn broke ABI in 1.34, but not in a way we care about (a new field got added to an
* open-coded struct we do not use), hence support both versions. */
- dl = dlopen("libidn.so.11", RTLD_LAZY);
+ dl = dlopen("libidn.so.11", RTLD_NOW|RTLD_NODELETE);
if (!dl)
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"libidn support is not installed: %s", dlerror());
@@ -54,7 +54,6 @@ int dlopen_idn(void) {
} else
log_debug("Loaded 'libidn.so.12' via dlopen()");
-
r = dlsym_many_or_warn(
dl,
LOG_DEBUG,
diff --git a/src/shared/mount-util.c b/src/shared/mount-util.c
index dd3fd7919bf..04804f35eec 100644
--- a/src/shared/mount-util.c
+++ b/src/shared/mount-util.c
@@ -446,8 +446,9 @@ int bind_remount_one_with_mountinfo(
fs = mnt_table_find_target(table, path, MNT_ITER_FORWARD);
if (!fs) {
- if (laccess(path, F_OK) < 0) /* Hmm, it's not in the mount table, but does it exist at all? */
- return -errno;
+ r = laccess(path, F_OK); /* Hmm, it's not in the mount table, but does it exist at all? */
+ if (r < 0)
+ return r;
return -EINVAL; /* Not a mount point we recognize */
}
diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c
index 1c6bdc5e431..ab985813f4e 100644
--- a/src/shared/seccomp-util.c
+++ b/src/shared/seccomp-util.c
@@ -854,6 +854,7 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
.name = "@sync",
.help = "Synchronize files and memory to storage",
.value =
+ /* Please also update the list in seccomp_suppress_sync(). */
"fdatasync\0"
"fsync\0"
"msync\0"
@@ -2331,8 +2332,10 @@ int seccomp_suppress_sync(void) {
uint32_t arch;
int r;
- /* This is mostly identical to SystemCallFilter=~@sync:0, but simpler to use, and separately
- * manageable, and also masks O_SYNC/O_DSYNC */
+ /* This behaves slightly differently from SystemCallFilter=~@sync:0, in that negative fds (which
+ * we can determine to be invalid) are still refused with EBADF. See #34478.
+ *
+ * Additionally, O_SYNC/O_DSYNC are masked. */
SECCOMP_FOREACH_LOCAL_ARCH(arch) {
_cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
@@ -2351,11 +2354,21 @@ int seccomp_suppress_sync(void) {
continue;
}
- r = seccomp_rule_add_exact(
- seccomp,
- SCMP_ACT_ERRNO(0), /* success → we want this to be a NOP after all */
- id,
- 0);
+ if (STR_IN_SET(c, "fdatasync", "fsync", "sync_file_range", "sync_file_range2", "syncfs"))
+ r = seccomp_rule_add_exact(
+ seccomp,
+ SCMP_ACT_ERRNO(0), /* success → we want this to be a NOP after all */
+ id,
+ 1,
+ SCMP_A0(SCMP_CMP_LE, INT_MAX)); /* The rule handles arguments in unsigned. Hence, this
+ * means non-negative fd matches the rule, and the negative
+ * fd passed to the syscall (then it fails with EBADF). */
+ else
+ r = seccomp_rule_add_exact(
+ seccomp,
+ SCMP_ACT_ERRNO(0), /* success → we want this to be a NOP after all */
+ id,
+ 0);
if (r < 0)
log_debug_errno(r, "Failed to add filter for system call %s, ignoring: %m", c);
}
diff --git a/src/shared/tests.c b/src/shared/tests.c
index a06e458d33a..d623a5a801a 100644
--- a/src/shared/tests.c
+++ b/src/shared/tests.c
@@ -35,6 +35,7 @@
#include "strv.h"
#include "tests.h"
#include "tmpfile-util.h"
+#include "uid-range.h"
char* setup_fake_runtime_dir(void) {
char t[] = "/tmp/fake-xdg-runtime-XXXXXX", *p;
@@ -172,6 +173,20 @@ bool have_namespaces(void) {
assert_not_reached();
}
+bool userns_has_single_user(void) {
+ _cleanup_(uid_range_freep) UidRange *uidrange = NULL;
+
+ /* Check if we're in a user namespace with only a single user mapped in. We special case this
+ * scenario in a few tests because it's the only kind of namespace that can be created unprivileged
+ * and as such happens more often than not, so we make sure to deal with it so that all tests pass
+ * in such environments. */
+
+ if (uid_range_load_userns(&uidrange, NULL) < 0)
+ return false;
+
+ return uidrange->n_entries == 1 && uidrange->entries[0].nr == 1;
+}
+
bool can_memlock(void) {
/* Let's see if we can mlock() a larger blob of memory. BPF programs are charged against
* RLIMIT_MEMLOCK, hence let's first make sure we can lock memory at all, and skip the test if we
diff --git a/src/shared/tests.h b/src/shared/tests.h
index a02bfa8f02d..d3c488deb9b 100644
--- a/src/shared/tests.h
+++ b/src/shared/tests.h
@@ -48,6 +48,7 @@ void test_setup_logging(int level);
int write_tmpfile(char *pattern, const char *contents);
bool have_namespaces(void);
+bool userns_has_single_user(void);
/* We use the small but non-trivial limit here */
#define CAN_MEMLOCK_SIZE (512 * 1024U)
diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c
index 04794c5be48..e8646e5b803 100644
--- a/src/shared/tpm2-util.c
+++ b/src/shared/tpm2-util.c
@@ -195,7 +195,7 @@ int tpm2_context_init(const char *device, struct tpm2_context *ret) {
if (!filename_is_valid(fn))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 driver name '%s' not valid, refusing.", driver);
- dl = dlopen(fn, RTLD_NOW);
+ dl = dlopen(fn, RTLD_NOW|RTLD_NODELETE);
if (!dl)
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to load %s: %s", fn, dlerror());
diff --git a/src/shared/userdb.c b/src/shared/userdb.c
index 4974ad0f5fb..7613223367f 100644
--- a/src/shared/userdb.c
+++ b/src/shared/userdb.c
@@ -1454,7 +1454,7 @@ int userdb_block_nss_systemd(int b) {
/* Note that we might be called from libnss_systemd.so.2 itself, but that should be fine, really. */
- dl = dlopen(ROOTLIBDIR "/libnss_systemd.so.2", RTLD_LAZY|RTLD_NODELETE);
+ dl = dlopen(ROOTLIBDIR "/libnss_systemd.so.2", RTLD_NOW|RTLD_NODELETE);
if (!dl) {
/* If the file isn't installed, don't complain loudly */
log_debug("Failed to dlopen(libnss_systemd.so.2), ignoring: %s", dlerror());
diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c
index ed3fefe51c2..4787f5767e7 100644
--- a/src/sysext/sysext.c
+++ b/src/sysext/sysext.c
@@ -676,13 +676,11 @@ static int merge_subprocess(Hashmap *images, const char *workspace) {
if (!p)
return log_oom();
- if (laccess(p, F_OK) < 0) {
- if (errno != ENOENT)
- return log_error_errno(errno, "Failed to check if '%s' exists: %m", p);
-
- /* Hierarchy apparently was empty in all extensions, and wasn't mounted, ignoring. */
+ r = laccess(p, F_OK);
+ if (r == -ENOENT) /* Hierarchy apparently was empty in all extensions, and wasn't mounted, ignoring. */
continue;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to check if '%s' exists: %m", p);
r = chase_symlinks(*h, arg_root, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &resolved, NULL);
if (r < 0)
diff --git a/src/system-update-generator/system-update-generator.c b/src/system-update-generator/system-update-generator.c
index fc5aaa9bac3..5ba5217f114 100644
--- a/src/system-update-generator/system-update-generator.c
+++ b/src/system-update-generator/system-update-generator.c
@@ -20,12 +20,14 @@ static const char *arg_dest = NULL;
static int generate_symlink(void) {
const char *p = NULL;
+ int r;
- if (laccess("/system-update", F_OK) < 0) {
- if (errno == ENOENT)
+ r = laccess("/system-update", F_OK);
+ if (r < 0) {
+ if (r == -ENOENT)
return 0;
- log_error_errno(errno, "Failed to check for system update: %m");
+ log_error_errno(r, "Failed to check for system update: %m");
return -EINVAL;
}
diff --git a/src/systemctl/systemctl-show.c b/src/systemctl/systemctl-show.c
index 1ce14f5aa51..07a2fe79473 100644
--- a/src/systemctl/systemctl-show.c
+++ b/src/systemctl/systemctl-show.c
@@ -1645,6 +1645,29 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
bus_print_property_value(name, expected_value, flags, affinity);
return 1;
+
+ } else if (streq(name, "RootImageOptions")) {
+ const char *a, *p;
+
+ /* In config files, the syntax allows the partition name to be omitted. Here, we
+ * always print the partition name, also because we have no way of knowing if it was
+ * originally omitted or not. We also print the partitions on separate lines. */
+
+ r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ while ((r = sd_bus_message_read(m, "(ss)", &a, &p)) > 0)
+ bus_print_property_valuef(name, expected_value, flags, "%s:%s", a, p);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = sd_bus_message_exit_container(m);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ return 1;
+
} else if (streq(name, "MountImages")) {
_cleanup_free_ char *paths = NULL;
diff --git a/src/test/test-acl-util.c b/src/test/test-acl-util.c
index 8e4fa69212f..f2288af2d14 100644
--- a/src/test/test-acl-util.c
+++ b/src/test/test-acl-util.c
@@ -34,7 +34,7 @@ TEST_RET(add_acls_for_user) {
cmd = strjoina("getfacl -p ", fn);
assert_se(system(cmd) == 0);
- if (getuid() == 0) {
+ if (getuid() == 0 && !userns_has_single_user()) {
const char *nobody = NOBODY_USER_NAME;
r = get_user_creds(&nobody, &uid, NULL, NULL, NULL, 0);
if (r < 0)
diff --git a/src/test/test-capability.c b/src/test/test-capability.c
index 466223e4788..40ad3916f5f 100644
--- a/src/test/test-capability.c
+++ b/src/test/test-capability.c
@@ -267,10 +267,13 @@ int main(int argc, char *argv[]) {
show_capabilities();
- test_drop_privileges();
+ if (!userns_has_single_user())
+ test_drop_privileges();
+
test_update_inherited_set();
- fork_test(test_have_effective_cap);
+ if (!userns_has_single_user())
+ fork_test(test_have_effective_cap);
if (run_ambient)
fork_test(test_apply_ambient_caps);
diff --git a/src/test/test-chown-rec.c b/src/test/test-chown-rec.c
index 0d8b3249676..7ff7f0c8cf4 100644
--- a/src/test/test-chown-rec.c
+++ b/src/test/test-chown-rec.c
@@ -153,8 +153,8 @@ TEST(chown_recursive) {
}
static int intro(void) {
- if (geteuid() != 0)
- return log_tests_skipped("not running as root");
+ if (geteuid() != 0 || userns_has_single_user())
+ return log_tests_skipped("not running as root or in userns with single user");
return EXIT_SUCCESS;
}
diff --git a/src/test/test-condition.c b/src/test/test-condition.c
index a4b75bd5ae1..0e3b5ff406f 100644
--- a/src/test/test-condition.c
+++ b/src/test/test-condition.c
@@ -995,6 +995,13 @@ TEST(condition_test_group) {
condition_free(condition);
free(gid);
+ /* In an unprivileged user namespace with the current user mapped to root, all the auxiliary groups
+ * of the user will be mapped to the nobody group, which means the user in the user namespace is in
+ * both the root and the nobody group, meaning the next test can't work, so let's skip it in that
+ * case. */
+ if (in_group(NOBODY_GROUP_NAME) && in_group("root"))
+ return (void) log_tests_skipped("user is in both root and nobody group");
+
groupname = (char*)(getegid() == 0 ? NOBODY_GROUP_NAME : "root");
condition = condition_new(CONDITION_GROUP, groupname, false, false);
assert_se(condition);
diff --git a/src/test/test-dlopen.c b/src/test/test-dlopen.c
index 9c315373b4f..6704e936e7b 100644
--- a/src/test/test-dlopen.c
+++ b/src/test/test-dlopen.c
@@ -10,7 +10,7 @@ int main(int argc, char **argv) {
int i;
for (i = 0; i < argc - 1; i++)
- assert_se(handles[i] = dlopen(argv[i + 1], RTLD_NOW));
+ assert_se(handles[i] = dlopen(argv[i + 1], RTLD_NOW|RTLD_NODELETE));
for (i--; i >= 0; i--)
assert_se(dlclose(handles[i]) == 0);
diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c
index 35b93b6a57b..69c1502aa55 100644
--- a/src/test/test-fs-util.c
+++ b/src/test/test-fs-util.c
@@ -775,8 +775,8 @@ TEST(chmod_and_chown) {
struct stat st;
const char *p;
- if (geteuid() != 0)
- return;
+ if (geteuid() != 0 || userns_has_single_user())
+ return (void) log_tests_skipped("not running as root or in userns with single user");
BLOCK_WITH_UMASK(0000);
diff --git a/src/test/test-nss-hosts.c b/src/test/test-nss-hosts.c
index 72a9c6454c6..611e1357664 100644
--- a/src/test/test-nss-hosts.c
+++ b/src/test/test-nss-hosts.c
@@ -380,7 +380,7 @@ static int test_one_module(const char *dir,
log_info("======== %s ========", module);
- _cleanup_(dlclosep) void *handle = nss_open_handle(dir, module, RTLD_LAZY|RTLD_NODELETE);
+ _cleanup_(dlclosep) void *handle = nss_open_handle(dir, module, RTLD_NOW|RTLD_NODELETE);
if (!handle)
return -EINVAL;
diff --git a/src/test/test-nss-users.c b/src/test/test-nss-users.c
index 5178779d54a..cba0f823b92 100644
--- a/src/test/test-nss-users.c
+++ b/src/test/test-nss-users.c
@@ -166,7 +166,7 @@ static int test_one_module(const char *dir,
log_info("======== %s ========", module);
- _cleanup_(dlclosep) void *handle = nss_open_handle(dir, module, RTLD_LAZY|RTLD_NODELETE);
+ _cleanup_(dlclosep) void *handle = nss_open_handle(dir, module, RTLD_NOW|RTLD_NODELETE);
if (!handle)
return -EINVAL;
diff --git a/src/test/test-rm-rf.c b/src/test/test-rm-rf.c
index 6a8b7d823fb..b560f89f60f 100644
--- a/src/test/test-rm-rf.c
+++ b/src/test/test-rm-rf.c
@@ -89,6 +89,9 @@ static void test_rm_rf_chmod_inner(void) {
TEST(rm_rf_chmod) {
int r;
+ if (getuid() == 0 && userns_has_single_user())
+ return (void) log_tests_skipped("running as root or in userns with single user");
+
if (getuid() == 0) {
/* This test only works unpriv (as only then the access mask for the owning user matters),
* hence drop privs here */
diff --git a/src/test/test-seccomp.c b/src/test/test-seccomp.c
index 874f08b59f0..27749d097ff 100644
--- a/src/test/test-seccomp.c
+++ b/src/test/test-seccomp.c
@@ -18,6 +18,7 @@
#include "capability-util.h"
#include "fd-util.h"
#include "fileio.h"
+#include "fs-util.h"
#include "macro.h"
#include "memory-util.h"
#include "missing_sched.h"
@@ -1227,4 +1228,55 @@ TEST(restrict_suid_sgid) {
assert_se(wait_for_terminate_and_check("suidsgidseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
}
+static void test_seccomp_suppress_sync_child(void) {
+ _cleanup_(unlink_and_freep) char *path = NULL;
+ _cleanup_close_ int fd = -EBADF;
+
+ assert_se(tempfn_random("/tmp/seccomp_suppress_sync", NULL, &path) >= 0);
+ assert_se((fd = open(path, O_RDWR | O_CREAT | O_SYNC | O_CLOEXEC, 0666)) >= 0);
+ fd = safe_close(fd);
+
+ assert_se(fdatasync(-1) < 0 && errno == EBADF);
+ assert_se(fsync(-1) < 0 && errno == EBADF);
+ assert_se(syncfs(-1) < 0 && errno == EBADF);
+
+ assert_se(fdatasync(INT_MAX) < 0 && errno == EBADF);
+ assert_se(fsync(INT_MAX) < 0 && errno == EBADF);
+ assert_se(syncfs(INT_MAX) < 0 && errno == EBADF);
+
+ assert_se(seccomp_suppress_sync() >= 0);
+
+ assert_se((fd = open(path, O_RDWR | O_CREAT | O_SYNC | O_CLOEXEC, 0666)) < 0 && errno == EINVAL);
+
+ assert_se(fdatasync(INT_MAX) >= 0);
+ assert_se(fsync(INT_MAX) >= 0);
+ assert_se(syncfs(INT_MAX) >= 0);
+
+ assert_se(fdatasync(-1) < 0 && errno == EBADF);
+ assert_se(fsync(-1) < 0 && errno == EBADF);
+ assert_se(syncfs(-1) < 0 && errno == EBADF);
+}
+
+TEST(seccomp_suppress_sync) {
+ pid_t pid;
+
+ if (!is_seccomp_available()) {
+ log_notice("Seccomp not available, skipping %s", __func__);
+ return;
+ }
+ if (!have_seccomp_privs()) {
+ log_notice("Not privileged, skipping %s", __func__);
+ return;
+ }
+
+ assert_se((pid = fork()) >= 0);
+
+ if (pid == 0) {
+ test_seccomp_suppress_sync_child();
+ _exit(EXIT_SUCCESS);
+ }
+
+ assert_se(wait_for_terminate_and_check("seccomp_suppress_sync", pid, WAIT_LOG) == EXIT_SUCCESS);
+}
+
DEFINE_TEST_MAIN(LOG_DEBUG);
diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c
index 2da98e700eb..2aad36287dc 100644
--- a/src/test/test-socket-util.c
+++ b/src/test/test-socket-util.c
@@ -170,7 +170,7 @@ TEST(getpeercred_getpeergroups) {
struct ucred ucred;
int pair[2];
- if (geteuid() == 0) {
+ if (geteuid() == 0 && !userns_has_single_user()) {
test_uid = 1;
test_gid = 2;
test_gids = (gid_t*) gids;
diff --git a/src/udev/cdrom_id/cdrom_id.c b/src/udev/cdrom_id/cdrom_id.c
index 1d3201aa918..449f65c4796 100644
--- a/src/udev/cdrom_id/cdrom_id.c
+++ b/src/udev/cdrom_id/cdrom_id.c
@@ -476,7 +476,7 @@ static int cd_profiles(Context *c) {
switch (feature) {
case 0x00:
- log_debug("GET CONFIGURATION: feature 'profiles', with %u entries", features[i + 3] / 4);
+ log_debug("GET CONFIGURATION: feature 'profiles', with %u entries", features[i + 3] / 4U);
feature_profiles(c, features + i + 4, MIN(features[i + 3], len - i - 4));
break;
default:
diff --git a/src/udev/dmi_memory_id/dmi_memory_id.c b/src/udev/dmi_memory_id/dmi_memory_id.c
index 4ce6b332410..4793c0f038e 100644
--- a/src/udev/dmi_memory_id/dmi_memory_id.c
+++ b/src/udev/dmi_memory_id/dmi_memory_id.c
@@ -399,7 +399,7 @@ static void dmi_memory_device_manufacturer_id(
/* LSB is 7-bit Odd Parity number of continuation codes */
if (code != 0)
printf("MEMORY_DEVICE_%u_%s=Bank %d, Hex 0x%02X\n", slot_num, attr_suffix,
- (code & 0x7F) + 1, code >> 8);
+ (code & 0x7F) + 1, (uint16_t) (code >> 8));
}
static void dmi_memory_device_product_id(
diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
index 9e34ea6b01f..cc103cf2de6 100644
--- a/src/udev/udev-node.c
+++ b/src/udev/udev-node.c
@@ -385,6 +385,87 @@ static int stack_directory_get_name(const char *slink, char **ret) {
return 0;
}
+static int link_update_diskseq(sd_device *dev, const char *slink, bool add) {
+ _cleanup_free_ char *buf = NULL;
+ const char *fname, *diskseq, *subsystem = NULL, *devtype = NULL;
+ int r;
+
+ assert(dev);
+ assert(slink);
+
+ (void) sd_device_get_subsystem(dev, &subsystem);
+ if (!streq_ptr(subsystem, "block"))
+ return 0;
+
+ fname = path_startswith(slink, "/dev/disk/by-diskseq");
+ if (isempty(fname))
+ return 0;
+
+ (void) sd_device_get_devtype(dev, &devtype);
+ if (streq_ptr(devtype, "partition")) {
+ _cleanup_free_ char *suffix = NULL;
+ const char *partn, *p;
+
+ /* Check if the symlink has an expected suffix "-part%n". See 60-persistent-storage.rules. */
+
+ r = sd_device_get_sysnum(dev, &partn);
+ if (r < 0) {
+ /* Cannot verify the symlink is owned by this device. Let's create the stack directory for the symlink. */
+ log_device_debug_errno(dev, r, "Failed to get sysnum, but symlink '%s' is requested, ignoring: %m", slink);
+ return 0;
+ }
+
+ suffix = strjoin("-part", partn);
+ if (!suffix)
+ return -ENOMEM;
+
+ p = endswith(fname, suffix);
+ if (!p) {
+ log_device_debug(dev, "Unexpected by-diskseq symlink '%s' is requested, proceeding anyway.", slink);
+ return 0;
+ }
+
+ buf = strndup(fname, p - fname);
+ if (!buf)
+ return -ENOMEM;
+
+ fname = buf;
+ }
+
+ /* Check if the diskseq part of the symlink is in digits. */
+ if (!in_charset(fname, DIGITS)) {
+ log_device_debug(dev, "Unexpected by-diskseq symlink '%s' is requested, proceeding anyway.", slink);
+ return 0; /* unexpected by-diskseq symlink */
+ }
+
+ /* On removal, we cannot verify the diskseq. Skipping further check below. */
+ if (!add) {
+ if (unlink(slink) < 0 && errno != ENOENT)
+ return log_device_debug_errno(dev, errno, "Failed to remove '%s': %m", slink);
+
+ (void) rmdir_parents(slink, "/dev");
+ return 1; /* done */
+ }
+
+ /* Check if the diskseq matches with the DISKSEQ property. */
+ r = sd_device_get_property_value(dev, "DISKSEQ", &diskseq);
+ if (r < 0) {
+ log_device_debug_errno(dev, r, "Failed to get DISKSEQ property, but symlink '%s' is requested, ignoring: %m", slink);
+ return 0;
+ }
+
+ if (!streq(fname, diskseq)) {
+ log_device_debug(dev, "Unexpected by-diskseq symlink '%s' is requested (DISKSEQ=%s), proceeding anyway.", slink, diskseq);
+ return 0;
+ }
+
+ r = node_symlink(dev, /* devnode = */ NULL, slink);
+ if (r < 0)
+ return r;
+
+ return 1; /* done */
+}
+
static int link_update(sd_device *dev, const char *slink, bool add) {
_cleanup_free_ char *dirname = NULL, *devnode = NULL;
_cleanup_close_ int dirfd = -1, lockfd = -1;
@@ -393,6 +474,10 @@ static int link_update(sd_device *dev, const char *slink, bool add) {
assert(dev);
assert(slink);
+ r = link_update_diskseq(dev, slink, add);
+ if (r != 0)
+ return r;
+
r = stack_directory_get_name(slink, &dirname);
if (r < 0)
return log_device_debug_errno(dev, r, "Failed to build stack directory name for '%s': %m", slink);
diff --git a/test/TEST-64-UDEV-STORAGE/test.sh b/test/TEST-64-UDEV-STORAGE/test.sh
index e329433a903..40c000db0d4 100755
--- a/test/TEST-64-UDEV-STORAGE/test.sh
+++ b/test/TEST-64-UDEV-STORAGE/test.sh
@@ -474,7 +474,7 @@ EOF
qemu_opts+=("-device pci-bridge,id=pci_bridge$brid,bus=pci_bridge$((brid-1)),chassis_nr=$((64+brid))")
done
- qemu_opts+=("-device virtio-blk-pci,drive=drive0,scsi=off,bus=pci_bridge$brid")
+ qemu_opts+=("-device virtio-blk-pci,drive=drive0,bus=pci_bridge$brid")
KERNEL_APPEND="systemd.setenv=TEST_FUNCTION_NAME=${FUNCNAME[0]} ${USER_KERNEL_APPEND:-}"
QEMU_OPTIONS="${qemu_opts[*]} ${USER_QEMU_OPTIONS:-}"
diff --git a/test/test-functions b/test/test-functions
index ec8c034b939..642a3df0123 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -1826,13 +1826,9 @@ strip_binaries() {
}
create_rc_local() {
- dinfo "Create rc.local"
- mkdir -p "${initdir:?}/etc/rc.d"
- cat >"$initdir/etc/rc.d/rc.local" </run/systemd/system/test-diskseq.service <"$output"
+ diff -u "$output" - </run/systemd/system/test1.service <"$output"
+ diff -u "$output" - </run/systemd/system.attached/minimal-app0.service
+[Unit]
+Description=Minimal App 0
+EOF
+cat </run/systemd/system.attached/minimal-app0.service.d/10-profile.conf
+[Unit]
+Description=Minimal App 0
+EOF
+cat </run/systemd/system.attached/minimal-app0.service.d/20-portable.conf
+[Unit]
+Description=Minimal App 0
+EOF
+systemctl daemon-reload
+
portablectl "${ARGS[@]}" attach --force --now --runtime /usr/share/minimal_0.raw minimal-app0
portablectl is-attached --force minimal-app0
@@ -210,6 +225,28 @@ systemctl is-active app1.service
portablectl detach --now --runtime overlay app1
+# Ensure --force works also when symlinking
+mkdir -p /run/systemd/system.attached/app1.service.d
+cat </run/systemd/system.attached/app1.service
+[Unit]
+Description=App 1
+EOF
+cat </run/systemd/system.attached/app1.service.d/10-profile.conf
+[Unit]
+Description=App 1
+EOF
+cat </run/systemd/system.attached/app1.service.d/20-portable.conf
+[Unit]
+Description=App 1
+EOF
+systemctl daemon-reload
+
+portablectl "${ARGS[@]}" attach --force --copy=symlink --now --runtime /tmp/overlay app1
+
+systemctl is-active app1.service
+
+portablectl detach --now --runtime overlay app1
+
umount /tmp/overlay
portablectl "${ARGS[@]}" attach --copy=symlink --now --runtime --extension /tmp/app0 --extension /tmp/app1 /tmp/rootdir app0 app1
diff --git a/test/units/testsuite-58.sh b/test/units/testsuite-58.sh
index 5b72a49e0fb..097d772e51c 100755
--- a/test/units/testsuite-58.sh
+++ b/test/units/testsuite-58.sh
@@ -914,6 +914,47 @@ EOF
assert_in "${loop}p3 : start= *${start}, size= *${size}, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=DB081670-07AE-48CA-9F5E-813D5E40B976, name=\"linux-generic-2\"" "$output"
}
+testcase_random_seed() {
+ local defs imgs output
+
+ # For issue #34257
+
+ defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
+ imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
+ # shellcheck disable=SC2064
+ trap "rm -rf '$defs' '$imgs'" RETURN
+ chmod 0755 "$defs"
+
+ tee "$defs/root.conf" <= 512 and <= PAGE_SIZE, and
# must be powers of 2. Which leaves exactly four different ones to test on
diff --git a/test/units/testsuite-75.sh b/test/units/testsuite-75.sh
index eb24b70b84d..4e49143c2cd 100755
--- a/test/units/testsuite-75.sh
+++ b/test/units/testsuite-75.sh
@@ -16,6 +16,12 @@ run() {
"$@" |& tee "$RUN_OUT"
}
+run_delv() {
+ # Since [0] delv no longer loads /etc/(bind/)bind.keys by default, so we
+ # have to do that explicitly for each invocation
+ run delv -a /etc/bind.keys "$@"
+}
+
monitor_check_rr() (
set +x
set +o pipefail
@@ -214,9 +220,9 @@ grep -qF "unsigned.test IN MX 15 mail.unsigned.test" "$RUN_OUT"
# Check the trust chain (with and without systemd-resolved in between
# Issue: https://github.com/systemd/systemd/issues/22002
# PR: https://github.com/systemd/systemd/pull/23289
-run delv @10.0.0.1 signed.test
+run_delv @10.0.0.1 signed.test
grep -qF "; fully validated" "$RUN_OUT"
-run delv signed.test
+run_delv signed.test
grep -qF "; fully validated" "$RUN_OUT"
run dig +short signed.test
@@ -239,9 +245,9 @@ grep -qF "authenticated: yes" "$RUN_OUT"
# DNSSEC validation with multiple records of the same type for the same name
# Issue: https://github.com/systemd/systemd/issues/22002
# PR: https://github.com/systemd/systemd/pull/23289
-run delv @10.0.0.1 dupe.signed.test
+run_delv @10.0.0.1 dupe.signed.test
grep -qF "; fully validated" "$RUN_OUT"
-run delv dupe.signed.test
+run_delv dupe.signed.test
grep -qF "; fully validated" "$RUN_OUT"
# Test resolution of CNAME chains
@@ -266,9 +272,9 @@ grep -qE "^follow14\.final\.signed\.test\..+IN\s+NSEC\s+" "$RUN_OUT"
# Check the trust chain (with and without systemd-resolved in between
# Issue: https://github.com/systemd/systemd/issues/22002
# PR: https://github.com/systemd/systemd/pull/23289
-run delv @10.0.0.1 sub.onlinesign.test
+run_delv @10.0.0.1 sub.onlinesign.test
grep -qF "; fully validated" "$RUN_OUT"
-run delv sub.onlinesign.test
+run_delv sub.onlinesign.test
grep -qF "; fully validated" "$RUN_OUT"
run dig +short sub.onlinesign.test