summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/make_release.yml8
-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.c68
-rw-r--r--src/basic/chase.h5
-rw-r--r--src/basic/fd-util.c20
-rw-r--r--src/basic/fileio.c11
-rw-r--r--src/basic/fileio.h5
-rw-r--r--src/basic/path-util.c8
-rw-r--r--src/boot/bootctl-uki.c6
-rw-r--r--src/shared/kernel-image.c9
-rw-r--r--src/shared/kernel-image.h1
-rw-r--r--src/test/test-path-util.c27
-rwxr-xr-xtest/units/testsuite-01.sh6
-rwxr-xr-xtest/units/testsuite-65.sh6
18 files changed, 154 insertions, 87 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/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..f62c317026 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 (unsafe_transition(&previous_stat, &st))
- return log_unsafe_transition(child, fd, path, flags);
+ if (fstat(fd, &st) < 0)
+ return -errno;
- 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;
}
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/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 2c28a7f6b3..48ffb4e5e6 100644
--- a/src/basic/fileio.c
+++ b/src/basic/fileio.c
@@ -339,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) {
diff --git a/src/basic/fileio.h b/src/basic/fileio.h
index bda18fd066..769bf394fd 100644
--- a/src/basic/fileio.h
+++ b/src/basic/fileio.h
@@ -67,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);
diff --git a/src/basic/path-util.c b/src/basic/path-util.c
index a5ab6045cd..0b0f0da760 100644
--- a/src/basic/path-util.c
+++ b/src/basic/path-util.c
@@ -901,6 +901,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;
@@ -925,6 +927,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/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/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/test/test-path-util.c b/src/test/test-path-util.c
index 87e33919e0..e40ffea4d5 100644
--- a/src/test/test-path-util.c
+++ b/src/test/test-path-util.c
@@ -676,9 +676,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);
}
@@ -691,6 +692,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));
+ }
}
}
@@ -712,7 +722,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);
@@ -728,7 +738,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);
@@ -770,6 +780,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/test/units/testsuite-01.sh b/test/units/testsuite-01.sh
index ebb8a78128..cd18a9fd74 100755
--- a/test/units/testsuite-01.sh
+++ b/test/units/testsuite-01.sh
@@ -35,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-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 || :