Compare commits

..

No commits in common. "990307c3da61b16c57d958910295b96ea6aa2a5e" and "a4df0c004a0e42dfbad02e9595420fcef3965b85" have entirely different histories.

43 changed files with 402 additions and 516 deletions

3
TODO
View File

@ -19,6 +19,9 @@ Features:
* nss-systemd: also synthesize shadow records for users/groups
* make use of the new statx mountid and rootmount fields in path_get_mnt_id()
and fd_is_mount_point()
* nspawn: move "incoming mount" directory to /run/host, move "inaccessible"
nodes to /run/host, move notify socket (for sd_notify() between payload and
container manager)

View File

@ -25,17 +25,6 @@ layout: default
note that emacs loads `.dir-locals.el` automatically, but vim needs to be
configured to load `.vimrc`, see that file for instructions.
- If you break a function declaration over multiple lines, do it like this:
```c
void some_function(
int foo,
bool bar,
char baz) {
int a, b, c;
```
- Try to write this:
```c

View File

@ -172,13 +172,6 @@ manager, please consider supporting the following interfaces.
unit they created for their container. That's private property of systemd,
and no other code should modify it.
6. systemd running inside the container can report when boot-up is complete
using the usual `sd_notify()` protocol that is also used when a service
wants to tell the service manager about readiness. A container manager can
set the `$NOTIFY_SOCKET` environment variable to a suitable socket path to
make use of this functionality. (Also see information about
`/run/host/notify` below.)
## Networking
1. Inside of a container, if a `veth` link is named `host0`, `systemd-networkd`
@ -196,62 +189,6 @@ manager, please consider supporting the following interfaces.
devices, for example hashed out of the container names. That way it is more
likely that DHCP and IPv4LL will acquire stable addresses.
## The `/run/host/` Hierarchy
Container managers may place certain resources the manager wants to provide to
the container payload below the `/run/host/` hierarchy. This hierarchy should
be mostly immutable (possibly some subdirs might be writable, but the top-level
hierarchy — and probably most subdirs should be read-only to the
container). Note that this hierarchy is used by various container managers, and
care should be taken to avoid naming conflicts. `systemd` (and in particular
`systemd-nspawn`) use the hierarchy for the following resources:
1. The `/run/host/incoming/` directory mount point is configured for `MS_SLAVE`
mount propagation with the host, and is used as intermediary location for
mounts to establish in the container, for the implementation of `machinectl
bind`. Container payload should usually not directly interact with this
directory: it's used by code outside the container to insert mounts inside
it only, and is mostly an internal vehicle to achieve this. Other container
managers that want to implement similar functionality might consider using
the same directory.
2. The `/run/host/inaccessible/` directory may be set up by the container
manager to include six file nodes: `reg`, `dir`, `fifo`, `sock`, `chr`,
`blk`. These nodes correspond with the six types of file nodes Linux knows
(with the exceptions of symlinks). Each node should be of the specific type
and have an all zero access mode, i.e. be inaccessible. The two device node
types should have major and minor of zero (which are unallocated devices on
Linux). These nodes are used as mount source for implementing the
`InaccessiblePath=` setting of unit files, i.e. file nodes to mask this way
are overmounted with these "inaccessible" inodes, guaranteeing that the file
node type does not change this way but the nodes still become
inaccessible. Note that systemd when run as PID 1 in the container payload
will create these nodes on its own if not passed in by the container
manager. However, in that case it likely lacks the privileges to create the
character and block devices nodes (there all fallbacks for this case).
3. The `/run/host/notify` path is a good choice to place the `sd_notify()`
socket in, that may be used for the container's PID 1 to report to the
container manager when boot-up is complete. The path used for this doesn't
matter much as it is communicated via the `$NOTIFY_SOCKET` environment
variable, following the usual protocol for this, however it's suitable, and
recommended place for this socket in case ready notification is desired.
4. The `/run/host/os-release` file contains the `/etc/os-release` file of the
host, i.e. may be used by the container payload to gather limited
information about the host environment, on top of what `uname -a` reports.
5. The `/run/host/container-manager` file may be used to pass the same
information as the `$container` environment variable (see above), i.e. a
short string identifying the container manager implementation. This file
should be newline terminated. Passing this information via this file has the
benefit that payload code can easily access it, even when running
unprivileged without access to the container PID1's environment block.
6. The `/run/host/container-uuid` file may be used to pass the same information
as the `$container_uuid` environment variable (see above). This file should
be newline terminated.
## What You Shouldn't Do
1. Do not drop `CAP_MKNOD` from the container. `PrivateDevices=` is a commonly

View File

@ -2134,20 +2134,6 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
</listitem>
</varlistentry>
<varlistentry>
<term><option>--timestamp=</option></term>
<listitem>
<para>Takes one of <literal>pretty</literal> (the default),
<literal>us</literal>, <literal>µs</literal>, <literal>utc</literal>.
Changes the format of printed timestamps.
<literal>pretty</literal>: <literal>Day YYYY-MM-DD HH:MM:SS TZ</literal>
<literal>us</literal> or <literal>µs</literal>: <literal>Day YYYY-MM-DD HH:MM:SS.UUUUUU TZ</literal>
<literal>utc</literal>: <literal>Day YYYY-MM-DD HH:MM:SS UTC</literal></para>
<literal>us+utc</literal> or <literal>µs+utc</literal>: <literal>Day YYYY-MM-DD HH:MM:SS.UUUUUU UTC</literal>
</listitem>
</varlistentry>
<xi:include href="user-system-options.xml" xpointer="host" />
<xi:include href="user-system-options.xml" xpointer="machine" />

View File

@ -261,42 +261,53 @@
</varlistentry>
<varlistentry>
<term><varname>MemoryMin=<replaceable>bytes</replaceable></varname>, <varname>MemoryLow=<replaceable>bytes</replaceable></varname></term>
<term><varname>MemoryMin=<replaceable>bytes</replaceable></varname></term>
<listitem>
<para>Specify the memory usage protection of the executed processes in this unit.
When reclaiming memory, the unit is treated as if it was using less memory resulting in memory
to be preferentially reclaimed from unprotected units.
Using <varname>MemoryLow=</varname> results in a weaker protection where memory may still
be reclaimed to avoid invoking the OOM killer in case there is no other reclaimable memory.</para>
<para>
For a protection to be effective, it is generally required to set a corresponding
allocation on all ancestors, which is then distributed between children
(with the exception of the root slice).
Any <varname>MemoryMin=</varname> or <varname>MemoryLow=</varname> allocation that is not
explicitly distributed to specific children is used to create a shared protection for all children.
As this is a shared protection, the children will freely compete for the memory.</para>
<para>Specify the memory usage protection of the executed processes in this unit. If the memory usages of
this unit and all its ancestors are below their minimum boundaries, this unit's memory won't be reclaimed.</para>
<para>Takes a memory size in bytes. If the value is suffixed with K, M, G or T, the specified memory size is
parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. Alternatively, a
percentage value may be specified, which is taken relative to the installed physical memory on the
system. If assigned the special value <literal>infinity</literal>, all available memory is protected, which may be
useful in order to always inherit all of the protection afforded by ancestors.
This controls the <literal>memory.min</literal> or <literal>memory.low</literal> control group attribute.
For details about this control group attribute, see <ulink
This controls the <literal>memory.min</literal> control group attribute. For details about this
control group attribute, see <ulink
url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html#memory-interface-files">Memory Interface Files</ulink>.</para>
<para>This setting is supported only if the unified control group hierarchy is used and disables
<varname>MemoryLimit=</varname>.</para>
<para>Units may have their children use a default <literal>memory.min</literal> or
<literal>memory.low</literal> value by specifying <varname>DefaultMemoryMin=</varname> or
<varname>DefaultMemoryLow=</varname>, which has the same semantics as
<varname>MemoryMin=</varname> and <varname>MemoryLow=</varname>.
This setting does not affect <literal>memory.min</literal> or <literal>memory.low</literal>
in the unit itself.
Using it to set a default child allocation is only useful on kernels older than 5.7,
which do not support the <literal>memory_recursiveprot</literal> cgroup2 mount option.</para>
<para>Units may have their children use a default <literal>memory.min</literal> value by specifying
<varname>DefaultMemoryMin=</varname>, which has the same semantics as <varname>MemoryMin=</varname>. This setting
does not affect <literal>memory.min</literal> in the unit itself.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>MemoryLow=<replaceable>bytes</replaceable></varname></term>
<listitem>
<para>Specify the best-effort memory usage protection of the executed processes in this unit. If the memory
usages of this unit and all its ancestors are below their low boundaries, this unit's memory won't be
reclaimed as long as memory can be reclaimed from unprotected units.</para>
<para>Takes a memory size in bytes. If the value is suffixed with K, M, G or T, the specified memory size is
parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. Alternatively, a
percentage value may be specified, which is taken relative to the installed physical memory on the
system. If assigned the special value <literal>infinity</literal>, all available memory is protected, which may be
useful in order to always inherit all of the protection afforded by ancestors.
This controls the <literal>memory.low</literal> control group attribute. For details about this
control group attribute, see <ulink
url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html#memory-interface-files">Memory Interface Files</ulink>.</para>
<para>This setting is supported only if the unified control group hierarchy is used and disables
<varname>MemoryLimit=</varname>.</para>
<para>Units may have their children use a default <literal>memory.low</literal> value by specifying
<varname>DefaultMemoryLow=</varname>, which has the same semantics as <varname>MemoryLow=</varname>. This setting
does not affect <literal>memory.low</literal> in the unit itself.</para>
</listitem>
</varlistentry>

View File

@ -1092,6 +1092,9 @@
<para>Except for <varname>ConditionPathIsSymbolicLink=</varname>, all path checks follow symlinks.</para>
<variablelist class='unit-directives'>
<!-- We do not document ConditionNull= here, as it is not particularly useful and probably just
confusing. -->
<varlistentry>
<term><varname>ConditionArchitecture=</varname></term>

View File

@ -127,7 +127,7 @@ _systemctl () {
--quiet -q --system --user --version --runtime --recursive -r --firmware-setup
--show-types -i --ignore-inhibitors --plain --failed --value --fail --dry-run --wait'
[ARG]='--host -H --kill-who --property -p --signal -s --type -t --state --job-mode --root
--preset-mode -n --lines -o --output -M --machine --message --timestamp'
--preset-mode -n --lines -o --output -M --machine --message'
)
if __contains_word "--user" ${COMP_WORDS[*]}; then
@ -176,9 +176,6 @@ _systemctl () {
--machine|-M)
comps=$( __get_machines )
;;
--timestamp)
comps='pretty us µs utc us+utc µs+utc'
;;
esac
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
return 0

View File

@ -431,13 +431,6 @@ done
_values -s , "${_modes[@]}"
}
(( $+functions[_systemctl_timestamp] )) ||
_systemctl_timestamp() {
local -a _styles
_styles=(help pretty us µs utc us+utc µs+utc)
_values -s , "${_styles[@]}"
}
# Build arguments for "systemctl" to be used in completion.
local -a _modes; _modes=("--user" "--system")
# Use the last mode (they are exclusive and the last one is used).
@ -478,5 +471,4 @@ _arguments -s \
'--firmware-setup[Tell the firmware to show the setup menu on next boot]' \
'--plain[When used with list-dependencies, print output as a list]' \
'--failed[Show failed units]' \
'--timestamp=[Change format of printed timestamps]:style:_systemctl_timestamp' \
'*::systemctl command:_systemctl_commands'

View File

@ -8,27 +8,83 @@
#include "load-fragment.h"
#include "service.h"
typedef struct condition_definition {
const char *name;
ConfigParserCallback parser;
ConditionType type;
} condition_definition;
static const condition_definition condition_definitions[] = {
{ "ConditionPathExists", config_parse_unit_condition_path, CONDITION_PATH_EXISTS },
{ "ConditionPathExistsGlob", config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB },
{ "ConditionPathIsDirectory", config_parse_unit_condition_path, CONDITION_PATH_IS_DIRECTORY },
{ "ConditionPathIsSymbolicLink", config_parse_unit_condition_path, CONDITION_PATH_IS_SYMBOLIC_LINK },
{ "ConditionPathIsMountPoint", config_parse_unit_condition_path, CONDITION_PATH_IS_MOUNT_POINT },
{ "ConditionPathIsReadWrite", config_parse_unit_condition_path, CONDITION_PATH_IS_READ_WRITE },
{ "ConditionPathIsEncrypted", config_parse_unit_condition_path, CONDITION_PATH_IS_ENCRYPTED },
{ "ConditionDirectoryNotEmpty", config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY },
{ "ConditionFileNotEmpty", config_parse_unit_condition_path, CONDITION_FILE_NOT_EMPTY },
{ "ConditionFileIsExecutable", config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE },
{ "ConditionNeedsUpdate", config_parse_unit_condition_path, CONDITION_NEEDS_UPDATE },
{ "ConditionFirstBoot", config_parse_unit_condition_string, CONDITION_FIRST_BOOT },
{ "ConditionKernelCommandLine", config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE },
{ "ConditionKernelVersion", config_parse_unit_condition_string, CONDITION_KERNEL_VERSION },
{ "ConditionArchitecture", config_parse_unit_condition_string, CONDITION_ARCHITECTURE },
{ "ConditionVirtualization", config_parse_unit_condition_string, CONDITION_VIRTUALIZATION },
{ "ConditionSecurity", config_parse_unit_condition_string, CONDITION_SECURITY },
{ "ConditionCapability", config_parse_unit_condition_string, CONDITION_CAPABILITY },
{ "ConditionHost", config_parse_unit_condition_string, CONDITION_HOST },
{ "ConditionACPower", config_parse_unit_condition_string, CONDITION_AC_POWER },
{ "ConditionUser", config_parse_unit_condition_string, CONDITION_USER },
{ "ConditionGroup", config_parse_unit_condition_string, CONDITION_GROUP },
{ "ConditionControlGroupController", config_parse_unit_condition_string, CONDITION_CONTROL_GROUP_CONTROLLER },
{ "AssertPathExists", config_parse_unit_condition_path, CONDITION_PATH_EXISTS },
{ "AssertPathExistsGlob", config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB },
{ "AssertPathIsDirectory", config_parse_unit_condition_path, CONDITION_PATH_IS_DIRECTORY },
{ "AssertPathIsSymbolicLink", config_parse_unit_condition_path, CONDITION_PATH_IS_SYMBOLIC_LINK },
{ "AssertPathIsMountPoint", config_parse_unit_condition_path, CONDITION_PATH_IS_MOUNT_POINT },
{ "AssertPathIsReadWrite", config_parse_unit_condition_path, CONDITION_PATH_IS_READ_WRITE },
{ "AssertPathIsEncrypted", config_parse_unit_condition_path, CONDITION_PATH_IS_ENCRYPTED },
{ "AssertDirectoryNotEmpty", config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY },
{ "AssertFileNotEmpty", config_parse_unit_condition_path, CONDITION_FILE_NOT_EMPTY },
{ "AssertFileIsExecutable", config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE },
{ "AssertNeedsUpdate", config_parse_unit_condition_path, CONDITION_NEEDS_UPDATE },
{ "AssertFirstBoot", config_parse_unit_condition_string, CONDITION_FIRST_BOOT },
{ "AssertKernelCommandLine", config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE },
{ "AssertKernelVersion", config_parse_unit_condition_string, CONDITION_KERNEL_VERSION },
{ "AssertArchitecture", config_parse_unit_condition_string, CONDITION_ARCHITECTURE },
{ "AssertVirtualization", config_parse_unit_condition_string, CONDITION_VIRTUALIZATION },
{ "AssertSecurity", config_parse_unit_condition_string, CONDITION_SECURITY },
{ "AssertCapability", config_parse_unit_condition_string, CONDITION_CAPABILITY },
{ "AssertHost", config_parse_unit_condition_string, CONDITION_HOST },
{ "AssertACPower", config_parse_unit_condition_string, CONDITION_AC_POWER },
{ "AssertUser", config_parse_unit_condition_string, CONDITION_USER },
{ "AssertGroup", config_parse_unit_condition_string, CONDITION_GROUP },
{ "AssertControlGroupController", config_parse_unit_condition_string, CONDITION_CONTROL_GROUP_CONTROLLER },
/* deprecated, but we should still parse them */
{ "ConditionNull", config_parse_unit_condition_null, 0 },
{ "AssertNull", config_parse_unit_condition_null, 0 },
};
static int parse_condition(Unit *u, const char *line) {
assert(u);
assert(line);
const char *p;
Condition **target;
for (ConditionType t = 0; t < _CONDITION_TYPE_MAX; t++) {
ConfigParserCallback callback;
Condition **target;
const char *p, *name;
if ((p = startswith(line, "Condition")))
target = &u->conditions;
else if ((p = startswith(line, "Assert")))
target = &u->asserts;
else
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot parse \"%s\".", line);
name = condition_type_to_string(t);
p = startswith(line, name);
if (p)
target = &u->conditions;
else {
name = assert_type_to_string(t);
p = startswith(line, name);
if (!p)
continue;
for (size_t i = 0; i < ELEMENTSOF(condition_definitions); i++) {
const condition_definition *c = &condition_definitions[i];
target = &u->asserts;
}
p = startswith(line, c->name);
if (!p)
continue;
p += strspn(p, WHITESPACE);
@ -38,12 +94,7 @@ static int parse_condition(Unit *u, const char *line) {
p += strspn(p, WHITESPACE);
if (condition_takes_path(t))
callback = config_parse_unit_condition_path;
else
callback = config_parse_unit_condition_string;
return callback(NULL, "(cmdline)", 0, NULL, 0, name, t, p, target, u);
return c->parser(NULL, "(stdin)", 0, NULL, 0, c->name, c->type, p, target, u);
}
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot parse \"%s\".", line);

View File

@ -8,47 +8,38 @@
#include <linux/stat.h>
#endif
/* Thew newest definition we are aware of (fa2fcf4f1df1559a0a4ee0f46915b496cc2ebf60; 5.8) */
#define STATX_DEFINITION { \
__u32 stx_mask; \
__u32 stx_blksize; \
__u64 stx_attributes; \
__u32 stx_nlink; \
__u32 stx_uid; \
__u32 stx_gid; \
__u16 stx_mode; \
__u16 __spare0[1]; \
__u64 stx_ino; \
__u64 stx_size; \
__u64 stx_blocks; \
__u64 stx_attributes_mask; \
struct statx_timestamp stx_atime; \
struct statx_timestamp stx_btime; \
struct statx_timestamp stx_ctime; \
struct statx_timestamp stx_mtime; \
__u32 stx_rdev_major; \
__u32 stx_rdev_minor; \
__u32 stx_dev_major; \
__u32 stx_dev_minor; \
__u64 stx_mnt_id; \
__u64 __spare2; \
__u64 __spare3[12]; \
}
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
#if !HAVE_STRUCT_STATX
struct statx_timestamp {
__s64 tv_sec;
__u32 tv_nsec;
__s32 __reserved;
};
struct statx STATX_DEFINITION;
struct statx {
__u32 stx_mask;
__u32 stx_blksize;
__u64 stx_attributes;
__u32 stx_nlink;
__u32 stx_uid;
__u32 stx_gid;
__u16 stx_mode;
__u16 __spare0[1];
__u64 stx_ino;
__u64 stx_size;
__u64 stx_blocks;
__u64 stx_attributes_mask;
struct statx_timestamp stx_atime;
struct statx_timestamp stx_btime;
struct statx_timestamp stx_ctime;
struct statx_timestamp stx_mtime;
__u32 stx_rdev_major;
__u32 stx_rdev_minor;
__u32 stx_dev_major;
__u32 stx_dev_minor;
__u64 __spare2[14];
};
#endif
/* Always define the newest version we are aware of as a distinct type, so that we can use it even if glibc
* defines an older definition */
struct new_statx STATX_DEFINITION;
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
#ifndef STATX_BTIME
#define STATX_BTIME 0x00000800U
@ -58,13 +49,3 @@ struct new_statx STATX_DEFINITION;
#ifndef AT_STATX_DONT_SYNC
#define AT_STATX_DONT_SYNC 0x4000
#endif
/* fa2fcf4f1df1559a0a4ee0f46915b496cc2ebf60 (5.8) */
#ifndef STATX_MNT_ID
#define STATX_MNT_ID 0x00001000U
#endif
/* 80340fe3605c0e78cfe496c3b3878be828cfdbfe (5.8) */
#ifndef STATX_ATTR_MOUNT_ROOT
#define STATX_ATTR_MOUNT_ROOT 0x00002000 /* Root of a mount */
#endif

View File

@ -482,7 +482,7 @@ static inline ssize_t missing_statx(int dfd, const char *filename, unsigned flag
# endif
}
# define statx(dfd, filename, flags, mask, buffer) missing_statx(dfd, filename, flags, mask, buffer)
# define statx missing_statx
#endif
#if !HAVE_SET_MEMPOLICY

View File

@ -8,8 +8,6 @@
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
#include "missing_stat.h"
#include "missing_syscall.h"
#include "mountpoint-util.h"
#include "parse-util.h"
#include "path-util.h"
@ -34,8 +32,6 @@ int name_to_handle_at_loop(
_cleanup_free_ struct file_handle *h = NULL;
size_t n = ORIGINAL_MAX_HANDLE_SZ;
assert((flags & ~(AT_SYMLINK_FOLLOW|AT_EMPTY_PATH)) == 0);
/* We need to invoke name_to_handle_at() in a loop, given that it might return EOVERFLOW when the specified
* buffer is too small. Note that in contrast to what the docs might suggest, MAX_HANDLE_SZ is only good as a
* start value, it is not an upper bound on the buffer size required.
@ -90,16 +86,13 @@ int name_to_handle_at_loop(
}
}
static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *ret_mnt_id) {
static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) {
char path[STRLEN("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
_cleanup_free_ char *fdinfo = NULL;
_cleanup_close_ int subfd = -1;
char *p;
int r;
assert(ret_mnt_id);
assert((flags & ~(AT_SYMLINK_FOLLOW|AT_EMPTY_PATH)) == 0);
if ((flags & AT_EMPTY_PATH) && isempty(filename))
xsprintf(path, "/proc/self/fdinfo/%i", fd);
else {
@ -128,7 +121,7 @@ static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *ret_mn
p += strspn(p, WHITESPACE);
p[strcspn(p, WHITESPACE)] = 0;
return safe_atoi(p, ret_mnt_id);
return safe_atoi(p, mnt_id);
}
int fd_is_mount_point(int fd, const char *filename, int flags) {
@ -136,46 +129,33 @@ int fd_is_mount_point(int fd, const char *filename, int flags) {
int mount_id = -1, mount_id_parent = -1;
bool nosupp = false, check_st_dev = true;
struct stat a, b;
struct statx sx
#if HAS_FEATURE_MEMORY_SANITIZER
= {}
# warning "Explicitly initializing struct statx, to work around msan limitation. Please remove as soon as msan has been updated to not require this."
#endif
;
int r;
assert(fd >= 0);
assert(filename);
assert((flags & ~(AT_SYMLINK_FOLLOW|AT_EMPTY_PATH)) == 0);
/* First we will try statx()' STATX_ATTR_MOUNT_ROOT attribute, which is our ideal API, available
* since kernel 5.8.
/* First we will try the name_to_handle_at() syscall, which
* tells us the mount id and an opaque file "handle". It is
* not supported everywhere though (kernel compile-time
* option, not all file systems are hooked up). If it works
* the mount id is usually good enough to tell us whether
* something is a mount point.
*
* If that fails, our second try is the name_to_handle_at() syscall, which tells us the mount id and
* an opaque file "handle". It is not supported everywhere though (kernel compile-time option, not
* all file systems are hooked up). If it works the mount id is usually good enough to tell us
* whether something is a mount point.
*
* If that didn't work we will try to read the mount id from /proc/self/fdinfo/<fd>. This is almost
* as good as name_to_handle_at(), however, does not return the opaque file handle. The opaque file
* handle is pretty useful to detect the root directory, which we should always consider a mount
* point. Hence we use this only as fallback. Exporting the mnt_id in fdinfo is a pretty recent
* If that didn't work we will try to read the mount id from
* /proc/self/fdinfo/<fd>. This is almost as good as
* name_to_handle_at(), however, does not return the
* opaque file handle. The opaque file handle is pretty useful
* to detect the root directory, which we should always
* consider a mount point. Hence we use this only as
* fallback. Exporting the mnt_id in fdinfo is a pretty recent
* kernel addition.
*
* As last fallback we do traditional fstat() based st_dev comparisons. This is how things were
* traditionally done, but unionfs breaks this since it exposes file systems with a variety of st_dev
* reported. Also, btrfs subvolumes have different st_dev, even though they aren't real mounts of
* their own. */
if (statx(fd, filename, (FLAGS_SET(flags, AT_SYMLINK_FOLLOW) ? 0 : AT_SYMLINK_NOFOLLOW) |
(flags & AT_EMPTY_PATH) |
AT_NO_AUTOMOUNT, 0, &sx) < 0) {
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
return -errno;
/* If statx() is not available or forbidden, fallback to name_to_handle_at() below */
} else if (FLAGS_SET(sx.stx_attributes_mask, STATX_ATTR_MOUNT_ROOT)) /* yay! */
return FLAGS_SET(sx.stx_attributes, STATX_ATTR_MOUNT_ROOT);
* As last fallback we do traditional fstat() based st_dev
* comparisons. This is how things were traditionally done,
* but unionfs breaks this since it exposes file
* systems with a variety of st_dev reported. Also, btrfs
* subvolumes have different st_dev, even though they aren't
* real mounts of their own. */
r = name_to_handle_at_loop(fd, filename, &h, &mount_id, flags);
if (IN_SET(r, -ENOSYS, -EACCES, -EPERM, -EOVERFLOW, -EINVAL))
@ -298,29 +278,8 @@ int path_is_mount_point(const char *t, const char *root, int flags) {
}
int path_get_mnt_id(const char *path, int *ret) {
union {
struct statx sx;
struct new_statx nsx;
} buf
#if HAS_FEATURE_MEMORY_SANITIZER
= {}
# warning "Explicitly initializing struct statx, to work around msan limitation. Please remove as soon as msan has been updated to not require this."
#endif
;
int r;
if (statx(AT_FDCWD, path, AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT, STATX_MNT_ID, &buf.sx) < 0) {
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
return -errno;
/* Fall back to name_to_handle_at() and then fdinfo if statx is not supported or we lack
* privileges */
} else if (FLAGS_SET(buf.nsx.stx_mask, STATX_MNT_ID)) {
*ret = buf.nsx.stx_mnt_id;
return 0;
}
r = name_to_handle_at_loop(AT_FDCWD, path, NULL, ret, 0);
if (IN_SET(r, -EOPNOTSUPP, -ENOSYS, -EACCES, -EPERM, -EOVERFLOW, -EINVAL)) /* kernel/fs don't support this, or seccomp blocks access, or untriggered mount, or name_to_handle_at() is flaky */
return fd_fdinfo_mnt_id(AT_FDCWD, path, 0, ret);

View File

@ -23,7 +23,6 @@
#include "path-util.h"
#include "process-util.h"
#include "stat-util.h"
#include "string-table.h"
#include "string-util.h"
#include "strv.h"
#include "time-util.h"
@ -283,11 +282,12 @@ struct timeval *timeval_store(struct timeval *tv, usec_t u) {
return tv;
}
char *format_timestamp_style(
static char *format_timestamp_internal(
char *buf,
size_t l,
usec_t t,
TimestampStyle style) {
bool utc,
bool us) {
/* The weekdays in non-localized (English) form. We use this instead of the localized form, so that our
* generated timestamps may be parsed with parse_timestamp(), and always read the same. */
@ -304,27 +304,9 @@ char *format_timestamp_style(
struct tm tm;
time_t sec;
size_t n;
bool utc = false, us = false;
assert(buf);
switch (style) {
case TIMESTAMP_PRETTY:
break;
case TIMESTAMP_US:
us = true;
break;
case TIMESTAMP_UTC:
utc = true;
break;
case TIMESTAMP_US_UTC:
us = true;
utc = true;
break;
default:
return NULL;
}
if (l < (size_t) (3 + /* week day */
1 + 10 + /* space and date */
1 + 8 + /* space and time */
@ -398,6 +380,22 @@ char *format_timestamp_style(
return buf;
}
char *format_timestamp(char *buf, size_t l, usec_t t) {
return format_timestamp_internal(buf, l, t, false, false);
}
char *format_timestamp_utc(char *buf, size_t l, usec_t t) {
return format_timestamp_internal(buf, l, t, true, false);
}
char *format_timestamp_us(char *buf, size_t l, usec_t t) {
return format_timestamp_internal(buf, l, t, false, true);
}
char *format_timestamp_us_utc(char *buf, size_t l, usec_t t) {
return format_timestamp_internal(buf, l, t, true, true);
}
char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
const char *s;
usec_t n, d;
@ -1570,27 +1568,3 @@ int time_change_fd(void) {
return -errno;
}
static const char* const timestamp_style_table[_TIMESTAMP_STYLE_MAX] = {
[TIMESTAMP_PRETTY] = "pretty",
[TIMESTAMP_US] = "us",
[TIMESTAMP_UTC] = "utc",
[TIMESTAMP_US_UTC] = "us+utc",
};
/* Use the macro for enum → string to allow for aliases */
_DEFINE_STRING_TABLE_LOOKUP_TO_STRING(timestamp_style, TimestampStyle,);
/* For the string → enum mapping we use the generic implementation, but also support two aliases */
TimestampStyle timestamp_style_from_string(const char *s) {
TimestampStyle t;
t = (TimestampStyle) string_table_lookup(timestamp_style_table, ELEMENTSOF(timestamp_style_table), s);
if (t >= 0)
return t;
if (streq_ptr(s, "µs"))
return TIMESTAMP_US;
if (streq_ptr(s, "µs+uts"))
return TIMESTAMP_US_UTC;
return t;
}

View File

@ -29,15 +29,6 @@ typedef struct triple_timestamp {
usec_t boottime;
} triple_timestamp;
typedef enum TimestampStyle {
TIMESTAMP_PRETTY,
TIMESTAMP_US,
TIMESTAMP_UTC,
TIMESTAMP_US_UTC,
_TIMESTAMP_STYLE_MAX,
_TIMESTAMP_STYLE_INVALID = -1,
} TimestampStyle;
#define USEC_INFINITY ((usec_t) UINT64_MAX)
#define NSEC_INFINITY ((nsec_t) UINT64_MAX)
@ -116,14 +107,13 @@ struct timespec *timespec_store(struct timespec *ts, usec_t u);
usec_t timeval_load(const struct timeval *tv) _pure_;
struct timeval *timeval_store(struct timeval *tv, usec_t u);
char *format_timestamp_style(char *buf, size_t l, usec_t t, TimestampStyle style);
char *format_timestamp(char *buf, size_t l, usec_t t);
char *format_timestamp_utc(char *buf, size_t l, usec_t t);
char *format_timestamp_us(char *buf, size_t l, usec_t t);
char *format_timestamp_us_utc(char *buf, size_t l, usec_t t);
char *format_timestamp_relative(char *buf, size_t l, usec_t t);
char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy);
static inline char *format_timestamp(char *buf, size_t l, usec_t t) {
return format_timestamp_style(buf, l, t, TIMESTAMP_PRETTY);
}
int parse_timestamp(const char *t, usec_t *usec);
int parse_sec(const char *t, usec_t *usec);
@ -195,6 +185,3 @@ static inline usec_t usec_sub_signed(usec_t timestamp, int64_t delta) {
#endif
int time_change_fd(void);
const char* timestamp_style_to_string(TimestampStyle t) _const_;
TimestampStyle timestamp_style_from_string(const char *s) _pure_;

View File

@ -491,16 +491,6 @@ int detect_container(void) {
}
}
/* The container manager might have placed this in the /run/host hierarchy for us, which is best
* because we can be consumed just like that, without special privileges. */
r = read_one_line_file("/run/host/container-manager", &m);
if (r > 0) {
e = m;
goto translate_name;
}
if (!IN_SET(r, -ENOENT, 0))
return log_debug_errno(r, "Failed to read /run/systemd/container: %m");
if (getpid_cached() == 1) {
/* If we are PID 1 we can just check our own environment variable, and that's authoritative.
* We distinguish three cases:

View File

@ -1974,11 +1974,14 @@ static int bus_set_transient_conditions(
if (t < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid condition type: %s", type_name);
if (isempty(param))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Condition parameter in %s is empty", type_name);
if (t != CONDITION_NULL) {
if (isempty(param))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Condition parameter in %s is empty", type_name);
if (condition_takes_path(t) && !path_is_absolute(param))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path in condition %s is not absolute: %s", type_name, param);
if (condition_takes_path(t) && !path_is_absolute(param))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path in condition %s is not absolute: %s", type_name, param);
} else
param = NULL;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
Condition *c;
@ -1989,9 +1992,14 @@ static int bus_set_transient_conditions(
LIST_PREPEND(conditions, *list, c);
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name,
"%s=%s%s%s", type_name,
trigger ? "|" : "", negate ? "!" : "", param);
if (t != CONDITION_NULL)
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name,
"%s=%s%s%s", type_name,
trigger ? "|" : "", negate ? "!" : "", param);
else
unit_write_settingf(u, flags, name,
"%s=%s%s", type_name,
trigger ? "|" : "", yes_no(!negate));
}
empty = false;

View File

@ -272,52 +272,46 @@ Unit.ConditionPathIsDirectory, config_parse_unit_condition_path, CONDITION_P
Unit.ConditionPathIsSymbolicLink,config_parse_unit_condition_path, CONDITION_PATH_IS_SYMBOLIC_LINK,offsetof(Unit, conditions)
Unit.ConditionPathIsMountPoint, config_parse_unit_condition_path, CONDITION_PATH_IS_MOUNT_POINT, offsetof(Unit, conditions)
Unit.ConditionPathIsReadWrite, config_parse_unit_condition_path, CONDITION_PATH_IS_READ_WRITE, offsetof(Unit, conditions)
Unit.ConditionPathIsEncrypted, config_parse_unit_condition_path, CONDITION_PATH_IS_ENCRYPTED, offsetof(Unit, conditions)
Unit.ConditionDirectoryNotEmpty, config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY, offsetof(Unit, conditions)
Unit.ConditionFileNotEmpty, config_parse_unit_condition_path, CONDITION_FILE_NOT_EMPTY, offsetof(Unit, conditions)
Unit.ConditionFileIsExecutable, config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE, offsetof(Unit, conditions)
Unit.ConditionNeedsUpdate, config_parse_unit_condition_path, CONDITION_NEEDS_UPDATE, offsetof(Unit, conditions)
Unit.ConditionFirstBoot, config_parse_unit_condition_string, CONDITION_FIRST_BOOT, offsetof(Unit, conditions)
Unit.ConditionArchitecture, config_parse_unit_condition_string, CONDITION_ARCHITECTURE, offsetof(Unit, conditions)
Unit.ConditionVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, offsetof(Unit, conditions)
Unit.ConditionHost, config_parse_unit_condition_string, CONDITION_HOST, offsetof(Unit, conditions)
Unit.ConditionKernelCommandLine, config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE, offsetof(Unit, conditions)
Unit.ConditionKernelVersion, config_parse_unit_condition_string, CONDITION_KERNEL_VERSION, offsetof(Unit, conditions)
Unit.ConditionArchitecture, config_parse_unit_condition_string, CONDITION_ARCHITECTURE, offsetof(Unit, conditions)
Unit.ConditionVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, offsetof(Unit, conditions)
Unit.ConditionSecurity, config_parse_unit_condition_string, CONDITION_SECURITY, offsetof(Unit, conditions)
Unit.ConditionCapability, config_parse_unit_condition_string, CONDITION_CAPABILITY, offsetof(Unit, conditions)
Unit.ConditionHost, config_parse_unit_condition_string, CONDITION_HOST, offsetof(Unit, conditions)
Unit.ConditionACPower, config_parse_unit_condition_string, CONDITION_AC_POWER, offsetof(Unit, conditions)
Unit.ConditionMemory, config_parse_unit_condition_string, CONDITION_MEMORY, offsetof(Unit, conditions)
Unit.ConditionCPUs, config_parse_unit_condition_string, CONDITION_CPUS, offsetof(Unit, conditions)
Unit.ConditionEnvironment, config_parse_unit_condition_string, CONDITION_ENVIRONMENT, offsetof(Unit, conditions)
Unit.ConditionUser, config_parse_unit_condition_string, CONDITION_USER, offsetof(Unit, conditions)
Unit.ConditionGroup, config_parse_unit_condition_string, CONDITION_GROUP, offsetof(Unit, conditions)
Unit.ConditionControlGroupController, config_parse_unit_condition_string, CONDITION_CONTROL_GROUP_CONTROLLER, offsetof(Unit, conditions)
Unit.ConditionControlGroupController, config_parse_unit_condition_string, CONDITION_CONTROL_GROUP_CONTROLLER, offsetof(Unit, conditions)
Unit.ConditionNull, config_parse_unit_condition_null, 0, offsetof(Unit, conditions)
Unit.AssertPathExists, config_parse_unit_condition_path, CONDITION_PATH_EXISTS, offsetof(Unit, asserts)
Unit.AssertPathExistsGlob, config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB, offsetof(Unit, asserts)
Unit.AssertPathIsDirectory, config_parse_unit_condition_path, CONDITION_PATH_IS_DIRECTORY, offsetof(Unit, asserts)
Unit.AssertPathIsSymbolicLink, config_parse_unit_condition_path, CONDITION_PATH_IS_SYMBOLIC_LINK,offsetof(Unit, asserts)
Unit.AssertPathIsMountPoint, config_parse_unit_condition_path, CONDITION_PATH_IS_MOUNT_POINT, offsetof(Unit, asserts)
Unit.AssertPathIsReadWrite, config_parse_unit_condition_path, CONDITION_PATH_IS_READ_WRITE, offsetof(Unit, asserts)
Unit.AssertPathIsEncrypted, config_parse_unit_condition_path, CONDITION_PATH_IS_ENCRYPTED, offsetof(Unit, asserts)
Unit.AssertDirectoryNotEmpty, config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY, offsetof(Unit, asserts)
Unit.AssertFileNotEmpty, config_parse_unit_condition_path, CONDITION_FILE_NOT_EMPTY, offsetof(Unit, asserts)
Unit.AssertFileIsExecutable, config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE, offsetof(Unit, asserts)
Unit.AssertNeedsUpdate, config_parse_unit_condition_path, CONDITION_NEEDS_UPDATE, offsetof(Unit, asserts)
Unit.AssertFirstBoot, config_parse_unit_condition_string, CONDITION_FIRST_BOOT, offsetof(Unit, asserts)
Unit.AssertArchitecture, config_parse_unit_condition_string, CONDITION_ARCHITECTURE, offsetof(Unit, asserts)
Unit.AssertVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, offsetof(Unit, asserts)
Unit.AssertHost, config_parse_unit_condition_string, CONDITION_HOST, offsetof(Unit, asserts)
Unit.AssertKernelCommandLine, config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE, offsetof(Unit, asserts)
Unit.AssertKernelVersion, config_parse_unit_condition_string, CONDITION_KERNEL_VERSION, offsetof(Unit, asserts)
Unit.AssertArchitecture, config_parse_unit_condition_string, CONDITION_ARCHITECTURE, offsetof(Unit, asserts)
Unit.AssertVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, offsetof(Unit, asserts)
Unit.AssertSecurity, config_parse_unit_condition_string, CONDITION_SECURITY, offsetof(Unit, asserts)
Unit.AssertCapability, config_parse_unit_condition_string, CONDITION_CAPABILITY, offsetof(Unit, asserts)
Unit.AssertHost, config_parse_unit_condition_string, CONDITION_HOST, offsetof(Unit, asserts)
Unit.AssertACPower, config_parse_unit_condition_string, CONDITION_AC_POWER, offsetof(Unit, asserts)
Unit.AssertMemory, config_parse_unit_condition_string, CONDITION_MEMORY, offsetof(Unit, asserts)
Unit.AssertCPUs, config_parse_unit_condition_string, CONDITION_CPUS, offsetof(Unit, asserts)
Unit.AssertEnvironment, config_parse_unit_condition_string, CONDITION_ENVIRONMENT, offsetof(Unit, asserts)
Unit.AssertUser, config_parse_unit_condition_string, CONDITION_USER, offsetof(Unit, asserts)
Unit.AssertGroup, config_parse_unit_condition_string, CONDITION_GROUP, offsetof(Unit, asserts)
Unit.AssertControlGroupController, config_parse_unit_condition_string, CONDITION_CONTROL_GROUP_CONTROLLER, offsetof(Unit, asserts)
Unit.AssertControlGroupController, config_parse_unit_condition_string, CONDITION_CONTROL_GROUP_CONTROLLER, offsetof(Unit, asserts)
Unit.AssertNull, config_parse_unit_condition_null, 0, offsetof(Unit, asserts)
Unit.CollectMode, config_parse_collect_mode, 0, offsetof(Unit, collect_mode)
m4_dnl
Service.PIDFile, config_parse_pid_file, 0, offsetof(Service, pid_file)

View File

@ -2999,6 +2999,60 @@ int config_parse_unit_condition_string(
return 0;
}
int config_parse_unit_condition_null(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
Condition **list = data, *c;
bool trigger, negate;
int b;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
log_syntax(unit, LOG_WARNING, filename, line, 0, "%s= is deprecated, please do not use.", lvalue);
if (isempty(rvalue)) {
/* Empty assignment resets the list */
*list = condition_free_list(*list);
return 0;
}
trigger = rvalue[0] == '|';
if (trigger)
rvalue++;
negate = rvalue[0] == '!';
if (negate)
rvalue++;
b = parse_boolean(rvalue);
if (b < 0) {
log_syntax(unit, LOG_ERR, filename, line, b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
return 0;
}
if (!b)
negate = !negate;
c = condition_new(CONDITION_NULL, NULL, trigger, negate);
if (!c)
return log_oom();
LIST_PREPEND(conditions, *list, c);
return 0;
}
int config_parse_unit_requires_mounts_for(
const char *unit,
const char *filename,
@ -5212,6 +5266,7 @@ void unit_dump_config_items(FILE *f) {
{ config_parse_ip_tos, "TOS" },
{ config_parse_unit_condition_path, "CONDITION" },
{ config_parse_unit_condition_string, "CONDITION" },
{ config_parse_unit_condition_null, "CONDITION" },
{ config_parse_unit_slice, "SLICE" },
{ config_parse_documentation, "URL" },
{ config_parse_service_timeout, "SECONDS" },

View File

@ -58,6 +58,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_unit_env_file);
CONFIG_PARSER_PROTOTYPE(config_parse_ip_tos);
CONFIG_PARSER_PROTOTYPE(config_parse_unit_condition_path);
CONFIG_PARSER_PROTOTYPE(config_parse_unit_condition_string);
CONFIG_PARSER_PROTOTYPE(config_parse_unit_condition_null);
CONFIG_PARSER_PROTOTYPE(config_parse_kill_mode);
CONFIG_PARSER_PROTOTYPE(config_parse_notify_access);
CONFIG_PARSER_PROTOTYPE(config_parse_emergency_action);

View File

@ -32,7 +32,6 @@
#include "dbus-manager.h"
#include "dbus.h"
#include "def.h"
#include "dev-setup.h"
#include "efi-random.h"
#include "efivars.h"
#include "emergency-action.h"
@ -54,7 +53,6 @@
#include "loopback-setup.h"
#include "machine-id-setup.h"
#include "manager.h"
#include "mkdir.h"
#include "mount-setup.h"
#include "os-util.h"
#include "pager.h"
@ -2075,20 +2073,6 @@ static int initialize_runtime(
if (r < 0)
log_warning_errno(r, "Failed to set watchdog device to %s, ignoring: %m", arg_watchdog_device);
}
} else {
_cleanup_free_ char *p = NULL;
/* Create the runtime directory and place the inaccessible device nodes there, if we run in
* user mode. In system mode mount_setup() already did that. */
r = xdg_user_runtime_dir(&p, "/systemd");
if (r < 0) {
*ret_error_message = "$XDG_RUNTIME_DIR is not set";
return log_emergency_errno(r, "Failed to determine $XDG_RUNTIME_DIR path: %m");
}
(void) mkdir_p(p, 0755);
(void) make_inaccessible_nodes(p, UID_INVALID, GID_INVALID);
}
if (arg_timer_slack_nsec != NSEC_INFINITY)

View File

@ -85,8 +85,6 @@ static const MountPoint mount_table[] = {
#endif
{ "tmpfs", "/run", "tmpfs", "mode=755" TMPFS_LIMITS_RUN, MS_NOSUID|MS_NODEV|MS_STRICTATIME,
NULL, MNT_FATAL|MNT_IN_CONTAINER },
{ "cgroup2", "/sys/fs/cgroup", "cgroup2", "nsdelegate,memory_recursiveprot", MS_NOSUID|MS_NOEXEC|MS_NODEV,
cg_is_unified_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
{ "cgroup2", "/sys/fs/cgroup", "cgroup2", "nsdelegate", MS_NOSUID|MS_NOEXEC|MS_NODEV,
cg_is_unified_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
{ "cgroup2", "/sys/fs/cgroup", "cgroup2", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
@ -538,17 +536,8 @@ int mount_setup(bool loaded_policy, bool leave_propagation) {
(void) mkdir_label("/run/systemd/system", 0755);
/* Also create /run/systemd/inaccessible nodes, so that we always have something to mount
* inaccessible nodes from. If we run in a container the host might have created these for us already
* in /run/host/inaccessible/. Use those if we can, since tht way we likely get access to block/char
* device nodes that are inaccessible, and if userns is used to nodes that are on mounts owned by a
* userns outside the container and thus nicely read-only and not remountable. */
if (access("/run/host/inaccessible/", F_OK) < 0) {
if (errno != ENOENT)
log_debug_errno(errno, "Failed to check if /run/host/inaccessible exists, ignoring: %m");
(void) make_inaccessible_nodes("/run/systemd", UID_INVALID, GID_INVALID);
} else
(void) symlink("../host/inaccessible", "/run/systemd/inaccessible");
* inaccessible nodes from. */
(void) make_inaccessible_nodes(NULL, UID_INVALID, GID_INVALID);
return 0;
}

View File

@ -265,7 +265,7 @@ get_parent:
static char *format_timestamp_maybe_utc(char *buf, size_t l, usec_t t) {
if (arg_utc)
return format_timestamp_style(buf, l, t, TIMESTAMP_UTC);
return format_timestamp_utc(buf, l, t);
return format_timestamp(buf, l, t);
}

View File

@ -544,11 +544,9 @@ static int bus_socket_read_auth(sd_bus *b) {
iov = IOVEC_MAKE((uint8_t *)b->rbuffer + b->rbuffer_size, n - b->rbuffer_size);
if (b->prefer_readv) {
if (b->prefer_readv)
k = readv(b->input_fd, &iov, 1);
if (k < 0)
k = -errno;
} else {
else {
mh = (struct msghdr) {
.msg_iov = &iov,
.msg_iovlen = 1,
@ -1189,11 +1187,9 @@ int bus_socket_read_message(sd_bus *bus) {
iov = IOVEC_MAKE((uint8_t *)bus->rbuffer + bus->rbuffer_size, need - bus->rbuffer_size);
if (bus->prefer_readv) {
if (bus->prefer_readv)
k = readv(bus->input_fd, &iov, 1);
if (k < 0)
k = -errno;
} else {
else {
mh = (struct msghdr) {
.msg_iov = &iov,
.msg_iovlen = 1,

View File

@ -7,10 +7,9 @@
#include "bus-error.h"
#include "dev-setup.h"
#include "format-util.h"
#include "fs-util.h"
#include "format-util.h"
#include "label.h"
#include "limits-util.h"
#include "main-func.h"
#include "mkdir.h"
#include "mountpoint-util.h"
@ -33,16 +32,12 @@ static int acquire_runtime_dir_properties(uint64_t *size, uint64_t *inodes) {
return log_error_errno(r, "Failed to connect to system bus: %m");
r = sd_bus_get_property_trivial(bus, "org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "RuntimeDirectorySize", &error, 't', size);
if (r < 0) {
log_warning_errno(r, "Failed to acquire runtime directory size, ignoring: %s", bus_error_message(&error, r));
*size = physical_memory_scale(10U, 100U); /* 10% */
}
if (r < 0)
return log_error_errno(r, "Failed to acquire runtime directory size: %s", bus_error_message(&error, r));
r = sd_bus_get_property_trivial(bus, "org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "RuntimeDirectoryInodesMax", &error, 't', inodes);
if (r < 0) {
log_warning_errno(r, "Failed to acquire number of inodes for runtime directory, ignoring: %s", bus_error_message(&error, r));
*inodes = DIV_ROUND_UP(*size, 4096);
}
if (r < 0)
return log_error_errno(r, "Failed to acquire number of inodes for runtime directory: %s", bus_error_message(&error, r));
return 0;
}
@ -88,8 +83,7 @@ static int user_mkdir_runtime_path(
goto fail;
}
log_debug_errno(errno,
"Failed to mount per-user tmpfs directory %s.\n"
log_debug_errno(errno, "Failed to mount per-user tmpfs directory %s.\n"
"Assuming containerized execution, ignoring: %m", runtime_path);
r = chmod_and_chown(runtime_path, 0700, uid, gid);
@ -104,6 +98,8 @@ static int user_mkdir_runtime_path(
log_warning_errno(r, "Failed to fix label of \"%s\", ignoring: %m", runtime_path);
}
/* Set up inaccessible nodes now so they're available if we decide to use them with user namespaces. */
(void) make_inaccessible_nodes(runtime_path, uid, gid);
return 0;
fail:

View File

@ -978,8 +978,9 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
goto finish;
}
if (r == 0) {
const char *mount_inside, *q;
const char *mount_inside;
int mntfd;
const char *q;
errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
@ -1000,11 +1001,12 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
(void) mkdir_p(dest, 0755);
else {
(void) mkdir_parents(dest, 0755);
(void) mknod(dest, S_IFREG|0600, 0);
safe_close(open(dest, O_CREAT|O_EXCL|O_WRONLY|O_CLOEXEC|O_NOCTTY, 0600));
}
}
mount_inside = strjoina("/run/host/incoming/", basename(mount_outside));
/* Fifth, move the mount to the right place inside */
mount_inside = strjoina("/run/systemd/nspawn/incoming/", basename(mount_outside));
if (mount(mount_inside, dest, NULL, MS_MOVE, NULL) < 0) {
r = log_error_errno(errno, "Failed to mount: %m");
goto child_fail;

View File

@ -101,8 +101,10 @@
#include "user-util.h"
#include "util.h"
/* The notify socket inside the container it can use to talk to nspawn using the sd_notify(3) protocol */
#define NSPAWN_NOTIFY_SOCKET_PATH "/run/host/notify"
/* nspawn is listening on the socket at the path in the constant nspawn_notify_socket_path
* nspawn_notify_socket_path is relative to the container
* the init process in the container pid can send messages to nspawn following the sd_notify(3) protocol */
#define NSPAWN_NOTIFY_SOCKET_PATH "/run/systemd/nspawn/notify"
#define EXIT_FORCE_RESTART 133
@ -2515,15 +2517,19 @@ static int setup_propagate(const char *root) {
p = strjoina("/run/systemd/nspawn/propagate/", arg_machine);
(void) mkdir_p(p, 0600);
r = userns_mkdir(root, "/run/host", 0755, 0, 0);
r = userns_mkdir(root, "/run/systemd", 0755, 0, 0);
if (r < 0)
return log_error_errno(r, "Failed to create /run/host: %m");
return log_error_errno(r, "Failed to create /run/systemd: %m");
r = userns_mkdir(root, "/run/host/incoming", 0600, 0, 0);
r = userns_mkdir(root, "/run/systemd/nspawn", 0755, 0, 0);
if (r < 0)
return log_error_errno(r, "Failed to create /run/host/incoming: %m");
return log_error_errno(r, "Failed to create /run/systemd/nspawn: %m");
q = prefix_roota(root, "/run/host/incoming");
r = userns_mkdir(root, "/run/systemd/nspawn/incoming", 0600, 0, 0);
if (r < 0)
return log_error_errno(r, "Failed to create /run/systemd/nspawn/incoming: %m");
q = prefix_roota(root, "/run/systemd/nspawn/incoming");
r = mount_verbose(LOG_ERR, p, q, NULL, MS_BIND, NULL);
if (r < 0)
return r;
@ -2532,7 +2538,8 @@ static int setup_propagate(const char *root) {
if (r < 0)
return r;
/* machined will MS_MOVE into that directory, and that's only supported for non-shared mounts. */
/* machined will MS_MOVE into that directory, and that's only
* supported for non-shared mounts. */
return mount_verbose(LOG_ERR, NULL, q, NULL, MS_SLAVE, NULL);
}
@ -3271,7 +3278,7 @@ static int inner_child(
return log_error_errno(errno, "execv(%s) failed: %m", exec_target);
}
static int setup_notify_child(void) {
static int setup_sd_notify_child(void) {
_cleanup_close_ int fd = -1;
union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
@ -3523,7 +3530,7 @@ static int outer_child(
(void) dev_setup(directory, arg_uid_shift, arg_uid_shift);
p = prefix_roota(directory, "/run/host");
p = prefix_roota(directory, "/run");
(void) make_inaccessible_nodes(p, arg_uid_shift, arg_uid_shift);
r = setup_pts(directory);
@ -3564,14 +3571,6 @@ static int outer_child(
if (r < 0)
return r;
/* The same stuff as the $container env var, but nicely readable for the entire payload */
p = prefix_roota(directory, "/run/host/container-manager");
(void) write_string_file(p, arg_container_service_name, WRITE_STRING_FILE_CREATE);
/* The same stuff as the $container_uuid env var */
p = prefix_roota(directory, "/run/host/container-uuid");
(void) write_string_filef(p, WRITE_STRING_FILE_CREATE, SD_ID128_UUID_FORMAT_STR, SD_ID128_FORMAT_VAL(arg_uuid));
if (!arg_use_cgns) {
r = mount_cgroups(
directory,
@ -3589,7 +3588,7 @@ static int outer_child(
if (r < 0)
return log_error_errno(r, "Failed to move root directory: %m");
fd = setup_notify_child();
fd = setup_sd_notify_child();
if (fd < 0)
return fd;
@ -3802,7 +3801,7 @@ static int nspawn_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t r
return 0;
}
static int setup_notify_parent(sd_event *event, int fd, pid_t *inner_child_pid, sd_event_source **notify_event_source) {
static int setup_sd_notify_parent(sd_event *event, int fd, pid_t *inner_child_pid, sd_event_source **notify_event_source) {
int r;
r = sd_event_add_io(event, notify_event_source, fd, EPOLLIN, nspawn_dispatch_notify_fd, inner_child_pid);
@ -4633,7 +4632,7 @@ static int run_container(
return log_error_errno(r, "Failed to attach bus to event loop: %m");
}
r = setup_notify_parent(event, notify_socket, PID_TO_PTR(*pid), &notify_event_source);
r = setup_sd_notify_parent(event, notify_socket, PID_TO_PTR(*pid), &notify_event_source);
if (r < 0)
return r;

View File

@ -52,7 +52,7 @@ Condition* condition_new(ConditionType type, const char *parameter, bool trigger
assert(type >= 0);
assert(type < _CONDITION_TYPE_MAX);
assert(parameter);
assert((!parameter) == (type == CONDITION_NULL));
c = new(Condition, 1);
if (!c)
@ -776,6 +776,15 @@ static int condition_test_file_is_executable(Condition *c, char **env) {
(st.st_mode & 0111));
}
static int condition_test_null(Condition *c, char **env) {
assert(c);
assert(c->type == CONDITION_NULL);
/* Note that during parsing we already evaluate the string and
* store it in c->negate */
return true;
}
int condition_test(Condition *c, char **env) {
static int (*const condition_tests[_CONDITION_TYPE_MAX])(Condition *c, char **env) = {
@ -802,6 +811,7 @@ int condition_test(Condition *c, char **env) {
[CONDITION_USER] = condition_test_user,
[CONDITION_GROUP] = condition_test_group,
[CONDITION_CONTROL_GROUP_CONTROLLER] = condition_test_control_group_controller,
[CONDITION_NULL] = condition_test_null,
[CONDITION_CPUS] = condition_test_cpus,
[CONDITION_MEMORY] = condition_test_memory,
[CONDITION_ENVIRONMENT] = condition_test_environment,
@ -849,20 +859,23 @@ bool condition_test_list(
r = condition_test(c, env);
if (logger) {
const char *p = c->type == CONDITION_NULL ? "true" : c->parameter;
assert(p);
if (r < 0)
logger(userdata, LOG_WARNING, r, PROJECT_FILE, __LINE__, __func__,
"Couldn't determine result for %s=%s%s%s, assuming failed: %m",
to_string(c->type),
c->trigger ? "|" : "",
c->negate ? "!" : "",
c->parameter);
p);
else
logger(userdata, LOG_DEBUG, 0, PROJECT_FILE, __LINE__, __func__,
"%s=%s%s%s %s.",
to_string(c->type),
c->trigger ? "|" : "",
c->negate ? "!" : "",
c->parameter,
p,
condition_result_to_string(c->result));
}
@ -924,6 +937,7 @@ static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
[CONDITION_USER] = "ConditionUser",
[CONDITION_GROUP] = "ConditionGroup",
[CONDITION_CONTROL_GROUP_CONTROLLER] = "ConditionControlGroupController",
[CONDITION_NULL] = "ConditionNull",
[CONDITION_CPUS] = "ConditionCPUs",
[CONDITION_MEMORY] = "ConditionMemory",
[CONDITION_ENVIRONMENT] = "ConditionEnvironment",
@ -955,6 +969,7 @@ static const char* const assert_type_table[_CONDITION_TYPE_MAX] = {
[CONDITION_USER] = "AssertUser",
[CONDITION_GROUP] = "AssertGroup",
[CONDITION_CONTROL_GROUP_CONTROLLER] = "AssertControlGroupController",
[CONDITION_NULL] = "AssertNull",
[CONDITION_CPUS] = "AssertCPUs",
[CONDITION_MEMORY] = "AssertMemory",
[CONDITION_ENVIRONMENT] = "AssertEnvironment",

View File

@ -34,6 +34,8 @@ typedef enum ConditionType {
CONDITION_FILE_NOT_EMPTY,
CONDITION_FILE_IS_EXECUTABLE,
CONDITION_NULL,
CONDITION_USER,
CONDITION_GROUP,

View File

@ -57,7 +57,7 @@ int dev_setup(const char *prefix, uid_t uid, gid_t gid) {
}
int make_inaccessible_nodes(
const char *parent_dir,
const char *runtime_dir,
uid_t uid,
gid_t gid) {
@ -65,26 +65,28 @@ int make_inaccessible_nodes(
const char *name;
mode_t mode;
} table[] = {
{ "inaccessible", S_IFDIR | 0755 },
{ "inaccessible/reg", S_IFREG | 0000 },
{ "inaccessible/dir", S_IFDIR | 0000 },
{ "inaccessible/fifo", S_IFIFO | 0000 },
{ "inaccessible/sock", S_IFSOCK | 0000 },
{ "/systemd", S_IFDIR | 0755 },
{ "/systemd/inaccessible", S_IFDIR | 0000 },
{ "/systemd/inaccessible/reg", S_IFREG | 0000 },
{ "/systemd/inaccessible/dir", S_IFDIR | 0000 },
{ "/systemd/inaccessible/fifo", S_IFIFO | 0000 },
{ "/systemd/inaccessible/sock", S_IFSOCK | 0000 },
/* The following two are likely to fail if we lack the privs for it (for example in an userns
* environment, if CAP_SYS_MKNOD is missing, or if a device node policy prohibit major/minor of 0
* device nodes to be created). But that's entirely fine. Consumers of these files should carry
* fallback to use a different node then, for example <root>/inaccessible/sock, which is close
* enough in behaviour and semantics for most uses. */
{ "inaccessible/chr", S_IFCHR | 0000 },
{ "inaccessible/blk", S_IFBLK | 0000 },
{ "/systemd/inaccessible/chr", S_IFCHR | 0000 },
{ "/systemd/inaccessible/blk", S_IFBLK | 0000 },
};
_cleanup_umask_ mode_t u;
size_t i;
int r;
if (!parent_dir)
parent_dir = "/run/systemd";
if (!runtime_dir)
runtime_dir = "/run";
u = umask(0000);
@ -93,10 +95,10 @@ int make_inaccessible_nodes(
* to lock down these nodes as much as we can, but otherwise try to match them as closely as possible with the
* underlying file, i.e. in the best case we offer the same node type as the underlying node. */
for (size_t i = 0; i < ELEMENTSOF(table); i++) {
for (i = 0; i < ELEMENTSOF(table); i++) {
_cleanup_free_ char *path = NULL;
path = path_join(parent_dir, table[i].name);
path = path_join(runtime_dir, table[i].name);
if (!path)
return log_oom();
@ -105,7 +107,8 @@ int make_inaccessible_nodes(
else
r = mknod_label(path, table[i].mode, makedev(0, 0));
if (r < 0) {
log_debug_errno(r, "Failed to create '%s', ignoring: %m", path);
if (r != -EEXIST)
log_debug_errno(r, "Failed to create '%s', ignoring: %m", path);
continue;
}

View File

@ -5,4 +5,4 @@
int dev_setup(const char *prefix, uid_t uid, gid_t gid);
int make_inaccessible_nodes(const char *parent_dir, uid_t uid, gid_t gid);
int make_inaccessible_nodes(const char *root, uid_t uid, gid_t gid);

View File

@ -1335,7 +1335,7 @@ static const char *table_data_format(Table *t, TableData *d, bool avoid_uppercas
if (d->type == TABLE_TIMESTAMP)
ret = format_timestamp(p, FORMAT_TIMESTAMP_MAX, d->timestamp);
else if (d->type == TABLE_TIMESTAMP_UTC)
ret = format_timestamp_style(p, FORMAT_TIMESTAMP_MAX, d->timestamp, TIMESTAMP_UTC);
ret = format_timestamp_utc(p, FORMAT_TIMESTAMP_MAX, d->timestamp);
else
ret = format_timestamp_relative(p, FORMAT_TIMESTAMP_MAX, d->timestamp);
if (!ret)

View File

@ -368,7 +368,7 @@ static int output_timestamp_realtime(FILE *f, sd_journal *j, OutputMode mode, Ou
const char *k;
if (flags & OUTPUT_UTC)
k = format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_UTC);
k = format_timestamp_utc(buf, sizeof(buf), x);
else
k = format_timestamp(buf, sizeof(buf), x);
if (!k)
@ -685,8 +685,8 @@ static int output_verbose(
if (r < 0)
return log_error_errno(r, "Failed to get cursor: %m");
timestamp = format_timestamp_style(ts, sizeof ts, realtime,
flags & OUTPUT_UTC ? TIMESTAMP_US_UTC : TIMESTAMP_US);
timestamp = flags & OUTPUT_UTC ? format_timestamp_us_utc(ts, sizeof ts, realtime)
: format_timestamp_us(ts, sizeof ts, realtime);
fprintf(f, "%s [%s]\n",
timestamp ?: "(no timestamp)",
cursor);

View File

@ -414,6 +414,7 @@ int mode_to_inaccessible_node(
_cleanup_free_ char *d = NULL;
const char *node = NULL;
bool fallback = false;
assert(ret);
@ -431,10 +432,12 @@ int mode_to_inaccessible_node(
case S_IFCHR:
node = "/systemd/inaccessible/chr";
fallback = true;
break;
case S_IFBLK:
node = "/systemd/inaccessible/blk";
fallback = true;
break;
case S_IFIFO:
@ -452,24 +455,7 @@ int mode_to_inaccessible_node(
if (!d)
return -ENOMEM;
/* On new kernels unprivileged users are permitted to create 0:0 char device nodes (because they also
* act as whiteout inode for overlayfs), but no other char or block device nodes. On old kernels no
* device node whatsoever may be created by unprivileged processes. Hence, if the caller asks for the
* inaccessible block device node let's see if the block device node actually exists, and if not,
* fall back to the character device node. From there fall back to the socket device node. This means
* in the best case we'll get the right device node type but if not we'll hopefully at least get a
* device node at all. */
if (S_ISBLK(mode) &&
access(d, F_OK) < 0 && errno == ENOENT) {
free(d);
d = path_join(runtime_dir, "/systemd/inaccessible/chr");
if (!d)
return -ENOMEM;
}
if (IN_SET(mode & S_IFMT, S_IFBLK, S_IFCHR) &&
access(d, F_OK) < 0 && errno == ENOENT) {
if (fallback && access(d, F_OK) < 0) {
free(d);
d = path_join(runtime_dir, "/systemd/inaccessible/sock");
if (!d)

View File

@ -170,7 +170,6 @@ static bool arg_now = false;
static bool arg_jobs_before = false;
static bool arg_jobs_after = false;
static char **arg_clean_what = NULL;
static TimestampStyle arg_timestamp_style = TIMESTAMP_PRETTY;
/* This is a global cache that will be constructed on first use. */
static Hashmap *cached_id_map = NULL;
@ -4196,7 +4195,7 @@ static void print_status_info(
i->active_exit_timestamp;
s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
s2 = format_timestamp_style(since2, sizeof(since2), timestamp, arg_timestamp_style);
s2 = format_timestamp(since2, sizeof(since2), timestamp);
if (s1)
printf(" since %s; %s\n", s2, s1);
@ -4230,7 +4229,7 @@ static void print_status_info(
dual_timestamp_get(&nw);
next_elapse = calc_next_elapse(&nw, &next);
next_rel_time = format_timestamp_relative(tstamp1, sizeof tstamp1, next_elapse);
next_time = format_timestamp_style(tstamp2, sizeof tstamp2, next_elapse, arg_timestamp_style);
next_time = format_timestamp(tstamp2, sizeof tstamp2, next_elapse);
if (next_time && next_rel_time)
printf("%s; %s\n", next_time, next_rel_time);
@ -4255,7 +4254,7 @@ static void print_status_info(
int n = 0;
s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
s2 = format_timestamp_style(since2, sizeof(since2), i->condition_timestamp, arg_timestamp_style);
s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
printf(" Condition: start %scondition failed%s at %s%s%s\n",
ansi_highlight_yellow(), ansi_normal(),
@ -4277,7 +4276,7 @@ static void print_status_info(
if (!i->assert_result && i->assert_timestamp > 0) {
s1 = format_timestamp_relative(since1, sizeof(since1), i->assert_timestamp);
s2 = format_timestamp_style(since2, sizeof(since2), i->assert_timestamp, arg_timestamp_style);
s2 = format_timestamp(since2, sizeof(since2), i->assert_timestamp);
printf(" Assert: start %sassertion failed%s at %s%s%s\n",
ansi_highlight_red(), ansi_normal(),
@ -5038,7 +5037,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
while ((r = sd_bus_message_read(m, "(sst)", &base, &spec, &next_elapse)) > 0) {
char timestamp[FORMAT_TIMESTAMP_MAX] = "n/a";
(void) format_timestamp_style(timestamp, sizeof(timestamp), next_elapse, arg_timestamp_style);
(void) format_timestamp(timestamp, sizeof(timestamp), next_elapse);
bus_print_property_valuef(name, expected_value, value,
"{ %s=%s ; next_elapse=%s }", base, spec, timestamp);
}
@ -5078,8 +5077,8 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
strna(info.path),
strna(tt),
strna(o),
strna(format_timestamp_style(timestamp1, sizeof(timestamp1), info.start_timestamp, arg_timestamp_style)),
strna(format_timestamp_style(timestamp2, sizeof(timestamp2), info.exit_timestamp, arg_timestamp_style)),
strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
info.pid,
sigchld_code_to_string(info.code),
info.status,
@ -5091,8 +5090,8 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
strna(info.path),
strna(tt),
yes_no(info.ignore),
strna(format_timestamp_style(timestamp1, sizeof(timestamp1), info.start_timestamp, arg_timestamp_style)),
strna(format_timestamp_style(timestamp2, sizeof(timestamp2), info.exit_timestamp, arg_timestamp_style)),
strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
info.pid,
sigchld_code_to_string(info.code),
info.status,
@ -5755,7 +5754,7 @@ static int show_system_status(sd_bus *bus) {
printf(" Failed: %" PRIu32 " units\n", mi.n_failed_units);
printf(" Since: %s; %s\n",
format_timestamp_style(since2, sizeof(since2), mi.timestamp, arg_timestamp_style),
format_timestamp(since2, sizeof(since2), mi.timestamp),
format_timestamp_relative(since1, sizeof(since1), mi.timestamp));
printf(" CGroup: %s\n", mi.control_group ?: "/");
@ -7805,11 +7804,6 @@ static int systemctl_help(void) {
" --boot-loader-entry=NAME\n"
" Boot into a specific boot loader entry on next boot\n"
" --plain Print unit dependencies as a list instead of a tree\n"
" --timestamp=FORMAT Change format of printed timestamps.\n"
" 'pretty' (default): 'Day YYYY-MM-DD HH:MM:SS TZ\n"
" 'us': 'Day YYYY-MM-DD HH:MM:SS.UUUUUU TZ\n"
" 'utc': 'Day YYYY-MM-DD HH:MM:SS UTC\n"
" 'us+utc': 'Day YYYY-MM-DD HH:MM:SS.UUUUUU UTC\n"
"\nSee the %2$s for details.\n"
, program_invocation_short_name
, link
@ -8058,7 +8052,6 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
ARG_WAIT,
ARG_WHAT,
ARG_REBOOT_ARG,
ARG_TIMESTAMP_STYLE,
};
static const struct option options[] = {
@ -8113,7 +8106,6 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
{ "show-transaction", no_argument, NULL, 'T' },
{ "what", required_argument, NULL, ARG_WHAT },
{ "reboot-argument", required_argument, NULL, ARG_REBOOT_ARG },
{ "timestamp", required_argument, NULL, ARG_TIMESTAMP_STYLE },
{}
};
@ -8513,19 +8505,6 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
arg_reboot_argument = optarg;
break;
case ARG_TIMESTAMP_STYLE:
if (streq(optarg, "help")) {
DUMP_STRING_TABLE(timestamp_style, TimestampStyle, _TIMESTAMP_STYLE_MAX);
return 0;
}
arg_timestamp_style = timestamp_style_from_string(optarg);
if (arg_timestamp_style < 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Invalid value: %s.", optarg);
break;
case '.':
/* Output an error mimicking getopt, and print a hint afterwards */
log_error("%s: invalid option -- '.'", program_invocation_name);
@ -9151,7 +9130,7 @@ static int logind_schedule_shutdown(void) {
return log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s", bus_error_message(&error, r));
if (!arg_quiet)
log_info("%s scheduled for %s, use 'shutdown -c' to cancel.", log_action, format_timestamp_style(date, sizeof(date), arg_when, arg_timestamp_style));
log_info("%s scheduled for %s, use 'shutdown -c' to cancel.", log_action, format_timestamp(date, sizeof(date), arg_when));
return 0;
#else
return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),

View File

@ -58,7 +58,7 @@ static void test_next(const char *input, const char *new_tz, usec_t after, usec_
u = after;
r = calendar_spec_next_usec(c, after, &u);
printf("At: %s\n", r < 0 ? strerror_safe(r) : format_timestamp_style(buf, sizeof buf, u, TIMESTAMP_US));
printf("At: %s\n", r < 0 ? strerror_safe(r) : format_timestamp_us(buf, sizeof buf, u));
if (expect != (usec_t)-1)
assert_se(r >= 0 && u == expect);
else
@ -83,7 +83,7 @@ static void test_timestamp(void) {
x = now(CLOCK_REALTIME);
assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US));
assert_se(format_timestamp_us(buf, sizeof(buf), x));
printf("%s\n", buf);
assert_se(calendar_spec_from_string(buf, &c) >= 0);
assert_se(calendar_spec_to_string(c, &t) >= 0);
@ -104,11 +104,11 @@ static void test_hourly_bug_4031(void) {
n = now(CLOCK_REALTIME);
assert_se((r = calendar_spec_next_usec(c, n, &u)) >= 0);
printf("Now: %s (%"PRIu64")\n", format_timestamp_style(buf, sizeof buf, n, TIMESTAMP_US), n);
printf("Next hourly: %s (%"PRIu64")\n", r < 0 ? strerror_safe(r) : format_timestamp_style(buf, sizeof buf, u, TIMESTAMP_US), u);
printf("Now: %s (%"PRIu64")\n", format_timestamp_us(buf, sizeof buf, n), n);
printf("Next hourly: %s (%"PRIu64")\n", r < 0 ? strerror_safe(r) : format_timestamp_us(buf, sizeof buf, u), u);
assert_se((r = calendar_spec_next_usec(c, u, &w)) >= 0);
printf("Next hourly: %s (%"PRIu64")\n", r < 0 ? strerror_safe(r) : format_timestamp_style(zaf, sizeof zaf, w, TIMESTAMP_US), w);
printf("Next hourly: %s (%"PRIu64")\n", r < 0 ? strerror_safe(r) : format_timestamp_us(zaf, sizeof zaf, w), w);
assert_se(n < u);
assert_se(u <= n + USEC_PER_HOUR);

View File

@ -438,6 +438,20 @@ static void test_condition_test_kernel_version(void) {
condition_free(condition);
}
static void test_condition_test_null(void) {
Condition *condition;
condition = condition_new(CONDITION_NULL, NULL, false, false);
assert_se(condition);
assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
condition = condition_new(CONDITION_NULL, NULL, false, true);
assert_se(condition);
assert_se(condition_test(condition, environ) == 0);
condition_free(condition);
}
static void test_condition_test_security(void) {
Condition *condition;
@ -854,6 +868,7 @@ int main(int argc, char *argv[]) {
test_condition_test_architecture();
test_condition_test_kernel_command_line();
test_condition_test_kernel_version();
test_condition_test_null();
test_condition_test_security();
print_securities();
test_condition_test_virtualization();

View File

@ -11,7 +11,7 @@ static void test_should_pass(const char *p) {
log_info("Test: %s", p);
assert_se(parse_timestamp(p, &t) >= 0);
assert_se(format_timestamp_style(buf, sizeof(buf), t, TIMESTAMP_US));
assert_se(format_timestamp_us(buf, sizeof(buf), t));
log_info("\"%s\"\"%s\"", p, buf);
assert_se(parse_timestamp(buf, &q) >= 0);
@ -19,7 +19,7 @@ static void test_should_pass(const char *p) {
char tmp[FORMAT_TIMESTAMP_MAX];
log_error("round-trip failed: \"%s\"\"%s\"",
buf, format_timestamp_style(tmp, sizeof(tmp), q, TIMESTAMP_US));
buf, format_timestamp_us(tmp, sizeof(tmp), q));
}
assert_se(q == t);

View File

@ -3,7 +3,6 @@
#include "capability-util.h"
#include "dev-setup.h"
#include "fs-util.h"
#include "mkdir.h"
#include "path-util.h"
#include "rm-rf.h"
#include "tmpfile-util.h"
@ -18,8 +17,8 @@ int main(int argc, char *argv[]) {
assert_se(mkdtemp_malloc("/tmp/test-dev-setupXXXXXX", &p) >= 0);
f = prefix_roota(p, "/run/systemd");
assert_se(mkdir_p(f, 0755) >= 0);
f = prefix_roota(p, "/run");
assert_se(mkdir(f, 0755) >= 0);
assert_se(make_inaccessible_nodes(f, 1, 1) >= 0);

View File

@ -333,17 +333,17 @@ static void test_format_timestamp(void) {
assert_se(parse_timestamp(buf, &y) >= 0);
assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_UTC));
assert_se(format_timestamp_utc(buf, sizeof(buf), x));
log_info("%s", buf);
assert_se(parse_timestamp(buf, &y) >= 0);
assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US));
assert_se(format_timestamp_us(buf, sizeof(buf), x));
log_info("%s", buf);
assert_se(parse_timestamp(buf, &y) >= 0);
assert_se(x == y);
assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US_UTC));
assert_se(format_timestamp_us_utc(buf, sizeof(buf), x));
log_info("%s", buf);
assert_se(parse_timestamp(buf, &y) >= 0);
assert_se(x == y);
@ -364,7 +364,7 @@ static void test_format_timestamp_utc_one(usec_t val, const char *result) {
char buf[FORMAT_TIMESTAMP_MAX];
const char *t;
t = format_timestamp_style(buf, sizeof(buf), val, TIMESTAMP_UTC);
t = format_timestamp_utc(buf, sizeof(buf), val);
assert_se(streq_ptr(t, result));
}

View File

@ -155,7 +155,7 @@ static int clock_state_update(
if (tx.status & STA_NANO)
tx.time.tv_usec /= 1000;
t = timeval_load(&tx.time);
ts = format_timestamp_style(buf, sizeof(buf), t, TIMESTAMP_US_UTC);
ts = format_timestamp_us_utc(buf, sizeof(buf), t);
if (!ts)
strcpy(buf, "unrepresentable");
log_info("adjtime state %d status %x time %s", sp->adjtime_state, tx.status, ts);

View File

@ -611,7 +611,7 @@ static int dir_cleanup(
/* Follows spelling in stat(1). */
log_debug("Directory \"%s\": modify time %s is too new.",
sub_path,
format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
format_timestamp_us(a, sizeof(a), age));
continue;
}
@ -620,7 +620,7 @@ static int dir_cleanup(
char a[FORMAT_TIMESTAMP_MAX];
log_debug("Directory \"%s\": access time %s is too new.",
sub_path,
format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
format_timestamp_us(a, sizeof(a), age));
continue;
}
@ -672,7 +672,7 @@ static int dir_cleanup(
/* Follows spelling in stat(1). */
log_debug("File \"%s\": modify time %s is too new.",
sub_path,
format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
format_timestamp_us(a, sizeof(a), age));
continue;
}
@ -681,7 +681,7 @@ static int dir_cleanup(
char a[FORMAT_TIMESTAMP_MAX];
log_debug("File \"%s\": access time %s is too new.",
sub_path,
format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
format_timestamp_us(a, sizeof(a), age));
continue;
}
@ -690,7 +690,7 @@ static int dir_cleanup(
char a[FORMAT_TIMESTAMP_MAX];
log_debug("File \"%s\": change time %s is too new.",
sub_path,
format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
format_timestamp_us(a, sizeof(a), age));
continue;
}
@ -713,8 +713,8 @@ finish:
log_debug("Restoring access and modification time on \"%s\": %s, %s",
p,
format_timestamp_style(a, sizeof(a), age1, TIMESTAMP_US),
format_timestamp_style(b, sizeof(b), age2, TIMESTAMP_US));
format_timestamp_us(a, sizeof(a), age1),
format_timestamp_us(b, sizeof(b), age2));
/* Restore original directory timestamps */
if (futimens(dirfd(d), (struct timespec[]) {
@ -2228,7 +2228,7 @@ static int clean_item_instance(Item *i, const char* instance) {
log_debug("Cleanup threshold for %s \"%s\" is %s",
mountpoint ? "mount point" : "directory",
instance,
format_timestamp_style(timestamp, sizeof(timestamp), cutoff, TIMESTAMP_US));
format_timestamp_us(timestamp, sizeof(timestamp), cutoff));
return dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
MAX_DEPTH, i->keep_first_level);

View File

@ -15,6 +15,9 @@ Documentation=https://www.freedesktop.org/wiki/Software/systemd/machined
Wants=machine.slice
After=machine.slice
RequiresMountsFor=/var/lib/machines
ConditionNull=true
ConditionNull=
ConditionNull=|!false
OnFailureIsolate=false
FailureActionExitStatus=222
FailureActionExitStatus=

View File

@ -60,7 +60,7 @@ function check_norbind {
function check_notification_socket {
# https://github.com/systemd/systemd/issues/4944
local _cmd='echo a | $(busybox which nc) -U -u -w 1 /run/host/notify'
local _cmd='echo a | $(busybox which nc) -U -u -w 1 /run/systemd/nspawn/notify'
# /testsuite-13.nc-container is prepared by test.sh
systemd-nspawn $SUSE_OPTS--register=no -D /testsuite-13.nc-container /bin/sh -x -c "$_cmd"
systemd-nspawn $SUSE_OPTS--register=no -D /testsuite-13.nc-container -U /bin/sh -x -c "$_cmd"