summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/make_release.yml8
-rw-r--r--hwdb.d/60-keyboard.hwdb20
-rw-r--r--man/org.freedesktop.systemd1.xml2
-rw-r--r--rules.d/60-persistent-storage-tape.rules4
-rw-r--r--rules.d/60-persistent-storage.rules.in4
-rw-r--r--shell-completion/bash/busctl2
-rw-r--r--shell-completion/zsh/_busctl1
-rw-r--r--src/analyze/analyze-blame.c2
-rw-r--r--src/analyze/analyze-critical-chain.c6
-rw-r--r--src/analyze/analyze-plot.c4
-rw-r--r--src/analyze/analyze-time-data.c45
-rw-r--r--src/analyze/analyze-time-data.h4
-rw-r--r--src/basic/chase.c82
-rw-r--r--src/basic/chase.h5
-rw-r--r--src/basic/compress.c12
-rw-r--r--src/basic/compress.h8
-rw-r--r--src/basic/conf-files.c147
-rw-r--r--src/basic/conf-files.h3
-rw-r--r--src/basic/env-file.c24
-rw-r--r--src/basic/env-file.h1
-rw-r--r--src/basic/fd-util.c20
-rw-r--r--src/basic/fileio.c205
-rw-r--r--src/basic/fileio.h33
-rw-r--r--src/basic/os-util.c29
-rw-r--r--src/basic/os-util.h11
-rw-r--r--src/basic/path-util.c76
-rw-r--r--src/basic/path-util.h10
-rw-r--r--src/boot/bootctl-uki.c6
-rw-r--r--src/busctl/busctl.c1
-rw-r--r--src/core/unit.c4
-rw-r--r--src/fuzz/fuzz-compress.c2
-rw-r--r--src/libsystemd/sd-journal/journal-file.c32
-rw-r--r--src/machine/machinectl.c4
-rw-r--r--src/portable/portabled-image-bus.c6
-rw-r--r--src/shared/copy.c8
-rw-r--r--src/shared/device-nodes.c4
-rw-r--r--src/shared/discover-image.c9
-rw-r--r--src/shared/edit-util.c125
-rw-r--r--src/shared/edit-util.h4
-rw-r--r--src/shared/find-esp.c16
-rw-r--r--src/shared/kernel-image.c9
-rw-r--r--src/shared/kernel-image.h1
-rw-r--r--src/systemctl/systemctl-edit.c8
-rw-r--r--src/systemctl/systemctl-show.c2
-rw-r--r--src/test/test-compress-benchmark.c2
-rw-r--r--src/test/test-compress.c36
-rw-r--r--src/test/test-conf-files.c172
-rw-r--r--src/test/test-copy.c2
-rw-r--r--src/test/test-fileio.c3
-rw-r--r--src/test/test-path-util.c120
-rw-r--r--src/udev/scsi_id/scsi_id.c10
-rw-r--r--src/udev/scsi_id/scsi_serial.c2
-rw-r--r--test/fuzz/fuzz-udev-rules/60-persistent-storage-tape.rules4
-rw-r--r--test/fuzz/fuzz-udev-rules/60-persistent-storage.rules4
-rwxr-xr-xtest/udev-test.pl2
-rwxr-xr-xtest/units/testsuite-01.sh52
-rwxr-xr-xtest/units/testsuite-29.sh2
-rwxr-xr-xtest/units/testsuite-65.sh6
-rwxr-xr-xtest/units/testsuite-75.sh2
59 files changed, 863 insertions, 565 deletions
diff --git a/.github/workflows/make_release.yml b/.github/workflows/make_release.yml
index 47dbbea374..c789d33f16 100644
--- a/.github/workflows/make_release.yml
+++ b/.github/workflows/make_release.yml
@@ -5,14 +5,20 @@ on:
tags:
- "v*"
+permissions:
+ contents: read
+
jobs:
build:
runs-on: ubuntu-latest
+ permissions:
+ contents: write
+ if: ${{ github.repository_owner == 'systemd' }}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Release
- uses: softprops/action-gh-release@v1
+ uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844
with:
prerelease: ${{ contains(github.ref_name, '-rc') }}
draft: ${{ github.repository == 'systemd/systemd' }}
diff --git a/hwdb.d/60-keyboard.hwdb b/hwdb.d/60-keyboard.hwdb
index 7195217bcd..82f3aaf051 100644
--- a/hwdb.d/60-keyboard.hwdb
+++ b/hwdb.d/60-keyboard.hwdb
@@ -933,7 +933,7 @@ evdev:input:b0003v17EFp6009*
KEYBOARD_KEY_090010=f20 # Microphone mute button; should be micmute
# Lenovo 3000
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*3000*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*3000*:pvr*
KEYBOARD_KEY_8b=switchvideomode # Fn+F7 video
KEYBOARD_KEY_96=wlan # Fn+F5 wireless
KEYBOARD_KEY_97=sleep # Fn+F4 suspend
@@ -945,7 +945,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO:pn0769AP2:pvr3000N200:*
KEYBOARD_KEY_b4=prog1
# Lenovo IdeaPad
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*:pvr*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pnS10-*:*
KEYBOARD_KEY_81=rfkill # does nothing in BIOS
KEYBOARD_KEY_83=display_off # BIOS toggles screen state
@@ -960,7 +960,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrIdeaPad5*:*
KEYBOARD_KEY_81=insert
# Thinkpad X200_Tablet
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPad*X2*T*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPad*X2*T*:rvn*
KEYBOARD_KEY_5d=menu
KEYBOARD_KEY_63=fn
KEYBOARD_KEY_66=screenlock
@@ -969,7 +969,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPad*X2*T*:*
KEYBOARD_KEY_6c=direction # rotate screen
# ThinkPad X6 Tablet
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPad*X6*Tablet*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPad*X6*Tablet*:rvn*
KEYBOARD_KEY_6c=direction # rotate
KEYBOARD_KEY_68=leftmeta # toolbox
KEYBOARD_KEY_6b=esc # escape
@@ -993,20 +993,20 @@ evdev:name:Ideapad extra buttons:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:*
KEYBOARD_KEY_42=f23
KEYBOARD_KEY_43=f22
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*Y550*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*Y550*:pvr*
KEYBOARD_KEY_95=media
KEYBOARD_KEY_a3=play
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*U300s*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*U300s*:pvr*
KEYBOARD_KEY_f1=f21
KEYBOARD_KEY_ce=f20 # micmute
-evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO*:pn*IdeaPad*Z370*:*
+evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO*:pn*IdeaPad*Z370*:pvr*
KEYBOARD_KEY_a0=!mute
KEYBOARD_KEY_ae=!volumedown
KEYBOARD_KEY_b0=!volumeup
-evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO*:pn*IdeaPadFlex5*:*
+evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO*:pn*IdeaPadFlex5*:pvr*
KEYBOARD_KEY_a0=!mute
KEYBOARD_KEY_ae=!volumedown
KEYBOARD_KEY_b0=!volumeup
@@ -1025,11 +1025,11 @@ evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO:pn81Q7*:pvrLenovoYogaS940:*
KEYBOARD_KEY_b0=!volumeup
# Lenovo Y50-70
-evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO*:pn*20378*:*
+evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO*:pn*20378*:pvr*
KEYBOARD_KEY_f3=f21 # Fn+F6 (toggle touchpad)
# V480
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*Lenovo*V480*:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*Lenovo*V480*:pvr*
KEYBOARD_KEY_f1=f21
# Lenovo ThinkCentre M800z/M820z/M920z AIO machines
diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml
index 50680e6b37..490c83bb96 100644
--- a/man/org.freedesktop.systemd1.xml
+++ b/man/org.freedesktop.systemd1.xml
@@ -2501,7 +2501,7 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
condition is a trigger condition, whether the condition is reversed, the right hand side of the
condition (e.g. the path in case of <varname>ConditionPathExists</varname>), and the status. The status
can be 0, in which case the condition hasn't been checked yet, a positive value, in which case the
- condition passed, or a negative value, in which case the condition failed. Currently only 0, +1, and -1
+ condition passed, or a negative value, in which case the condition is not met. Currently only 0, +1, and -1
are used, but additional values may be used in the future, retaining the meaning of
zero/positive/negative values.</para>
diff --git a/rules.d/60-persistent-storage-tape.rules b/rules.d/60-persistent-storage-tape.rules
index 607e51ae2a..8c00cc76d9 100644
--- a/rules.d/60-persistent-storage-tape.rules
+++ b/rules.d/60-persistent-storage-tape.rules
@@ -6,7 +6,7 @@ ACTION=="remove", GOTO="persistent_storage_tape_end"
ENV{UDEV_DISABLE_PERSISTENT_STORAGE_RULES_FLAG}=="1", GOTO="persistent_storage_tape_end"
# type 8 devices are "Medium Changers"
-SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="8", IMPORT{program}="scsi_id --sg-version=3 --export --whitelisted -d $devnode", \
+SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="8", IMPORT{program}="scsi_id --sg-version=3 --export --allowlisted -d $devnode", \
SYMLINK+="tape/by-id/scsi-$env{ID_SERIAL} tape/by-id/scsi-$env{ID_SERIAL}-changer"
# iSCSI devices from the same host have all the same ID_SERIAL,
@@ -22,7 +22,7 @@ SUBSYSTEM!="scsi_tape", GOTO="persistent_storage_tape_end"
KERNEL=="st*[0-9]|nst*[0-9]", ATTRS{ieee1394_id}=="?*", ENV{ID_SERIAL}="$attr{ieee1394_id}", ENV{ID_BUS}="ieee1394"
KERNEL=="st*[0-9]|nst*[0-9]", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id"
KERNEL=="st*[0-9]|nst*[0-9]", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="scsi", KERNELS=="[0-9]*:*[0-9]", ENV{.BSG_DEV}="$root/bsg/$id"
-KERNEL=="st*[0-9]|nst*[0-9]", ENV{ID_SERIAL}!="?*", IMPORT{program}="scsi_id --whitelisted --export --device=$env{.BSG_DEV}", ENV{ID_BUS}="scsi"
+KERNEL=="st*[0-9]|nst*[0-9]", ENV{ID_SERIAL}!="?*", IMPORT{program}="scsi_id --allowlisted --export --device=$env{.BSG_DEV}", ENV{ID_BUS}="scsi"
KERNEL=="st*[0-9]", ENV{ID_SERIAL}=="?*", SYMLINK+="tape/by-id/$env{ID_BUS}-$env{ID_SERIAL}", OPTIONS+="link_priority=10"
KERNEL=="st*[0-9]", ENV{ID_SCSI_SERIAL}=="?*", SYMLINK+="tape/by-id/$env{ID_BUS}-$env{ID_SCSI_SERIAL}"
KERNEL=="nst*[0-9]", ENV{ID_SERIAL}=="?*", SYMLINK+="tape/by-id/$env{ID_BUS}-$env{ID_SERIAL}-nst"
diff --git a/rules.d/60-persistent-storage.rules.in b/rules.d/60-persistent-storage.rules.in
index c093e21500..89c064fb66 100644
--- a/rules.d/60-persistent-storage.rules.in
+++ b/rules.d/60-persistent-storage.rules.in
@@ -79,8 +79,8 @@ KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", ATTR{removable}=="0", SUBSYSTEMS=
KERNEL=="sd*[!0-9]|sr*", SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id"
# SCSI devices
-KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", IMPORT{program}="scsi_id --export --whitelisted -d $devnode", ENV{ID_BUS}="scsi"
-KERNEL=="cciss*", ENV{DEVTYPE}=="disk", ENV{ID_SERIAL}!="?*", IMPORT{program}="scsi_id --export --whitelisted -d $devnode", ENV{ID_BUS}="cciss"
+KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", IMPORT{program}="scsi_id --export --allowlisted -d $devnode", ENV{ID_BUS}="scsi"
+KERNEL=="cciss*", ENV{DEVTYPE}=="disk", ENV{ID_SERIAL}!="?*", IMPORT{program}="scsi_id --export --allowlisted -d $devnode", ENV{ID_BUS}="cciss"
KERNEL=="sd*|sr*|cciss*", ENV{DEVTYPE}=="disk", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/$env{ID_BUS}-$env{ID_SERIAL}"
KERNEL=="sd*|cciss*", ENV{DEVTYPE}=="partition", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/$env{ID_BUS}-$env{ID_SERIAL}-part%n"
# Previously, ata_id in the above might not be able to retrieve attributes correctly,
diff --git a/shell-completion/bash/busctl b/shell-completion/bash/busctl
index ee160a7900..5464225b15 100644
--- a/shell-completion/bash/busctl
+++ b/shell-completion/bash/busctl
@@ -86,7 +86,7 @@ _busctl() {
--show-machine --unique --acquired --activatable --list
-q --quiet --verbose --expect-reply=no --auto-start=no
--allow-interactive-authorization=no --augment-creds=no
- --watch-bind=yes -j -l --full'
+ --watch-bind=yes -j -l --full --xml-interface'
[ARG]='--address -H --host -M --machine --match --timeout --size --json
--destination'
)
diff --git a/shell-completion/zsh/_busctl b/shell-completion/zsh/_busctl
index 0cb1c44a43..b0cd4d5db5 100644
--- a/shell-completion/zsh/_busctl
+++ b/shell-completion/zsh/_busctl
@@ -276,6 +276,7 @@ _arguments \
'--list[Do not show tree, but simple object path list]' \
{-q,--quiet}'[Do not show method call reply]'\
'--verbose[Show result values in long format]' \
+ '--xml-interface[Dump the XML description in introspect command]' \
'--json=[Show result values in long format]:format:_busctl_get_json' \
'-j[Show pretty json in interactive sessions, short json otherwise]' \
'--expect-reply=[Expect a method call reply]:boolean:(1 0)' \
diff --git a/src/analyze/analyze-blame.c b/src/analyze/analyze-blame.c
index c9112685f8..81e5c590b9 100644
--- a/src/analyze/analyze-blame.c
+++ b/src/analyze/analyze-blame.c
@@ -16,7 +16,7 @@ int verb_blame(int argc, char *argv[], void *userdata) {
if (r < 0)
return bus_log_connect_error(r, arg_transport);
- n = acquire_time_data(bus, &times);
+ n = acquire_time_data(bus, /* require_finished = */ false, &times);
if (n <= 0)
return n;
diff --git a/src/analyze/analyze-critical-chain.c b/src/analyze/analyze-critical-chain.c
index f782f95d5f..f80f3ddb63 100644
--- a/src/analyze/analyze-critical-chain.c
+++ b/src/analyze/analyze-critical-chain.c
@@ -93,7 +93,7 @@ static int list_dependencies_one(sd_bus *bus, const char *name, unsigned level,
typesafe_qsort(deps, strv_length(deps), list_dependencies_compare);
- r = acquire_boot_times(bus, &boot);
+ r = acquire_boot_times(bus, /* require_finished = */ true, &boot);
if (r < 0)
return r;
@@ -178,7 +178,7 @@ static int list_dependencies(sd_bus *bus, const char *name) {
times = hashmap_get(unit_times_hashmap, id);
- r = acquire_boot_times(bus, &boot);
+ r = acquire_boot_times(bus, /* require_finished = */ true, &boot);
if (r < 0)
return r;
@@ -205,7 +205,7 @@ int verb_critical_chain(int argc, char *argv[], void *userdata) {
if (r < 0)
return bus_log_connect_error(r, arg_transport);
- n = acquire_time_data(bus, &times);
+ n = acquire_time_data(bus, /* require_finished = */ true, &times);
if (n <= 0)
return n;
diff --git a/src/analyze/analyze-plot.c b/src/analyze/analyze-plot.c
index e44b9c11f6..ef40e64631 100644
--- a/src/analyze/analyze-plot.c
+++ b/src/analyze/analyze-plot.c
@@ -439,7 +439,7 @@ int verb_plot(int argc, char *argv[], void *userdata) {
if (r < 0)
return bus_log_connect_error(r, arg_transport);
- n = acquire_boot_times(bus, &boot);
+ n = acquire_boot_times(bus, /* require_finished = */ true, &boot);
if (n < 0)
return n;
@@ -453,7 +453,7 @@ int verb_plot(int argc, char *argv[], void *userdata) {
return n;
}
- n = acquire_time_data(bus, &times);
+ n = acquire_time_data(bus, /* require_finished = */ true, &times);
if (n <= 0)
return n;
diff --git a/src/analyze/analyze-time-data.c b/src/analyze/analyze-time-data.c
index 07843f74bc..baee3cedbb 100644
--- a/src/analyze/analyze-time-data.c
+++ b/src/analyze/analyze-time-data.c
@@ -17,7 +17,16 @@ static void subtract_timestamp(usec_t *a, usec_t b) {
}
}
-int acquire_boot_times(sd_bus *bus, BootTimes **ret) {
+static int log_not_finished(usec_t finish_time) {
+ return log_error_errno(SYNTHETIC_ERRNO(EINPROGRESS),
+ "Bootup is not yet finished (org.freedesktop.systemd1.Manager.FinishTimestampMonotonic=%"PRIu64").\n"
+ "Please try again later.\n"
+ "Hint: Use 'systemctl%s list-jobs' to see active jobs",
+ finish_time,
+ arg_runtime_scope == RUNTIME_SCOPE_SYSTEM ? "" : " --user");
+}
+
+int acquire_boot_times(sd_bus *bus, bool require_finished, BootTimes **ret) {
static const struct bus_properties_map property_map[] = {
{ "FirmwareTimestampMonotonic", "t", NULL, offsetof(BootTimes, firmware_time) },
{ "LoaderTimestampMonotonic", "t", NULL, offsetof(BootTimes, loader_time) },
@@ -44,8 +53,14 @@ int acquire_boot_times(sd_bus *bus, BootTimes **ret) {
static bool cached = false;
int r;
- if (cached)
- goto finish;
+ if (cached) {
+ if (require_finished && times.finish_time <= 0)
+ return log_not_finished(times.finish_time);
+
+ if (ret)
+ *ret = &times;
+ return 0;
+ }
assert_cc(sizeof(usec_t) == sizeof(uint64_t));
@@ -61,13 +76,8 @@ int acquire_boot_times(sd_bus *bus, BootTimes **ret) {
if (r < 0)
return log_error_errno(r, "Failed to get timestamp properties: %s", bus_error_message(&error, r));
- if (times.finish_time <= 0)
- return log_error_errno(SYNTHETIC_ERRNO(EINPROGRESS),
- "Bootup is not yet finished (org.freedesktop.systemd1.Manager.FinishTimestampMonotonic=%"PRIu64").\n"
- "Please try again later.\n"
- "Hint: Use 'systemctl%s list-jobs' to see active jobs",
- times.finish_time,
- arg_runtime_scope == RUNTIME_SCOPE_SYSTEM ? "" : " --user");
+ if (require_finished && times.finish_time <= 0)
+ return log_not_finished(times.finish_time);
if (arg_runtime_scope == RUNTIME_SCOPE_SYSTEM && times.security_start_time > 0) {
/* security_start_time is set when systemd is not running under container environment. */
@@ -85,7 +95,8 @@ int acquire_boot_times(sd_bus *bus, BootTimes **ret) {
times.firmware_time = times.loader_time = times.kernel_time = times.initrd_time =
times.userspace_time = times.security_start_time = times.security_finish_time = 0;
- subtract_timestamp(&times.finish_time, times.reverse_offset);
+ if (times.finish_time > 0)
+ subtract_timestamp(&times.finish_time, times.reverse_offset);
subtract_timestamp(&times.generators_start_time, times.reverse_offset);
subtract_timestamp(&times.generators_finish_time, times.reverse_offset);
@@ -96,8 +107,8 @@ int acquire_boot_times(sd_bus *bus, BootTimes **ret) {
cached = true;
-finish:
- *ret = &times;
+ if (ret)
+ *ret = &times;
return 0;
}
@@ -132,7 +143,7 @@ int pretty_boot_time(sd_bus *bus, char **ret) {
BootTimes *t;
int r;
- r = acquire_boot_times(bus, &t);
+ r = acquire_boot_times(bus, /* require_finished = */ true, &t);
if (r < 0)
return r;
@@ -214,7 +225,7 @@ UnitTimes* unit_times_free_array(UnitTimes *t) {
return mfree(t);
}
-int acquire_time_data(sd_bus *bus, UnitTimes **out) {
+int acquire_time_data(sd_bus *bus, bool require_finished, UnitTimes **out) {
static const struct bus_properties_map property_map[] = {
{ "InactiveExitTimestampMonotonic", "t", NULL, offsetof(UnitTimes, activating) },
{ "ActiveEnterTimestampMonotonic", "t", NULL, offsetof(UnitTimes, activated) },
@@ -225,12 +236,12 @@ int acquire_time_data(sd_bus *bus, UnitTimes **out) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(unit_times_free_arrayp) UnitTimes *unit_times = NULL;
- BootTimes *boot_times = NULL;
+ BootTimes *boot_times;
size_t c = 0;
UnitInfo u;
int r;
- r = acquire_boot_times(bus, &boot_times);
+ r = acquire_boot_times(bus, require_finished, &boot_times);
if (r < 0)
return r;
diff --git a/src/analyze/analyze-time-data.h b/src/analyze/analyze-time-data.h
index 02ee16a714..79240745cb 100644
--- a/src/analyze/analyze-time-data.h
+++ b/src/analyze/analyze-time-data.h
@@ -47,10 +47,10 @@ typedef struct UnitTimes {
usec_t time;
} UnitTimes;
-int acquire_boot_times(sd_bus *bus, BootTimes **ret);
+int acquire_boot_times(sd_bus *bus, bool require_finished, BootTimes **ret);
int pretty_boot_time(sd_bus *bus, char **ret);
UnitTimes* unit_times_free_array(UnitTimes *t);
DEFINE_TRIVIAL_CLEANUP_FUNC(UnitTimes*, unit_times_free_array);
-int acquire_time_data(sd_bus *bus, UnitTimes **out);
+int acquire_time_data(sd_bus *bus, bool require_finished, UnitTimes **out);
diff --git a/src/basic/chase.c b/src/basic/chase.c
index 318454ca88..e8d38279fd 100644
--- a/src/basic/chase.c
+++ b/src/basic/chase.c
@@ -77,7 +77,7 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
_cleanup_close_ int fd = -EBADF, root_fd = -EBADF;
unsigned max_follow = CHASE_MAX; /* how many symlinks to follow before giving up and returning ELOOP */
bool exists = true, append_trail_slash = false;
- struct stat previous_stat;
+ struct stat st; /* stat obtained from fd */
const char *todo;
int r;
@@ -176,7 +176,7 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
/* Shortcut the ret_fd case if the caller isn't interested in the actual path and has no root
* set and doesn't care about any of the other special features we provide either. */
- r = openat(dir_fd, buffer ?: path, O_PATH|O_CLOEXEC|((flags & CHASE_NOFOLLOW) ? O_NOFOLLOW : 0));
+ r = openat(dir_fd, path, O_PATH|O_CLOEXEC|((flags & CHASE_NOFOLLOW) ? O_NOFOLLOW : 0));
if (r < 0)
return -errno;
@@ -184,11 +184,9 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
return 0;
}
- if (!buffer) {
- buffer = strdup(path);
- if (!buffer)
- return -ENOMEM;
- }
+ buffer = strdup(path);
+ if (!buffer)
+ return -ENOMEM;
/* If we receive an absolute path together with AT_FDCWD, we need to return an absolute path, because
* a relative path would be interpreted relative to the current working directory. */
@@ -220,7 +218,7 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
if (fd < 0)
return -errno;
- if (fstat(fd, &previous_stat) < 0)
+ if (fstat(fd, &st) < 0)
return -errno;
if (flags & CHASE_TRAIL_SLASH)
@@ -229,7 +227,7 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
for (todo = buffer;;) {
_cleanup_free_ char *first = NULL;
_cleanup_close_ int child = -EBADF;
- struct stat st;
+ struct stat st_child;
const char *e;
r = path_find_first_component(&todo, /* accept_dot_dot= */ true, &e);
@@ -250,6 +248,7 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
if (path_equal(first, "..")) {
_cleanup_free_ char *parent = NULL;
_cleanup_close_ int fd_parent = -EBADF;
+ struct stat st_parent;
/* If we already are at the top, then going up will not change anything. This is
* in-line with how the kernel handles this. */
@@ -260,13 +259,19 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
if (fd_parent < 0)
return -errno;
- if (fstat(fd_parent, &st) < 0)
+ if (fstat(fd_parent, &st_parent) < 0)
return -errno;
- /* If we opened the same directory, that means we're at the host root directory, so
+ /* If we opened the same directory, that _may_ indicate that we're at the host root
+ * directory. Let's confirm that in more detail with dir_fd_is_root(). And if so,
* going up won't change anything. */
- if (st.st_dev == previous_stat.st_dev && st.st_ino == previous_stat.st_ino)
- continue;
+ if (stat_inode_same(&st_parent, &st)) {
+ r = dir_fd_is_root(fd);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ continue;
+ }
r = path_extract_directory(done, &parent);
if (r >= 0 || r == -EDESTADDRREQ)
@@ -281,18 +286,16 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
if (flags & CHASE_STEP)
goto chased_one;
- if (flags & CHASE_SAFE) {
- if (unsafe_transition(&previous_stat, &st))
- return log_unsafe_transition(fd, fd_parent, path, flags);
-
- previous_stat = st;
- }
+ if (flags & CHASE_SAFE &&
+ unsafe_transition(&st, &st_parent))
+ return log_unsafe_transition(fd, fd_parent, path, flags);
if (FLAGS_SET(flags, CHASE_PARENT) && isempty(todo))
break;
+ /* update fd and stat */
+ st = st_parent;
close_and_replace(fd, fd_parent);
-
continue;
}
@@ -324,19 +327,18 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
return r;
}
- if (fstat(child, &st) < 0)
+ if (fstat(child, &st_child) < 0)
return -errno;
+
if ((flags & CHASE_SAFE) &&
- unsafe_transition(&previous_stat, &st))
+ unsafe_transition(&st, &st_child))
return log_unsafe_transition(fd, child, path, flags);
- previous_stat = st;
-
if ((flags & CHASE_NO_AUTOFS) &&
fd_is_fs_type(child, AUTOFS_SUPER_MAGIC) > 0)
return log_autofs_mount_point(child, path, flags);
- if (S_ISLNK(st.st_mode) && !((flags & CHASE_NOFOLLOW) && isempty(todo))) {
+ if (S_ISLNK(st_child.st_mode) && !((flags & CHASE_NOFOLLOW) && isempty(todo))) {
_cleanup_free_ char *destination = NULL;
if (flags & CHASE_PROHIBIT_SYMLINKS)
@@ -363,15 +365,12 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
if (fd < 0)
return fd;
- if (flags & CHASE_SAFE) {
- if (fstat(fd, &st) < 0)
- return -errno;
+ if (fstat(fd, &st) < 0)
+ return -errno;
- if (unsafe_transition(&previous_stat, &st))
- return log_unsafe_transition(child, fd, path, flags);
-
- previous_stat = st;
- }
+ if (flags & CHASE_SAFE &&
+ unsafe_transition(&st_child, &st))
+ return log_unsafe_transition(child, fd, path, flags);
r = free_and_strdup(&done, need_absolute ? "/" : NULL);
if (r < 0)
@@ -400,11 +399,12 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
break;
/* And iterate again, but go one directory further down. */
+ st = st_child;
close_and_replace(fd, child);
}
if (flags & CHASE_PARENT) {
- r = fd_verify_directory(fd);
+ r = stat_verify_directory(&st);
if (r < 0)
return r;
}
@@ -493,18 +493,19 @@ int chase(const char *path, const char *original_root, ChaseFlags flags, char **
return r;
/* Simplify the root directory, so that it has no duplicate slashes and nothing at the
- * end. While we won't resolve the root path we still simplify it. Note that dropping the
- * trailing slash should not change behaviour, since when opening it we specify O_DIRECTORY
- * anyway. Moreover at the end of this function after processing everything we'll always turn
- * the empty string back to "/". */
- delete_trailing_chars(root, "/");
+ * end. While we won't resolve the root path we still simplify it. */
path_simplify(root);
+ assert(path_is_absolute(root));
+ assert(!empty_or_root(root));
+
if (flags & CHASE_PREFIX_ROOT) {
absolute = path_join(root, path);
if (!absolute)
return -ENOMEM;
}
+
+ flags |= CHASE_AT_RESOLVE_IN_ROOT;
}
if (!absolute) {
@@ -524,9 +525,6 @@ int chase(const char *path, const char *original_root, ChaseFlags flags, char **
if (fd < 0)
return -errno;
- if (!empty_or_root(root))
- flags |= CHASE_AT_RESOLVE_IN_ROOT;
-
r = chaseat(fd, path, flags & ~CHASE_PREFIX_ROOT, ret_path ? &p : NULL, ret_fd ? &pfd : NULL);
if (r < 0)
return r;
diff --git a/src/basic/chase.h b/src/basic/chase.h
index 1314777cb4..7e9ebe0685 100644
--- a/src/basic/chase.h
+++ b/src/basic/chase.h
@@ -22,7 +22,9 @@ typedef enum ChaseFlags {
CHASE_PROHIBIT_SYMLINKS = 1 << 9, /* Refuse all symlinks */
CHASE_PARENT = 1 << 10, /* Chase the parent directory of the given path. Note that the
* full path is still stored in ret_path and only the returned
- * file descriptor will point to the parent directory. */
+ * file descriptor will point to the parent directory. Note that
+ * the result path is the root or '.', then the file descriptor
+ * also points to the result path even if this flag is set. */
CHASE_MKDIR_0755 = 1 << 11, /* Create any missing parent directories in the given path. */
CHASE_EXTRACT_FILENAME = 1 << 12, /* Only return the last component of the resolved path */
} ChaseFlags;
@@ -51,4 +53,3 @@ int chase_and_accessat(int dir_fd, const char *path, ChaseFlags chase_flags, int
int chase_and_fopenat_unlocked(int dir_fd, const char *path, ChaseFlags chase_flags, const char *open_flags, char **ret_path, FILE **ret_file);
int chase_and_unlinkat(int dir_fd, const char *path, ChaseFlags chase_flags, int unlink_flags, char **ret_path);
int chase_and_open_parent_at(int dir_fd, const char *path, ChaseFlags chase_flags, char **ret_filename);
-
diff --git a/src/basic/compress.c b/src/basic/compress.c
index 59621dc05b..10e7aaec59 100644
--- a/src/basic/compress.c
+++ b/src/basic/compress.c
@@ -107,7 +107,7 @@ int compress_blob_xz(const void *src, uint64_t src_size,
return -ENOBUFS;
*dst_size = out_pos;
- return COMPRESSION_XZ;
+ return 0;
#else
return -EPROTONOSUPPORT;
#endif
@@ -137,7 +137,7 @@ int compress_blob_lz4(const void *src, uint64_t src_size,
unaligned_write_le64(dst, src_size);
*dst_size = r + 8;
- return COMPRESSION_LZ4;
+ return 0;
#else
return -EPROTONOSUPPORT;
#endif
@@ -160,7 +160,7 @@ int compress_blob_zstd(
return zstd_ret_to_errno(k);
*dst_size = k;
- return COMPRESSION_ZSTD;
+ return 0;
#else
return -EPROTONOSUPPORT;
#endif
@@ -626,7 +626,7 @@ int compress_stream_xz(int fdf, int fdt, uint64_t max_bytes, uint64_t *ret_uncom
s.total_in, s.total_out,
(double) s.total_out / s.total_in * 100);
- return COMPRESSION_XZ;
+ return 0;
}
}
}
@@ -717,7 +717,7 @@ int compress_stream_lz4(int fdf, int fdt, uint64_t max_bytes, uint64_t *ret_unco
total_in, total_out,
(double) total_out / total_in * 100);
- return COMPRESSION_LZ4;
+ return 0;
#else
return -EPROTONOSUPPORT;
#endif
@@ -961,7 +961,7 @@ int compress_stream_zstd(int fdf, int fdt, uint64_t max_bytes, uint64_t *ret_unc
log_debug("ZSTD compression finished (%" PRIu64 " -> %" PRIu64 " bytes)",
in_bytes, max_bytes - left);
- return COMPRESSION_ZSTD;
+ return 0;
#else
return -EPROTONOSUPPORT;
#endif
diff --git a/src/basic/compress.h b/src/basic/compress.h
index 2201bca74c..1b5c645e32 100644
--- a/src/basic/compress.h
+++ b/src/basic/compress.h
@@ -63,7 +63,7 @@ int decompress_stream_xz(int fdf, int fdt, uint64_t max_size);
int decompress_stream_lz4(int fdf, int fdt, uint64_t max_size);
int decompress_stream_zstd(int fdf, int fdt, uint64_t max_size);
-static inline int compress_blob_explicit(
+static inline int compress_blob(
Compression compression,
const void *src, uint64_t src_size,
void *dst, size_t dst_alloc_size, size_t *dst_size) {
@@ -80,12 +80,6 @@ static inline int compress_blob_explicit(
}
}
-#define compress_blob(src, src_size, dst, dst_alloc_size, dst_size) \
- compress_blob_explicit( \
- DEFAULT_COMPRESSION, \
- src, src_size, \
- dst, dst_alloc_size, dst_size)
-
static inline int compress_stream(int fdf, int fdt, uint64_t max_bytes, uint64_t *ret_uncompressed_size) {
switch (DEFAULT_COMPRESSION) {
case COMPRESSION_ZSTD:
diff --git a/src/basic/conf-files.c b/src/basic/conf-files.c
index 215e7951dc..c31fe79ebd 100644
--- a/src/basic/conf-files.c
+++ b/src/basic/conf-files.c
@@ -23,26 +23,19 @@
#include "terminal-util.h"
static int files_add(
- Hashmap **h,
+ DIR *dir,
+ const char *dirpath,
+ Hashmap **files,
Set **masked,
const char *suffix,
- const char *root,
- unsigned flags,
- const char *path) {
+ unsigned flags) {
- _cleanup_free_ char *dirpath = NULL;
- _cleanup_closedir_ DIR *dir = NULL;
int r;
- assert(h);
+ assert(dir);
+ assert(dirpath);
+ assert(files);
assert(masked);
- assert(path);
-
- r = chase_and_opendir(path, root, CHASE_PREFIX_ROOT, &dirpath, &dir);
- if (r == -ENOENT)
- return 0;
- if (r < 0)
- return log_debug_errno(r, "Failed to open directory '%s/%s': %m", empty_or_root(root) ? "" : root, dirpath);
FOREACH_DIRENT(de, dir, return -errno) {
_cleanup_free_ char *n = NULL, *p = NULL;
@@ -53,7 +46,7 @@ static int files_add(
continue;
/* Has this file already been found in an earlier directory? */
- if (hashmap_contains(*h, de->d_name)) {
+ if (hashmap_contains(*files, de->d_name)) {
log_debug("Skipping overridden file '%s/%s'.", dirpath, de->d_name);
continue;
}
@@ -107,13 +100,13 @@ static int files_add(
return -ENOMEM;
if ((flags & CONF_FILES_BASENAME))
- r = hashmap_ensure_put(h, &string_hash_ops_free, n, n);
+ r = hashmap_ensure_put(files, &string_hash_ops_free, n, n);
else {
p = path_join(dirpath, de->d_name);
if (!p)
return -ENOMEM;
- r = hashmap_ensure_put(h, &string_hash_ops_free_free, n, p);
+ r = hashmap_ensure_put(files, &string_hash_ops_free_free, n, p);
}
if (r < 0)
return r;
@@ -127,49 +120,99 @@ static int files_add(
}
static int base_cmp(char * const *a, char * const *b) {
- return strcmp(basename(*a), basename(*b));
+ assert(a);
+ assert(b);
+ return path_compare_filename(*a, *b);
}
-static int conf_files_list_strv_internal(
+static int copy_and_sort_files_from_hashmap(Hashmap *fh, char ***ret) {
+ _cleanup_free_ char **sv = NULL;
+ char **files;
+
+ assert(ret);
+
+ sv = hashmap_get_strv(fh);
+ if (!sv)
+ return -ENOMEM;
+
+ /* The entries in the array given by hashmap_get_strv() are still owned by the hashmap. */
+ files = strv_copy(sv);
+ if (!files)
+ return -ENOMEM;
+
+ typesafe_qsort(files, strv_length(files), base_cmp);
+
+ *ret = files;
+ return 0;
+}
+
+int conf_files_list_strv(
char ***ret,
const char *suffix,
const char *root,
unsigned flags,
- char **dirs) {
+ const char * const *dirs) {
_cleanup_hashmap_free_ Hashmap *fh = NULL;
_cleanup_set_free_ Set *masked = NULL;
- _cleanup_strv_free_ char **files = NULL;
- _cleanup_free_ char **sv = NULL;
int r;
assert(ret);
- /* This alters the dirs string array */
- if (!path_strv_resolve_uniq(dirs, root))
- return -ENOMEM;
-
STRV_FOREACH(p, dirs) {
- r = files_add(&fh, &masked, suffix, root, flags, *p);
+ _cleanup_closedir_ DIR *dir = NULL;
+ _cleanup_free_ char *path = NULL;
+
+ r = chase_and_opendir(*p, root, CHASE_PREFIX_ROOT, &path, &dir);
+ if (r < 0) {
+ if (r != -ENOENT)
+ log_debug_errno(r, "Failed to chase and open directory '%s', ignoring: %m", *p);
+ continue;
+ }
+
+ r = files_add(dir, path, &fh, &masked, suffix, flags);
if (r == -ENOMEM)
return r;
if (r < 0)
- log_debug_errno(r, "Failed to search for files in %s, ignoring: %m", *p);
+ log_debug_errno(r, "Failed to search for files in '%s', ignoring: %m", path);
}
- sv = hashmap_get_strv(fh);
- if (!sv)
- return -ENOMEM;
+ return copy_and_sort_files_from_hashmap(fh, ret);
+}
- /* The entries in the array given by hashmap_get_strv() are still owned by the hashmap. */
- files = strv_copy(sv);
- if (!files)
- return -ENOMEM;
+int conf_files_list_strv_at(
+ char ***ret,
+ const char *suffix,
+ int rfd,
+ unsigned flags,
+ const char * const *dirs) {
- typesafe_qsort(files, strv_length(files), base_cmp);
- *ret = TAKE_PTR(files);
+ _cleanup_hashmap_free_ Hashmap *fh = NULL;
+ _cleanup_set_free_ Set *masked = NULL;
+ int r;
- return 0;
+ assert(rfd >= 0 || rfd == AT_FDCWD);
+ assert(ret);
+
+ STRV_FOREACH(p, dirs) {
+ _cleanup_closedir_ DIR *dir = NULL;
+ _cleanup_free_ char *path = NULL;
+
+ r = chase_and_opendirat(rfd, *p, CHASE_AT_RESOLVE_IN_ROOT, &path, &dir);
+ if (r < 0) {
+ if (r != -ENOENT)
+ log_debug_errno(r, "Failed to chase and open directory '%s', ignoring: %m", *p);
+ continue;
+ }
+
+ r = files_add(dir, path, &fh, &masked, suffix, flags);
+ if (r == -ENOMEM)
+ return r;
+ if (r < 0)
+ log_debug_errno(r, "Failed to search for files in '%s', ignoring: %m", path);
+ }
+
+ return copy_and_sort_files_from_hashmap(fh, ret);
}
int conf_files_insert(char ***strv, const char *root, char **dirs, const char *path) {
@@ -240,31 +283,27 @@ int conf_files_insert(char ***strv, const char *root, char **dirs, const char *p
return r;
}
-int conf_files_list_strv(char ***ret, const char *suffix, const char *root, unsigned flags, const char* const* dirs) {
- _cleanup_strv_free_ char **copy = NULL;
-
- assert(ret);
-
- copy = strv_copy((char**) dirs);
- if (!copy)
- return -ENOMEM;
+int conf_files_list(char ***ret, const char *suffix, const char *root, unsigned flags, const char *dir) {
+ return conf_files_list_strv(ret, suffix, root, flags, STRV_MAKE_CONST(dir));
+}
- return conf_files_list_strv_internal(ret, suffix, root, flags, copy);
+int conf_files_list_at(char ***ret, const char *suffix, int rfd, unsigned flags, const char *dir) {
+ return conf_files_list_strv_at(ret, suffix, rfd, flags, STRV_MAKE_CONST(dir));
}
-int conf_files_list(char ***ret, const char *suffix, const char *root, unsigned flags, const char *dir) {
- _cleanup_strv_free_ char **dirs = NULL;
+int conf_files_list_nulstr(char ***ret, const char *suffix, const char *root, unsigned flags, const char *dirs) {
+ _cleanup_strv_free_ char **d = NULL;
assert(ret);
- dirs = strv_new(dir);
- if (!dirs)
+ d = strv_split_nulstr(dirs);
+ if (!d)
return -ENOMEM;
- return conf_files_list_strv_internal(ret, suffix, root, flags, dirs);
+ return conf_files_list_strv(ret, suffix, root, flags, (const char**) d);
}
-int conf_files_list_nulstr(char ***ret, const char *suffix, const char *root, unsigned flags, const char *dirs) {
+int conf_files_list_nulstr_at(char ***ret, const char *suffix, int rfd, unsigned flags, const char *dirs) {
_cleanup_strv_free_ char **d = NULL;
assert(ret);
@@ -273,7 +312,7 @@ int conf_files_list_nulstr(char ***ret, const char *suffix, const char *root, un
if (!d)
return -ENOMEM;
- return conf_files_list_strv_internal(ret, suffix, root, flags, d);
+ return conf_files_list_strv_at(ret, suffix, rfd, flags, (const char**) d);
}
int conf_files_list_with_replacement(
diff --git a/src/basic/conf-files.h b/src/basic/conf-files.h
index 7774ed7054..547c2fc137 100644
--- a/src/basic/conf-files.h
+++ b/src/basic/conf-files.h
@@ -12,8 +12,11 @@ enum {
};
int conf_files_list(char ***ret, const char *suffix, const char *root, unsigned flags, const char *dir);
+int conf_files_list_at(char ***ret, const char *suffix, int rfd, unsigned flags, const char *dir);
int conf_files_list_strv(char ***ret, const char *suffix, const char *root, unsigned flags, const char* const* dirs);
+int conf_files_list_strv_at(char ***ret, const char *suffix, int rfd, unsigned flags, const char * const *dirs);
int conf_files_list_nulstr(char ***ret, const char *suffix, const char *root, unsigned flags, const char *dirs);
+int conf_files_list_nulstr_at(char ***ret, const char *suffix, int rfd, unsigned flags, const char *dirs);
int conf_files_insert(char ***strv, const char *root, char **dirs, const char *path);
int conf_files_list_with_replacement(
const char *root,
diff --git a/src/basic/env-file.c b/src/basic/env-file.c
index 01ed443d5f..7b3e209ddc 100644
--- a/src/basic/env-file.c
+++ b/src/basic/env-file.c
@@ -359,6 +359,23 @@ int parse_env_filev(
return r;
}
+int parse_env_file_fdv(int fd, const char *fname, va_list ap) {
+ _cleanup_fclose_ FILE *f = NULL;
+ va_list aq;
+ int r;
+
+ assert(fd >= 0);
+
+ r = fdopen_independent(fd, "re", &f);
+ if (r < 0)
+ return r;
+
+ va_copy(aq, ap);
+ r = parse_env_file_internal(f, fname, parse_env_file_push, &aq);
+ va_end(aq);
+ return r;
+}
+
int parse_env_file_sentinel(
FILE *f,
const char *fname,
@@ -381,18 +398,13 @@ int parse_env_file_fd_sentinel(
const char *fname, /* only used for logging */
...) {
- _cleanup_fclose_ FILE *f = NULL;
va_list ap;
int r;
assert(fd >= 0);
- r = fdopen_independent(fd, "re", &f);
- if (r < 0)
- return r;
-
va_start(ap, fname);
- r = parse_env_filev(f, fname, ap);
+ r = parse_env_file_fdv(fd, fname, ap);
va_end(ap);
return r;
diff --git a/src/basic/env-file.h b/src/basic/env-file.h
index fa22d2209c..2465eeddf4 100644
--- a/src/basic/env-file.h
+++ b/src/basic/env-file.h
@@ -8,6 +8,7 @@
#include "macro.h"
int parse_env_filev(FILE *f, const char *fname, va_list ap);
+int parse_env_file_fdv(int fd, const char *fname, va_list ap);
int parse_env_file_sentinel(FILE *f, const char *fname, ...) _sentinel_;
#define parse_env_file(f, fname, ...) parse_env_file_sentinel(f, fname, __VA_ARGS__, NULL)
int parse_env_file_fd_sentinel(int fd, const char *fname, ...) _sentinel_;
diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c
index 3cc4f44bcd..7125e28e1b 100644
--- a/src/basic/fd-util.c
+++ b/src/basic/fd-util.c
@@ -903,6 +903,14 @@ int dir_fd_is_root(int dir_fd) {
if (r < 0)
return r;
+ r = statx_fallback(dir_fd, "..", 0, STATX_TYPE|STATX_INO|STATX_MNT_ID, &pst.sx);
+ if (r < 0)
+ return r;
+
+ /* First, compare inode. If these are different, the fd does not point to the root directory "/". */
+ if (!statx_inode_same(&st.sx, &pst.sx))
+ return false;
+
if (!FLAGS_SET(st.nsx.stx_mask, STATX_MNT_ID)) {
int mntid;
@@ -915,10 +923,6 @@ int dir_fd_is_root(int dir_fd) {
st.nsx.stx_mask |= STATX_MNT_ID;
}
- r = statx_fallback(dir_fd, "..", 0, STATX_TYPE|STATX_INO|STATX_MNT_ID, &pst.sx);
- if (r < 0)
- return r;
-
if (!FLAGS_SET(pst.nsx.stx_mask, STATX_MNT_ID)) {
int mntid;
@@ -931,14 +935,14 @@ int dir_fd_is_root(int dir_fd) {
pst.nsx.stx_mask |= STATX_MNT_ID;
}
- /* If the parent directory is the same inode, the fd points to the root directory "/". We also check
- * that the mount ids are the same. Otherwise, a construct like the following could be used to trick
- * us:
+ /* Even if the parent directory has the same inode, the fd may not point to the root directory "/",
+ * and we also need to check that the mount ids are the same. Otherwise, a construct like the
+ * following could be used to trick us:
*
* $ mkdir /tmp/x /tmp/x/y
* $ mount --bind /tmp/x /tmp/x/y
*/
- return statx_inode_same(&st.sx, &pst.sx) && statx_mount_same(&st.nsx, &pst.nsx);
+ return statx_mount_same(&st.nsx, &pst.nsx);
}
const char *accmode_to_string(int flags) {
diff --git a/src/basic/fileio.c b/src/basic/fileio.c
index 340f9b4860..48ffb4e5e6 100644
--- a/src/basic/fileio.c
+++ b/src/basic/fileio.c
@@ -44,20 +44,6 @@
* can detect EOFs. */
#define READ_VIRTUAL_BYTES_MAX (4U*1024U*1024U - 2U)
-int fopen_unlocked_at(int dir_fd, const char *path, const char *options, int flags, FILE **ret) {
- int r;
-
- assert(ret);
-
- r = xfopenat(dir_fd, path, options, flags, ret);
- if (r < 0)
- return r;
-
- (void) __fsetlocking(*ret, FSETLOCKING_BYCALLER);
-
- return 0;
-}
-
int fdopen_unlocked(int fd, const char *options, FILE **ret) {
assert(ret);
@@ -267,7 +253,8 @@ int write_string_file_ts_at(
const struct timespec *ts) {
_cleanup_fclose_ FILE *f = NULL;
- int q, r, fd;
+ _cleanup_close_ int fd = -EBADF;
+ int q, r;
assert(fn);
assert(line);
@@ -304,11 +291,9 @@ int write_string_file_ts_at(
goto fail;
}
- r = fdopen_unlocked(fd, "w", &f);
- if (r < 0) {
- safe_close(fd);
+ r = take_fdopen_unlocked(&fd, "w", &f);
+ if (r < 0)
goto fail;
- }
if (flags & WRITE_STRING_FILE_DISABLE_BUFFER)
setvbuf(f, NULL, _IONBF, 0);
@@ -354,18 +339,19 @@ int write_string_filef(
return write_string_file(fn, p, flags);
}
-int read_one_line_file(const char *fn, char **line) {
+int read_one_line_file_at(int dir_fd, const char *filename, char **ret) {
_cleanup_fclose_ FILE *f = NULL;
int r;
- assert(fn);
- assert(line);
+ assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
+ assert(filename);
+ assert(ret);
- r = fopen_unlocked(fn, "re", &f);
+ r = fopen_unlocked_at(dir_fd, filename, "re", 0, &f);
if (r < 0)
return r;
- return read_line(f, LONG_LINE_MAX, line);
+ return read_line(f, LONG_LINE_MAX, ret);
}
int verify_file_at(int dir_fd, const char *fn, const char *blob, bool accept_extra_nl) {
@@ -760,62 +746,19 @@ int read_full_file_full(
size_t *ret_size) {
_cleanup_fclose_ FILE *f = NULL;
+ XfopenFlags xflags = XFOPEN_UNLOCKED;
int r;
assert(filename);
assert(ret_contents);
- r = xfopenat(dir_fd, filename, "re", 0, &f);
- if (r < 0) {
- _cleanup_close_ int sk = -EBADF;
-
- /* ENXIO is what Linux returns if we open a node that is an AF_UNIX socket */
- if (r != -ENXIO)
- return r;
-
- /* If this is enabled, let's try to connect to it */
- if (!FLAGS_SET(flags, READ_FULL_FILE_CONNECT_SOCKET))
- return -ENXIO;
+ if (FLAGS_SET(flags, READ_FULL_FILE_CONNECT_SOCKET) && /* If this is enabled, let's try to connect to it */
+ offset == UINT64_MAX) /* Seeking is not supported on AF_UNIX sockets */
+ xflags |= XFOPEN_SOCKET;
- /* Seeking is not supported on AF_UNIX sockets */
- if (offset != UINT64_MAX)
- return -ENXIO;
-
- sk = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
- if (sk < 0)
- return -errno;
-
- if (bind_name) {
- /* If the caller specified a socket name to bind to, do so before connecting. This is
- * useful to communicate some minor, short meta-information token from the client to
- * the server. */
- union sockaddr_union bsa;
-
- r = sockaddr_un_set_path(&bsa.un, bind_name);
- if (r < 0)
- return r;
-
- if (bind(sk, &bsa.sa, r) < 0)
- return -errno;
- }
-
- r = connect_unix_path(sk, dir_fd, filename);
- if (IN_SET(r, -ENOTSOCK, -EINVAL)) /* propagate original error if this is not a socket after all */
- return -ENXIO;
- if (r < 0)
- return r;
-
- if (shutdown(sk, SHUT_WR) < 0)
- return -errno;
-
- f = fdopen(sk, "r");
- if (!f)
- return -errno;
-
- TAKE_FD(sk);
- }
-
- (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
+ r = xfopenat_full(dir_fd, filename, "re", 0, xflags, bind_name, &f);
+ if (r < 0)
+ return r;
return read_full_stream_full(f, filename, offset, size, flags, ret_contents, ret_size);
}
@@ -922,8 +865,7 @@ int get_proc_field(const char *filename, const char *pattern, const char *termin
}
DIR *xopendirat(int fd, const char *name, int flags) {
- int nfd;
- DIR *d;
+ _cleanup_close_ int nfd = -EBADF;
assert(!(flags & O_CREAT));
@@ -934,13 +876,7 @@ DIR *xopendirat(int fd, const char *name, int flags) {
if (nfd < 0)
return NULL;
- d = fdopendir(nfd);
- if (!d) {
- safe_close(nfd);
- return NULL;
- }
-
- return d;
+ return take_fdopendir(&nfd);
}
int fopen_mode_to_flags(const char *mode) {
@@ -989,33 +925,111 @@ int fopen_mode_to_flags(const char *mode) {
return flags;
}
-int xfopenat(int dir_fd, const char *path, const char *mode, int flags, FILE **ret) {
+static int xfopenat_regular(int dir_fd, const char *path, const char *mode, int open_flags, FILE **ret) {
FILE *f;
/* A combination of fopen() with openat() */
- if (dir_fd == AT_FDCWD && flags == 0) {
+ assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
+ assert(path);
+ assert(mode);
+ assert(ret);
+
+ if (dir_fd == AT_FDCWD && open_flags == 0)
f = fopen(path, mode);
- if (!f)
- return -errno;
- } else {
- int fd, mode_flags;
+ else {
+ _cleanup_close_ int fd = -EBADF;
+ int mode_flags;
mode_flags = fopen_mode_to_flags(mode);
if (mode_flags < 0)
return mode_flags;
- fd = openat(dir_fd, path, mode_flags | flags);
+ fd = openat(dir_fd, path, mode_flags | open_flags);
if (fd < 0)
return -errno;
- f = fdopen(fd, mode);
- if (!f) {
- safe_close(fd);
+ f = take_fdopen(&fd, mode);
+ }
+ if (!f)
+ return -errno;
+
+ *ret = f;
+ return 0;
+}
+
+static int xfopenat_unix_socket(int dir_fd, const char *path, const char *bind_name, FILE **ret) {
+ _cleanup_close_ int sk = -EBADF;
+ FILE *f;
+ int r;
+
+ assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
+ assert(path);
+ assert(ret);
+
+ sk = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
+ if (sk < 0)
+ return -errno;
+
+ if (bind_name) {
+ /* If the caller specified a socket name to bind to, do so before connecting. This is
+ * useful to communicate some minor, short meta-information token from the client to
+ * the server. */
+ union sockaddr_union bsa;
+
+ r = sockaddr_un_set_path(&bsa.un, bind_name);
+ if (r < 0)
+ return r;
+
+ if (bind(sk, &bsa.sa, r) < 0)
return -errno;
- }
}
+ r = connect_unix_path(sk, dir_fd, path);
+ if (r < 0)
+ return r;
+
+ if (shutdown(sk, SHUT_WR) < 0)
+ return -errno;
+
+ f = take_fdopen(&sk, "r");
+ if (!f)
+ return -errno;
+
+ *ret = f;
+ return 0;
+}
+
+int xfopenat_full(
+ int dir_fd,
+ const char *path,
+ const char *mode,
+ int open_flags,
+ XfopenFlags flags,
+ const char *bind_name,
+ FILE **ret) {
+
+ FILE *f = NULL; /* avoid false maybe-uninitialized warning */
+ int r;
+
+ assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
+ assert(path);
+ assert(mode);
+ assert(ret);
+
+ r = xfopenat_regular(dir_fd, path, mode, open_flags, &f);
+ if (r == -ENXIO && FLAGS_SET(flags, XFOPEN_SOCKET)) {
+ /* ENXIO is what Linux returns if we open a node that is an AF_UNIX socket */
+ r = xfopenat_unix_socket(dir_fd, path, bind_name, &f);
+ if (IN_SET(r, -ENOTSOCK, -EINVAL))
+ return -ENXIO; /* propagate original error if this is not a socket after all */
+ }
+ if (r < 0)
+ return r;
+
+ if (FLAGS_SET(flags, XFOPEN_UNLOCKED))
+ (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
+
*ret = f;
return 0;
}
@@ -1040,11 +1054,10 @@ int fdopen_independent(int fd, const char *mode, FILE **ret) {
if (copy_fd < 0)
return copy_fd;
- f = fdopen(copy_fd, mode);
+ f = take_fdopen(&copy_fd, mode);
if (!f)
return -errno;
- TAKE_FD(copy_fd);
*ret = TAKE_PTR(f);
return 0;
}
diff --git a/src/basic/fileio.h b/src/basic/fileio.h
index 0a88a19146..769bf394fd 100644
--- a/src/basic/fileio.h
+++ b/src/basic/fileio.h
@@ -43,10 +43,6 @@ typedef enum {
READ_FULL_FILE_FAIL_WHEN_LARGER = 1 << 5, /* fail loading if file is larger than specified size */
} ReadFullFileFlags;
-int fopen_unlocked_at(int dir_fd, const char *path, const char *options, int flags, FILE **ret);
-static inline int fopen_unlocked(const char *path, const char *options, FILE **ret) {
- return fopen_unlocked_at(AT_FDCWD, path, options, 0, ret);
-}
int fdopen_unlocked(int fd, const char *options, FILE **ret);
int take_fdopen_unlocked(int *fd, const char *options, FILE **ret);
FILE* take_fdopen(int *fd, const char *options);
@@ -71,7 +67,10 @@ static inline int write_string_file(const char *fn, const char *line, WriteStrin
int write_string_filef(const char *fn, WriteStringFileFlags flags, const char *format, ...) _printf_(3, 4);
-int read_one_line_file(const char *filename, char **line);
+int read_one_line_file_at(int dir_fd, const char *filename, char **ret);
+static inline int read_one_line_file(const char *filename, char **ret) {
+ return read_one_line_file_at(AT_FDCWD, filename, ret);
+}
int read_full_file_full(int dir_fd, const char *filename, uint64_t offset, size_t size, ReadFullFileFlags flags, const char *bind_name, char **ret_contents, size_t *ret_size);
static inline int read_full_file_at(int dir_fd, const char *filename, char **ret_contents, size_t *ret_size) {
return read_full_file_full(dir_fd, filename, UINT64_MAX, SIZE_MAX, 0, NULL, ret_contents, ret_size);
@@ -104,7 +103,29 @@ int executable_is_script(const char *path, char **interpreter);
int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field);
DIR *xopendirat(int dirfd, const char *name, int flags);
-int xfopenat(int dir_fd, const char *path, const char *mode, int flags, FILE **ret);
+
+typedef enum XfopenFlags {
+ XFOPEN_UNLOCKED = 1 << 0, /* call __fsetlocking(FSETLOCKING_BYCALLER) after opened */
+ XFOPEN_SOCKET = 1 << 1, /* also try to open unix socket */
+} XfopenFlags;
+
+int xfopenat_full(
+ int dir_fd,
+ const char *path,
+ const char *mode,
+ int open_flags,
+ XfopenFlags flags,
+ const char *bind_name,
+ FILE **ret);
+static inline int xfopenat(int dir_fd, const char *path, const char *mode, int open_flags, FILE **ret) {
+ return xfopenat_full(dir_fd, path, mode, open_flags, 0, NULL, ret);
+}
+static inline int fopen_unlocked_at(int dir_fd, const char *path, const char *mode, int open_flags, FILE **ret) {
+ return xfopenat_full(dir_fd, path, mode, open_flags, XFOPEN_UNLOCKED, NULL, ret);
+}
+static inline int fopen_unlocked(const char *path, const char *mode, FILE **ret) {
+ return fopen_unlocked_at(AT_FDCWD, path, mode, 0, ret);
+}
int fdopen_independent(int fd, const char *mode, FILE **ret);
diff --git a/src/basic/os-util.c b/src/basic/os-util.c
index 8cb8d9302b..5f1c26b87c 100644
--- a/src/basic/os-util.c
+++ b/src/basic/os-util.c
@@ -14,11 +14,21 @@
#include "parse-util.h"
#include "path-util.h"
#include "stat-util.h"
+#include "string-table.h"
#include "string-util.h"
#include "strv.h"
#include "utf8.h"
#include "xattr-util.h"
+static const char* const image_class_table[_IMAGE_CLASS_MAX] = {
+ [IMAGE_MACHINE] = "machine",
+ [IMAGE_PORTABLE] = "portable",
+ [IMAGE_SYSEXT] = "extension",
+ [IMAGE_CONFEXT] = "confext",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(image_class, ImageClass);
+
/* Helper struct for naming simplicity and reusability */
static const struct {
const char *release_file_directory;
@@ -55,8 +65,6 @@ int path_is_extension_tree(ImageClass image_class, const char *path, const char
int r;
assert(path);
- assert(image_class >= 0);
- assert(image_class < _IMAGE_CLASS_MAX);
/* 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
@@ -295,24 +303,12 @@ int _parse_os_release(const char *root, ...) {
int r;
va_start(ap, root);
- r = parse_release_internal(root, -1, /* relax_extension_release_check= */ false, NULL, ap);
+ r = parse_release_internal(root, _IMAGE_CLASS_INVALID, /* relax_extension_release_check= */ false, NULL, ap);
va_end(ap);
return r;
}
-int load_os_release_pairs(const char *root, char ***ret) {
- _cleanup_fclose_ FILE *f = NULL;
- _cleanup_free_ char *p = NULL;
- int r;
-
- r = fopen_os_release(root, &p, &f);
- if (r < 0)
- return r;
-
- return load_env_file_pairs(f, p, ret);
-}
-
int load_os_release_pairs_with_prefix(const char *root, const char *prefix, char ***ret) {
_cleanup_strv_free_ char **os_release_pairs = NULL, **os_release_pairs_prefixed = NULL;
int r;
@@ -347,9 +343,6 @@ int load_extension_release_pairs(const char *root, ImageClass image_class, const
_cleanup_free_ char *p = NULL;
int r;
- assert(image_class >= 0);
- assert(image_class < _IMAGE_CLASS_MAX);
-
r = fopen_extension_release(root, image_class, extension, relax_extension_release_check, &p, &f);
if (r < 0)
return r;
diff --git a/src/basic/os-util.h b/src/basic/os-util.h
index 2f641ba9cd..01dcde7a80 100644
--- a/src/basic/os-util.h
+++ b/src/basic/os-util.h
@@ -5,6 +5,7 @@
#include <stdio.h>
#include "time-util.h"
+
typedef enum ImageClass {
IMAGE_MACHINE,
IMAGE_PORTABLE,
@@ -24,17 +25,17 @@ bool image_name_is_valid(const char *s) _pure_;
int path_is_extension_tree(ImageClass image_class, const char *path, const char *extension, bool relax_extension_release_check);
static inline int path_is_os_tree(const char *path) {
- return path_is_extension_tree(IMAGE_SYSEXT, path, NULL, false);
+ return path_is_extension_tree(_IMAGE_CLASS_INVALID, path, NULL, false);
}
int open_extension_release(const char *root, ImageClass image_class, const char *extension, bool relax_extension_release_check, char **ret_path, int *ret_fd);
static inline int open_os_release(const char *root, char **ret_path, int *ret_fd) {
- return open_extension_release(root, IMAGE_SYSEXT, NULL, false, ret_path, ret_fd);
+ return open_extension_release(root, _IMAGE_CLASS_INVALID, NULL, false, ret_path, ret_fd);
}
int fopen_extension_release(const char *root, ImageClass image_class, const char *extension, bool relax_extension_release_check, char **ret_path, FILE **ret_file);
static inline int fopen_os_release(const char *root, char **ret_path, FILE **ret_file) {
- return fopen_extension_release(root, IMAGE_SYSEXT, NULL, false, ret_path, ret_file);
+ return fopen_extension_release(root, _IMAGE_CLASS_INVALID, NULL, false, ret_path, ret_file);
}
int _parse_extension_release(const char *root, ImageClass image_class, bool relax_extension_release_check, const char *extension, ...) _sentinel_;
@@ -43,7 +44,9 @@ int _parse_os_release(const char *root, ...) _sentinel_;
#define parse_os_release(root, ...) _parse_os_release(root, __VA_ARGS__, NULL)
int load_extension_release_pairs(const char *root, ImageClass image_class, const char *extension, bool relax_extension_release_check, char ***ret);
-int load_os_release_pairs(const char *root, char ***ret);
+static inline int load_os_release_pairs(const char *root, char ***ret) {
+ return load_extension_release_pairs(root, _IMAGE_CLASS_INVALID, NULL, false, 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, usec_t *ret_eol);
diff --git a/src/basic/path-util.c b/src/basic/path-util.c
index ae0b25d155..fa2e26789f 100644
--- a/src/basic/path-util.c
+++ b/src/basic/path-util.c
@@ -100,6 +100,34 @@ int path_make_absolute_cwd(const char *p, char **ret) {
return 0;
}
+int path_prefix_root_cwd(const char *p, const char *root, char **ret) {
+ _cleanup_free_ char *root_abs = NULL;
+ char *c;
+ int r;
+
+ assert(p);
+ assert(ret);
+
+ /* Unlike path_make_absolute(), this always prefixes root path if specified.
+ * The root path is always simplified, but the provided path will not.
+ * This is useful for prefixing the result of chaseat(). */
+
+ if (empty_or_root(root))
+ return path_make_absolute_cwd(p, ret);
+
+ r = path_make_absolute_cwd(root, &root_abs);
+ if (r < 0)
+ return r;
+
+ path_simplify(root_abs);
+ c = path_join(root_abs, p);
+ if (!c)
+ return -ENOMEM;
+
+ *ret = c;
+ return 0;
+}
+
int path_make_relative(const char *from, const char *to, char **ret) {
_cleanup_free_ char *result = NULL;
unsigned n_parents;
@@ -491,25 +519,33 @@ bool path_equal_or_files_same(const char *a, const char *b, int flags) {
return path_equal(a, b) || files_same(a, b, flags) > 0;
}
-bool path_equal_filename(const char *a, const char *b) {
- _cleanup_free_ char *a_basename = NULL, *b_basename = NULL;
- int r;
+int path_compare_filename(const char *a, const char *b) {
+ _cleanup_free_ char *fa = NULL, *fb = NULL;
+ int r, j, k;
- assert(a);
- assert(b);
+ /* Order NULL before non-NULL */
+ r = CMP(!!a, !!b);
+ if (r != 0)
+ return r;
- r = path_extract_filename(a, &a_basename);
- if (r < 0) {
- log_debug_errno(r, "Failed to parse basename of %s: %m", a);
- return false;
- }
- r = path_extract_filename(b, &b_basename);
- if (r < 0) {
- log_debug_errno(r, "Failed to parse basename of %s: %m", b);
- return false;
- }
+ j = path_extract_filename(a, &fa);
+ k = path_extract_filename(b, &fb);
- return path_equal(a_basename, b_basename);
+ /* When one of paths is "." or root, then order it earlier. */
+ r = CMP(j != -EADDRNOTAVAIL, k != -EADDRNOTAVAIL);
+ if (r != 0)
+ return r;
+
+ /* When one of paths is invalid (or we get OOM), order invalid path after valid one. */
+ r = CMP(j < 0, k < 0);
+ if (r != 0)
+ return r;
+
+ /* fallback to use strcmp() if both paths are invalid. */
+ if (j < 0)
+ return strcmp(a, b);
+
+ return strcmp(fa, fb);
}
char* path_extend_internal(char **x, ...) {
@@ -893,6 +929,8 @@ static const char *skip_slash_or_dot_backward(const char *path, const char *q) {
continue;
if (q > path && strneq(q - 1, "/.", 2))
continue;
+ if (q == path && *q == '.')
+ continue;
break;
}
return q;
@@ -917,6 +955,12 @@ int path_find_last_component(const char *path, bool accept_dot_dot, const char *
* ret: "bbbbb/cc//././"
* return value: 5 (== strlen("bbbbb"))
*
+ * Input: path: "//.//aaa///bbbbb/cc//././"
+ * next: "///bbbbb/cc//././"
+ * Output: next: "//.//aaa///bbbbb/cc//././" (next == path)
+ * ret: "aaa///bbbbb/cc//././"
+ * return value: 3 (== strlen("aaa"))
+ *
* Input: path: "/", ".", "", or NULL
* Output: next: equivalent to path
* ret: NULL
diff --git a/src/basic/path-util.h b/src/basic/path-util.h
index 56f01f41d8..a0af9de674 100644
--- a/src/basic/path-util.h
+++ b/src/basic/path-util.h
@@ -60,21 +60,25 @@ int path_split_and_make_absolute(const char *p, char ***ret);
char* path_make_absolute(const char *p, const char *prefix);
int safe_getcwd(char **ret);
int path_make_absolute_cwd(const char *p, char **ret);
+int path_prefix_root_cwd(const char *p, const char *root, char **ret);
int path_make_relative(const char *from, const char *to, char **ret);
int path_make_relative_parent(const char *from_child, const char *to, char **ret);
char *path_startswith_full(const char *path, const char *prefix, bool accept_dot_dot) _pure_;
static inline char* path_startswith(const char *path, const char *prefix) {
return path_startswith_full(path, prefix, true);
}
-int path_compare(const char *a, const char *b) _pure_;
+int path_compare(const char *a, const char *b) _pure_;
static inline bool path_equal(const char *a, const char *b) {
return path_compare(a, b) == 0;
}
+int path_compare_filename(const char *a, const char *b);
+static inline bool path_equal_filename(const char *a, const char *b) {
+ return path_compare_filename(a, b) == 0;
+}
+
bool path_equal_or_files_same(const char *a, const char *b, int flags);
-/* Compares only the last portion of the input paths, ie: the filenames */
-bool path_equal_filename(const char *a, const char *b);
char* path_extend_internal(char **x, ...);
#define path_extend(x, ...) path_extend_internal(x, __VA_ARGS__, POINTER_MAX)
diff --git a/src/boot/bootctl-uki.c b/src/boot/bootctl-uki.c
index 718bac5ab2..8808c30569 100644
--- a/src/boot/bootctl-uki.c
+++ b/src/boot/bootctl-uki.c
@@ -1,5 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#include <fcntl.h>
+
#include "alloc-util.h"
#include "bootctl-uki.h"
#include "kernel-image.h"
@@ -8,7 +10,7 @@ int verb_kernel_identify(int argc, char *argv[], void *userdata) {
KernelImageType t;
int r;
- r = inspect_kernel(argv[1], &t, NULL, NULL, NULL);
+ r = inspect_kernel(AT_FDCWD, argv[1], &t, NULL, NULL, NULL);
if (r < 0)
return r;
@@ -21,7 +23,7 @@ int verb_kernel_inspect(int argc, char *argv[], void *userdata) {
KernelImageType t;
int r;
- r = inspect_kernel(argv[1], &t, &cmdline, &uname, &pname);
+ r = inspect_kernel(AT_FDCWD, argv[1], &t, &cmdline, &uname, &pname);
if (r < 0)
return r;
diff --git a/src/busctl/busctl.c b/src/busctl/busctl.c
index 37ba05680f..90f20c05a1 100644
--- a/src/busctl/busctl.c
+++ b/src/busctl/busctl.c
@@ -2307,6 +2307,7 @@ static int help(void) {
" --verbose Show result values in long format\n"
" --json=MODE Output as JSON\n"
" -j Same as --json=pretty on tty, --json=short otherwise\n"
+ " --xml-interface Dump the XML description in introspect command\n"
" --expect-reply=BOOL Expect a method call reply\n"
" --auto-start=BOOL Auto-start destination service\n"
" --allow-interactive-authorization=BOOL\n"
diff --git a/src/core/unit.c b/src/core/unit.c
index 846d15b415..409801aed2 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -1890,12 +1890,12 @@ int unit_start(Unit *u, ActivationDetails *details) {
if (UNIT_VTABLE(u)->once_only && dual_timestamp_is_set(&u->inactive_enter_timestamp))
return -ESTALE;
- /* If the conditions failed, don't do anything at all. If we already are activating this call might
+ /* If the conditions were unmet, don't do anything at all. If we already are activating this call might
* still be useful to speed up activation in case there is some hold-off time, but we don't want to
* recheck the condition in that case. */
if (state != UNIT_ACTIVATING &&
!unit_test_condition(u))
- return log_unit_debug_errno(u, SYNTHETIC_ERRNO(ECOMM), "Starting requested but condition failed. Not starting unit.");
+ return log_unit_debug_errno(u, SYNTHETIC_ERRNO(ECOMM), "Starting requested but condition not met. Not starting unit.");
/* If the asserts failed, fail the entire job */
if (state != UNIT_ACTIVATING &&
diff --git a/src/fuzz/fuzz-compress.c b/src/fuzz/fuzz-compress.c
index 10956cc548..9cd571dfb8 100644
--- a/src/fuzz/fuzz-compress.c
+++ b/src/fuzz/fuzz-compress.c
@@ -45,7 +45,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
}
size_t csize;
- r = compress_blob_explicit(alg, h->data, data_len, buf, size, &csize);
+ r = compress_blob(alg, h->data, data_len, buf, size, &csize);
if (r < 0) {
log_error_errno(r, "Compression failed: %m");
return 0;
diff --git a/src/libsystemd/sd-journal/journal-file.c b/src/libsystemd/sd-journal/journal-file.c
index a616390ad8..3753e29d0d 100644
--- a/src/libsystemd/sd-journal/journal-file.c
+++ b/src/libsystemd/sd-journal/journal-file.c
@@ -1671,7 +1671,7 @@ static int journal_file_append_field(
return 0;
}
-static Compression maybe_compress_payload(JournalFile *f, uint8_t *dst, const uint8_t *src, uint64_t size, size_t *rsize) {
+static int maybe_compress_payload(JournalFile *f, uint8_t *dst, const uint8_t *src, uint64_t size, size_t *rsize) {
assert(f);
assert(f->header);
@@ -1681,21 +1681,17 @@ static Compression maybe_compress_payload(JournalFile *f, uint8_t *dst, const ui
c = JOURNAL_FILE_COMPRESSION(f);
if (c == COMPRESSION_NONE || size < f->compress_threshold_bytes)
- return COMPRESSION_NONE;
+ return 0;
- r = compress_blob_explicit(c, src, size, dst, size - 1, rsize);
- if (r < 0) {
- log_debug_errno(r, "Failed to compress data object using %s, ignoring: %m", compression_to_string(c));
- /* Compression didn't work, we don't really care why, let's continue without compression */
- return COMPRESSION_NONE;
- }
+ r = compress_blob(c, src, size, dst, size - 1, rsize);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to compress data object using %s, ignoring: %m", compression_to_string(c));
- assert(r == c);
log_debug("Compressed data object %"PRIu64" -> %zu using %s", size, *rsize, compression_to_string(c));
- return c;
+ return 1; /* compressed */
#else
- return COMPRESSION_NONE;
+ return 0;
#endif
}
@@ -1709,7 +1705,6 @@ static int journal_file_append_data(
uint64_t hash, p, osize;
Object *o, *fo;
size_t rsize = 0;
- Compression c;
const void *eq;
int r;
@@ -1737,13 +1732,18 @@ static int journal_file_append_data(
o->data.hash = htole64(hash);
- c = maybe_compress_payload(f, journal_file_data_payload_field(f, o), data, size, &rsize);
+ r = maybe_compress_payload(f, journal_file_data_payload_field(f, o), data, size, &rsize);
+ if (r <= 0)
+ /* We don't really care failures, let's continue without compression */
+ memcpy_safe(journal_file_data_payload_field(f, o), data, size);
+ else {
+ Compression c = JOURNAL_FILE_COMPRESSION(f);
+
+ assert(c >= 0 && c < _COMPRESSION_MAX && c != COMPRESSION_NONE);
- if (c != COMPRESSION_NONE) {
o->object.size = htole64(journal_file_data_payload_offset(f) + rsize);
o->object.flags |= COMPRESSION_TO_OBJECT_FLAG(c);
- } else
- memcpy_safe(journal_file_data_payload_field(f, o), data, size);
+ }
r = journal_file_link_data(f, o, p, hash);
if (r < 0)
diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index 447f1a70b0..71b9d0d4c1 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -1454,9 +1454,7 @@ static int get_settings_path(const char *name, char **ret_path) {
}
static int edit_settings(int argc, char *argv[], void *userdata) {
- _cleanup_(edit_file_context_done) EditFileContext context = {
- .remove_parent = false,
- };
+ _cleanup_(edit_file_context_done) EditFileContext context = {};
int r;
if (!on_tty())
diff --git a/src/portable/portabled-image-bus.c b/src/portable/portabled-image-bus.c
index 6c4cb6ec9d..be8e65df3f 100644
--- a/src/portable/portabled-image-bus.c
+++ b/src/portable/portabled-image-bus.c
@@ -83,9 +83,9 @@ static int append_fd(sd_bus_message *m, PortableMetadata *d) {
if (d) {
assert(d->fd >= 0);
- f = take_fdopen(&d->fd, "r");
- if (!f)
- return -errno;
+ r = fdopen_independent(d->fd, "r", &f);
+ if (r < 0)
+ return r;
r = read_full_stream(f, &buf, &n);
if (r < 0)
diff --git a/src/shared/copy.c b/src/shared/copy.c
index 23d72ad1ca..f283394545 100644
--- a/src/shared/copy.c
+++ b/src/shared/copy.c
@@ -157,6 +157,7 @@ int copy_bytes_full(
copy_progress_bytes_t progress,
void *userdata) {
+ _cleanup_close_ int fdf_opened = -EBADF, fdt_opened = -EBADF;
bool try_cfr = true, try_sendfile = true, try_splice = true, copied_something = false;
int r, nonblock_pipe = -1;
size_t m = SSIZE_MAX; /* that is the maximum that sendfile and c_f_r accept */
@@ -177,6 +178,13 @@ int copy_bytes_full(
if (ret_remains_size)
*ret_remains_size = 0;
+ fdf = fd_reopen_condition(fdf, O_CLOEXEC | O_NOCTTY | O_RDONLY, O_PATH, &fdf_opened);
+ if (fdf < 0)
+ return fdf;
+ fdt = fd_reopen_condition(fdt, O_CLOEXEC | O_NOCTTY | O_RDWR, O_PATH, &fdt_opened);
+ if (fdt < 0)
+ return fdt;
+
/* Try btrfs reflinks first. This only works on regular, seekable files, hence let's check the file offsets of
* source and destination first. */
if ((copy_flags & COPY_REFLINK)) {
diff --git a/src/shared/device-nodes.c b/src/shared/device-nodes.c
index 40e469379f..bdbbb98c2c 100644
--- a/src/shared/device-nodes.c
+++ b/src/shared/device-nodes.c
@@ -8,12 +8,12 @@
#include "string-util.h"
#include "utf8.h"
-int allow_listed_char_for_devnode(char c, const char *white) {
+int allow_listed_char_for_devnode(char c, const char *additional) {
return
ascii_isdigit(c) ||
ascii_isalpha(c) ||
strchr("#+-.:=@_", c) ||
- (white && strchr(white, c));
+ (additional && strchr(additional, c));
}
int encode_devnode_name(const char *str, char *str_enc, size_t len) {
diff --git a/src/shared/discover-image.c b/src/shared/discover-image.c
index 0343d2e20b..d0b3245a27 100644
--- a/src/shared/discover-image.c
+++ b/src/shared/discover-image.c
@@ -1326,12 +1326,3 @@ static const char* const image_type_table[_IMAGE_TYPE_MAX] = {
};
DEFINE_STRING_TABLE_LOOKUP(image_type, ImageType);
-
-static const char* const image_class_table[_IMAGE_CLASS_MAX] = {
- [IMAGE_MACHINE] = "machine",
- [IMAGE_PORTABLE] = "portable",
- [IMAGE_SYSEXT] = "extension",
- [IMAGE_CONFEXT] = "confext"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(image_class, ImageClass);
diff --git a/src/shared/edit-util.c b/src/shared/edit-util.c
index f1eb7987f4..9fd74973aa 100644
--- a/src/shared/edit-util.c
+++ b/src/shared/edit-util.c
@@ -12,11 +12,9 @@
#include "mkdir-label.h"
#include "path-util.h"
#include "process-util.h"
-#include "selinux-util.h"
-#include "stat-util.h"
#include "string-util.h"
#include "strv.h"
-#include "tmpfile-util.h"
+#include "tmpfile-util-label.h"
void edit_file_context_done(EditFileContext *context) {
int r;
@@ -103,6 +101,9 @@ int edit_files_add(
static int create_edit_temp_file(EditFile *e) {
_cleanup_(unlink_and_freep) char *temp = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ const char *source;
+ bool has_original, has_target;
unsigned line = 1;
int r;
@@ -114,62 +115,37 @@ static int create_edit_temp_file(EditFile *e) {
if (e->temp)
return 0;
- r = tempfn_random(e->path, NULL, &temp);
+ r = mkdir_parents_label(e->path, 0755);
if (r < 0)
- return log_error_errno(r, "Failed to determine temporary filename for \"%s\": %m", e->path);
+ return log_error_errno(r, "Failed to create parent directories for '%s': %m", e->path);
- r = mkdir_parents_label(e->path, 0755);
+ r = fopen_temporary_label(e->path, e->path, &f, &temp);
if (r < 0)
- return log_error_errno(r, "Failed to create parent directories for \"%s\": %m", e->path);
+ return log_error_errno(r, "Failed to create temporary file for '%s': %m", e->path);
- if (!e->original_path && !e->comment_paths) {
- r = mac_selinux_create_file_prepare(e->path, S_IFREG);
- if (r < 0)
- return r;
+ if (fchmod(fileno(f), 0644) < 0)
+ return log_error_errno(errno, "Failed to change mode of temporary file '%s': %m", temp);
- r = touch(temp);
- mac_selinux_create_file_clear();
- if (r < 0)
- return log_error_errno(r, "Failed to create temporary file \"%s\": %m", temp);
- }
+ has_original = e->original_path && access(e->original_path, F_OK) >= 0;
+ has_target = access(e->path, F_OK) >= 0;
- if (e->original_path) {
- r = mac_selinux_create_file_prepare(e->path, S_IFREG);
- if (r < 0)
- return r;
-
- r = copy_file(e->original_path, temp, 0, 0644, COPY_REFLINK);
- if (r == -ENOENT) {
- r = touch(temp);
- mac_selinux_create_file_clear();
- if (r < 0)
- return log_error_errno(r, "Failed to create temporary file \"%s\": %m", temp);
- } else {
- mac_selinux_create_file_clear();
- if (r < 0)
- return log_error_errno(r, "Failed to create temporary file for \"%s\": %m", e->path);
- }
- }
+ if (has_original && (!has_target || e->context->overwrite_with_origin))
+ /* We are asked to overwrite target with original_path or target doesn't exist. */
+ source = e->original_path;
+ else if (has_target)
+ /* Target exists and shouldn't be overwritten. */
+ source = e->path;
+ else
+ source = NULL;
if (e->comment_paths) {
- _cleanup_free_ char *target_contents = NULL;
- _cleanup_fclose_ FILE *f = NULL;
+ _cleanup_free_ char *source_contents = NULL;
- r = mac_selinux_create_file_prepare(e->path, S_IFREG);
- if (r < 0)
- return r;
-
- f = fopen(temp, "we");
- mac_selinux_create_file_clear();
- if (!f)
- return log_error_errno(errno, "Failed to open temporary file \"%s\": %m", temp);
-
- if (fchmod(fileno(f), 0644) < 0)
- return log_error_errno(errno, "Failed to change mode of temporary file \"%s\": %m", temp);
-
- r = read_full_file(e->path, &target_contents, NULL);
- if (r < 0 && r != -ENOENT)
- return log_error_errno(r, "Failed to read target file \"%s\": %m", e->path);
+ if (source) {
+ r = read_full_file(source, &source_contents, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to read source file '%s': %m", source);
+ }
fprintf(f,
"### Editing %s\n"
@@ -180,41 +156,47 @@ static int create_edit_temp_file(EditFile *e) {
"%s\n",
e->path,
e->context->marker_start,
- strempty(target_contents),
- target_contents && endswith(target_contents, "\n") ? "" : "\n",
+ strempty(source_contents),
+ source_contents && endswith(source_contents, "\n") ? "" : "\n",
e->context->marker_end);
line = 4; /* Start editing at the contents area */
- /* Add a comment with the contents of the original files */
STRV_FOREACH(path, e->comment_paths) {
- _cleanup_free_ char *contents = NULL;
+ _cleanup_free_ char *comment = NULL;
- /* Skip the file that's being edited, already processed in above */
- if (path_equal(*path, e->path))
+ /* Skip the file which is being edited and the source file (can be the same) */
+ if (PATH_IN_SET(*path, e->path, source))
continue;
- r = read_full_file(*path, &contents, NULL);
+ r = read_full_file(*path, &comment, NULL);
if (r < 0)
- return log_error_errno(r, "Failed to read original file \"%s\": %m", *path);
+ return log_error_errno(r, "Failed to read comment file '%s': %m", *path);
fprintf(f, "\n\n### %s", *path);
- if (!isempty(contents)) {
- _cleanup_free_ char *commented_contents = NULL;
- commented_contents = strreplace(strstrip(contents), "\n", "\n# ");
- if (!commented_contents)
+ if (!isempty(comment)) {
+ _cleanup_free_ char *c = NULL;
+
+ c = strreplace(strstrip(comment), "\n", "\n# ");
+ if (!c)
return log_oom();
- fprintf(f, "\n# %s", commented_contents);
+ fprintf(f, "\n# %s", c);
}
}
-
- r = fflush_and_check(f);
- if (r < 0)
- return log_error_errno(r, "Failed to create temporary file \"%s\": %m", temp);
+ } else if (source) {
+ r = copy_file_fd(source, fileno(f), COPY_REFLINK);
+ if (r < 0) {
+ assert(r != -ENOENT);
+ return log_error_errno(r, "Failed to copy file '%s' to temporary file '%s': %m", source, temp);
+ }
}
+ r = fflush_and_check(f);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write to temporary file '%s': %m", temp);
+
e->temp = TAKE_PTR(temp);
e->line = line;
@@ -310,7 +292,7 @@ static int strip_edit_temp_file(EditFile *e) {
r = read_full_file(e->temp, &old_contents, NULL);
if (r < 0)
- return log_error_errno(r, "Failed to read temporary file \"%s\": %m", e->temp);
+ return log_error_errno(r, "Failed to read temporary file '%s': %m", e->temp);
if (e->context->marker_start) {
/* Trim out the lines between the two markers */
@@ -344,7 +326,7 @@ static int strip_edit_temp_file(EditFile *e) {
r = write_string_file(e->temp, new_contents, WRITE_STRING_FILE_CREATE | WRITE_STRING_FILE_TRUNCATE | WRITE_STRING_FILE_AVOID_NEWLINE);
if (r < 0)
- return log_error_errno(r, "Failed to modify temporary file \"%s\": %m", e->temp);
+ return log_error_errno(r, "Failed to strip temporary file '%s': %m", e->temp);
return 1; /* Contents have real changes and are changed after stripping */
}
@@ -377,7 +359,10 @@ int do_edit_files_and_install(EditFileContext *context) {
r = RET_NERRNO(rename(i->temp, i->path));
if (r < 0)
- return log_error_errno(r, "Failed to rename \"%s\" to \"%s\": %m", i->temp, i->path);
+ return log_error_errno(r,
+ "Failed to rename temporary file '%s' to target file '%s': %m",
+ i->temp,
+ i->path);
i->temp = mfree(i->temp);
log_info("Successfully installed edited file '%s'.", i->path);
diff --git a/src/shared/edit-util.h b/src/shared/edit-util.h
index 63c6190ef8..83b3df8683 100644
--- a/src/shared/edit-util.h
+++ b/src/shared/edit-util.h
@@ -3,6 +3,9 @@
#include <stdbool.h>
+#define DROPIN_MARKER_START "### Anything between here and the comment below will become the contents of the drop-in file"
+#define DROPIN_MARKER_END "### Edits below this comment will be discarded"
+
typedef struct EditFile EditFile;
typedef struct EditFileContext EditFileContext;
@@ -21,6 +24,7 @@ struct EditFileContext {
const char *marker_start;
const char *marker_end;
bool remove_parent;
+ bool overwrite_with_origin; /* whether to always overwrite target with original file */
};
void edit_file_context_done(EditFileContext *context);
diff --git a/src/shared/find-esp.c b/src/shared/find-esp.c
index 0d45249d63..6a0002a2bd 100644
--- a/src/shared/find-esp.c
+++ b/src/shared/find-esp.c
@@ -540,11 +540,9 @@ int find_esp_and_warn(
return r;
if (ret_path) {
- char *q = path_join(empty_to_root(root), p);
- if (!q)
- return -ENOMEM;
-
- *ret_path = TAKE_PTR(q);
+ r = path_prefix_root_cwd(p, root, ret_path);
+ if (r < 0)
+ return r;
}
if (ret_part)
*ret_part = part;
@@ -861,11 +859,9 @@ int find_xbootldr_and_warn(
return r;
if (ret_path) {
- char *q = path_join(empty_to_root(root), p);
- if (!q)
- return -ENOMEM;
-
- *ret_path = TAKE_PTR(q);
+ r = path_prefix_root_cwd(p, root, ret_path);
+ if (r < 0)
+ return r;
}
if (ret_uuid)
*ret_uuid = uuid;
diff --git a/src/shared/kernel-image.c b/src/shared/kernel-image.c
index b5ea1bb2a0..3d2ec820d9 100644
--- a/src/shared/kernel-image.c
+++ b/src/shared/kernel-image.c
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "fd-util.h"
+#include "fileio.h"
#include "env-file.h"
#include "kernel-image.h"
#include "os-util.h"
@@ -255,6 +256,7 @@ static int inspect_uki(
}
int inspect_kernel(
+ int dir_fd,
const char *filename,
KernelImageType *ret_type,
char **ret_cmdline,
@@ -267,11 +269,12 @@ int inspect_kernel(
KernelImageType t;
int r;
+ assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
assert(filename);
- f = fopen(filename, "re");
- if (!f)
- return log_error_errno(errno, "Failed to open kernel image file '%s': %m", filename);
+ r = xfopenat(dir_fd, filename, "re", 0, &f);
+ if (r < 0)
+ return log_error_errno(r, "Failed to open kernel image file '%s': %m", filename);
r = pe_sections(f, &sections, &scount);
if (r < 0)
diff --git a/src/shared/kernel-image.h b/src/shared/kernel-image.h
index d1875920cc..41b2c08f9a 100644
--- a/src/shared/kernel-image.h
+++ b/src/shared/kernel-image.h
@@ -16,6 +16,7 @@ typedef enum KernelImageType {
const char* kernel_image_type_to_string(KernelImageType t) _const_;
int inspect_kernel(
+ int dir_fd,
const char *filename,
KernelImageType *ret_type,
char **ret_cmdline,
diff --git a/src/systemctl/systemctl-edit.c b/src/systemctl/systemctl-edit.c
index 5f42dc239f..561b01a67a 100644
--- a/src/systemctl/systemctl-edit.c
+++ b/src/systemctl/systemctl-edit.c
@@ -13,9 +13,6 @@
#include "systemctl.h"
#include "terminal-util.h"
-#define EDIT_MARKER_START "### Anything between here and the comment below will become the contents of the drop-in file"
-#define EDIT_MARKER_END "### Edits below this comment will be discarded"
-
int verb_cat(int argc, char *argv[], void *userdata) {
_cleanup_(hashmap_freep) Hashmap *cached_name_map = NULL, *cached_id_map = NULL;
_cleanup_(lookup_paths_free) LookupPaths lp = {};
@@ -316,9 +313,10 @@ static int find_paths_to_edit(
int verb_edit(int argc, char *argv[], void *userdata) {
_cleanup_(edit_file_context_done) EditFileContext context = {
- .marker_start = EDIT_MARKER_START,
- .marker_end = EDIT_MARKER_END,
+ .marker_start = DROPIN_MARKER_START,
+ .marker_end = DROPIN_MARKER_END,
.remove_parent = !arg_full,
+ .overwrite_with_origin = true,
};
_cleanup_(lookup_paths_free) LookupPaths lp = {};
_cleanup_strv_free_ char **names = NULL;
diff --git a/src/systemctl/systemctl-show.c b/src/systemctl/systemctl-show.c
index 4a14c105dd..6422550af4 100644
--- a/src/systemctl/systemctl-show.c
+++ b/src/systemctl/systemctl-show.c
@@ -516,7 +516,7 @@ static void print_status_info(
if (!i->condition_result && i->condition_timestamp > 0) {
int n = 0;
- printf(" Condition: start %scondition failed%s at %s; %s\n",
+ printf(" Condition: start %scondition unmet%s at %s; %s\n",
ansi_highlight_yellow(), ansi_normal(),
FORMAT_TIMESTAMP_STYLE(i->condition_timestamp, arg_timestamp_style),
FORMAT_TIMESTAMP_RELATIVE(i->condition_timestamp));
diff --git a/src/test/test-compress-benchmark.c b/src/test/test-compress-benchmark.c
index da0f5e137a..6180e19839 100644
--- a/src/test/test-compress-benchmark.c
+++ b/src/test/test-compress-benchmark.c
@@ -102,7 +102,7 @@ static void test_compress_decompress(const char* label, const char* type,
r = compress(text, size, buf, size, &j);
/* assume compression must be successful except for small or random inputs */
- assert_se(r > 0 || (size < 2048 && r == -ENOBUFS) || streq(type, "random"));
+ assert_se(r >= 0 || (size < 2048 && r == -ENOBUFS) || streq(type, "random"));
/* check for overwrites */
assert_se(buf[size] == 0);
diff --git a/src/test/test-compress.c b/src/test/test-compress.c
index f5ec47cb3c..18f8ce3b35 100644
--- a/src/test/test-compress.c
+++ b/src/test/test-compress.c
@@ -46,7 +46,6 @@ typedef int (decompress_stream_t)(int fdf, int fdt, uint64_t max_size);
#if HAVE_COMPRESSION
_unused_ static void test_compress_decompress(
- int flag,
const char *compression,
compress_blob_t compress,
decompress_blob_t decompress,
@@ -67,7 +66,7 @@ _unused_ static void test_compress_decompress(
log_info_errno(r, "compression failed: %m");
assert_se(may_fail);
} else {
- assert_se(r == flag);
+ assert_se(r >= 0);
r = decompress(compressed, csize,
(void **) &decompressed, &csize, 0);
assert_se(r == 0);
@@ -120,7 +119,7 @@ _unused_ static void test_decompress_startswith(const char *compression,
assert_se(compressed2);
r = compress(data, data_len, compressed, BUFSIZE_2, &csize);
}
- assert_se(r > 0);
+ assert_se(r >= 0);
len = strlen(data);
@@ -151,7 +150,7 @@ _unused_ static void test_decompress_startswith_short(const char *compression,
log_info("/* %s with %s */", __func__, compression);
r = compress(TEXT, sizeof TEXT, buf, sizeof buf, &csize);
- assert_se(r > 0);
+ assert_se(r >= 0);
for (size_t i = 1; i < strlen(TEXT); i++) {
_cleanup_free_ void *buf2 = NULL;
@@ -163,8 +162,7 @@ _unused_ static void test_decompress_startswith_short(const char *compression,
}
}
-_unused_ static void test_compress_stream(int flag,
- const char *compression,
+_unused_ static void test_compress_stream(const char *compression,
const char *cat,
compress_stream_t compress,
decompress_stream_t decompress,
@@ -195,7 +193,7 @@ _unused_ static void test_compress_stream(int flag,
assert_se((dst = mkostemp_safe(pattern)) >= 0);
- assert_se(compress(src, dst, -1, &uncompressed_size) == flag);
+ assert_se(compress(src, dst, -1, &uncompressed_size) >= 0);
if (cat) {
assert_se(asprintf(&cmd, "%s %s | diff %s -", cat, pattern, srcfile) > 0);
@@ -293,11 +291,9 @@ int main(int argc, char *argv[]) {
random_bytes(data + 7, sizeof(data) - 7);
#if HAVE_XZ
- test_compress_decompress(COMPRESSION_XZ, "XZ",
- compress_blob_xz, decompress_blob_xz,
+ test_compress_decompress("XZ", compress_blob_xz, decompress_blob_xz,
text, sizeof(text), false);
- test_compress_decompress(COMPRESSION_XZ, "XZ",
- compress_blob_xz, decompress_blob_xz,
+ test_compress_decompress("XZ", compress_blob_xz, decompress_blob_xz,
data, sizeof(data), true);
test_decompress_startswith("XZ",
@@ -310,7 +306,7 @@ int main(int argc, char *argv[]) {
compress_blob_xz, decompress_startswith_xz,
huge, HUGE_SIZE, true);
- test_compress_stream(COMPRESSION_XZ, "XZ", "xzcat",
+ test_compress_stream("XZ", "xzcat",
compress_stream_xz, decompress_stream_xz, srcfile);
test_decompress_startswith_short("XZ", compress_blob_xz, decompress_startswith_xz);
@@ -320,11 +316,9 @@ int main(int argc, char *argv[]) {
#endif
#if HAVE_LZ4
- test_compress_decompress(COMPRESSION_LZ4, "LZ4",
- compress_blob_lz4, decompress_blob_lz4,
+ test_compress_decompress("LZ4", compress_blob_lz4, decompress_blob_lz4,
text, sizeof(text), false);
- test_compress_decompress(COMPRESSION_LZ4, "LZ4",
- compress_blob_lz4, decompress_blob_lz4,
+ test_compress_decompress("LZ4", compress_blob_lz4, decompress_blob_lz4,
data, sizeof(data), true);
test_decompress_startswith("LZ4",
@@ -337,7 +331,7 @@ int main(int argc, char *argv[]) {
compress_blob_lz4, decompress_startswith_lz4,
huge, HUGE_SIZE, true);
- test_compress_stream(COMPRESSION_LZ4, "LZ4", "lz4cat",
+ test_compress_stream("LZ4", "lz4cat",
compress_stream_lz4, decompress_stream_lz4, srcfile);
test_lz4_decompress_partial();
@@ -349,11 +343,9 @@ int main(int argc, char *argv[]) {
#endif
#if HAVE_ZSTD
- test_compress_decompress(COMPRESSION_ZSTD, "ZSTD",
- compress_blob_zstd, decompress_blob_zstd,
+ test_compress_decompress("ZSTD", compress_blob_zstd, decompress_blob_zstd,
text, sizeof(text), false);
- test_compress_decompress(COMPRESSION_ZSTD, "ZSTD",
- compress_blob_zstd, decompress_blob_zstd,
+ test_compress_decompress("ZSTD", compress_blob_zstd, decompress_blob_zstd,
data, sizeof(data), true);
test_decompress_startswith("ZSTD",
@@ -366,7 +358,7 @@ int main(int argc, char *argv[]) {
compress_blob_zstd, decompress_startswith_zstd,
huge, HUGE_SIZE, true);
- test_compress_stream(COMPRESSION_ZSTD, "ZSTD", "zstdcat",
+ test_compress_stream("ZSTD", "zstdcat",
compress_stream_zstd, decompress_stream_zstd, srcfile);
test_decompress_startswith_short("ZSTD", compress_blob_zstd, decompress_startswith_zstd);
diff --git a/src/test/test-conf-files.c b/src/test/test-conf-files.c
index beda749fb8..4253490443 100644
--- a/src/test/test-conf-files.c
+++ b/src/test/test-conf-files.c
@@ -8,89 +8,151 @@
#include "alloc-util.h"
#include "conf-files.h"
+#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
#include "macro.h"
#include "mkdir.h"
-#include "parse-util.h"
#include "path-util.h"
#include "rm-rf.h"
#include "string-util.h"
#include "strv.h"
#include "tests.h"
-#include "user-util.h"
+#include "tmpfile-util.h"
-static void setup_test_dir(char *tmp_dir, const char *files, ...) {
- va_list ap;
+TEST(conf_files_list) {
+ _cleanup_(rm_rf_physical_and_freep) char *t = NULL;
+ _cleanup_close_ int tfd = -EBADF;
+ _cleanup_strv_free_ char **result = NULL;
+ const char *search1, *search2, *search1_a, *search1_b, *search1_c, *search2_aa;
+
+ tfd = mkdtemp_open("/tmp/test-conf-files-XXXXXX", O_PATH, &t);
+ assert(tfd >= 0);
- assert_se(mkdtemp(tmp_dir));
+ assert_se(mkdirat(tfd, "dir1", 0755) >= 0);
+ assert_se(mkdirat(tfd, "dir2", 0755) >= 0);
- va_start(ap, files);
- while (files) {
- _cleanup_free_ char *path;
+ search1 = strjoina(t, "/dir1/");
+ search2 = strjoina(t, "/dir2/");
- assert_se(path = path_join(tmp_dir, files));
- assert_se(write_string_file(path, "foobar", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755) >= 0);
+ FOREACH_STRING(p, "a.conf", "b.conf", "c.foo") {
+ _cleanup_free_ char *path = NULL;
- files = va_arg(ap, const char *);
+ assert_se(path = path_join(search1, p));
+ assert_se(write_string_file(path, "foobar", WRITE_STRING_FILE_CREATE) >= 0);
}
- va_end(ap);
-}
-static void test_conf_files_list_one(bool use_root) {
- char tmp_dir[] = "/tmp/test-conf-files-XXXXXX";
- _cleanup_strv_free_ char **found_files = NULL, **found_files2 = NULL;
- const char *root_dir, *search, *expect_a, *expect_b, *expect_c, *mask;
+ assert_se(symlinkat("/dev/null", tfd, "dir1/m.conf") >= 0);
+
+ FOREACH_STRING(p, "a.conf", "aa.conf", "m.conf") {
+ _cleanup_free_ char *path = NULL;
- log_info("/* %s(%s) */", __func__, yes_no(use_root));
+ assert_se(path = path_join(search2, p));
+ assert_se(write_string_file(path, "hogehoge", WRITE_STRING_FILE_CREATE) >= 0);
+ }
- setup_test_dir(tmp_dir,
- "/dir/a.conf",
- "/dir/b.conf",
- "/dir/c.foo",
- NULL);
+ search1_a = strjoina(search1, "a.conf");
+ search1_b = strjoina(search1, "b.conf");
+ search1_c = strjoina(search1, "c.foo");
+ search2_aa = strjoina(search2, "aa.conf");
- mask = strjoina(tmp_dir, "/dir/d.conf");
- assert_se(symlink("/dev/null", mask) >= 0);
+ /* search dir1 without suffix */
+ assert_se(conf_files_list(&result, NULL, NULL, CONF_FILES_FILTER_MASKED, search1) >= 0);
+ strv_print(result);
+ assert_se(strv_equal(result, STRV_MAKE(search1_a, search1_b, search1_c)));
- if (use_root) {
- root_dir = tmp_dir;
- search = "/dir";
- } else {
- root_dir = NULL;
- search = strjoina(tmp_dir, "/dir");
- }
+ result = strv_free(result);
- expect_a = strjoina(tmp_dir, "/dir/a.conf");
- expect_b = strjoina(tmp_dir, "/dir/b.conf");
- expect_c = strjoina(tmp_dir, "/dir/c.foo");
+ assert_se(conf_files_list(&result, NULL, t, CONF_FILES_FILTER_MASKED, "/dir1/") >= 0);
+ strv_print(result);
+ assert_se(strv_equal(result, STRV_MAKE(search1_a, search1_b, search1_c)));
- log_debug("/* Check when filtered by suffix */");
+ result = strv_free(result);
- assert_se(conf_files_list(&found_files, ".conf", root_dir, CONF_FILES_FILTER_MASKED, search) == 0);
- strv_print(found_files);
+ assert_se(conf_files_list_at(&result, NULL, AT_FDCWD, CONF_FILES_FILTER_MASKED, search1) >= 0);
+ strv_print(result);
+ assert_se(strv_equal(result, STRV_MAKE(search1_a, search1_b, search1_c)));
- assert_se(found_files);
- assert_se(streq_ptr(found_files[0], expect_a));
- assert_se(streq_ptr(found_files[1], expect_b));
- assert_se(!found_files[2]);
+ result = strv_free(result);
- log_debug("/* Check when unfiltered */");
- assert_se(conf_files_list(&found_files2, NULL, root_dir, CONF_FILES_FILTER_MASKED, search) == 0);
- strv_print(found_files2);
+ assert_se(conf_files_list_at(&result, NULL, tfd, CONF_FILES_FILTER_MASKED, "/dir1/") >= 0);
+ strv_print(result);
+ assert_se(strv_equal(result, STRV_MAKE("dir1/a.conf", "dir1/b.conf", "dir1/c.foo")));
- assert_se(found_files2);
- assert_se(streq_ptr(found_files2[0], expect_a));
- assert_se(streq_ptr(found_files2[1], expect_b));
- assert_se(streq_ptr(found_files2[2], expect_c));
- assert_se(!found_files2[3]);
+ result = strv_free(result);
- assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
-}
+ /* search dir1 with suffix */
+ assert_se(conf_files_list(&result, ".conf", NULL, CONF_FILES_FILTER_MASKED, search1) >= 0);
+ strv_print(result);
+ assert_se(strv_equal(result, STRV_MAKE(search1_a, search1_b)));
-TEST(conf_files_list) {
- test_conf_files_list_one(false);
- test_conf_files_list_one(true);
+ result = strv_free(result);
+
+ assert_se(conf_files_list(&result, ".conf", t, CONF_FILES_FILTER_MASKED, "/dir1/") >= 0);
+ strv_print(result);
+ assert_se(strv_equal(result, STRV_MAKE(search1_a, search1_b)));
+
+ result = strv_free(result);
+
+ assert_se(conf_files_list_at(&result, ".conf", AT_FDCWD, CONF_FILES_FILTER_MASKED, search1) >= 0);
+ strv_print(result);
+ assert_se(strv_equal(result, STRV_MAKE(search1_a, search1_b)));
+
+ result = strv_free(result);
+
+ assert_se(conf_files_list_at(&result, ".conf", tfd, CONF_FILES_FILTER_MASKED, "/dir1/") >= 0);
+ strv_print(result);
+ assert_se(strv_equal(result, STRV_MAKE("dir1/a.conf", "dir1/b.conf")));
+
+ result = strv_free(result);
+
+ /* search two dirs */
+ assert_se(conf_files_list_strv(&result, ".conf", NULL, CONF_FILES_FILTER_MASKED, STRV_MAKE_CONST(search1, search2)) >= 0);
+ strv_print(result);
+ assert_se(strv_equal(result, STRV_MAKE(search1_a, search2_aa, search1_b)));
+
+ result = strv_free(result);
+
+ assert_se(conf_files_list_strv(&result, ".conf", t, CONF_FILES_FILTER_MASKED, STRV_MAKE_CONST("/dir1/", "/dir2/")) >= 0);
+ strv_print(result);
+ assert_se(strv_equal(result, STRV_MAKE(search1_a, search2_aa, search1_b)));
+
+ result = strv_free(result);
+
+ assert_se(conf_files_list_strv_at(&result, ".conf", AT_FDCWD, CONF_FILES_FILTER_MASKED, STRV_MAKE_CONST(search1, search2)) >= 0);
+ strv_print(result);
+ assert_se(strv_equal(result, STRV_MAKE(search1_a, search2_aa, search1_b)));
+
+ result = strv_free(result);
+
+ assert_se(conf_files_list_strv_at(&result, ".conf", tfd, CONF_FILES_FILTER_MASKED, STRV_MAKE_CONST("/dir1/", "/dir2/")) >= 0);
+ strv_print(result);
+ assert_se(strv_equal(result, STRV_MAKE("dir1/a.conf", "dir2/aa.conf", "dir1/b.conf")));
+
+ result = strv_free(result);
+
+ /* filename only */
+ assert_se(conf_files_list_strv(&result, ".conf", NULL, CONF_FILES_FILTER_MASKED | CONF_FILES_BASENAME, STRV_MAKE_CONST(search1, search2)) >= 0);
+ strv_print(result);
+ assert_se(strv_equal(result, STRV_MAKE("a.conf", "aa.conf", "b.conf")));
+
+ result = strv_free(result);
+
+ assert_se(conf_files_list_strv(&result, ".conf", t, CONF_FILES_FILTER_MASKED | CONF_FILES_BASENAME, STRV_MAKE_CONST("/dir1/", "/dir2/")) >= 0);
+ strv_print(result);
+ assert_se(strv_equal(result, STRV_MAKE("a.conf", "aa.conf", "b.conf")));
+
+ result = strv_free(result);
+
+ assert_se(conf_files_list_strv_at(&result, ".conf", AT_FDCWD, CONF_FILES_FILTER_MASKED | CONF_FILES_BASENAME, STRV_MAKE_CONST(search1, search2)) >= 0);
+ strv_print(result);
+ assert_se(strv_equal(result, STRV_MAKE("a.conf", "aa.conf", "b.conf")));
+
+ result = strv_free(result);
+
+ assert_se(conf_files_list_strv_at(&result, ".conf", tfd, CONF_FILES_FILTER_MASKED | CONF_FILES_BASENAME, STRV_MAKE_CONST("/dir1/", "/dir2/")) >= 0);
+ strv_print(result);
+ assert_se(strv_equal(result, STRV_MAKE("a.conf", "aa.conf", "b.conf")));
}
static void test_conf_files_insert_one(const char *root) {
diff --git a/src/test/test-copy.c b/src/test/test-copy.c
index 4cd83dbeea..df08b7ed61 100644
--- a/src/test/test-copy.c
+++ b/src/test/test-copy.c
@@ -301,7 +301,7 @@ static void test_copy_bytes_regular_file_one(const char *src, bool try_reflink,
log_info("%s try_reflink=%s max_bytes=%" PRIu64, __func__, yes_no(try_reflink), max_bytes);
- fd = open(src, O_RDONLY | O_CLOEXEC | O_NOCTTY);
+ fd = open(src, O_CLOEXEC | O_PATH);
assert_se(fd >= 0);
fd2 = mkostemp_safe(fn2);
diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c
index d8d622e44d..a570941cf3 100644
--- a/src/test/test-fileio.c
+++ b/src/test/test-fileio.c
@@ -1067,7 +1067,8 @@ static void test_read_virtual_file_one(size_t max_size) {
IN_SET(r,
-ENOENT, /* Some of the files might be absent */
-EINVAL, /* too small reads from /proc/self/pagemap trigger EINVAL */
- -EFBIG)); /* /proc/kcore and /proc/self/pagemap should be too large */
+ -EFBIG, /* /proc/kcore and /proc/self/pagemap should be too large */
+ -EBADF)); /* /proc/kcore is masked when we are running in docker. */
} else
log_info("read_virtual_file(\"%s\", %zu): %s (%zu bytes)", filename, max_size, r ? "non-truncated" : "truncated", size);
}
diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c
index 136005d51f..22e8f3481a 100644
--- a/src/test/test-path-util.c
+++ b/src/test/test-path-util.c
@@ -46,11 +46,6 @@ TEST(path) {
assert_se(!path_equal_ptr("/a", "/b"));
assert_se(!path_equal_ptr("/a", NULL));
assert_se(!path_equal_ptr(NULL, "/a"));
-
- assert_se(path_equal_filename("/a/c", "/b/c"));
- assert_se(path_equal_filename("/a", "/a"));
- assert_se(!path_equal_filename("/a/b", "/a/c"));
- assert_se(!path_equal_filename("/b", "/c"));
}
static void test_path_simplify_one(const char *in, const char *out) {
@@ -150,6 +145,55 @@ TEST(path_compare) {
test_path_compare_one("/foo/a/b", "/foo/aaa", -1);
}
+static void test_path_compare_filename_one(const char *a, const char *b, int expected) {
+ int r;
+
+ assert_se(path_compare_filename(a, a) == 0);
+ assert_se(path_compare_filename(b, b) == 0);
+
+ r = path_compare_filename(a, b);
+ assert_se((r > 0) == (expected > 0) && (r < 0) == (expected < 0));
+ r = path_compare_filename(b, a);
+ assert_se((r < 0) == (expected > 0) && (r > 0) == (expected < 0));
+
+ assert_se(path_equal_filename(a, a) == 1);
+ assert_se(path_equal_filename(b, b) == 1);
+ assert_se(path_equal_filename(a, b) == (expected == 0));
+ assert_se(path_equal_filename(b, a) == (expected == 0));
+}
+
+TEST(path_compare_filename) {
+ test_path_compare_filename_one("/goo", "/goo", 0);
+ test_path_compare_filename_one("/goo", "/goo", 0);
+ test_path_compare_filename_one("//goo", "/goo", 0);
+ test_path_compare_filename_one("//goo/////", "/goo", 0);
+ test_path_compare_filename_one("goo/////", "goo", 0);
+ test_path_compare_filename_one("/goo/boo", "/goo//boo", 0);
+ test_path_compare_filename_one("//goo/boo", "/goo/boo//", 0);
+ test_path_compare_filename_one("//goo/././//./boo//././//", "/goo/boo//.", 0);
+ test_path_compare_filename_one("/.", "//.///", -1);
+ test_path_compare_filename_one("/x", "x/", 0);
+ test_path_compare_filename_one("x/", "/", 1);
+ test_path_compare_filename_one("/x/./y", "x/y", 0);
+ test_path_compare_filename_one("/x/./y", "/x/y", 0);
+ test_path_compare_filename_one("/x/./././y", "/x/y/././.", 0);
+ test_path_compare_filename_one("./x/./././y", "./x/y/././.", 0);
+ test_path_compare_filename_one(".", "./.", -1);
+ test_path_compare_filename_one(".", "././.", -1);
+ test_path_compare_filename_one("./..", ".", 1);
+ test_path_compare_filename_one("x/.y", "x/y", -1);
+ test_path_compare_filename_one("foo", "/foo", 0);
+ test_path_compare_filename_one("/foo", "/foo/bar", 1);
+ test_path_compare_filename_one("/foo/aaa", "/foo/b", -1);
+ test_path_compare_filename_one("/foo/aaa", "/foo/b/a", 1);
+ test_path_compare_filename_one("/foo/a", "/foo/aaa", -1);
+ test_path_compare_filename_one("/foo/a/b", "/foo/aaa", 1);
+ test_path_compare_filename_one("/a/c", "/b/c", 0);
+ test_path_compare_filename_one("/a", "/a", 0);
+ test_path_compare_filename_one("/a/b", "/a/c", -1);
+ test_path_compare_filename_one("/b", "/c", -1);
+}
+
TEST(path_equal_root) {
/* Nail down the details of how path_equal("/", ...) works. */
@@ -450,6 +494,45 @@ TEST(fsck_exists) {
assert_se(fsck_exists_for_fstype("/../bin/") == 0);
}
+TEST(path_prefix_root_cwd) {
+ _cleanup_free_ char *cwd = NULL, *ret = NULL, *expected = NULL;
+
+ assert_se(safe_getcwd(&cwd) >= 0);
+
+ assert_se(path_prefix_root_cwd("hoge", NULL, &ret) >= 0);
+ assert_se(expected = path_join(cwd, "hoge"));
+ assert_se(streq(ret, expected));
+
+ ret = mfree(ret);
+ expected = mfree(expected);
+
+ assert_se(path_prefix_root_cwd("/hoge", NULL, &ret) >= 0);
+ assert_se(streq(ret, "/hoge"));
+
+ ret = mfree(ret);
+
+ assert_se(path_prefix_root_cwd("hoge", "/a/b//./c///", &ret) >= 0);
+ assert_se(streq(ret, "/a/b/c/hoge"));
+
+ ret = mfree(ret);
+
+ assert_se(path_prefix_root_cwd("hoge", "a/b//./c///", &ret) >= 0);
+ assert_se(expected = path_join(cwd, "a/b/c/hoge"));
+ assert_se(streq(ret, expected));
+
+ ret = mfree(ret);
+ expected = mfree(expected);
+
+ assert_se(path_prefix_root_cwd("/../hoge/aaa/../././b", "/a/b//./c///", &ret) >= 0);
+ assert_se(streq(ret, "/a/b/c/../hoge/aaa/../././b"));
+
+ ret = mfree(ret);
+
+ assert_se(path_prefix_root_cwd("/../hoge/aaa/../././b", "a/b//./c///", &ret) >= 0);
+ assert_se(expected = path_join(cwd, "a/b/c/../hoge/aaa/../././b"));
+ assert_se(streq(ret, expected));
+}
+
static void test_path_make_relative_one(const char *from, const char *to, const char *expected) {
_cleanup_free_ char *z = NULL;
int r;
@@ -632,9 +715,10 @@ static void test_path_find_first_component_one(
r = path_find_first_component(&p, accept_dot_dot, &e);
if (r <= 0) {
if (r == 0) {
- if (path)
+ if (path) {
assert_se(p == path + strlen_ptr(path));
- else
+ assert_se(isempty(p));
+ } else
assert_se(!p);
assert_se(!e);
}
@@ -647,6 +731,15 @@ static void test_path_find_first_component_one(
assert_se(strcspn(e, "/") == (size_t) r);
assert_se(strlen_ptr(*expected) == (size_t) r);
assert_se(strneq(e, *expected++, r));
+
+ assert_se(p);
+ log_debug("p=%s", p);
+ if (!isempty(*expected))
+ assert_se(startswith(p, *expected));
+ else if (ret >= 0) {
+ assert_se(p == path + strlen_ptr(path));
+ assert_se(isempty(p));
+ }
}
}
@@ -668,7 +761,7 @@ TEST(path_find_first_component) {
test_path_find_first_component_one("././//.///aa/bbb//./ccc", false, STRV_MAKE("aa", "bbb", "ccc"), 0);
test_path_find_first_component_one("././//.///aa/.../../bbb//./ccc/.", false, STRV_MAKE("aa", "..."), -EINVAL);
test_path_find_first_component_one("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/.", false, STRV_MAKE("aaa", ".bbb"), -EINVAL);
- test_path_find_first_component_one("a/foo./b", false, STRV_MAKE("a", "foo.", "b"), 0);
+ test_path_find_first_component_one("a/foo./b//././/", false, STRV_MAKE("a", "foo.", "b"), 0);
test_path_find_first_component_one(NULL, true, NULL, 0);
test_path_find_first_component_one("", true, NULL, 0);
@@ -684,7 +777,7 @@ TEST(path_find_first_component) {
test_path_find_first_component_one("././//.///aa/bbb//./ccc", true, STRV_MAKE("aa", "bbb", "ccc"), 0);
test_path_find_first_component_one("././//.///aa/.../../bbb//./ccc/.", true, STRV_MAKE("aa", "...", "..", "bbb", "ccc"), 0);
test_path_find_first_component_one("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/.", true, STRV_MAKE("aaa", ".bbb", "..", "c.", "d.dd", "..eeee"), 0);
- test_path_find_first_component_one("a/foo./b", true, STRV_MAKE("a", "foo.", "b"), 0);
+ test_path_find_first_component_one("a/foo./b//././/", true, STRV_MAKE("a", "foo.", "b"), 0);
memset(foo, 'a', sizeof(foo) -1);
char_array_0(foo);
@@ -726,6 +819,15 @@ static void test_path_find_last_component_one(
assert_se(strcspn(e, "/") == (size_t) r);
assert_se(strlen_ptr(*expected) == (size_t) r);
assert_se(strneq(e, *expected++, r));
+
+ assert_se(next);
+ log_debug("path=%s\nnext=%s", path, next);
+ if (!isempty(*expected)) {
+ assert_se(next < path + strlen(path));
+ assert_se(next >= path + strlen(*expected));
+ assert_se(startswith(next - strlen(*expected), *expected));
+ } else if (ret >= 0)
+ assert_se(next == path);
}
}
diff --git a/src/udev/scsi_id/scsi_id.c b/src/udev/scsi_id/scsi_id.c
index 364d567705..e7d8da7c50 100644
--- a/src/udev/scsi_id/scsi_id.c
+++ b/src/udev/scsi_id/scsi_id.c
@@ -32,8 +32,10 @@ static const struct option options[] = {
{ "device", required_argument, NULL, 'd' },
{ "config", required_argument, NULL, 'f' },
{ "page", required_argument, NULL, 'p' },
- { "blacklisted", no_argument, NULL, 'b' },
- { "whitelisted", no_argument, NULL, 'g' },
+ { "denylisted", no_argument, NULL, 'b' },
+ { "allowlisted", no_argument, NULL, 'g' },
+ { "blacklisted", no_argument, NULL, 'b' }, /* backward compat */
+ { "whitelisted", no_argument, NULL, 'g' }, /* backward compat */
{ "replace-whitespace", no_argument, NULL, 'u' },
{ "sg-version", required_argument, NULL, 's' },
{ "verbose", no_argument, NULL, 'v' },
@@ -222,8 +224,8 @@ static void help(void) {
" -f --config= Location of config file\n"
" -p --page=0x80|0x83|pre-spc3-83 SCSI page (0x80, 0x83, pre-spc3-83)\n"
" -s --sg-version=3|4 Use SGv3 or SGv4\n"
- " -b --blacklisted Treat device as blacklisted\n"
- " -g --whitelisted Treat device as whitelisted\n"
+ " -b --denylisted Treat device as denylisted\n"
+ " -g --allowlisted Treat device as allowlisted\n"
" -u --replace-whitespace Replace all whitespace by underscores\n"
" -v --verbose Verbose logging\n"
" -x --export Print values as environment keys\n",
diff --git a/src/udev/scsi_id/scsi_serial.c b/src/udev/scsi_id/scsi_serial.c
index c619506877..a271b1786c 100644
--- a/src/udev/scsi_id/scsi_serial.c
+++ b/src/udev/scsi_id/scsi_serial.c
@@ -161,7 +161,7 @@ static int scsi_dump_sense(struct scsi_id_device *dev_scsi,
* Figure out and print the sense key, asc and ascq.
*
* If you want to suppress these for a particular drive model, add
- * a black list entry in the scsi_id config file.
+ * a deny list entry in the scsi_id config file.
*
* XXX We probably need to: lookup the sense/asc/ascq in a retry
* table, and if found return 1 (after dumping the sense, asc, and
diff --git a/test/fuzz/fuzz-udev-rules/60-persistent-storage-tape.rules b/test/fuzz/fuzz-udev-rules/60-persistent-storage-tape.rules
index 0136140a46..40d6261c6e 100644
--- a/test/fuzz/fuzz-udev-rules/60-persistent-storage-tape.rules
+++ b/test/fuzz/fuzz-udev-rules/60-persistent-storage-tape.rules
@@ -6,7 +6,7 @@ ACTION=="remove", GOTO="persistent_storage_tape_end"
ENV{UDEV_DISABLE_PERSISTENT_STORAGE_RULES_FLAG}=="1", GOTO="persistent_storage_tape_end"
# type 8 devices are "Medium Changers"
-SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="8", IMPORT{program}="scsi_id --sg-version=3 --export --whitelisted -d $devnode", \
+SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="8", IMPORT{program}="scsi_id --sg-version=3 --export --allowlisted -d $devnode", \
SYMLINK+="tape/by-id/scsi-$env{ID_SERIAL}"
# iSCSI devices from the same host have all the same ID_SERIAL,
@@ -22,7 +22,7 @@ SUBSYSTEM!="scsi_tape", GOTO="persistent_storage_tape_end"
KERNEL=="st*[0-9]|nst*[0-9]", ATTRS{ieee1394_id}=="?*", ENV{ID_SERIAL}="$attr{ieee1394_id}", ENV{ID_BUS}="ieee1394"
KERNEL=="st*[0-9]|nst*[0-9]", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id"
KERNEL=="st*[0-9]|nst*[0-9]", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="scsi", KERNELS=="[0-9]*:*[0-9]", ENV{.BSG_DEV}="$root/bsg/$id"
-KERNEL=="st*[0-9]|nst*[0-9]", ENV{ID_SERIAL}!="?*", IMPORT{program}="scsi_id --whitelisted --export --device=$env{.BSG_DEV}", ENV{ID_BUS}="scsi"
+KERNEL=="st*[0-9]|nst*[0-9]", ENV{ID_SERIAL}!="?*", IMPORT{program}="scsi_id --allowlisted --export --device=$env{.BSG_DEV}", ENV{ID_BUS}="scsi"
KERNEL=="st*[0-9]", ENV{ID_SERIAL}=="?*", SYMLINK+="tape/by-id/$env{ID_BUS}-$env{ID_SERIAL}"
KERNEL=="st*[0-9]", ENV{ID_SCSI_SERIAL}=="?*", SYMLINK+="tape/by-id/$env{ID_BUS}-$env{ID_SCSI_SERIAL}"
KERNEL=="nst*[0-9]", ENV{ID_SERIAL}=="?*", SYMLINK+="tape/by-id/$env{ID_BUS}-$env{ID_SERIAL}-nst"
diff --git a/test/fuzz/fuzz-udev-rules/60-persistent-storage.rules b/test/fuzz/fuzz-udev-rules/60-persistent-storage.rules
index 93d562b070..b63225875b 100644
--- a/test/fuzz/fuzz-udev-rules/60-persistent-storage.rules
+++ b/test/fuzz/fuzz-udev-rules/60-persistent-storage.rules
@@ -49,8 +49,8 @@ KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", ATTR{removable}=="0", SUBSYSTEMS=
KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id"
# SCSI devices
-KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", IMPORT{program}="scsi_id --export --whitelisted -d $devnode", ENV{ID_BUS}="scsi"
-KERNEL=="cciss*", ENV{DEVTYPE}=="disk", ENV{ID_SERIAL}!="?*", IMPORT{program}="scsi_id --export --whitelisted -d $devnode", ENV{ID_BUS}="cciss"
+KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", IMPORT{program}="scsi_id --export --allowlisted -d $devnode", ENV{ID_BUS}="scsi"
+KERNEL=="cciss*", ENV{DEVTYPE}=="disk", ENV{ID_SERIAL}!="?*", IMPORT{program}="scsi_id --export --allowlisted -d $devnode", ENV{ID_BUS}="cciss"
KERNEL=="sd*|sr*|cciss*", ENV{DEVTYPE}=="disk", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/$env{ID_BUS}-$env{ID_SERIAL}"
KERNEL=="sd*|cciss*", ENV{DEVTYPE}=="partition", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/$env{ID_BUS}-$env{ID_SERIAL}-part%n"
diff --git a/test/udev-test.pl b/test/udev-test.pl
index 16c82bec0c..5873a5b646 100755
--- a/test/udev-test.pl
+++ b/test/udev-test.pl
@@ -2191,7 +2191,7 @@ TAGS=="aaa", SYMLINK+="bad"
EOF
},
{
- desc => "continuations with white only line",
+ desc => "continuations with space only line",
devices => [
{
devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
diff --git a/test/units/testsuite-01.sh b/test/units/testsuite-01.sh
index 469c5fe278..cd18a9fd74 100755
--- a/test/units/testsuite-01.sh
+++ b/test/units/testsuite-01.sh
@@ -3,33 +3,29 @@
set -eux
set -o pipefail
-STTY_ORIGINAL="$(stty --file=/dev/console --save)"
-
-at_exit() {
- set +e
- stty --file=/dev/console "${STTY_ORIGINAL:?}"
-}
-
-trap at_exit EXIT
-
-# Do one reexec beforehand to get /dev/console into some predictable state
-systemctl daemon-reexec
-
-# Check if we do skip the early setup when doing daemon-reexec
-# See: https://github.com/systemd/systemd/issues/27106
+# Check if we properly differentiate between a full systemd setup and a "light"
+# version of it that's done during daemon-reexec
#
-# Change a couple of console settings, do a reexec, and then check if our
-# changes persisted, since we reset the terminal stuff only on "full" reexec
-#
-# Relevant function: reset_terminal_fd() from terminal-util.cs
-stty --file=/dev/console brkint igncr inlcr istrip iuclc -icrnl -imaxbel -iutf8 \
- kill ^K quit ^I
-STTY_NEW="$(stty --file=/dev/console --save)"
-systemctl daemon-reexec
-diff <(echo "$STTY_NEW") <(stty --file=/dev/console --save)
+# See: https://github.com/systemd/systemd/issues/27106
+if systemd-detect-virt -q --container; then
+ # We initialize /run/systemd/container only during a full setup
+ test -e /run/systemd/container
+ cp -afv /run/systemd/container /tmp/container
+ rm -fv /run/systemd/container
+ systemctl daemon-reexec
+ test ! -e /run/systemd/container
+ cp -afv /tmp/container /run/systemd/container
+else
+ # We bring the loopback netdev up only during a full setup, so it should
+ # not get brought back up during reexec if we disable it beforehand
+ [[ "$(ip -o link show lo)" =~ LOOPBACK,UP ]]
+ ip link set lo down
+ [[ "$(ip -o link show lo)" =~ state\ DOWN ]]
+ systemctl daemon-reexec
+ [[ "$(ip -o link show lo)" =~ state\ DOWN ]]
+ ip link set lo up
-if ! systemd-detect-virt -qc; then
- # We also disable coredumps when doing a "full" reexec, so check for that too
+ # We also disable coredumps only during a full setup
sysctl -w kernel.core_pattern=dont-overwrite-me
systemctl daemon-reexec
diff <(echo dont-overwrite-me) <(sysctl --values kernel.core_pattern)
@@ -39,4 +35,10 @@ fi
systemctl --state=failed --no-legend --no-pager | tee /failed
systemctl daemon-reload
+# Check that the early setup is actually skipped on reexec.
+# If the early setup is done more than once, then several timestamps,
+# e.g. SecurityStartTimestamp, are re-initialized, and causes an ABRT
+# of systemd-analyze blame. See issue #27187.
+systemd-analyze blame
+
echo OK >/testok
diff --git a/test/units/testsuite-29.sh b/test/units/testsuite-29.sh
index c1cb2bc33e..1e4bd4ec42 100755
--- a/test/units/testsuite-29.sh
+++ b/test/units/testsuite-29.sh
@@ -29,7 +29,7 @@ if [[ -v ASAN_OPTIONS || -v UBSAN_OPTIONS ]]; then
STATE_DIRECTORY=/var/lib/
fi
# Bump the timeout if we're running with plain QEMU
-[[ "$(systemd-detect-virt -v)" == "qemu" ]] && TIMEOUT=60 || TIMEOUT=30
+[[ "$(systemd-detect-virt -v)" == "qemu" ]] && TIMEOUT=90 || TIMEOUT=30
systemd-dissect --no-pager /usr/share/minimal_0.raw | grep -q '✓ portable service'
systemd-dissect --no-pager /usr/share/minimal_1.raw | grep -q '✓ portable service'
diff --git a/test/units/testsuite-65.sh b/test/units/testsuite-65.sh
index edaf667107..0ee56dfc00 100755
--- a/test/units/testsuite-65.sh
+++ b/test/units/testsuite-65.sh
@@ -11,13 +11,15 @@ export SYSTEMD_LOG_LEVEL=debug
# Sanity checks
#
-# We can't really test time, blame, critical-chain and plot verbs here, as
+# We can't really test time, critical-chain and plot verbs here, as
# the testsuite service is a part of the boot transaction, so let's assume
# they fail
systemd-analyze || :
systemd-analyze time || :
-systemd-analyze blame || :
systemd-analyze critical-chain || :
+# blame
+systemd-analyze blame
+systemd-run --wait --user --pipe -M testuser@.host systemd-analyze blame
# plot
systemd-analyze plot >/dev/null || :
systemd-analyze plot --json=pretty >/dev/null || :
diff --git a/test/units/testsuite-75.sh b/test/units/testsuite-75.sh
index ddd86d09bb..c5487555b6 100755
--- a/test/units/testsuite-75.sh
+++ b/test/units/testsuite-75.sh
@@ -46,7 +46,7 @@ monitor_check_rr() (
# Test for resolvectl, resolvconf
systemctl unmask systemd-resolved.service
-systemctl start systemd-resolved.service
+systemctl enable --now systemd-resolved.service
systemctl service-log-level systemd-resolved.service debug
ip link add hoge type dummy
ip link add hoge.foo type dummy