mirror of
https://github.com/systemd/systemd
synced 2026-03-17 10:34:46 +01:00
Compare commits
27 Commits
7b6b7d484d
...
399c8152ae
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
399c8152ae | ||
|
|
112cbc3790 | ||
|
|
103f7d2303 | ||
|
|
fe7692227d | ||
|
|
f02e4b4f38 | ||
|
|
73b82070e1 | ||
|
|
ff9c4ace70 | ||
|
|
badff4ce2a | ||
|
|
a3f0d88fee | ||
|
|
01885138be | ||
|
|
c55aadc13e | ||
|
|
12effc32da | ||
|
|
490067d41c | ||
|
|
7fb883fea8 | ||
|
|
0fcad6eead | ||
|
|
3e9ed98514 | ||
|
|
6527f64600 | ||
|
|
80499cf1c8 | ||
|
|
7e64b58f4c | ||
|
|
192f71baed | ||
|
|
95abe4beff | ||
|
|
c67abc9c43 | ||
|
|
ded2531764 | ||
|
|
874971b1c0 | ||
|
|
5667cbcacf | ||
|
|
ef582ab201 | ||
|
|
ee79c9d309 |
@ -7,6 +7,10 @@ SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
# 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.
|
||||
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.
|
||||
@ -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"
|
||||
* 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.
|
||||
|
||||
Note that there are some areas where systemd currently provides a certain amount of compatibility where we expect this compatibility to be removed eventually.
|
||||
|
||||
@ -760,12 +760,15 @@ evdev:name:AlpsPS/2 ALPS GlidePoint:dmi:*svnLENOVO:*pvrLenovoU41-70:*
|
||||
EVDEV_ABS_35=117:3958:36
|
||||
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:*pvrThinkPadT495:*
|
||||
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:*pvrThinkPadT14Gen2i:*
|
||||
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:*pvrThinkPadP14sGen2i:*
|
||||
EVDEV_ABS_00=::44
|
||||
EVDEV_ABS_01=::52
|
||||
EVDEV_ABS_35=::44
|
||||
|
||||
@ -284,11 +284,11 @@
|
||||
<para>Old-style daemons are usually activated exclusively on boot (and manually by the administrator)
|
||||
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
|
||||
Linux Standard Base Core Specification</ulink>. This method of activation is supported ubiquitously on
|
||||
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. New-style init systems generally use
|
||||
updated versions of activation, both during boot-up and during runtime and using more minimal service
|
||||
description files.</para>
|
||||
Linux Standard Base Core Specification</ulink>. Among other issues, SysV init scripts have
|
||||
the disadvantage of involving shell scripts in the boot process. Support for init scripts has been
|
||||
phased out in modern Linux init systems, and should not be relied upon. New-style init systems
|
||||
generally use updated versions of activation, both during boot-up and during runtime and using
|
||||
more minimal service description files.</para>
|
||||
|
||||
<para>In systemd, if the developer or administrator wants to
|
||||
make sure that a service or other unit is activated
|
||||
|
||||
@ -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,
|
||||
description : 'This option is deprecated and will be removed in a future release')
|
||||
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',
|
||||
description : 'install services for use when running systemd in initrd')
|
||||
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' },
|
||||
description : 'libidn2 support')
|
||||
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,
|
||||
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' },
|
||||
description : 'libqrencode support')
|
||||
option('gcrypt', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' },
|
||||
|
||||
@ -25,7 +25,6 @@ VolatilePackages=
|
||||
systemd-networkd
|
||||
systemd-portable
|
||||
systemd-resolved
|
||||
systemd-sysvcompat
|
||||
systemd-testsuite
|
||||
systemd-ukify
|
||||
udev
|
||||
|
||||
@ -23,11 +23,7 @@ TS="${SOURCE_DATE_EPOCH:-$(date +%s)}"
|
||||
# when the upstream spec is updated
|
||||
while read -r filelist; do
|
||||
sed -E \
|
||||
-e 's/\.gz$//; /systemd-cgroups-agent/d; s/import-pubring.gpg/import-pubring.pgp/' \
|
||||
-e '/(initctl|runlevel|telinit)/ d' \
|
||||
-e 's/systemd-quotacheck.service.8/systemd-quotacheck@.service.8/' \
|
||||
-e '/systemd-sysv-generator/d' \
|
||||
-e '/rc-local/d' \
|
||||
-e 's/\.gz$//' \
|
||||
"$filelist" >"/tmp/$(basename "$filelist")"
|
||||
mount --bind "/tmp/$(basename "$filelist")" "$filelist"
|
||||
done < <(find "pkg/$PKG_SUBDIR${GIT_SUBDIR:+/$GIT_SUBDIR}" -name "files.*")
|
||||
@ -97,6 +93,7 @@ build() {
|
||||
--noprep \
|
||||
--build-in-place \
|
||||
--with upstream \
|
||||
--without sysvcompat \
|
||||
$( ((WITH_TESTS)) || echo "--nocheck") \
|
||||
--define "_topdir /var/tmp" \
|
||||
--define "_sourcedir $PWD/pkg/$PKG_SUBDIR${GIT_SUBDIR:+/$GIT_SUBDIR}" \
|
||||
|
||||
@ -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 */
|
||||
bool exists = true, append_trail_slash = false;
|
||||
struct stat st; /* stat obtained from fd */
|
||||
bool need_absolute = false; /* allocate early to avoid compiler warnings around goto */
|
||||
const char *todo;
|
||||
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_STEP|CHASE_EXTRACT_FILENAME));
|
||||
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))
|
||||
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.
|
||||
*/
|
||||
|
||||
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
|
||||
* 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)
|
||||
return r;
|
||||
|
||||
bool need_absolute = r;
|
||||
need_absolute = r;
|
||||
if (need_absolute) {
|
||||
done = strdup("/");
|
||||
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);
|
||||
}
|
||||
|
||||
success:
|
||||
if (exists) {
|
||||
if (FLAGS_SET(flags, CHASE_MUST_BE_DIRECTORY)) {
|
||||
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.",
|
||||
absolute, root);
|
||||
|
||||
fd = open(root, O_CLOEXEC|O_DIRECTORY|O_PATH);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
if (empty_or_root(root))
|
||||
fd = XAT_FDROOT;
|
||||
else {
|
||||
fd = open(root, O_CLOEXEC|O_DIRECTORY|O_PATH);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
r = chaseat(fd, path, flags & ~CHASE_PREFIX_ROOT, ret_path ? &p : NULL, ret_fd ? &pfd : NULL);
|
||||
if (r < 0)
|
||||
|
||||
@ -572,10 +572,12 @@ bool fdname_is_valid(const char *s) {
|
||||
int fd_get_path(int fd, char **ret) {
|
||||
int r;
|
||||
|
||||
assert(fd >= 0 || fd == AT_FDCWD);
|
||||
assert(fd >= 0 || IN_SET(fd, AT_FDCWD, XAT_FDROOT));
|
||||
|
||||
if (fd == AT_FDCWD)
|
||||
return safe_getcwd(ret);
|
||||
if (fd == XAT_FDROOT)
|
||||
return strdup_to(ret, "/");
|
||||
|
||||
r = readlink_malloc(FORMAT_PROC_FD_PATH(fd), ret);
|
||||
if (r == -ENOENT)
|
||||
@ -770,7 +772,7 @@ finish:
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
/* 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 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
|
||||
* 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
|
||||
@ -795,6 +799,9 @@ int fd_reopen(int fd, int flags) {
|
||||
* the same way as the non-O_DIRECTORY case. */
|
||||
return -ELOOP;
|
||||
|
||||
if (fd == XAT_FDROOT)
|
||||
return RET_NERRNO(open("/", flags | O_DIRECTORY));
|
||||
|
||||
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
|
||||
* 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;
|
||||
}
|
||||
|
||||
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) {
|
||||
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;
|
||||
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)
|
||||
return errno == ENOTDIR ? false : -errno;
|
||||
return 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)
|
||||
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) {
|
||||
struct statx sx1 = {}, sx2 = {}; /* explicitly initialize the struct to make msan silent. */
|
||||
|
||||
assert(fd1 >= 0);
|
||||
assert(fd2 >= 0);
|
||||
assert(fd1 >= 0 || IN_SET(fd1, AT_FDCWD, XAT_FDROOT));
|
||||
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;
|
||||
|
||||
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 statx_inode_same(&sx1, &sx2) && statx_mount_same(&sx1, &sx2);
|
||||
|
||||
@ -57,6 +57,13 @@
|
||||
#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)))
|
||||
|
||||
/* 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 safe_close(int fd);
|
||||
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);
|
||||
}
|
||||
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) {
|
||||
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);
|
||||
|
||||
@ -713,10 +713,15 @@ char* unlink_and_free(char *p) {
|
||||
}
|
||||
|
||||
int access_fd(int fd, int mode) {
|
||||
assert(fd >= 0);
|
||||
|
||||
/* 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)
|
||||
return 0;
|
||||
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;
|
||||
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. */
|
||||
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 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)
|
||||
mode = (open_flags & O_DIRECTORY) ? 0755 : 0644;
|
||||
|
||||
|
||||
@ -31,10 +31,25 @@ static int verify_stat_at(
|
||||
struct stat st;
|
||||
int r;
|
||||
|
||||
assert(fd >= 0 || fd == AT_FDCWD);
|
||||
assert(fd >= 0 || IN_SET(fd, AT_FDCWD, XAT_FDROOT));
|
||||
assert(!isempty(path) || !follow);
|
||||
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,
|
||||
(isempty(path) ? AT_EMPTY_PATH : 0) | (follow ? 0 : AT_SYMLINK_NOFOLLOW)) < 0)
|
||||
return -errno;
|
||||
@ -66,8 +81,10 @@ int verify_regular_at(int fd, const char *path, bool follow) {
|
||||
}
|
||||
|
||||
int fd_verify_regular(int fd) {
|
||||
assert(fd >= 0);
|
||||
return verify_regular_at(fd, NULL, false);
|
||||
if (IN_SET(fd, AT_FDCWD, XAT_FDROOT))
|
||||
return -EISDIR;
|
||||
|
||||
return verify_regular_at(fd, /* path= */ NULL, /* follow= */ false);
|
||||
}
|
||||
|
||||
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) {
|
||||
assert(fd >= 0);
|
||||
if (IN_SET(fd, AT_FDCWD, XAT_FDROOT))
|
||||
return 0;
|
||||
|
||||
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) {
|
||||
assert(fd >= 0);
|
||||
|
||||
if (fd == XAT_FDROOT)
|
||||
return 0;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int fd_is_read_only_fs(int fd) {
|
||||
struct statfs st;
|
||||
static int xfstatfs(int fd, struct statfs *ret) {
|
||||
assert(ret);
|
||||
|
||||
if (fd == AT_FDCWD)
|
||||
return RET_NERRNO(statfs(".", ret));
|
||||
if (fd == XAT_FDROOT)
|
||||
return RET_NERRNO(statfs("/", ret));
|
||||
|
||||
assert(fd >= 0);
|
||||
return RET_NERRNO(fstatfs(fd, ret));
|
||||
}
|
||||
|
||||
if (fstatfs(fd, &st) < 0)
|
||||
return -errno;
|
||||
int fd_is_read_only_fs(int fd) {
|
||||
int r;
|
||||
|
||||
struct statfs st;
|
||||
r = xfstatfs(fd, &st);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (st.f_flags & ST_RDONLY)
|
||||
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.
|
||||
* Let's try again with access(W_OK) which is more reliable, at least sometimes. */
|
||||
if (access_fd(fd, W_OK) == -EROFS)
|
||||
return true;
|
||||
}
|
||||
return access_fd(fd, W_OK) == -EROFS;
|
||||
|
||||
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) {
|
||||
struct statfs s;
|
||||
int r;
|
||||
|
||||
struct statfs s;
|
||||
r = xstatfsat(dir_fd, path, &s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -383,19 +415,23 @@ bool is_network_fs(const struct statfs *s) {
|
||||
}
|
||||
|
||||
int fd_is_temporary_fs(int fd) {
|
||||
struct statfs s;
|
||||
int r;
|
||||
|
||||
if (fstatfs(fd, &s) < 0)
|
||||
return -errno;
|
||||
struct statfs s;
|
||||
r = xfstatfs(fd, &s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return is_temporary_fs(&s);
|
||||
}
|
||||
|
||||
int fd_is_network_fs(int fd) {
|
||||
struct statfs s;
|
||||
int r;
|
||||
|
||||
if (fstatfs(fd, &s) < 0)
|
||||
return -errno;
|
||||
struct statfs s;
|
||||
r = xfstatfs(fd, &s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
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) {
|
||||
_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);
|
||||
|
||||
if (!isempty(path)) {
|
||||
@ -499,7 +535,7 @@ int xstatfsat(int dir_fd, const char *path, struct statfs *ret) {
|
||||
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) {
|
||||
|
||||
@ -2146,10 +2146,9 @@ static int method_enqueue_marked_jobs(sd_bus_message *message, void *userdata, s
|
||||
reply, &error);
|
||||
if (ERRNO_IS_NEG_RESOURCE(r))
|
||||
return r;
|
||||
if (r < 0) {
|
||||
RET_GATHER(ret, r);
|
||||
log_warning_errno(r, "%s", bus_error_message(&error, r));
|
||||
}
|
||||
if (r < 0)
|
||||
RET_GATHER(ret, log_unit_warning_errno(u, r, "Failed to enqueue marked job: %s",
|
||||
bus_error_message(&error, r)));
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
|
||||
@ -1199,7 +1199,7 @@ static int property_get_cpu_usage(
|
||||
|
||||
r = unit_get_cpu_usage(u, &ns);
|
||||
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);
|
||||
}
|
||||
@ -1962,10 +1962,10 @@ int bus_unit_queue_job_one(
|
||||
|
||||
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)
|
||||
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,
|
||||
BUS_ERROR_ONLY_BY_DEPENDENCY,
|
||||
"Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).",
|
||||
|
||||
@ -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");
|
||||
|
||||
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)
|
||||
return;
|
||||
|
||||
@ -4748,12 +4748,11 @@ int unit_write_setting(Unit *u, UnitWriteFlags flags, const char *name, const ch
|
||||
if (r < 0)
|
||||
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)
|
||||
return r;
|
||||
q = NULL;
|
||||
|
||||
strv_uniq(u->dropin_paths);
|
||||
strv_free_and_replace(u->dropin_paths, dropins);
|
||||
|
||||
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,
|
||||
JobType *type, /* input and output */
|
||||
bool reload_if_possible) {
|
||||
@ -7012,7 +7011,7 @@ int unit_queue_job_check_and_collapse_type(
|
||||
/* Returns:
|
||||
*
|
||||
* -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 */
|
||||
|
||||
JobType t;
|
||||
@ -7029,6 +7028,8 @@ int unit_queue_job_check_and_collapse_type(
|
||||
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)
|
||||
return -ENOENT;
|
||||
|
||||
@ -7036,7 +7037,7 @@ int unit_queue_job_check_and_collapse_type(
|
||||
(t == JOB_STOP && 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))
|
||||
return -EUNATCH;
|
||||
return -ELIBEXEC;
|
||||
|
||||
/* 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
|
||||
|
||||
@ -1092,7 +1092,7 @@ UnitDependency unit_mount_dependency_type_to_dependency_type(UnitMountDependency
|
||||
|
||||
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 */
|
||||
|
||||
|
||||
@ -315,10 +315,10 @@ static int varlink_manager_queue_job_one(
|
||||
|
||||
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)
|
||||
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);
|
||||
if (r == -ESHUTDOWN)
|
||||
return sd_varlink_errorb(link, VARLINK_ERROR_MANAGER_BUS_SHUTTING_DOWN);
|
||||
|
||||
@ -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) {
|
||||
_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);
|
||||
|
||||
fd = xopenat(dir_fd, path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
|
||||
@ -3318,7 +3318,9 @@ use_extra:
|
||||
|
||||
static int test_object_offset(JournalFile *f, uint64_t p, uint64_t needle) {
|
||||
assert(f);
|
||||
assert(p > 0);
|
||||
|
||||
if (p <= 0)
|
||||
return -EBADMSG;
|
||||
|
||||
if (p == needle)
|
||||
return TEST_FOUND;
|
||||
@ -3354,7 +3356,6 @@ static int test_object_seqnum(JournalFile *f, uint64_t p, uint64_t needle) {
|
||||
int r;
|
||||
|
||||
assert(f);
|
||||
assert(p > 0);
|
||||
|
||||
r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
|
||||
if (r < 0)
|
||||
@ -3395,7 +3396,6 @@ static int test_object_realtime(JournalFile *f, uint64_t p, uint64_t needle) {
|
||||
int r;
|
||||
|
||||
assert(f);
|
||||
assert(p > 0);
|
||||
|
||||
r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
|
||||
if (r < 0)
|
||||
@ -3436,7 +3436,6 @@ static int test_object_monotonic(JournalFile *f, uint64_t p, uint64_t needle) {
|
||||
int r;
|
||||
|
||||
assert(f);
|
||||
assert(p > 0);
|
||||
|
||||
r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
|
||||
if (r < 0)
|
||||
|
||||
@ -184,6 +184,9 @@ static int vl_method_create_session(sd_varlink *link, sd_json_variant *parameter
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
if (p.class == SESSION_NONE)
|
||||
return sd_varlink_error_invalid_parameter_name(link, "Class");
|
||||
|
||||
Seat *seat = NULL;
|
||||
if (p.seat) {
|
||||
seat = hashmap_get(m->seats, p.seat);
|
||||
|
||||
@ -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) {
|
||||
_cleanup_(mount_options_free_allp) MountOptions *options = NULL;
|
||||
MountOptions **p = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
*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) {
|
||||
options = new0(MountOptions, 1);
|
||||
if (!options)
|
||||
return -ENOMEM;
|
||||
return json_log_oom(variant, flags);
|
||||
}
|
||||
|
||||
options->options[pd] = strdup(sd_json_variant_string(e));
|
||||
if (!options->options[pd])
|
||||
return -ENOMEM;
|
||||
r = free_and_strdup(&options->options[pd], sd_json_variant_string(e));
|
||||
if (r < 0)
|
||||
return json_log_oom(variant, flags);
|
||||
}
|
||||
|
||||
mount_options_free_all(*p);
|
||||
|
||||
@ -332,7 +332,7 @@ static int verify_esp(
|
||||
dev_t devid = 0;
|
||||
int r;
|
||||
|
||||
assert(rfd >= 0 || rfd == AT_FDCWD);
|
||||
assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
|
||||
assert(path);
|
||||
|
||||
/* This logs about all errors, except:
|
||||
@ -442,14 +442,14 @@ int find_esp_and_warn_at(
|
||||
VerifyESPFlags flags;
|
||||
int r;
|
||||
|
||||
assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
|
||||
|
||||
/* This logs about all errors except:
|
||||
*
|
||||
* -ENOKEY → when we can't find the partition
|
||||
* -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");
|
||||
|
||||
if (path)
|
||||
@ -527,9 +527,13 @@ int find_esp_and_warn(
|
||||
dev_t devid;
|
||||
int r;
|
||||
|
||||
rfd = open(empty_to_root(root), O_PATH|O_DIRECTORY|O_CLOEXEC);
|
||||
if (rfd < 0)
|
||||
return -errno;
|
||||
if (empty_or_root(root))
|
||||
rfd = XAT_FDROOT;
|
||||
else {
|
||||
rfd = open(root, O_PATH|O_DIRECTORY|O_CLOEXEC);
|
||||
if (rfd < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
r = find_esp_and_warn_at(
|
||||
rfd,
|
||||
@ -737,7 +741,7 @@ static int verify_xbootldr(
|
||||
dev_t devid = 0;
|
||||
int r;
|
||||
|
||||
assert(rfd >= 0 || rfd == AT_FDCWD);
|
||||
assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
|
||||
assert(path);
|
||||
|
||||
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. */
|
||||
|
||||
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");
|
||||
|
||||
@ -862,9 +866,13 @@ int find_xbootldr_and_warn(
|
||||
dev_t devid;
|
||||
int r;
|
||||
|
||||
rfd = open(empty_to_root(root), O_PATH|O_DIRECTORY|O_CLOEXEC);
|
||||
if (rfd < 0)
|
||||
return -errno;
|
||||
if (empty_or_root(root))
|
||||
rfd = XAT_FDROOT;
|
||||
else {
|
||||
rfd = open(root, O_PATH|O_DIRECTORY|O_CLOEXEC);
|
||||
if (rfd < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
r = find_xbootldr_and_warn_at(
|
||||
rfd,
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#include "alloc-util.h"
|
||||
#include "env-file.h"
|
||||
#include "fd-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "kernel-image.h"
|
||||
#include "log.h"
|
||||
#include "pe-binary.h"
|
||||
@ -134,12 +135,12 @@ int inspect_kernel(
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
int r;
|
||||
|
||||
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||
assert(dir_fd >= 0 || IN_SET(dir_fd, AT_FDCWD, XAT_FDROOT));
|
||||
assert(filename);
|
||||
|
||||
fd = openat(dir_fd, filename, O_RDONLY|O_CLOEXEC);
|
||||
fd = xopenat(dir_fd, filename, O_RDONLY|O_CLOEXEC);
|
||||
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);
|
||||
if (r == -EBADMSG) /* not a valid PE file */
|
||||
|
||||
@ -96,15 +96,6 @@ int verb_enable(int argc, char *argv[], void *userdata) {
|
||||
if (r < 0)
|
||||
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"))
|
||||
r = normalize_names(names);
|
||||
else if (streq(verb, "link"))
|
||||
|
||||
@ -499,6 +499,36 @@ TEST(chaseat) {
|
||||
|
||||
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
|
||||
* unless the result is outside of the specified file descriptor. */
|
||||
|
||||
|
||||
@ -819,11 +819,6 @@ TEST(linkat_replace) {
|
||||
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) {
|
||||
_cleanup_(rm_rf_physical_and_freep) char *t = NULL;
|
||||
_cleanup_close_ int tfd = -EBADF, fd = -EBADF;
|
||||
@ -859,4 +854,68 @@ TEST(readlinkat_malloc) {
|
||||
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);
|
||||
|
||||
@ -712,6 +712,17 @@ EOF
|
||||
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
|
||||
|
||||
touch /testok
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user