1
0
mirror of https://github.com/systemd/systemd synced 2026-03-17 10:34:46 +01:00

Compare commits

...

27 Commits

Author SHA1 Message Date
novenary
399c8152ae hwdb: set touchpad resolution for all ThinkPad T49x chassis laptops
Confirmed with owners of T495 and T14 Gen2i.
P14s should be identical.
2026-01-18 21:26:04 +09:00
Yu Watanabe
112cbc3790 journal-file: do not trigger assertion on removed or corrupted journal file
When a journal file is removed or corrupted, then the value `p`, which is
read from Object.data.entry_offset, may be zero.

Note, journal_file_move_to_object() checks the passed offset and return
-EBADMSG if it is invalid.

Fixes the issue reported at
https://github.com/systemd/systemd/pull/40372#issuecomment-3762907261.
2026-01-18 21:25:20 +09:00
Daan De Meyer
103f7d2303
fd-util: introduce XAT_FDROOT fd shortcut for the root dir (#39244) 2026-01-18 11:57:11 +01:00
Yu Watanabe
fe7692227d mountfsd: fix potential memleak on malicious json message
This also makes json_log_oom() used on OOM.

Follow-up for 78b40aea611256228e898fc6a6dab414a1798889.
2026-01-18 18:03:21 +09:00
Yu Watanabe
f02e4b4f38
Several follow-ups for removal of SysV compat (#40371) 2026-01-18 18:02:53 +09:00
Mike Yuan
73b82070e1 docs,man: more SysV compat removal notes 2026-01-18 15:50:54 +09:00
Yu Watanabe
ff9c4ace70 mkosi/opensuse: do not build/install systemd-sysvcompat package
The package is now empty. It is not necessary to build it.

This also drops unnecessary modifications for files.*.
2026-01-18 15:49:37 +09:00
Yu Watanabe
badff4ce2a meson: update description of deprecated options 2026-01-18 15:48:02 +09:00
Yu Watanabe
a3f0d88fee systemctl: drop unnecessary shortcut for removed SysV compat support
Follow-up for 986fee6217051ce1ffdb53de45fdf9d7bae611ce.
2026-01-18 15:48:02 +09:00
Yu Watanabe
01885138be
Assorted cleanups (#40373) 2026-01-18 14:41:44 +09:00
Heran Yang
c55aadc13e core/unit: re-find dropin paths of a unit after writting settings
Fixes: ab932a622d57 ("core: simplify unit_need_daemon_reload() a bit")
Fixes #35710

Co-authored-by: Jian Wen <wenjianhn@gmail.com>
2026-01-18 14:14:24 +09:00
Mike Yuan
12effc32da
core/unit: several cleanups for unit_queue_job_check_and_collapse_type()
* Rename to _mangle_type() - it turned out this one doesn't collapse
  anything, but rather mangles the type if reload_if_possible is set.
  Hence name accordingly.
* Use -ELIBEXEC rather than -EUNATCH to denote dependency only units.
* Add a comment about the JOB_STOP and load state check.
2026-01-17 15:00:10 +01:00
Mike Yuan
490067d41c
core/dbus-manager: be explicit that job enqueue errors are from EnqueueMarkedJobs call
Follow-up for 502d6f4bc9b96009627f923dcc0ab53e5a181d78
2026-01-17 15:00:10 +01:00
Mike Yuan
7fb883fea8
core/dbus-unit: remove reference to cgroup v1 attribute 2026-01-17 15:00:09 +01:00
Mike Yuan
0fcad6eead
core/main: use saturate_add() where appropriate 2026-01-17 15:00:09 +01:00
Mike Yuan
3e9ed98514
logind-varlink: add missing validation for session class
D-Bus CreateSession() method carries this check, but the varlink
one didn't.
2026-01-17 15:00:09 +01:00
Lennart Poettering
6527f64600 test-fs-util: some basic tests for XAT_FDROOT 2026-01-17 12:37:55 +01:00
Lennart Poettering
80499cf1c8 find-esp: make use of XAT_FDROOT 2026-01-17 12:37:39 +01:00
Lennart Poettering
7e64b58f4c kernel-image: pass through XAT_FDROOT 2026-01-17 12:37:39 +01:00
Lennart Poettering
192f71baed id128-util: pass through XAT_FDROOT 2026-01-17 12:37:39 +01:00
Lennart Poettering
95abe4beff stat-util: write up XAT_FDROOT in stat-util.[ch] 2026-01-17 12:37:39 +01:00
Lennart Poettering
c67abc9c43 chase: extend coverage of the root fd shortcut
Let's use dir_fd_is_root() to check if we are looking at the real root
fs.
2026-01-17 12:37:39 +01:00
Lennart Poettering
ded2531764 chase: optimize the special case where no root dir specified
Now that we can recognize the root dir in chaseat() sanely, let's use it
top optimize the very common special case where we have no root dir to
consider, and directly call open_tree().
2026-01-17 12:37:39 +01:00
Lennart Poettering
874971b1c0 chase: wire up XAT_FDROOT 2026-01-17 12:37:39 +01:00
Lennart Poettering
5667cbcacf fd-util: wire up XAT_FDROOT in various really basic fd-util.h calls 2026-01-17 12:37:39 +01:00
Lennart Poettering
ef582ab201 fs-util: wire up XAT_FDROOT in xopenat_full() and access_fd() 2026-01-17 12:37:33 +01:00
Lennart Poettering
ee79c9d309 fd-util: introduce XAT_FDROOT fd shortcut for the root dir
This takes inspiration from AT_FDCWD, but always references the root dir
rather than the cwd. This allows various convenience uses, as we can now
reference the root dir without actually allocating an fd for chaseat(),
fd_get_path() and various others.

The value of XAT_FDROOT is chosen so that it is not a valid fd (essential,
because we do not intend to hook this up everywhere, just where we need
it, just like AT_FCWD only works in some syscalls), and we want uses at
the wrong places to fail cleanly. It also uses a valud outside of the
range where we usually return negative errnos, i.e. < -ERRNO_MAX.
2026-01-17 12:35:33 +01:00
27 changed files with 365 additions and 115 deletions

View File

@ -7,6 +7,10 @@ SPDX-License-Identifier: LGPL-2.1-or-later
# Compatibility with SysV # Compatibility with SysV
Since systemd v260, support for SysV functionalities has been removed. The documentation below is preserved for historical references only.
## Pre v260 state
systemd provides a fair degree of compatibility with the behavior exposed by the SysV init system as implemented by many distributions. systemd provides a fair degree of compatibility with the behavior exposed by the SysV init system as implemented by many distributions.
Compatibility is provided both for the user experience and the SysV scripting APIs. Compatibility is provided both for the user experience and the SysV scripting APIs.
However, there are some areas where compatibility is limited due to technical reasons or design decisions of systemd and the distributions. However, there are some areas where compatibility is limited due to technical reasons or design decisions of systemd and the distributions.
@ -33,5 +37,3 @@ Many of the incompatibilities are specific to distribution-specific extensions o
* systemd's handling of the existing "nofail" mount option in /etc/fstab is stricter than it used to be on some sysvinit distributions: mount points that fail and are not listed as "nofail" will cause the boot to be stopped, for security reasons, as we should not permit unprivileged code to run without everything listed — and not expressly exempted through "nofail" — being around. Hence, please mark all mounts where booting shall proceed regardless whether they succeeded or not with "nofail" * systemd's handling of the existing "nofail" mount option in /etc/fstab is stricter than it used to be on some sysvinit distributions: mount points that fail and are not listed as "nofail" will cause the boot to be stopped, for security reasons, as we should not permit unprivileged code to run without everything listed — and not expressly exempted through "nofail" — being around. Hence, please mark all mounts where booting shall proceed regardless whether they succeeded or not with "nofail"
* Some SysV systems support an "rc.local" script that is supposed to be called "last" during boot. In systemd, the script is supported, but the semantics are less strict, as there is simply no concept of "last service", as the boot process is event- and request-based, parallelized and compositive. In general, it's a good idea to write proper unit files with properly defined dependencies, and avoid making use of rc.local. * Some SysV systems support an "rc.local" script that is supposed to be called "last" during boot. In systemd, the script is supported, but the semantics are less strict, as there is simply no concept of "last service", as the boot process is event- and request-based, parallelized and compositive. In general, it's a good idea to write proper unit files with properly defined dependencies, and avoid making use of rc.local.
* systemd assumes that the UID boundary between system and regular users is a choice the distribution makes, and not the administrator. Hence it expects this setting as compile-time option to be picked by the distribution. It will _not_ check /etc/login.defs during runtime. * systemd assumes that the UID boundary between system and regular users is a choice the distribution makes, and not the administrator. Hence it expects this setting as compile-time option to be picked by the distribution. It will _not_ check /etc/login.defs during runtime.
Note that there are some areas where systemd currently provides a certain amount of compatibility where we expect this compatibility to be removed eventually.

View File

@ -760,12 +760,15 @@ evdev:name:AlpsPS/2 ALPS GlidePoint:dmi:*svnLENOVO:*pvrLenovoU41-70:*
EVDEV_ABS_35=117:3958:36 EVDEV_ABS_35=117:3958:36
EVDEV_ABS_36=104:1960:26 EVDEV_ABS_36=104:1960:26
# Lenovo Thinkpad T490 and T14/P14s Gen1/2 # Lenovo Thinkpad T490/T495 and T14/P14s Gen1/2 (identical chassis)
evdev:name:SynPS/2 Synaptics TouchPad:dmi:*:svnLENOVO:*pvrThinkPadT490:* evdev:name:SynPS/2 Synaptics TouchPad:dmi:*:svnLENOVO:*pvrThinkPadT490:*
evdev:name:SynPS/2 Synaptics TouchPad:dmi:*:svnLENOVO:*pvrThinkPadT495:*
evdev:name:SynPS/2 Synaptics TouchPad:dmi:*:svnLENOVO:*pvrThinkPadT14Gen1:* evdev:name:SynPS/2 Synaptics TouchPad:dmi:*:svnLENOVO:*pvrThinkPadT14Gen1:*
evdev:name:SynPS/2 Synaptics TouchPad:dmi:*:svnLENOVO:*pvrThinkPadT14Gen2a:* evdev:name:SynPS/2 Synaptics TouchPad:dmi:*:svnLENOVO:*pvrThinkPadT14Gen2a:*
evdev:name:SynPS/2 Synaptics TouchPad:dmi:*:svnLENOVO:*pvrThinkPadT14Gen2i:*
evdev:name:SynPS/2 Synaptics TouchPad:dmi:*:svnLENOVO:*pvrThinkPadP14sGen1:* evdev:name:SynPS/2 Synaptics TouchPad:dmi:*:svnLENOVO:*pvrThinkPadP14sGen1:*
evdev:name:SynPS/2 Synaptics TouchPad:dmi:*:svnLENOVO:*pvrThinkPadP14sGen2a:* evdev:name:SynPS/2 Synaptics TouchPad:dmi:*:svnLENOVO:*pvrThinkPadP14sGen2a:*
evdev:name:SynPS/2 Synaptics TouchPad:dmi:*:svnLENOVO:*pvrThinkPadP14sGen2i:*
EVDEV_ABS_00=::44 EVDEV_ABS_00=::44
EVDEV_ABS_01=::52 EVDEV_ABS_01=::52
EVDEV_ABS_35=::44 EVDEV_ABS_35=::44

View File

@ -284,11 +284,11 @@
<para>Old-style daemons are usually activated exclusively on boot (and manually by the administrator) <para>Old-style daemons are usually activated exclusively on boot (and manually by the administrator)
via SysV init scripts, as detailed in the <ulink via SysV init scripts, as detailed in the <ulink
url="http://refspecs.linuxbase.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic/iniscrptact.html">LSB url="http://refspecs.linuxbase.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic/iniscrptact.html">LSB
Linux Standard Base Core Specification</ulink>. This method of activation is supported ubiquitously on Linux Standard Base Core Specification</ulink>. Among other issues, SysV init scripts have
Linux init systems, both old-style and new-style systems. Among other issues, SysV init scripts have the disadvantage of involving shell scripts in the boot process. Support for init scripts has been
the disadvantage of involving shell scripts in the boot process. New-style init systems generally use phased out in modern Linux init systems, and should not be relied upon. New-style init systems
updated versions of activation, both during boot-up and during runtime and using more minimal service generally use updated versions of activation, both during boot-up and during runtime and using
description files.</para> more minimal service description files.</para>
<para>In systemd, if the developer or administrator wants to <para>In systemd, if the developer or administrator wants to
make sure that a service or other unit is activated make sure that a service or other unit is activated

View File

@ -46,7 +46,8 @@ option('sysvinit-path', type : 'string', value : '/etc/init.d', deprecated : tru
option('sysvrcnd-path', type : 'string', value : '/etc/rc.d', deprecated : true, option('sysvrcnd-path', type : 'string', value : '/etc/rc.d', deprecated : true,
description : 'This option is deprecated and will be removed in a future release') description : 'This option is deprecated and will be removed in a future release')
option('rc-local', type : 'string', value : '/etc/rc.local', deprecated : true, option('rc-local', type : 'string', value : '/etc/rc.local', deprecated : true,
description : 'path to SysV rc.local script') description : 'This option is deprecated and will be removed in a future release')
option('initrd', type : 'boolean', option('initrd', type : 'boolean',
description : 'install services for use when running systemd in initrd') description : 'install services for use when running systemd in initrd')
option('compat-mutable-uid-boundaries', type : 'boolean', value : false, option('compat-mutable-uid-boundaries', type : 'boolean', value : false,
@ -439,9 +440,9 @@ option('idn', type : 'boolean',
option('libidn2', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' }, option('libidn2', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' },
description : 'libidn2 support') description : 'libidn2 support')
option('libidn', type : 'feature', deprecated : true, option('libidn', type : 'feature', deprecated : true,
description : 'libidn support') description : 'This option is deprecated and will be removed in a future release')
option('libiptc', type : 'feature', deprecated : true, option('libiptc', type : 'feature', deprecated : true,
description : 'libiptc support') description : 'This option is deprecated and will be removed in a future release')
option('qrencode', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' }, option('qrencode', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' },
description : 'libqrencode support') description : 'libqrencode support')
option('gcrypt', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' }, option('gcrypt', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' },

View File

@ -25,7 +25,6 @@ VolatilePackages=
systemd-networkd systemd-networkd
systemd-portable systemd-portable
systemd-resolved systemd-resolved
systemd-sysvcompat
systemd-testsuite systemd-testsuite
systemd-ukify systemd-ukify
udev udev

View File

@ -23,11 +23,7 @@ TS="${SOURCE_DATE_EPOCH:-$(date +%s)}"
# when the upstream spec is updated # when the upstream spec is updated
while read -r filelist; do while read -r filelist; do
sed -E \ sed -E \
-e 's/\.gz$//; /systemd-cgroups-agent/d; s/import-pubring.gpg/import-pubring.pgp/' \ -e 's/\.gz$//' \
-e '/(initctl|runlevel|telinit)/ d' \
-e 's/systemd-quotacheck.service.8/systemd-quotacheck@.service.8/' \
-e '/systemd-sysv-generator/d' \
-e '/rc-local/d' \
"$filelist" >"/tmp/$(basename "$filelist")" "$filelist" >"/tmp/$(basename "$filelist")"
mount --bind "/tmp/$(basename "$filelist")" "$filelist" mount --bind "/tmp/$(basename "$filelist")" "$filelist"
done < <(find "pkg/$PKG_SUBDIR${GIT_SUBDIR:+/$GIT_SUBDIR}" -name "files.*") done < <(find "pkg/$PKG_SUBDIR${GIT_SUBDIR:+/$GIT_SUBDIR}" -name "files.*")
@ -97,6 +93,7 @@ build() {
--noprep \ --noprep \
--build-in-place \ --build-in-place \
--with upstream \ --with upstream \
--without sysvcompat \
$( ((WITH_TESTS)) || echo "--nocheck") \ $( ((WITH_TESTS)) || echo "--nocheck") \
--define "_topdir /var/tmp" \ --define "_topdir /var/tmp" \
--define "_sourcedir $PWD/pkg/$PKG_SUBDIR${GIT_SUBDIR:+/$GIT_SUBDIR}" \ --define "_sourcedir $PWD/pkg/$PKG_SUBDIR${GIT_SUBDIR:+/$GIT_SUBDIR}" \

View File

@ -128,6 +128,7 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
unsigned max_follow = CHASE_MAX; /* how many symlinks to follow before giving up and returning ELOOP */ unsigned max_follow = CHASE_MAX; /* how many symlinks to follow before giving up and returning ELOOP */
bool exists = true, append_trail_slash = false; bool exists = true, append_trail_slash = false;
struct stat st; /* stat obtained from fd */ struct stat st; /* stat obtained from fd */
bool need_absolute = false; /* allocate early to avoid compiler warnings around goto */
const char *todo; const char *todo;
int r; int r;
@ -135,7 +136,7 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
assert(!FLAGS_SET(flags, CHASE_MUST_BE_DIRECTORY|CHASE_MUST_BE_REGULAR)); assert(!FLAGS_SET(flags, CHASE_MUST_BE_DIRECTORY|CHASE_MUST_BE_REGULAR));
assert(!FLAGS_SET(flags, CHASE_STEP|CHASE_EXTRACT_FILENAME)); assert(!FLAGS_SET(flags, CHASE_STEP|CHASE_EXTRACT_FILENAME));
assert(!FLAGS_SET(flags, CHASE_NO_AUTOFS|CHASE_TRIGGER_AUTOFS)); assert(!FLAGS_SET(flags, CHASE_NO_AUTOFS|CHASE_TRIGGER_AUTOFS));
assert(dir_fd >= 0 || dir_fd == AT_FDCWD); assert(dir_fd >= 0 || IN_SET(dir_fd, AT_FDCWD, XAT_FDROOT));
if (FLAGS_SET(flags, CHASE_STEP)) if (FLAGS_SET(flags, CHASE_STEP))
assert(!ret_fd); assert(!ret_fd);
@ -218,7 +219,45 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
* the mount point is emitted. CHASE_WARN cannot be used in PID 1. * the mount point is emitted. CHASE_WARN cannot be used in PID 1.
*/ */
if (FLAGS_SET(flags, CHASE_AT_RESOLVE_IN_ROOT)) { _cleanup_close_ int _dir_fd = -EBADF;
r = dir_fd_is_root(dir_fd);
if (r < 0)
return r;
if (r > 0) {
/* Shortcut the common case where no root dir is specified, and no special flags are given to
* a regular open() */
if (!ret_path &&
(flags & (CHASE_STEP|CHASE_NO_AUTOFS|CHASE_NONEXISTENT|CHASE_SAFE|CHASE_WARN|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0) {
_cleanup_free_ char *slash_path = NULL;
if (!path_is_absolute(path)) {
slash_path = strjoin("/", path);
if (!slash_path)
return -ENOMEM;
}
/* We use open_tree() rather than regular open() here, because it gives us direct
* control over automount behaviour, and otherwise is equivalent to open() with
* O_PATH */
fd = open_tree(-EBADF, slash_path ?: path, OPEN_TREE_CLOEXEC|(FLAGS_SET(flags, CHASE_TRIGGER_AUTOFS) ? 0 : AT_NO_AUTOMOUNT));
if (fd < 0)
return -errno;
if (fstat(fd, &st) < 0)
return -errno;
exists = true;
goto success;
}
_dir_fd = open("/", O_DIRECTORY|O_RDONLY|O_CLOEXEC);
if (_dir_fd < 0)
return -errno;
dir_fd = _dir_fd;
flags &= ~CHASE_AT_RESOLVE_IN_ROOT;
} else if (FLAGS_SET(flags, CHASE_AT_RESOLVE_IN_ROOT)) {
/* If we get AT_FDCWD or dir_fd points to "/", then we always resolve symlinks relative to /* If we get AT_FDCWD or dir_fd points to "/", then we always resolve symlinks relative to
* the host's root. Hence, CHASE_AT_RESOLVE_IN_ROOT is meaningless. */ * the host's root. Hence, CHASE_AT_RESOLVE_IN_ROOT is meaningless. */
@ -251,7 +290,7 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
if (r < 0) if (r < 0)
return r; return r;
bool need_absolute = r; need_absolute = r;
if (need_absolute) { if (need_absolute) {
done = strdup("/"); done = strdup("/");
if (!done) if (!done)
@ -514,6 +553,7 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
close_and_replace(fd, child); close_and_replace(fd, child);
} }
success:
if (exists) { if (exists) {
if (FLAGS_SET(flags, CHASE_MUST_BE_DIRECTORY)) { if (FLAGS_SET(flags, CHASE_MUST_BE_DIRECTORY)) {
r = stat_verify_directory(&st); r = stat_verify_directory(&st);
@ -656,9 +696,13 @@ int chase(const char *path, const char *root, ChaseFlags flags, char **ret_path,
"Specified path '%s' is outside of specified root directory '%s', refusing to resolve.", "Specified path '%s' is outside of specified root directory '%s', refusing to resolve.",
absolute, root); absolute, root);
if (empty_or_root(root))
fd = XAT_FDROOT;
else {
fd = open(root, O_CLOEXEC|O_DIRECTORY|O_PATH); fd = open(root, O_CLOEXEC|O_DIRECTORY|O_PATH);
if (fd < 0) if (fd < 0)
return -errno; return -errno;
}
r = chaseat(fd, path, flags & ~CHASE_PREFIX_ROOT, ret_path ? &p : NULL, ret_fd ? &pfd : NULL); r = chaseat(fd, path, flags & ~CHASE_PREFIX_ROOT, ret_path ? &p : NULL, ret_fd ? &pfd : NULL);
if (r < 0) if (r < 0)

View File

@ -572,10 +572,12 @@ bool fdname_is_valid(const char *s) {
int fd_get_path(int fd, char **ret) { int fd_get_path(int fd, char **ret) {
int r; int r;
assert(fd >= 0 || fd == AT_FDCWD); assert(fd >= 0 || IN_SET(fd, AT_FDCWD, XAT_FDROOT));
if (fd == AT_FDCWD) if (fd == AT_FDCWD)
return safe_getcwd(ret); return safe_getcwd(ret);
if (fd == XAT_FDROOT)
return strdup_to(ret, "/");
r = readlink_malloc(FORMAT_PROC_FD_PATH(fd), ret); r = readlink_malloc(FORMAT_PROC_FD_PATH(fd), ret);
if (r == -ENOENT) if (r == -ENOENT)
@ -770,7 +772,7 @@ finish:
} }
int fd_reopen(int fd, int flags) { int fd_reopen(int fd, int flags) {
assert(fd >= 0 || fd == AT_FDCWD); assert(fd >= 0 || IN_SET(fd, AT_FDCWD, XAT_FDROOT));
assert(!FLAGS_SET(flags, O_CREAT)); assert(!FLAGS_SET(flags, O_CREAT));
/* Reopens the specified fd with new flags. This is useful for convert an O_PATH fd into a regular one, or to /* Reopens the specified fd with new flags. This is useful for convert an O_PATH fd into a regular one, or to
@ -782,6 +784,8 @@ int fd_reopen(int fd, int flags) {
* *
* If AT_FDCWD is specified as file descriptor gets an fd to the current cwd. * If AT_FDCWD is specified as file descriptor gets an fd to the current cwd.
* *
* If XAT_FDROOT is specified as fd get an fd to the root directory.
*
* If the specified file descriptor refers to a symlink via O_PATH, then this function cannot be used * If the specified file descriptor refers to a symlink via O_PATH, then this function cannot be used
* to follow that symlink. Because we cannot have non-O_PATH fds to symlinks reopening it without * to follow that symlink. Because we cannot have non-O_PATH fds to symlinks reopening it without
* O_PATH will always result in -ELOOP. Or in other words: if you have an O_PATH fd to a symlink you * O_PATH will always result in -ELOOP. Or in other words: if you have an O_PATH fd to a symlink you
@ -795,6 +799,9 @@ int fd_reopen(int fd, int flags) {
* the same way as the non-O_DIRECTORY case. */ * the same way as the non-O_DIRECTORY case. */
return -ELOOP; return -ELOOP;
if (fd == XAT_FDROOT)
return RET_NERRNO(open("/", flags | O_DIRECTORY));
if (FLAGS_SET(flags, O_DIRECTORY) || fd == AT_FDCWD) if (FLAGS_SET(flags, O_DIRECTORY) || fd == AT_FDCWD)
/* If we shall reopen the fd as directory we can just go via "." and thus bypass the whole /* If we shall reopen the fd as directory we can just go via "." and thus bypass the whole
* magic /proc/ directory, and make ourselves independent of that being mounted. */ * magic /proc/ directory, and make ourselves independent of that being mounted. */
@ -1025,19 +1032,36 @@ int fd_get_diskseq(int fd, uint64_t *ret) {
return 0; return 0;
} }
static bool is_literal_root(const char *p) {
if (!p)
return false;
/* Check if string consists of at least one '/', and possibly more, but nothing else */
size_t n = strspn(p, "/");
return n >= 1 && p[n] == 0;
}
int path_is_root_at(int dir_fd, const char *path) { int path_is_root_at(int dir_fd, const char *path) {
assert(dir_fd >= 0 || dir_fd == AT_FDCWD); assert(dir_fd >= 0 || IN_SET(dir_fd, AT_FDCWD, XAT_FDROOT));
if (dir_fd == XAT_FDROOT && isempty(path))
return true;
if (IN_SET(dir_fd, XAT_FDROOT, AT_FDCWD) && is_literal_root(path))
return true;
_cleanup_close_ int fd = -EBADF; _cleanup_close_ int fd = -EBADF;
if (!isempty(path)) { if (!isempty(path)) {
fd = openat(dir_fd, path, O_PATH|O_DIRECTORY|O_CLOEXEC); fd = xopenat(dir_fd, path, O_PATH|O_DIRECTORY|O_CLOEXEC);
if (fd == -ENOTDIR)
return false; /* the root dir must be a dir */
if (fd < 0) if (fd < 0)
return errno == ENOTDIR ? false : -errno; return fd;
dir_fd = fd; dir_fd = fd;
} }
_cleanup_close_ int root_fd = openat(AT_FDCWD, "/", O_PATH|O_DIRECTORY|O_CLOEXEC); _cleanup_close_ int root_fd = open("/", O_PATH|O_DIRECTORY|O_CLOEXEC);
if (root_fd < 0) if (root_fd < 0)
return -errno; return -errno;
@ -1055,13 +1079,27 @@ int path_is_root_at(int dir_fd, const char *path) {
int fds_are_same_mount(int fd1, int fd2) { int fds_are_same_mount(int fd1, int fd2) {
struct statx sx1 = {}, sx2 = {}; /* explicitly initialize the struct to make msan silent. */ struct statx sx1 = {}, sx2 = {}; /* explicitly initialize the struct to make msan silent. */
assert(fd1 >= 0); assert(fd1 >= 0 || IN_SET(fd1, AT_FDCWD, XAT_FDROOT));
assert(fd2 >= 0); assert(fd2 >= 0 || IN_SET(fd2, AT_FDCWD, XAT_FDROOT));
if (statx(fd1, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sx1) < 0) const char *fn1;
if (fd1 == XAT_FDROOT) {
fd1 = AT_FDCWD;
fn1 = "/";
} else
fn1 = "";
if (statx(fd1, fn1, AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sx1) < 0)
return -errno; return -errno;
if (statx(fd2, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sx2) < 0) const char *fn2;
if (fd2 == XAT_FDROOT) {
fd2 = AT_FDCWD;
fn2 = "/";
} else
fn2 = "";
if (statx(fd2, fn2, AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sx2) < 0)
return -errno; return -errno;
return statx_inode_same(&sx1, &sx2) && statx_mount_same(&sx1, &sx2); return statx_inode_same(&sx1, &sx2) && statx_mount_same(&sx1, &sx2);

View File

@ -57,6 +57,13 @@
#define NR_OPEN_MINIMUM ((unsigned) (sizeof(long) * 8)) #define NR_OPEN_MINIMUM ((unsigned) (sizeof(long) * 8))
#define NR_OPEN_MAXIMUM ((unsigned) (CONST_MIN((size_t) INT_MAX, SIZE_MAX / __SIZEOF_POINTER__) & ~(sizeof(long) * 8 - 1))) #define NR_OPEN_MAXIMUM ((unsigned) (CONST_MIN((size_t) INT_MAX, SIZE_MAX / __SIZEOF_POINTER__) & ~(sizeof(long) * 8 - 1)))
/* A special fd that can be passed in various helpers instead of an fd indicating the root dir. Inspired by,
* and an alternative to AT_FDCWD. We use specific negative value that is outside of the negative errno
* range, to avoid any potential ambiguities. */
#define XAT_FDROOT -8192
assert_cc(XAT_FDROOT != AT_FDCWD);
assert_cc(XAT_FDROOT < -ERRNO_MAX);
int close_nointr(int fd); int close_nointr(int fd);
int safe_close(int fd); int safe_close(int fd);
void safe_close_pair(int p[static 2]); void safe_close_pair(int p[static 2]);
@ -166,10 +173,10 @@ static inline int path_is_root(const char *path) {
return path_is_root_at(AT_FDCWD, path); return path_is_root_at(AT_FDCWD, path);
} }
static inline int dir_fd_is_root(int dir_fd) { static inline int dir_fd_is_root(int dir_fd) {
return path_is_root_at(dir_fd, NULL); return dir_fd == XAT_FDROOT ? true : path_is_root_at(dir_fd, NULL);
} }
static inline int dir_fd_is_root_or_cwd(int dir_fd) { static inline int dir_fd_is_root_or_cwd(int dir_fd) {
return dir_fd == AT_FDCWD ? true : path_is_root_at(dir_fd, NULL); return IN_SET(dir_fd, AT_FDCWD, XAT_FDROOT) ? true : path_is_root_at(dir_fd, NULL);
} }
int fds_are_same_mount(int fd1, int fd2); int fds_are_same_mount(int fd1, int fd2);

View File

@ -713,10 +713,15 @@ char* unlink_and_free(char *p) {
} }
int access_fd(int fd, int mode) { int access_fd(int fd, int mode) {
assert(fd >= 0);
/* Like access() but operates on an already open fd */ /* Like access() but operates on an already open fd */
if (fd == AT_FDCWD)
return RET_NERRNO(access(".", mode));
if (fd == XAT_FDROOT)
return RET_NERRNO(access("/", mode));
assert(fd >= 0);
if (faccessat(fd, "", mode, AT_EMPTY_PATH) >= 0) if (faccessat(fd, "", mode, AT_EMPTY_PATH) >= 0)
return 0; return 0;
if (errno != EINVAL) if (errno != EINVAL)
@ -1160,7 +1165,7 @@ int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_
bool made_dir = false, made_file = false; bool made_dir = false, made_file = false;
int r; int r;
assert(dir_fd >= 0 || dir_fd == AT_FDCWD); assert(dir_fd >= 0 || IN_SET(dir_fd, AT_FDCWD, XAT_FDROOT));
/* An inode cannot be both a directory and a regular file at the same time. */ /* An inode cannot be both a directory and a regular file at the same time. */
assert(!(FLAGS_SET(open_flags, O_DIRECTORY) && FLAGS_SET(xopen_flags, XO_REGULAR))); assert(!(FLAGS_SET(open_flags, O_DIRECTORY) && FLAGS_SET(xopen_flags, XO_REGULAR)));
@ -1179,8 +1184,23 @@ int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_
* if XO_REGULAR is specified will return an error if inode is not a regular file. * if XO_REGULAR is specified will return an error if inode is not a regular file.
* *
* If mode is specified as MODE_INVALID, we'll use 0755 for dirs, and 0644 for regular files. * If mode is specified as MODE_INVALID, we'll use 0755 for dirs, and 0644 for regular files.
*
* The dir fd can be passed as XAT_FDROOT, in which case any relative paths will be taken relative to the root fs.
*/ */
_cleanup_close_ int _dir_fd = -EBADF;
if (dir_fd == XAT_FDROOT) {
if (path_is_absolute(path))
dir_fd = AT_FDCWD;
else {
_dir_fd = open("/", O_CLOEXEC|O_DIRECTORY|O_RDONLY);
if (_dir_fd < 0)
return -errno;
dir_fd = _dir_fd;
}
}
if (mode == MODE_INVALID) if (mode == MODE_INVALID)
mode = (open_flags & O_DIRECTORY) ? 0755 : 0644; mode = (open_flags & O_DIRECTORY) ? 0755 : 0644;

View File

@ -31,10 +31,25 @@ static int verify_stat_at(
struct stat st; struct stat st;
int r; int r;
assert(fd >= 0 || fd == AT_FDCWD); assert(fd >= 0 || IN_SET(fd, AT_FDCWD, XAT_FDROOT));
assert(!isempty(path) || !follow); assert(!isempty(path) || !follow);
assert(verify_func); assert(verify_func);
_cleanup_free_ char *p = NULL;
if (fd == XAT_FDROOT) {
fd = AT_FDCWD;
if (isempty(path))
path = "/";
else if (!path_is_absolute(path)) {
p = strjoin("/", path);
if (!p)
return -ENOMEM;
path = p;
}
}
if (fstatat(fd, strempty(path), &st, if (fstatat(fd, strempty(path), &st,
(isempty(path) ? AT_EMPTY_PATH : 0) | (follow ? 0 : AT_SYMLINK_NOFOLLOW)) < 0) (isempty(path) ? AT_EMPTY_PATH : 0) | (follow ? 0 : AT_SYMLINK_NOFOLLOW)) < 0)
return -errno; return -errno;
@ -66,8 +81,10 @@ int verify_regular_at(int fd, const char *path, bool follow) {
} }
int fd_verify_regular(int fd) { int fd_verify_regular(int fd) {
assert(fd >= 0); if (IN_SET(fd, AT_FDCWD, XAT_FDROOT))
return verify_regular_at(fd, NULL, false); return -EISDIR;
return verify_regular_at(fd, /* path= */ NULL, /* follow= */ false);
} }
int stat_verify_directory(const struct stat *st) { int stat_verify_directory(const struct stat *st) {
@ -83,7 +100,9 @@ int stat_verify_directory(const struct stat *st) {
} }
int fd_verify_directory(int fd) { int fd_verify_directory(int fd) {
assert(fd >= 0); if (IN_SET(fd, AT_FDCWD, XAT_FDROOT))
return 0;
return verify_stat_at(fd, NULL, false, stat_verify_directory, true); return verify_stat_at(fd, NULL, false, stat_verify_directory, true);
} }
@ -127,7 +146,10 @@ int stat_verify_linked(const struct stat *st) {
} }
int fd_verify_linked(int fd) { int fd_verify_linked(int fd) {
assert(fd >= 0);
if (fd == XAT_FDROOT)
return 0;
return verify_stat_at(fd, NULL, false, stat_verify_linked, true); return verify_stat_at(fd, NULL, false, stat_verify_linked, true);
} }
@ -223,23 +245,33 @@ int null_or_empty_path_with_root(const char *fn, const char *root) {
return null_or_empty(&st); return null_or_empty(&st);
} }
int fd_is_read_only_fs(int fd) { static int xfstatfs(int fd, struct statfs *ret) {
struct statfs st; assert(ret);
if (fd == AT_FDCWD)
return RET_NERRNO(statfs(".", ret));
if (fd == XAT_FDROOT)
return RET_NERRNO(statfs("/", ret));
assert(fd >= 0); assert(fd >= 0);
return RET_NERRNO(fstatfs(fd, ret));
}
if (fstatfs(fd, &st) < 0) int fd_is_read_only_fs(int fd) {
return -errno; int r;
struct statfs st;
r = xfstatfs(fd, &st);
if (r < 0)
return r;
if (st.f_flags & ST_RDONLY) if (st.f_flags & ST_RDONLY)
return true; return true;
if (is_network_fs(&st)) { if (is_network_fs(&st))
/* On NFS, fstatfs() might not reflect whether we can actually write to the remote share. /* On NFS, fstatfs() might not reflect whether we can actually write to the remote share.
* Let's try again with access(W_OK) which is more reliable, at least sometimes. */ * Let's try again with access(W_OK) which is more reliable, at least sometimes. */
if (access_fd(fd, W_OK) == -EROFS) return access_fd(fd, W_OK) == -EROFS;
return true;
}
return false; return false;
} }
@ -364,9 +396,9 @@ bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
} }
int is_fs_type_at(int dir_fd, const char *path, statfs_f_type_t magic_value) { int is_fs_type_at(int dir_fd, const char *path, statfs_f_type_t magic_value) {
struct statfs s;
int r; int r;
struct statfs s;
r = xstatfsat(dir_fd, path, &s); r = xstatfsat(dir_fd, path, &s);
if (r < 0) if (r < 0)
return r; return r;
@ -383,19 +415,23 @@ bool is_network_fs(const struct statfs *s) {
} }
int fd_is_temporary_fs(int fd) { int fd_is_temporary_fs(int fd) {
struct statfs s; int r;
if (fstatfs(fd, &s) < 0) struct statfs s;
return -errno; r = xfstatfs(fd, &s);
if (r < 0)
return r;
return is_temporary_fs(&s); return is_temporary_fs(&s);
} }
int fd_is_network_fs(int fd) { int fd_is_network_fs(int fd) {
struct statfs s; int r;
if (fstatfs(fd, &s) < 0) struct statfs s;
return -errno; r = xfstatfs(fd, &s);
if (r < 0)
return r;
return is_network_fs(&s); return is_network_fs(&s);
} }
@ -489,7 +525,7 @@ bool statx_mount_same(const struct statx *a, const struct statx *b) {
int xstatfsat(int dir_fd, const char *path, struct statfs *ret) { int xstatfsat(int dir_fd, const char *path, struct statfs *ret) {
_cleanup_close_ int fd = -EBADF; _cleanup_close_ int fd = -EBADF;
assert(dir_fd >= 0 || dir_fd == AT_FDCWD); assert(dir_fd >= 0 || IN_SET(dir_fd, AT_FDCWD, XAT_FDROOT));
assert(ret); assert(ret);
if (!isempty(path)) { if (!isempty(path)) {
@ -499,7 +535,7 @@ int xstatfsat(int dir_fd, const char *path, struct statfs *ret) {
dir_fd = fd; dir_fd = fd;
} }
return RET_NERRNO(fstatfs(dir_fd, ret)); return RET_NERRNO(xfstatfs(dir_fd, ret));
} }
usec_t statx_timestamp_load(const struct statx_timestamp *ts) { usec_t statx_timestamp_load(const struct statx_timestamp *ts) {

View File

@ -2146,10 +2146,9 @@ static int method_enqueue_marked_jobs(sd_bus_message *message, void *userdata, s
reply, &error); reply, &error);
if (ERRNO_IS_NEG_RESOURCE(r)) if (ERRNO_IS_NEG_RESOURCE(r))
return r; return r;
if (r < 0) { if (r < 0)
RET_GATHER(ret, r); RET_GATHER(ret, log_unit_warning_errno(u, r, "Failed to enqueue marked job: %s",
log_warning_errno(r, "%s", bus_error_message(&error, r)); bus_error_message(&error, r)));
}
} }
if (ret < 0) if (ret < 0)

View File

@ -1199,7 +1199,7 @@ static int property_get_cpu_usage(
r = unit_get_cpu_usage(u, &ns); r = unit_get_cpu_usage(u, &ns);
if (r < 0 && r != -ENODATA) if (r < 0 && r != -ENODATA)
log_unit_warning_errno(u, r, "Failed to get cpuacct.usage attribute: %m"); log_unit_warning_errno(u, r, "Failed to get CPU usage: %m");
return sd_bus_message_append(reply, "t", ns); return sd_bus_message_append(reply, "t", ns);
} }
@ -1962,10 +1962,10 @@ int bus_unit_queue_job_one(
assert(u); assert(u);
r = unit_queue_job_check_and_collapse_type(u, &type, /* reload_if_possible= */ FLAGS_SET(flags, BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE)); r = unit_queue_job_check_and_mangle_type(u, &type, /* reload_if_possible= */ FLAGS_SET(flags, BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE));
if (r == -ENOENT) if (r == -ENOENT)
return sd_bus_error_setf(reterr_error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id); return sd_bus_error_setf(reterr_error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
if (r == -EUNATCH) if (r == -ELIBEXEC)
return sd_bus_error_setf(reterr_error, return sd_bus_error_setf(reterr_error,
BUS_ERROR_ONLY_BY_DEPENDENCY, BUS_ERROR_ONLY_BY_DEPENDENCY,
"Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).", "Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).",

View File

@ -2808,7 +2808,7 @@ static void determine_default_oom_score_adjust(void) {
return (void) log_warning_errno(r, "Failed to determine current OOM score adjustment value, ignoring: %m"); return (void) log_warning_errno(r, "Failed to determine current OOM score adjustment value, ignoring: %m");
assert_cc(100 <= OOM_SCORE_ADJ_MAX); assert_cc(100 <= OOM_SCORE_ADJ_MAX);
b = a >= OOM_SCORE_ADJ_MAX - 100 ? OOM_SCORE_ADJ_MAX : a + 100; b = saturate_add(a, 100, OOM_SCORE_ADJ_MAX);
if (a == b) if (a == b)
return; return;

View File

@ -4748,12 +4748,11 @@ int unit_write_setting(Unit *u, UnitWriteFlags flags, const char *name, const ch
if (r < 0) if (r < 0)
return r; return r;
r = strv_push(&u->dropin_paths, q); _cleanup_strv_free_ char **dropins = NULL;
r = unit_find_dropin_paths(u, /* use_unit_path_cache= */ true, &dropins);
if (r < 0) if (r < 0)
return r; return r;
q = NULL; strv_free_and_replace(u->dropin_paths, dropins);
strv_uniq(u->dropin_paths);
u->dropin_mtime = now(CLOCK_REALTIME); u->dropin_mtime = now(CLOCK_REALTIME);
@ -7004,7 +7003,7 @@ UnitDependency unit_mount_dependency_type_to_dependency_type(UnitMountDependency
} }
} }
int unit_queue_job_check_and_collapse_type( int unit_queue_job_check_and_mangle_type(
Unit *u, Unit *u,
JobType *type, /* input and output */ JobType *type, /* input and output */
bool reload_if_possible) { bool reload_if_possible) {
@ -7012,7 +7011,7 @@ int unit_queue_job_check_and_collapse_type(
/* Returns: /* Returns:
* *
* -ENOENT Unit not loaded * -ENOENT Unit not loaded
* -EUNATCH Unit can only be activated via dependency, not directly * -ELIBEXEC Unit can only be activated via dependency, not directly
* -ESHUTDOWN System bus is shutting down */ * -ESHUTDOWN System bus is shutting down */
JobType t; JobType t;
@ -7029,6 +7028,8 @@ int unit_queue_job_check_and_collapse_type(
t = JOB_TRY_RELOAD; t = JOB_TRY_RELOAD;
} }
/* Our transaction logic allows units not properly loaded to be stopped. But if already dead
* let's return clear error to caller. */
if (t == JOB_STOP && UNIT_IS_LOAD_ERROR(u->load_state) && unit_active_state(u) == UNIT_INACTIVE) if (t == JOB_STOP && UNIT_IS_LOAD_ERROR(u->load_state) && unit_active_state(u) == UNIT_INACTIVE)
return -ENOENT; return -ENOENT;
@ -7036,7 +7037,7 @@ int unit_queue_job_check_and_collapse_type(
(t == JOB_STOP && u->refuse_manual_stop) || (t == JOB_STOP && u->refuse_manual_stop) ||
(IN_SET(t, JOB_RESTART, JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)) || (IN_SET(t, JOB_RESTART, JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)) ||
(t == JOB_RELOAD_OR_START && job_type_collapse(t, u) == JOB_START && u->refuse_manual_start)) (t == JOB_RELOAD_OR_START && job_type_collapse(t, u) == JOB_START && u->refuse_manual_start))
return -EUNATCH; return -ELIBEXEC;
/* dbus-broker issues StartUnit for activation requests, and Type=dbus services automatically /* dbus-broker issues StartUnit for activation requests, and Type=dbus services automatically
* gain dependency on dbus.socket. Therefore, if dbus has a pending stop job, the new start * gain dependency on dbus.socket. Therefore, if dbus has a pending stop job, the new start

View File

@ -1092,7 +1092,7 @@ UnitDependency unit_mount_dependency_type_to_dependency_type(UnitMountDependency
DECLARE_STRING_TABLE_LOOKUP(oom_policy, OOMPolicy); DECLARE_STRING_TABLE_LOOKUP(oom_policy, OOMPolicy);
int unit_queue_job_check_and_collapse_type(Unit *u, JobType *type, bool reload_if_possible); int unit_queue_job_check_and_mangle_type(Unit *u, JobType *type, bool reload_if_possible);
/* Macros which append UNIT= or USER_UNIT= to the message */ /* Macros which append UNIT= or USER_UNIT= to the message */

View File

@ -315,10 +315,10 @@ static int varlink_manager_queue_job_one(
assert(u); assert(u);
r = unit_queue_job_check_and_collapse_type(u, &type, /* reload_if_possible= */ BIT_SET(u->markers, UNIT_MARKER_NEEDS_RELOAD)); r = unit_queue_job_check_and_mangle_type(u, &type, /* reload_if_possible= */ BIT_SET(u->markers, UNIT_MARKER_NEEDS_RELOAD));
if (r == -ENOENT) if (r == -ENOENT)
return varlink_error_no_such_unit(link, "name"); return varlink_error_no_such_unit(link, "name");
if (r == -EUNATCH) if (r == -ELIBEXEC)
return sd_varlink_errorb(link, VARLINK_ERROR_MANAGER_ONLY_BY_DEPENDENCY); return sd_varlink_errorb(link, VARLINK_ERROR_MANAGER_ONLY_BY_DEPENDENCY);
if (r == -ESHUTDOWN) if (r == -ESHUTDOWN)
return sd_varlink_errorb(link, VARLINK_ERROR_MANAGER_BUS_SHUTTING_DOWN); return sd_varlink_errorb(link, VARLINK_ERROR_MANAGER_BUS_SHUTTING_DOWN);

View File

@ -140,7 +140,7 @@ int id128_read_fd(int fd, Id128Flag f, sd_id128_t *ret) {
int id128_read_at(int dir_fd, const char *path, Id128Flag f, sd_id128_t *ret) { int id128_read_at(int dir_fd, const char *path, Id128Flag f, sd_id128_t *ret) {
_cleanup_close_ int fd = -EBADF; _cleanup_close_ int fd = -EBADF;
assert(dir_fd >= 0 || dir_fd == AT_FDCWD); assert(dir_fd >= 0 || IN_SET(dir_fd, AT_FDCWD, XAT_FDROOT));
assert(path); assert(path);
fd = xopenat(dir_fd, path, O_RDONLY|O_CLOEXEC|O_NOCTTY); fd = xopenat(dir_fd, path, O_RDONLY|O_CLOEXEC|O_NOCTTY);

View File

@ -3318,7 +3318,9 @@ use_extra:
static int test_object_offset(JournalFile *f, uint64_t p, uint64_t needle) { static int test_object_offset(JournalFile *f, uint64_t p, uint64_t needle) {
assert(f); assert(f);
assert(p > 0);
if (p <= 0)
return -EBADMSG;
if (p == needle) if (p == needle)
return TEST_FOUND; return TEST_FOUND;
@ -3354,7 +3356,6 @@ static int test_object_seqnum(JournalFile *f, uint64_t p, uint64_t needle) {
int r; int r;
assert(f); assert(f);
assert(p > 0);
r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o); r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
if (r < 0) if (r < 0)
@ -3395,7 +3396,6 @@ static int test_object_realtime(JournalFile *f, uint64_t p, uint64_t needle) {
int r; int r;
assert(f); assert(f);
assert(p > 0);
r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o); r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
if (r < 0) if (r < 0)
@ -3436,7 +3436,6 @@ static int test_object_monotonic(JournalFile *f, uint64_t p, uint64_t needle) {
int r; int r;
assert(f); assert(f);
assert(p > 0);
r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o); r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
if (r < 0) if (r < 0)

View File

@ -184,6 +184,9 @@ static int vl_method_create_session(sd_varlink *link, sd_json_variant *parameter
if (r != 0) if (r != 0)
return r; return r;
if (p.class == SESSION_NONE)
return sd_varlink_error_invalid_parameter_name(link, "Class");
Seat *seat = NULL; Seat *seat = NULL;
if (p.seat) { if (p.seat) {
seat = hashmap_get(m->seats, p.seat); seat = hashmap_get(m->seats, p.seat);

View File

@ -65,6 +65,7 @@ static const ImagePolicy image_policy_untrusted = {
static int json_dispatch_image_options(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) { static int json_dispatch_image_options(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
_cleanup_(mount_options_free_allp) MountOptions *options = NULL; _cleanup_(mount_options_free_allp) MountOptions *options = NULL;
MountOptions **p = ASSERT_PTR(userdata); MountOptions **p = ASSERT_PTR(userdata);
int r;
if (sd_json_variant_is_null(variant)) { if (sd_json_variant_is_null(variant)) {
*p = mount_options_free_all(*p); *p = mount_options_free_all(*p);
@ -87,12 +88,12 @@ static int json_dispatch_image_options(const char *name, sd_json_variant *varian
if (!options) { if (!options) {
options = new0(MountOptions, 1); options = new0(MountOptions, 1);
if (!options) if (!options)
return -ENOMEM; return json_log_oom(variant, flags);
} }
options->options[pd] = strdup(sd_json_variant_string(e)); r = free_and_strdup(&options->options[pd], sd_json_variant_string(e));
if (!options->options[pd]) if (r < 0)
return -ENOMEM; return json_log_oom(variant, flags);
} }
mount_options_free_all(*p); mount_options_free_all(*p);

View File

@ -332,7 +332,7 @@ static int verify_esp(
dev_t devid = 0; dev_t devid = 0;
int r; int r;
assert(rfd >= 0 || rfd == AT_FDCWD); assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
assert(path); assert(path);
/* This logs about all errors, except: /* This logs about all errors, except:
@ -442,14 +442,14 @@ int find_esp_and_warn_at(
VerifyESPFlags flags; VerifyESPFlags flags;
int r; int r;
assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
/* This logs about all errors except: /* This logs about all errors except:
* *
* -ENOKEY when we can't find the partition * -ENOKEY when we can't find the partition
* -EACCESS when unprivileged_mode is true, and we can't access something * -EACCESS when unprivileged_mode is true, and we can't access something
*/ */
assert(rfd >= 0 || rfd == AT_FDCWD);
flags = verify_esp_flags_init(unprivileged_mode, "SYSTEMD_RELAX_ESP_CHECKS"); flags = verify_esp_flags_init(unprivileged_mode, "SYSTEMD_RELAX_ESP_CHECKS");
if (path) if (path)
@ -527,9 +527,13 @@ int find_esp_and_warn(
dev_t devid; dev_t devid;
int r; int r;
rfd = open(empty_to_root(root), O_PATH|O_DIRECTORY|O_CLOEXEC); if (empty_or_root(root))
rfd = XAT_FDROOT;
else {
rfd = open(root, O_PATH|O_DIRECTORY|O_CLOEXEC);
if (rfd < 0) if (rfd < 0)
return -errno; return -errno;
}
r = find_esp_and_warn_at( r = find_esp_and_warn_at(
rfd, rfd,
@ -737,7 +741,7 @@ static int verify_xbootldr(
dev_t devid = 0; dev_t devid = 0;
int r; int r;
assert(rfd >= 0 || rfd == AT_FDCWD); assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
assert(path); assert(path);
r = chaseat(rfd, path, CHASE_AT_RESOLVE_IN_ROOT|CHASE_PARENT|CHASE_TRIGGER_AUTOFS, &p, &pfd); r = chaseat(rfd, path, CHASE_AT_RESOLVE_IN_ROOT|CHASE_PARENT|CHASE_TRIGGER_AUTOFS, &p, &pfd);
@ -800,7 +804,7 @@ int find_xbootldr_and_warn_at(
/* Similar to find_esp_and_warn(), but finds the XBOOTLDR partition. Returns the same errors. */ /* Similar to find_esp_and_warn(), but finds the XBOOTLDR partition. Returns the same errors. */
assert(rfd >= 0 || rfd == AT_FDCWD); assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
flags = verify_esp_flags_init(unprivileged_mode, "SYSTEMD_RELAX_XBOOTLDR_CHECKS"); flags = verify_esp_flags_init(unprivileged_mode, "SYSTEMD_RELAX_XBOOTLDR_CHECKS");
@ -862,9 +866,13 @@ int find_xbootldr_and_warn(
dev_t devid; dev_t devid;
int r; int r;
rfd = open(empty_to_root(root), O_PATH|O_DIRECTORY|O_CLOEXEC); if (empty_or_root(root))
rfd = XAT_FDROOT;
else {
rfd = open(root, O_PATH|O_DIRECTORY|O_CLOEXEC);
if (rfd < 0) if (rfd < 0)
return -errno; return -errno;
}
r = find_xbootldr_and_warn_at( r = find_xbootldr_and_warn_at(
rfd, rfd,

View File

@ -3,6 +3,7 @@
#include "alloc-util.h" #include "alloc-util.h"
#include "env-file.h" #include "env-file.h"
#include "fd-util.h" #include "fd-util.h"
#include "fs-util.h"
#include "kernel-image.h" #include "kernel-image.h"
#include "log.h" #include "log.h"
#include "pe-binary.h" #include "pe-binary.h"
@ -134,12 +135,12 @@ int inspect_kernel(
_cleanup_close_ int fd = -EBADF; _cleanup_close_ int fd = -EBADF;
int r; int r;
assert(dir_fd >= 0 || dir_fd == AT_FDCWD); assert(dir_fd >= 0 || IN_SET(dir_fd, AT_FDCWD, XAT_FDROOT));
assert(filename); assert(filename);
fd = openat(dir_fd, filename, O_RDONLY|O_CLOEXEC); fd = xopenat(dir_fd, filename, O_RDONLY|O_CLOEXEC);
if (fd < 0) if (fd < 0)
return log_error_errno(errno, "Failed to open kernel image file '%s': %m", filename); return log_error_errno(fd, "Failed to open kernel image file '%s': %m", filename);
r = pe_load_headers(fd, &dos_header, &pe_header); r = pe_load_headers(fd, &dos_header, &pe_header);
if (r == -EBADMSG) /* not a valid PE file */ if (r == -EBADMSG) /* not a valid PE file */

View File

@ -96,15 +96,6 @@ int verb_enable(int argc, char *argv[], void *userdata) {
if (r < 0) if (r < 0)
return r; return r;
/* If the operation was fully executed by the SysV compat, let's finish early */
if (strv_isempty(names)) {
if (arg_no_reload || install_client_side() != INSTALL_CLIENT_SIDE_NO)
return 0;
r = daemon_reload(ACTION_RELOAD, /* graceful= */ false);
return r > 0 ? 0 : r;
}
if (streq(verb, "disable")) if (streq(verb, "disable"))
r = normalize_names(names); r = normalize_names(names);
else if (streq(verb, "link")) else if (streq(verb, "link"))

View File

@ -499,6 +499,36 @@ TEST(chaseat) {
fd = safe_close(fd); fd = safe_close(fd);
/* Same but with XAT_FDROOT */
_cleanup_close_ int found_fd1 = -EBADF;
ASSERT_OK(chaseat(XAT_FDROOT, p, 0, &result, &found_fd1));
ASSERT_STREQ(result, "/usr");
result = mfree(result);
_cleanup_close_ int found_fd2 = -EBADF;
ASSERT_OK(chaseat(XAT_FDROOT, p, CHASE_AT_RESOLVE_IN_ROOT, &result, &found_fd2));
ASSERT_STREQ(result, "/usr");
result = mfree(result);
assert(fd_inode_same(found_fd1, found_fd2) > 0);
/* Do the same XAT_FDROOT tests again, this time without querying the path, so that the open_tree()
* shortcut can work */
_cleanup_close_ int found_fd3 = -EBADF;
ASSERT_OK(chaseat(XAT_FDROOT, p, 0, NULL, &found_fd3));
assert(fd_inode_same(found_fd1, found_fd3) > 0);
assert(fd_inode_same(found_fd2, found_fd3) > 0);
_cleanup_close_ int found_fd4 = -EBADF;
ASSERT_OK(chaseat(XAT_FDROOT, p, CHASE_AT_RESOLVE_IN_ROOT, NULL, &found_fd4));
assert(fd_inode_same(found_fd1, found_fd4) > 0);
assert(fd_inode_same(found_fd2, found_fd4) > 0);
assert(fd_inode_same(found_fd3, found_fd4) > 0);
found_fd1 = safe_close(found_fd1);
found_fd2 = safe_close(found_fd2);
found_fd3 = safe_close(found_fd3);
found_fd4 = safe_close(found_fd4);
/* If the file descriptor does not point to the root directory, the result will be relative /* If the file descriptor does not point to the root directory, the result will be relative
* unless the result is outside of the specified file descriptor. */ * unless the result is outside of the specified file descriptor. */

View File

@ -819,11 +819,6 @@ TEST(linkat_replace) {
assert_se(inode_same_at(fd1, NULL, fd2_check, NULL, AT_EMPTY_PATH) > 0); assert_se(inode_same_at(fd1, NULL, fd2_check, NULL, AT_EMPTY_PATH) > 0);
} }
static int intro(void) {
arg_test_dir = saved_argv[1];
return EXIT_SUCCESS;
}
TEST(readlinkat_malloc) { TEST(readlinkat_malloc) {
_cleanup_(rm_rf_physical_and_freep) char *t = NULL; _cleanup_(rm_rf_physical_and_freep) char *t = NULL;
_cleanup_close_ int tfd = -EBADF, fd = -EBADF; _cleanup_close_ int tfd = -EBADF, fd = -EBADF;
@ -859,4 +854,68 @@ TEST(readlinkat_malloc) {
q = mfree(q); q = mfree(q);
} }
TEST(xat_fdroot) {
_cleanup_free_ char *p = NULL;
ASSERT_OK(fd_get_path(XAT_FDROOT, &p));
ASSERT_STREQ(p, "/");
_cleanup_close_ int fd = -EBADF;
fd = fd_reopen(XAT_FDROOT, O_CLOEXEC);
ASSERT_OK(fd);
ASSERT_OK_POSITIVE(path_is_root_at(XAT_FDROOT, NULL));
ASSERT_OK_POSITIVE(path_is_root_at(XAT_FDROOT, "."));
ASSERT_OK_POSITIVE(path_is_root_at(XAT_FDROOT, "/"));
ASSERT_OK_POSITIVE(path_is_root_at(fd, NULL));
ASSERT_OK_POSITIVE(path_is_root_at(fd, "."));
ASSERT_OK_POSITIVE(path_is_root_at(fd, "/"));
ASSERT_OK_POSITIVE(fds_are_same_mount(fd, fd));
ASSERT_OK_POSITIVE(fds_are_same_mount(XAT_FDROOT, XAT_FDROOT));
ASSERT_OK_POSITIVE(fds_are_same_mount(fd, XAT_FDROOT));
ASSERT_OK_POSITIVE(fds_are_same_mount(XAT_FDROOT, fd));
ASSERT_OK_POSITIVE(dir_fd_is_root(XAT_FDROOT));
ASSERT_OK_POSITIVE(dir_fd_is_root(fd));
ASSERT_OK_POSITIVE(dir_fd_is_root_or_cwd(XAT_FDROOT));
ASSERT_OK_POSITIVE(dir_fd_is_root_or_cwd(AT_FDCWD));
ASSERT_OK_POSITIVE(dir_fd_is_root_or_cwd(fd));
ASSERT_OK(access_fd(XAT_FDROOT, F_OK));
ASSERT_OK(access_fd(fd, F_OK));
fd = safe_close(fd);
fd = xopenat(XAT_FDROOT, ".", O_RDONLY);
ASSERT_OK(fd);
fd = safe_close(fd);
fd = xopenat(XAT_FDROOT, "/", O_RDONLY);
ASSERT_OK(fd);
ASSERT_OK(fd_verify_directory(fd));
ASSERT_OK(fd_verify_directory(XAT_FDROOT));
ASSERT_OK(fd_verify_linked(fd));
ASSERT_OK(fd_verify_linked(XAT_FDROOT));
int a = fd_is_read_only_fs(fd);
ASSERT_OK(a);
int b = fd_is_read_only_fs(XAT_FDROOT);
ASSERT_OK(b);
ASSERT_EQ(a, b);
a = fd_is_temporary_fs(fd);
ASSERT_OK(a);
b = fd_is_temporary_fs(XAT_FDROOT);
ASSERT_OK(b);
ASSERT_EQ(a, b);
}
static int intro(void) {
arg_test_dir = saved_argv[1];
return EXIT_SUCCESS;
}
DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro); DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);

View File

@ -712,6 +712,17 @@ EOF
clear_units test15-a.service clear_units test15-a.service
} }
testcase_order_dropin_paths_set_property() {
# For issue #35710.
echo "Testing the order of dropin paths that are created by set-property"
create_service test15-a
systemctl set-property test15-a DevicePolicy=strict DeviceAllow="char-* m"
check_ok test15-a NeedDaemonReload no
clear_units test15-a.service
}
run_testcases run_testcases
touch /testok touch /testok