Compare commits
27 Commits
a4df0c004a
...
990307c3da
Author | SHA1 | Date |
---|---|---|
Zbigniew Jędrzejewski-Szmek | 990307c3da | |
Lennart Poettering | cbed1dc8af | |
Lennart Poettering | 5b14956385 | |
Lennart Poettering | c1093c34d7 | |
Lennart Poettering | 476cfe626d | |
Lennart Poettering | 4f55a5b0bf | |
Lennart Poettering | 625a164069 | |
Luca Boccassi | 7489ccc350 | |
Lennart Poettering | 037857507a | |
Lennart Poettering | 7b24e6e3fa | |
Lennart Poettering | 5d1e68b494 | |
Zbigniew Jędrzejewski-Szmek | ec673ad4ab | |
Zbigniew Jędrzejewski-Szmek | 0cd9ccb654 | |
Lennart Poettering | 3242980582 | |
Lennart Poettering | 00e64c6d06 | |
Lennart Poettering | 0f48ba7b84 | |
Lennart Poettering | 9fac502920 | |
Lennart Poettering | e96ceabac9 | |
Lennart Poettering | 5a27b39518 | |
Luca Boccassi | 46ad9c5378 | |
Luca Boccassi | 7b3eb5c97e | |
Benjamin Berg | 29bb3d7fc4 | |
Benjamin Berg | 56f47800d8 | |
Lennart Poettering | 8609bb80dd | |
Lennart Poettering | 5f10408044 | |
Lennart Poettering | 69b3fa14cd | |
Lennart Poettering | ffaf45e4f3 |
3
TODO
3
TODO
|
@ -19,9 +19,6 @@ 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)
|
||||
|
|
|
@ -25,6 +25,17 @@ 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
|
||||
|
|
|
@ -172,6 +172,13 @@ 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`
|
||||
|
@ -189,6 +196,62 @@ 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
|
||||
|
|
|
@ -2134,6 +2134,20 @@ 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" />
|
||||
|
||||
|
|
|
@ -261,53 +261,42 @@
|
|||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>MemoryMin=<replaceable>bytes</replaceable></varname></term>
|
||||
<term><varname>MemoryMin=<replaceable>bytes</replaceable></varname>, <varname>MemoryLow=<replaceable>bytes</replaceable></varname></term>
|
||||
|
||||
<listitem>
|
||||
<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>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>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> control group attribute. For details about this
|
||||
control group attribute, see <ulink
|
||||
This controls the <literal>memory.min</literal> or <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.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>
|
||||
<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>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
|
|
@ -1092,9 +1092,6 @@
|
|||
<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>
|
||||
|
||||
|
|
|
@ -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'
|
||||
--preset-mode -n --lines -o --output -M --machine --message --timestamp'
|
||||
)
|
||||
|
||||
if __contains_word "--user" ${COMP_WORDS[*]}; then
|
||||
|
@ -176,6 +176,9 @@ _systemctl () {
|
|||
--machine|-M)
|
||||
comps=$( __get_machines )
|
||||
;;
|
||||
--timestamp)
|
||||
comps='pretty us µs utc us+utc µs+utc'
|
||||
;;
|
||||
esac
|
||||
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
|
||||
return 0
|
||||
|
|
|
@ -431,6 +431,13 @@ 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).
|
||||
|
@ -471,4 +478,5 @@ _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'
|
||||
|
|
|
@ -8,84 +8,28 @@
|
|||
#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) {
|
||||
const char *p;
|
||||
assert(u);
|
||||
assert(line);
|
||||
|
||||
for (ConditionType t = 0; t < _CONDITION_TYPE_MAX; t++) {
|
||||
ConfigParserCallback callback;
|
||||
Condition **target;
|
||||
const char *p, *name;
|
||||
|
||||
if ((p = startswith(line, "Condition")))
|
||||
name = condition_type_to_string(t);
|
||||
p = startswith(line, name);
|
||||
if (p)
|
||||
target = &u->conditions;
|
||||
else if ((p = startswith(line, "Assert")))
|
||||
target = &u->asserts;
|
||||
else
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot parse \"%s\".", line);
|
||||
|
||||
for (size_t i = 0; i < ELEMENTSOF(condition_definitions); i++) {
|
||||
const condition_definition *c = &condition_definitions[i];
|
||||
|
||||
p = startswith(line, c->name);
|
||||
else {
|
||||
name = assert_type_to_string(t);
|
||||
p = startswith(line, name);
|
||||
if (!p)
|
||||
continue;
|
||||
|
||||
target = &u->asserts;
|
||||
}
|
||||
|
||||
p += strspn(p, WHITESPACE);
|
||||
|
||||
if (*p != '=')
|
||||
|
@ -94,7 +38,12 @@ static int parse_condition(Unit *u, const char *line) {
|
|||
|
||||
p += strspn(p, WHITESPACE);
|
||||
|
||||
return c->parser(NULL, "(stdin)", 0, NULL, 0, c->name, c->type, p, target, u);
|
||||
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 log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot parse \"%s\".", line);
|
||||
|
|
|
@ -8,38 +8,47 @@
|
|||
#include <linux/stat.h>
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
/* 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]; \
|
||||
}
|
||||
|
||||
#if !HAVE_STRUCT_STATX
|
||||
struct statx_timestamp {
|
||||
__s64 tv_sec;
|
||||
__u32 tv_nsec;
|
||||
__s32 __reserved;
|
||||
};
|
||||
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];
|
||||
};
|
||||
|
||||
struct statx STATX_DEFINITION;
|
||||
#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
|
||||
|
@ -49,3 +58,13 @@ struct statx {
|
|||
#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
|
||||
|
|
|
@ -482,7 +482,7 @@ static inline ssize_t missing_statx(int dfd, const char *filename, unsigned flag
|
|||
# endif
|
||||
}
|
||||
|
||||
# define statx missing_statx
|
||||
# define statx(dfd, filename, flags, mask, buffer) missing_statx(dfd, filename, flags, mask, buffer)
|
||||
#endif
|
||||
|
||||
#if !HAVE_SET_MEMPOLICY
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#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"
|
||||
|
@ -32,6 +34,8 @@ 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.
|
||||
|
@ -86,13 +90,16 @@ int name_to_handle_at_loop(
|
|||
}
|
||||
}
|
||||
|
||||
static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) {
|
||||
static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *ret_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 {
|
||||
|
@ -121,7 +128,7 @@ static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id
|
|||
p += strspn(p, WHITESPACE);
|
||||
p[strcspn(p, WHITESPACE)] = 0;
|
||||
|
||||
return safe_atoi(p, mnt_id);
|
||||
return safe_atoi(p, ret_mnt_id);
|
||||
}
|
||||
|
||||
int fd_is_mount_point(int fd, const char *filename, int flags) {
|
||||
|
@ -129,33 +136,46 @@ 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 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.
|
||||
/* First we will try statx()' STATX_ATTR_MOUNT_ROOT attribute, which is our ideal API, available
|
||||
* since kernel 5.8.
|
||||
*
|
||||
* 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 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
|
||||
* 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. */
|
||||
* 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);
|
||||
|
||||
r = name_to_handle_at_loop(fd, filename, &h, &mount_id, flags);
|
||||
if (IN_SET(r, -ENOSYS, -EACCES, -EPERM, -EOVERFLOW, -EINVAL))
|
||||
|
@ -278,8 +298,29 @@ 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);
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#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"
|
||||
|
@ -282,12 +283,11 @@ struct timeval *timeval_store(struct timeval *tv, usec_t u) {
|
|||
return tv;
|
||||
}
|
||||
|
||||
static char *format_timestamp_internal(
|
||||
char *format_timestamp_style(
|
||||
char *buf,
|
||||
size_t l,
|
||||
usec_t t,
|
||||
bool utc,
|
||||
bool us) {
|
||||
TimestampStyle style) {
|
||||
|
||||
/* 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,9 +304,27 @@ static char *format_timestamp_internal(
|
|||
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 */
|
||||
|
@ -380,22 +398,6 @@ static char *format_timestamp_internal(
|
|||
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;
|
||||
|
@ -1568,3 +1570,27 @@ 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;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,15 @@ 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)
|
||||
|
||||
|
@ -107,13 +116,14 @@ 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(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_style(char *buf, size_t l, usec_t t, TimestampStyle style);
|
||||
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);
|
||||
|
@ -185,3 +195,6 @@ 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_;
|
||||
|
|
|
@ -491,6 +491,16 @@ 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:
|
||||
|
|
|
@ -1974,14 +1974,11 @@ 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 (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);
|
||||
} else
|
||||
param = NULL;
|
||||
|
||||
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||
Condition *c;
|
||||
|
@ -1992,14 +1989,9 @@ static int bus_set_transient_conditions(
|
|||
|
||||
LIST_PREPEND(conditions, *list, c);
|
||||
|
||||
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;
|
||||
|
|
|
@ -272,46 +272,52 @@ 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.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.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.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.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.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.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.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.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)
|
||||
|
|
|
@ -2999,60 +2999,6 @@ 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,
|
||||
|
@ -5266,7 +5212,6 @@ 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" },
|
||||
|
|
|
@ -58,7 +58,6 @@ 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);
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#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"
|
||||
|
@ -53,6 +54,7 @@
|
|||
#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"
|
||||
|
@ -2073,6 +2075,20 @@ 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)
|
||||
|
|
|
@ -85,6 +85,8 @@ 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,
|
||||
|
@ -536,8 +538,17 @@ 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. */
|
||||
(void) make_inaccessible_nodes(NULL, UID_INVALID, GID_INVALID);
|
||||
* 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");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -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_utc(buf, l, t);
|
||||
return format_timestamp_style(buf, l, t, TIMESTAMP_UTC);
|
||||
|
||||
return format_timestamp(buf, l, t);
|
||||
}
|
||||
|
|
|
@ -544,9 +544,11 @@ 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);
|
||||
else {
|
||||
if (k < 0)
|
||||
k = -errno;
|
||||
} else {
|
||||
mh = (struct msghdr) {
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
|
@ -1187,9 +1189,11 @@ 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);
|
||||
else {
|
||||
if (k < 0)
|
||||
k = -errno;
|
||||
} else {
|
||||
mh = (struct msghdr) {
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
|
|
|
@ -7,9 +7,10 @@
|
|||
|
||||
#include "bus-error.h"
|
||||
#include "dev-setup.h"
|
||||
#include "fs-util.h"
|
||||
#include "format-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "label.h"
|
||||
#include "limits-util.h"
|
||||
#include "main-func.h"
|
||||
#include "mkdir.h"
|
||||
#include "mountpoint-util.h"
|
||||
|
@ -32,12 +33,16 @@ 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)
|
||||
return log_error_errno(r, "Failed to acquire runtime directory size: %s", bus_error_message(&error, r));
|
||||
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% */
|
||||
}
|
||||
|
||||
r = sd_bus_get_property_trivial(bus, "org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "RuntimeDirectoryInodesMax", &error, 't', inodes);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to acquire number of inodes for runtime directory: %s", bus_error_message(&error, r));
|
||||
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);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -83,7 +88,8 @@ 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);
|
||||
|
@ -98,8 +104,6 @@ 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:
|
||||
|
|
|
@ -978,9 +978,8 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
|
|||
goto finish;
|
||||
}
|
||||
if (r == 0) {
|
||||
const char *mount_inside;
|
||||
const char *mount_inside, *q;
|
||||
int mntfd;
|
||||
const char *q;
|
||||
|
||||
errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
|
||||
|
||||
|
@ -1001,12 +1000,11 @@ 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);
|
||||
safe_close(open(dest, O_CREAT|O_EXCL|O_WRONLY|O_CLOEXEC|O_NOCTTY, 0600));
|
||||
(void) mknod(dest, S_IFREG|0600, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Fifth, move the mount to the right place inside */
|
||||
mount_inside = strjoina("/run/systemd/nspawn/incoming/", basename(mount_outside));
|
||||
mount_inside = strjoina("/run/host/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;
|
||||
|
|
|
@ -101,10 +101,8 @@
|
|||
#include "user-util.h"
|
||||
#include "util.h"
|
||||
|
||||
/* 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"
|
||||
/* 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"
|
||||
|
||||
#define EXIT_FORCE_RESTART 133
|
||||
|
||||
|
@ -2517,19 +2515,15 @@ 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/systemd", 0755, 0, 0);
|
||||
r = userns_mkdir(root, "/run/host", 0755, 0, 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create /run/systemd: %m");
|
||||
return log_error_errno(r, "Failed to create /run/host: %m");
|
||||
|
||||
r = userns_mkdir(root, "/run/systemd/nspawn", 0755, 0, 0);
|
||||
r = userns_mkdir(root, "/run/host/incoming", 0600, 0, 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create /run/systemd/nspawn: %m");
|
||||
return log_error_errno(r, "Failed to create /run/host/incoming: %m");
|
||||
|
||||
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");
|
||||
q = prefix_roota(root, "/run/host/incoming");
|
||||
r = mount_verbose(LOG_ERR, p, q, NULL, MS_BIND, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -2538,8 +2532,7 @@ 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);
|
||||
}
|
||||
|
||||
|
@ -3278,7 +3271,7 @@ static int inner_child(
|
|||
return log_error_errno(errno, "execv(%s) failed: %m", exec_target);
|
||||
}
|
||||
|
||||
static int setup_sd_notify_child(void) {
|
||||
static int setup_notify_child(void) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
union sockaddr_union sa = {
|
||||
.un.sun_family = AF_UNIX,
|
||||
|
@ -3530,7 +3523,7 @@ static int outer_child(
|
|||
|
||||
(void) dev_setup(directory, arg_uid_shift, arg_uid_shift);
|
||||
|
||||
p = prefix_roota(directory, "/run");
|
||||
p = prefix_roota(directory, "/run/host");
|
||||
(void) make_inaccessible_nodes(p, arg_uid_shift, arg_uid_shift);
|
||||
|
||||
r = setup_pts(directory);
|
||||
|
@ -3571,6 +3564,14 @@ 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,
|
||||
|
@ -3588,7 +3589,7 @@ static int outer_child(
|
|||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to move root directory: %m");
|
||||
|
||||
fd = setup_sd_notify_child();
|
||||
fd = setup_notify_child();
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
|
@ -3801,7 +3802,7 @@ static int nspawn_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t r
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int setup_sd_notify_parent(sd_event *event, int fd, pid_t *inner_child_pid, sd_event_source **notify_event_source) {
|
||||
static int setup_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);
|
||||
|
@ -4632,7 +4633,7 @@ static int run_container(
|
|||
return log_error_errno(r, "Failed to attach bus to event loop: %m");
|
||||
}
|
||||
|
||||
r = setup_sd_notify_parent(event, notify_socket, PID_TO_PTR(*pid), ¬ify_event_source);
|
||||
r = setup_notify_parent(event, notify_socket, PID_TO_PTR(*pid), ¬ify_event_source);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ Condition* condition_new(ConditionType type, const char *parameter, bool trigger
|
|||
|
||||
assert(type >= 0);
|
||||
assert(type < _CONDITION_TYPE_MAX);
|
||||
assert((!parameter) == (type == CONDITION_NULL));
|
||||
assert(parameter);
|
||||
|
||||
c = new(Condition, 1);
|
||||
if (!c)
|
||||
|
@ -776,15 +776,6 @@ 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) = {
|
||||
|
@ -811,7 +802,6 @@ 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,
|
||||
|
@ -859,23 +849,20 @@ 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 ? "!" : "",
|
||||
p);
|
||||
c->parameter);
|
||||
else
|
||||
logger(userdata, LOG_DEBUG, 0, PROJECT_FILE, __LINE__, __func__,
|
||||
"%s=%s%s%s %s.",
|
||||
to_string(c->type),
|
||||
c->trigger ? "|" : "",
|
||||
c->negate ? "!" : "",
|
||||
p,
|
||||
c->parameter,
|
||||
condition_result_to_string(c->result));
|
||||
}
|
||||
|
||||
|
@ -937,7 +924,6 @@ 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",
|
||||
|
@ -969,7 +955,6 @@ 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",
|
||||
|
|
|
@ -34,8 +34,6 @@ typedef enum ConditionType {
|
|||
CONDITION_FILE_NOT_EMPTY,
|
||||
CONDITION_FILE_IS_EXECUTABLE,
|
||||
|
||||
CONDITION_NULL,
|
||||
|
||||
CONDITION_USER,
|
||||
CONDITION_GROUP,
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ int dev_setup(const char *prefix, uid_t uid, gid_t gid) {
|
|||
}
|
||||
|
||||
int make_inaccessible_nodes(
|
||||
const char *runtime_dir,
|
||||
const char *parent_dir,
|
||||
uid_t uid,
|
||||
gid_t gid) {
|
||||
|
||||
|
@ -65,28 +65,26 @@ int make_inaccessible_nodes(
|
|||
const char *name;
|
||||
mode_t mode;
|
||||
} table[] = {
|
||||
{ "/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 },
|
||||
{ "inaccessible", S_IFDIR | 0755 },
|
||||
{ "inaccessible/reg", S_IFREG | 0000 },
|
||||
{ "inaccessible/dir", S_IFDIR | 0000 },
|
||||
{ "inaccessible/fifo", S_IFIFO | 0000 },
|
||||
{ "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. */
|
||||
{ "/systemd/inaccessible/chr", S_IFCHR | 0000 },
|
||||
{ "/systemd/inaccessible/blk", S_IFBLK | 0000 },
|
||||
{ "inaccessible/chr", S_IFCHR | 0000 },
|
||||
{ "inaccessible/blk", S_IFBLK | 0000 },
|
||||
};
|
||||
|
||||
_cleanup_umask_ mode_t u;
|
||||
size_t i;
|
||||
int r;
|
||||
|
||||
if (!runtime_dir)
|
||||
runtime_dir = "/run";
|
||||
if (!parent_dir)
|
||||
parent_dir = "/run/systemd";
|
||||
|
||||
u = umask(0000);
|
||||
|
||||
|
@ -95,10 +93,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 (i = 0; i < ELEMENTSOF(table); i++) {
|
||||
for (size_t i = 0; i < ELEMENTSOF(table); i++) {
|
||||
_cleanup_free_ char *path = NULL;
|
||||
|
||||
path = path_join(runtime_dir, table[i].name);
|
||||
path = path_join(parent_dir, table[i].name);
|
||||
if (!path)
|
||||
return log_oom();
|
||||
|
||||
|
@ -107,7 +105,6 @@ int make_inaccessible_nodes(
|
|||
else
|
||||
r = mknod_label(path, table[i].mode, makedev(0, 0));
|
||||
if (r < 0) {
|
||||
if (r != -EEXIST)
|
||||
log_debug_errno(r, "Failed to create '%s', ignoring: %m", path);
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -5,4 +5,4 @@
|
|||
|
||||
int dev_setup(const char *prefix, uid_t uid, gid_t gid);
|
||||
|
||||
int make_inaccessible_nodes(const char *root, uid_t uid, gid_t gid);
|
||||
int make_inaccessible_nodes(const char *parent_dir, uid_t uid, gid_t gid);
|
||||
|
|
|
@ -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_utc(p, FORMAT_TIMESTAMP_MAX, d->timestamp);
|
||||
ret = format_timestamp_style(p, FORMAT_TIMESTAMP_MAX, d->timestamp, TIMESTAMP_UTC);
|
||||
else
|
||||
ret = format_timestamp_relative(p, FORMAT_TIMESTAMP_MAX, d->timestamp);
|
||||
if (!ret)
|
||||
|
|
|
@ -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_utc(buf, sizeof(buf), x);
|
||||
k = format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_UTC);
|
||||
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 = flags & OUTPUT_UTC ? format_timestamp_us_utc(ts, sizeof ts, realtime)
|
||||
: format_timestamp_us(ts, sizeof ts, realtime);
|
||||
timestamp = format_timestamp_style(ts, sizeof ts, realtime,
|
||||
flags & OUTPUT_UTC ? TIMESTAMP_US_UTC : TIMESTAMP_US);
|
||||
fprintf(f, "%s [%s]\n",
|
||||
timestamp ?: "(no timestamp)",
|
||||
cursor);
|
||||
|
|
|
@ -414,7 +414,6 @@ int mode_to_inaccessible_node(
|
|||
|
||||
_cleanup_free_ char *d = NULL;
|
||||
const char *node = NULL;
|
||||
bool fallback = false;
|
||||
|
||||
assert(ret);
|
||||
|
||||
|
@ -432,12 +431,10 @@ 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:
|
||||
|
@ -455,7 +452,24 @@ int mode_to_inaccessible_node(
|
|||
if (!d)
|
||||
return -ENOMEM;
|
||||
|
||||
if (fallback && access(d, F_OK) < 0) {
|
||||
/* 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) {
|
||||
free(d);
|
||||
d = path_join(runtime_dir, "/systemd/inaccessible/sock");
|
||||
if (!d)
|
||||
|
|
|
@ -170,6 +170,7 @@ 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;
|
||||
|
@ -4195,7 +4196,7 @@ static void print_status_info(
|
|||
i->active_exit_timestamp;
|
||||
|
||||
s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
|
||||
s2 = format_timestamp(since2, sizeof(since2), timestamp);
|
||||
s2 = format_timestamp_style(since2, sizeof(since2), timestamp, arg_timestamp_style);
|
||||
|
||||
if (s1)
|
||||
printf(" since %s; %s\n", s2, s1);
|
||||
|
@ -4229,7 +4230,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(tstamp2, sizeof tstamp2, next_elapse);
|
||||
next_time = format_timestamp_style(tstamp2, sizeof tstamp2, next_elapse, arg_timestamp_style);
|
||||
|
||||
if (next_time && next_rel_time)
|
||||
printf("%s; %s\n", next_time, next_rel_time);
|
||||
|
@ -4254,7 +4255,7 @@ static void print_status_info(
|
|||
int n = 0;
|
||||
|
||||
s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
|
||||
s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
|
||||
s2 = format_timestamp_style(since2, sizeof(since2), i->condition_timestamp, arg_timestamp_style);
|
||||
|
||||
printf(" Condition: start %scondition failed%s at %s%s%s\n",
|
||||
ansi_highlight_yellow(), ansi_normal(),
|
||||
|
@ -4276,7 +4277,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(since2, sizeof(since2), i->assert_timestamp);
|
||||
s2 = format_timestamp_style(since2, sizeof(since2), i->assert_timestamp, arg_timestamp_style);
|
||||
|
||||
printf(" Assert: start %sassertion failed%s at %s%s%s\n",
|
||||
ansi_highlight_red(), ansi_normal(),
|
||||
|
@ -5037,7 +5038,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(timestamp, sizeof(timestamp), next_elapse);
|
||||
(void) format_timestamp_style(timestamp, sizeof(timestamp), next_elapse, arg_timestamp_style);
|
||||
bus_print_property_valuef(name, expected_value, value,
|
||||
"{ %s=%s ; next_elapse=%s }", base, spec, timestamp);
|
||||
}
|
||||
|
@ -5077,8 +5078,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(timestamp1, sizeof(timestamp1), info.start_timestamp)),
|
||||
strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
|
||||
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)),
|
||||
info.pid,
|
||||
sigchld_code_to_string(info.code),
|
||||
info.status,
|
||||
|
@ -5090,8 +5091,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(timestamp1, sizeof(timestamp1), info.start_timestamp)),
|
||||
strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
|
||||
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)),
|
||||
info.pid,
|
||||
sigchld_code_to_string(info.code),
|
||||
info.status,
|
||||
|
@ -5754,7 +5755,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(since2, sizeof(since2), mi.timestamp),
|
||||
format_timestamp_style(since2, sizeof(since2), mi.timestamp, arg_timestamp_style),
|
||||
format_timestamp_relative(since1, sizeof(since1), mi.timestamp));
|
||||
|
||||
printf(" CGroup: %s\n", mi.control_group ?: "/");
|
||||
|
@ -7804,6 +7805,11 @@ 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
|
||||
|
@ -8052,6 +8058,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
|
|||
ARG_WAIT,
|
||||
ARG_WHAT,
|
||||
ARG_REBOOT_ARG,
|
||||
ARG_TIMESTAMP_STYLE,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
|
@ -8106,6 +8113,7 @@ 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 },
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -8505,6 +8513,19 @@ 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);
|
||||
|
@ -9130,7 +9151,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(date, sizeof(date), arg_when));
|
||||
log_info("%s scheduled for %s, use 'shutdown -c' to cancel.", log_action, format_timestamp_style(date, sizeof(date), arg_when, arg_timestamp_style));
|
||||
return 0;
|
||||
#else
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
|
||||
|
|
|
@ -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_us(buf, sizeof buf, u));
|
||||
printf("At: %s\n", r < 0 ? strerror_safe(r) : format_timestamp_style(buf, sizeof buf, u, TIMESTAMP_US));
|
||||
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_us(buf, sizeof(buf), x));
|
||||
assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US));
|
||||
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_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);
|
||||
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);
|
||||
|
||||
assert_se((r = calendar_spec_next_usec(c, u, &w)) >= 0);
|
||||
printf("Next hourly: %s (%"PRIu64")\n", r < 0 ? strerror_safe(r) : format_timestamp_us(zaf, sizeof zaf, w), w);
|
||||
printf("Next hourly: %s (%"PRIu64")\n", r < 0 ? strerror_safe(r) : format_timestamp_style(zaf, sizeof zaf, w, TIMESTAMP_US), w);
|
||||
|
||||
assert_se(n < u);
|
||||
assert_se(u <= n + USEC_PER_HOUR);
|
||||
|
|
|
@ -438,20 +438,6 @@ 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;
|
||||
|
||||
|
@ -868,7 +854,6 @@ 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();
|
||||
|
|
|
@ -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_us(buf, sizeof(buf), t));
|
||||
assert_se(format_timestamp_style(buf, sizeof(buf), t, TIMESTAMP_US));
|
||||
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_us(tmp, sizeof(tmp), q));
|
||||
buf, format_timestamp_style(tmp, sizeof(tmp), q, TIMESTAMP_US));
|
||||
}
|
||||
assert_se(q == t);
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#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"
|
||||
|
@ -17,8 +18,8 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
assert_se(mkdtemp_malloc("/tmp/test-dev-setupXXXXXX", &p) >= 0);
|
||||
|
||||
f = prefix_roota(p, "/run");
|
||||
assert_se(mkdir(f, 0755) >= 0);
|
||||
f = prefix_roota(p, "/run/systemd");
|
||||
assert_se(mkdir_p(f, 0755) >= 0);
|
||||
|
||||
assert_se(make_inaccessible_nodes(f, 1, 1) >= 0);
|
||||
|
||||
|
|
|
@ -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_utc(buf, sizeof(buf), x));
|
||||
assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_UTC));
|
||||
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_us(buf, sizeof(buf), x));
|
||||
assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US));
|
||||
log_info("%s", buf);
|
||||
assert_se(parse_timestamp(buf, &y) >= 0);
|
||||
assert_se(x == y);
|
||||
|
||||
assert_se(format_timestamp_us_utc(buf, sizeof(buf), x));
|
||||
assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US_UTC));
|
||||
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_utc(buf, sizeof(buf), val);
|
||||
t = format_timestamp_style(buf, sizeof(buf), val, TIMESTAMP_UTC);
|
||||
assert_se(streq_ptr(t, result));
|
||||
}
|
||||
|
||||
|
|
|
@ -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_us_utc(buf, sizeof(buf), t);
|
||||
ts = format_timestamp_style(buf, sizeof(buf), t, TIMESTAMP_US_UTC);
|
||||
if (!ts)
|
||||
strcpy(buf, "unrepresentable");
|
||||
log_info("adjtime state %d status %x time %s", sp->adjtime_state, tx.status, ts);
|
||||
|
|
|
@ -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_us(a, sizeof(a), age));
|
||||
format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
|
||||
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_us(a, sizeof(a), age));
|
||||
format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
|
||||
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_us(a, sizeof(a), age));
|
||||
format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
|
||||
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_us(a, sizeof(a), age));
|
||||
format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
|
||||
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_us(a, sizeof(a), age));
|
||||
format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -713,8 +713,8 @@ finish:
|
|||
|
||||
log_debug("Restoring access and modification time on \"%s\": %s, %s",
|
||||
p,
|
||||
format_timestamp_us(a, sizeof(a), age1),
|
||||
format_timestamp_us(b, sizeof(b), age2));
|
||||
format_timestamp_style(a, sizeof(a), age1, TIMESTAMP_US),
|
||||
format_timestamp_style(b, sizeof(b), age2, TIMESTAMP_US));
|
||||
|
||||
/* 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_us(timestamp, sizeof(timestamp), cutoff));
|
||||
format_timestamp_style(timestamp, sizeof(timestamp), cutoff, TIMESTAMP_US));
|
||||
|
||||
return dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
|
||||
MAX_DEPTH, i->keep_first_level);
|
||||
|
|
|
@ -15,9 +15,6 @@ 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=
|
||||
|
|
|
@ -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/systemd/nspawn/notify'
|
||||
local _cmd='echo a | $(busybox which nc) -U -u -w 1 /run/host/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"
|
||||
|
|
Loading…
Reference in New Issue