Compare commits
No commits in common. "990307c3da61b16c57d958910295b96ea6aa2a5e" and "a4df0c004a0e42dfbad02e9595420fcef3965b85" have entirely different histories.
990307c3da
...
a4df0c004a
3
TODO
3
TODO
|
@ -19,6 +19,9 @@ Features:
|
||||||
|
|
||||||
* nss-systemd: also synthesize shadow records for users/groups
|
* 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"
|
* nspawn: move "incoming mount" directory to /run/host, move "inaccessible"
|
||||||
nodes to /run/host, move notify socket (for sd_notify() between payload and
|
nodes to /run/host, move notify socket (for sd_notify() between payload and
|
||||||
container manager)
|
container manager)
|
||||||
|
|
|
@ -25,17 +25,6 @@ layout: default
|
||||||
note that emacs loads `.dir-locals.el` automatically, but vim needs to be
|
note that emacs loads `.dir-locals.el` automatically, but vim needs to be
|
||||||
configured to load `.vimrc`, see that file for instructions.
|
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:
|
- Try to write this:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
|
|
|
@ -172,13 +172,6 @@ manager, please consider supporting the following interfaces.
|
||||||
unit they created for their container. That's private property of systemd,
|
unit they created for their container. That's private property of systemd,
|
||||||
and no other code should modify it.
|
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
|
## Networking
|
||||||
|
|
||||||
1. Inside of a container, if a `veth` link is named `host0`, `systemd-networkd`
|
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
|
devices, for example hashed out of the container names. That way it is more
|
||||||
likely that DHCP and IPv4LL will acquire stable addresses.
|
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
|
## What You Shouldn't Do
|
||||||
|
|
||||||
1. Do not drop `CAP_MKNOD` from the container. `PrivateDevices=` is a commonly
|
1. Do not drop `CAP_MKNOD` from the container. `PrivateDevices=` is a commonly
|
||||||
|
|
|
@ -2134,20 +2134,6 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</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="host" />
|
||||||
<xi:include href="user-system-options.xml" xpointer="machine" />
|
<xi:include href="user-system-options.xml" xpointer="machine" />
|
||||||
|
|
||||||
|
|
|
@ -261,42 +261,53 @@
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<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>
|
<listitem>
|
||||||
<para>Specify the memory usage protection of the executed processes in this unit.
|
<para>Specify the memory usage protection of the executed processes in this unit. If the memory usages of
|
||||||
When reclaiming memory, the unit is treated as if it was using less memory resulting in memory
|
this unit and all its ancestors are below their minimum boundaries, this unit's memory won't be reclaimed.</para>
|
||||||
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
|
<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
|
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
|
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
|
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.
|
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.
|
This controls the <literal>memory.min</literal> control group attribute. For details about this
|
||||||
For details about this control group attribute, see <ulink
|
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>
|
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
|
<para>This setting is supported only if the unified control group hierarchy is used and disables
|
||||||
<varname>MemoryLimit=</varname>.</para>
|
<varname>MemoryLimit=</varname>.</para>
|
||||||
|
|
||||||
<para>Units may have their children use a default <literal>memory.min</literal> or
|
<para>Units may have their children use a default <literal>memory.min</literal> value by specifying
|
||||||
<literal>memory.low</literal> value by specifying <varname>DefaultMemoryMin=</varname> or
|
<varname>DefaultMemoryMin=</varname>, which has the same semantics as <varname>MemoryMin=</varname>. This setting
|
||||||
<varname>DefaultMemoryLow=</varname>, which has the same semantics as
|
does not affect <literal>memory.min</literal> in the unit itself.</para>
|
||||||
<varname>MemoryMin=</varname> and <varname>MemoryLow=</varname>.
|
</listitem>
|
||||||
This setting does not affect <literal>memory.min</literal> or <literal>memory.low</literal>
|
</varlistentry>
|
||||||
in the unit itself.
|
|
||||||
Using it to set a default child allocation is only useful on kernels older than 5.7,
|
<varlistentry>
|
||||||
which do not support the <literal>memory_recursiveprot</literal> cgroup2 mount option.</para>
|
<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>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
|
@ -1092,6 +1092,9 @@
|
||||||
<para>Except for <varname>ConditionPathIsSymbolicLink=</varname>, all path checks follow symlinks.</para>
|
<para>Except for <varname>ConditionPathIsSymbolicLink=</varname>, all path checks follow symlinks.</para>
|
||||||
|
|
||||||
<variablelist class='unit-directives'>
|
<variablelist class='unit-directives'>
|
||||||
|
<!-- We do not document ConditionNull= here, as it is not particularly useful and probably just
|
||||||
|
confusing. -->
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><varname>ConditionArchitecture=</varname></term>
|
<term><varname>ConditionArchitecture=</varname></term>
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,7 @@ _systemctl () {
|
||||||
--quiet -q --system --user --version --runtime --recursive -r --firmware-setup
|
--quiet -q --system --user --version --runtime --recursive -r --firmware-setup
|
||||||
--show-types -i --ignore-inhibitors --plain --failed --value --fail --dry-run --wait'
|
--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
|
[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
|
if __contains_word "--user" ${COMP_WORDS[*]}; then
|
||||||
|
@ -176,9 +176,6 @@ _systemctl () {
|
||||||
--machine|-M)
|
--machine|-M)
|
||||||
comps=$( __get_machines )
|
comps=$( __get_machines )
|
||||||
;;
|
;;
|
||||||
--timestamp)
|
|
||||||
comps='pretty us µs utc us+utc µs+utc'
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
|
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
|
||||||
return 0
|
return 0
|
||||||
|
|
|
@ -431,13 +431,6 @@ done
|
||||||
_values -s , "${_modes[@]}"
|
_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.
|
# Build arguments for "systemctl" to be used in completion.
|
||||||
local -a _modes; _modes=("--user" "--system")
|
local -a _modes; _modes=("--user" "--system")
|
||||||
# Use the last mode (they are exclusive and the last one is used).
|
# 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]' \
|
'--firmware-setup[Tell the firmware to show the setup menu on next boot]' \
|
||||||
'--plain[When used with list-dependencies, print output as a list]' \
|
'--plain[When used with list-dependencies, print output as a list]' \
|
||||||
'--failed[Show failed units]' \
|
'--failed[Show failed units]' \
|
||||||
'--timestamp=[Change format of printed timestamps]:style:_systemctl_timestamp' \
|
|
||||||
'*::systemctl command:_systemctl_commands'
|
'*::systemctl command:_systemctl_commands'
|
||||||
|
|
|
@ -8,28 +8,84 @@
|
||||||
#include "load-fragment.h"
|
#include "load-fragment.h"
|
||||||
#include "service.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) {
|
static int parse_condition(Unit *u, const char *line) {
|
||||||
assert(u);
|
const char *p;
|
||||||
assert(line);
|
|
||||||
|
|
||||||
for (ConditionType t = 0; t < _CONDITION_TYPE_MAX; t++) {
|
|
||||||
ConfigParserCallback callback;
|
|
||||||
Condition **target;
|
Condition **target;
|
||||||
const char *p, *name;
|
|
||||||
|
|
||||||
name = condition_type_to_string(t);
|
if ((p = startswith(line, "Condition")))
|
||||||
p = startswith(line, name);
|
|
||||||
if (p)
|
|
||||||
target = &u->conditions;
|
target = &u->conditions;
|
||||||
else {
|
else if ((p = startswith(line, "Assert")))
|
||||||
name = assert_type_to_string(t);
|
target = &u->asserts;
|
||||||
p = startswith(line, name);
|
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);
|
||||||
if (!p)
|
if (!p)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
target = &u->asserts;
|
|
||||||
}
|
|
||||||
|
|
||||||
p += strspn(p, WHITESPACE);
|
p += strspn(p, WHITESPACE);
|
||||||
|
|
||||||
if (*p != '=')
|
if (*p != '=')
|
||||||
|
@ -38,12 +94,7 @@ static int parse_condition(Unit *u, const char *line) {
|
||||||
|
|
||||||
p += strspn(p, WHITESPACE);
|
p += strspn(p, WHITESPACE);
|
||||||
|
|
||||||
if (condition_takes_path(t))
|
return c->parser(NULL, "(stdin)", 0, NULL, 0, c->name, c->type, p, target, u);
|
||||||
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);
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot parse \"%s\".", line);
|
||||||
|
|
|
@ -8,47 +8,38 @@
|
||||||
#include <linux/stat.h>
|
#include <linux/stat.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Thew newest definition we are aware of (fa2fcf4f1df1559a0a4ee0f46915b496cc2ebf60; 5.8) */
|
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||||
#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
|
#if !HAVE_STRUCT_STATX
|
||||||
struct statx_timestamp {
|
struct statx_timestamp {
|
||||||
__s64 tv_sec;
|
__s64 tv_sec;
|
||||||
__u32 tv_nsec;
|
__u32 tv_nsec;
|
||||||
__s32 __reserved;
|
__s32 __reserved;
|
||||||
};
|
};
|
||||||
|
struct statx {
|
||||||
struct statx 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 __spare2[14];
|
||||||
|
};
|
||||||
#endif
|
#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) */
|
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||||
#ifndef STATX_BTIME
|
#ifndef STATX_BTIME
|
||||||
#define STATX_BTIME 0x00000800U
|
#define STATX_BTIME 0x00000800U
|
||||||
|
@ -58,13 +49,3 @@ struct new_statx STATX_DEFINITION;
|
||||||
#ifndef AT_STATX_DONT_SYNC
|
#ifndef AT_STATX_DONT_SYNC
|
||||||
#define AT_STATX_DONT_SYNC 0x4000
|
#define AT_STATX_DONT_SYNC 0x4000
|
||||||
#endif
|
#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
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
# define statx(dfd, filename, flags, mask, buffer) missing_statx(dfd, filename, flags, mask, buffer)
|
# define statx missing_statx
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !HAVE_SET_MEMPOLICY
|
#if !HAVE_SET_MEMPOLICY
|
||||||
|
|
|
@ -8,8 +8,6 @@
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
#include "missing_stat.h"
|
|
||||||
#include "missing_syscall.h"
|
|
||||||
#include "mountpoint-util.h"
|
#include "mountpoint-util.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
|
@ -34,8 +32,6 @@ int name_to_handle_at_loop(
|
||||||
_cleanup_free_ struct file_handle *h = NULL;
|
_cleanup_free_ struct file_handle *h = NULL;
|
||||||
size_t n = ORIGINAL_MAX_HANDLE_SZ;
|
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
|
/* 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
|
* 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.
|
* 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)];
|
char path[STRLEN("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
|
||||||
_cleanup_free_ char *fdinfo = NULL;
|
_cleanup_free_ char *fdinfo = NULL;
|
||||||
_cleanup_close_ int subfd = -1;
|
_cleanup_close_ int subfd = -1;
|
||||||
char *p;
|
char *p;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(ret_mnt_id);
|
|
||||||
assert((flags & ~(AT_SYMLINK_FOLLOW|AT_EMPTY_PATH)) == 0);
|
|
||||||
|
|
||||||
if ((flags & AT_EMPTY_PATH) && isempty(filename))
|
if ((flags & AT_EMPTY_PATH) && isempty(filename))
|
||||||
xsprintf(path, "/proc/self/fdinfo/%i", fd);
|
xsprintf(path, "/proc/self/fdinfo/%i", fd);
|
||||||
else {
|
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 += strspn(p, WHITESPACE);
|
||||||
p[strcspn(p, WHITESPACE)] = 0;
|
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) {
|
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;
|
int mount_id = -1, mount_id_parent = -1;
|
||||||
bool nosupp = false, check_st_dev = true;
|
bool nosupp = false, check_st_dev = true;
|
||||||
struct stat a, b;
|
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;
|
int r;
|
||||||
|
|
||||||
assert(fd >= 0);
|
assert(fd >= 0);
|
||||||
assert(filename);
|
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
|
/* First we will try the name_to_handle_at() syscall, which
|
||||||
* since kernel 5.8.
|
* 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
|
* If that didn't work we will try to read the mount id from
|
||||||
* an opaque file "handle". It is not supported everywhere though (kernel compile-time option, not
|
* /proc/self/fdinfo/<fd>. This is almost as good as
|
||||||
* all file systems are hooked up). If it works the mount id is usually good enough to tell us
|
* name_to_handle_at(), however, does not return the
|
||||||
* whether something is a mount point.
|
* opaque file handle. The opaque file handle is pretty useful
|
||||||
*
|
* to detect the root directory, which we should always
|
||||||
* If that didn't work we will try to read the mount id from /proc/self/fdinfo/<fd>. This is almost
|
* consider a mount point. Hence we use this only as
|
||||||
* as good as name_to_handle_at(), however, does not return the opaque file handle. The opaque file
|
* fallback. Exporting the mnt_id in fdinfo is a pretty recent
|
||||||
* 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.
|
* kernel addition.
|
||||||
*
|
*
|
||||||
* As last fallback we do traditional fstat() based st_dev comparisons. This is how things were
|
* As last fallback we do traditional fstat() based st_dev
|
||||||
* traditionally done, but unionfs breaks this since it exposes file systems with a variety of st_dev
|
* comparisons. This is how things were traditionally done,
|
||||||
* reported. Also, btrfs subvolumes have different st_dev, even though they aren't real mounts of
|
* but unionfs breaks this since it exposes file
|
||||||
* their own. */
|
* systems with a variety of st_dev reported. Also, btrfs
|
||||||
|
* subvolumes have different st_dev, even though they aren't
|
||||||
if (statx(fd, filename, (FLAGS_SET(flags, AT_SYMLINK_FOLLOW) ? 0 : AT_SYMLINK_NOFOLLOW) |
|
* real mounts of their own. */
|
||||||
(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);
|
r = name_to_handle_at_loop(fd, filename, &h, &mount_id, flags);
|
||||||
if (IN_SET(r, -ENOSYS, -EACCES, -EPERM, -EOVERFLOW, -EINVAL))
|
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) {
|
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;
|
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);
|
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 */
|
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);
|
return fd_fdinfo_mnt_id(AT_FDCWD, path, 0, ret);
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
#include "process-util.h"
|
#include "process-util.h"
|
||||||
#include "stat-util.h"
|
#include "stat-util.h"
|
||||||
#include "string-table.h"
|
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
#include "time-util.h"
|
#include "time-util.h"
|
||||||
|
@ -283,11 +282,12 @@ struct timeval *timeval_store(struct timeval *tv, usec_t u) {
|
||||||
return tv;
|
return tv;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *format_timestamp_style(
|
static char *format_timestamp_internal(
|
||||||
char *buf,
|
char *buf,
|
||||||
size_t l,
|
size_t l,
|
||||||
usec_t t,
|
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
|
/* 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. */
|
* generated timestamps may be parsed with parse_timestamp(), and always read the same. */
|
||||||
|
@ -304,27 +304,9 @@ char *format_timestamp_style(
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
time_t sec;
|
time_t sec;
|
||||||
size_t n;
|
size_t n;
|
||||||
bool utc = false, us = false;
|
|
||||||
|
|
||||||
assert(buf);
|
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 */
|
if (l < (size_t) (3 + /* week day */
|
||||||
1 + 10 + /* space and date */
|
1 + 10 + /* space and date */
|
||||||
1 + 8 + /* space and time */
|
1 + 8 + /* space and time */
|
||||||
|
@ -398,6 +380,22 @@ char *format_timestamp_style(
|
||||||
return buf;
|
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) {
|
char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
|
||||||
const char *s;
|
const char *s;
|
||||||
usec_t n, d;
|
usec_t n, d;
|
||||||
|
@ -1570,27 +1568,3 @@ int time_change_fd(void) {
|
||||||
|
|
||||||
return -errno;
|
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,15 +29,6 @@ typedef struct triple_timestamp {
|
||||||
usec_t boottime;
|
usec_t boottime;
|
||||||
} triple_timestamp;
|
} 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 USEC_INFINITY ((usec_t) UINT64_MAX)
|
||||||
#define NSEC_INFINITY ((nsec_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_;
|
usec_t timeval_load(const struct timeval *tv) _pure_;
|
||||||
struct timeval *timeval_store(struct timeval *tv, usec_t u);
|
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_timestamp_relative(char *buf, size_t l, usec_t t);
|
||||||
char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy);
|
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_timestamp(const char *t, usec_t *usec);
|
||||||
|
|
||||||
int parse_sec(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
|
#endif
|
||||||
|
|
||||||
int time_change_fd(void);
|
int time_change_fd(void);
|
||||||
|
|
||||||
const char* timestamp_style_to_string(TimestampStyle t) _const_;
|
|
||||||
TimestampStyle timestamp_style_from_string(const char *s) _pure_;
|
|
||||||
|
|
|
@ -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 (getpid_cached() == 1) {
|
||||||
/* If we are PID 1 we can just check our own environment variable, and that's authoritative.
|
/* If we are PID 1 we can just check our own environment variable, and that's authoritative.
|
||||||
* We distinguish three cases:
|
* We distinguish three cases:
|
||||||
|
|
|
@ -1974,11 +1974,14 @@ static int bus_set_transient_conditions(
|
||||||
if (t < 0)
|
if (t < 0)
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid condition type: %s", type_name);
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid condition type: %s", type_name);
|
||||||
|
|
||||||
|
if (t != CONDITION_NULL) {
|
||||||
if (isempty(param))
|
if (isempty(param))
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Condition parameter in %s is empty", type_name);
|
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))
|
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);
|
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)) {
|
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||||
Condition *c;
|
Condition *c;
|
||||||
|
@ -1989,9 +1992,14 @@ static int bus_set_transient_conditions(
|
||||||
|
|
||||||
LIST_PREPEND(conditions, *list, c);
|
LIST_PREPEND(conditions, *list, c);
|
||||||
|
|
||||||
|
if (t != CONDITION_NULL)
|
||||||
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name,
|
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name,
|
||||||
"%s=%s%s%s", type_name,
|
"%s=%s%s%s", type_name,
|
||||||
trigger ? "|" : "", negate ? "!" : "", param);
|
trigger ? "|" : "", negate ? "!" : "", param);
|
||||||
|
else
|
||||||
|
unit_write_settingf(u, flags, name,
|
||||||
|
"%s=%s%s", type_name,
|
||||||
|
trigger ? "|" : "", yes_no(!negate));
|
||||||
}
|
}
|
||||||
|
|
||||||
empty = false;
|
empty = false;
|
||||||
|
|
|
@ -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.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.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.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.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.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.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.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.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.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.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.ConditionSecurity, config_parse_unit_condition_string, CONDITION_SECURITY, offsetof(Unit, conditions)
|
||||||
Unit.ConditionCapability, config_parse_unit_condition_string, CONDITION_CAPABILITY, 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.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.ConditionUser, config_parse_unit_condition_string, CONDITION_USER, offsetof(Unit, conditions)
|
||||||
Unit.ConditionGroup, config_parse_unit_condition_string, CONDITION_GROUP, 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.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.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.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.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.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.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.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.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.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.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.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.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.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.AssertSecurity, config_parse_unit_condition_string, CONDITION_SECURITY, offsetof(Unit, asserts)
|
||||||
Unit.AssertCapability, config_parse_unit_condition_string, CONDITION_CAPABILITY, 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.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.AssertUser, config_parse_unit_condition_string, CONDITION_USER, offsetof(Unit, asserts)
|
||||||
Unit.AssertGroup, config_parse_unit_condition_string, CONDITION_GROUP, 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)
|
Unit.CollectMode, config_parse_collect_mode, 0, offsetof(Unit, collect_mode)
|
||||||
m4_dnl
|
m4_dnl
|
||||||
Service.PIDFile, config_parse_pid_file, 0, offsetof(Service, pid_file)
|
Service.PIDFile, config_parse_pid_file, 0, offsetof(Service, pid_file)
|
||||||
|
|
|
@ -2999,6 +2999,60 @@ int config_parse_unit_condition_string(
|
||||||
return 0;
|
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(
|
int config_parse_unit_requires_mounts_for(
|
||||||
const char *unit,
|
const char *unit,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
|
@ -5212,6 +5266,7 @@ void unit_dump_config_items(FILE *f) {
|
||||||
{ config_parse_ip_tos, "TOS" },
|
{ config_parse_ip_tos, "TOS" },
|
||||||
{ config_parse_unit_condition_path, "CONDITION" },
|
{ config_parse_unit_condition_path, "CONDITION" },
|
||||||
{ config_parse_unit_condition_string, "CONDITION" },
|
{ config_parse_unit_condition_string, "CONDITION" },
|
||||||
|
{ config_parse_unit_condition_null, "CONDITION" },
|
||||||
{ config_parse_unit_slice, "SLICE" },
|
{ config_parse_unit_slice, "SLICE" },
|
||||||
{ config_parse_documentation, "URL" },
|
{ config_parse_documentation, "URL" },
|
||||||
{ config_parse_service_timeout, "SECONDS" },
|
{ config_parse_service_timeout, "SECONDS" },
|
||||||
|
|
|
@ -58,6 +58,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_unit_env_file);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_ip_tos);
|
CONFIG_PARSER_PROTOTYPE(config_parse_ip_tos);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_unit_condition_path);
|
CONFIG_PARSER_PROTOTYPE(config_parse_unit_condition_path);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_unit_condition_string);
|
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_kill_mode);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_notify_access);
|
CONFIG_PARSER_PROTOTYPE(config_parse_notify_access);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_emergency_action);
|
CONFIG_PARSER_PROTOTYPE(config_parse_emergency_action);
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
#include "dbus-manager.h"
|
#include "dbus-manager.h"
|
||||||
#include "dbus.h"
|
#include "dbus.h"
|
||||||
#include "def.h"
|
#include "def.h"
|
||||||
#include "dev-setup.h"
|
|
||||||
#include "efi-random.h"
|
#include "efi-random.h"
|
||||||
#include "efivars.h"
|
#include "efivars.h"
|
||||||
#include "emergency-action.h"
|
#include "emergency-action.h"
|
||||||
|
@ -54,7 +53,6 @@
|
||||||
#include "loopback-setup.h"
|
#include "loopback-setup.h"
|
||||||
#include "machine-id-setup.h"
|
#include "machine-id-setup.h"
|
||||||
#include "manager.h"
|
#include "manager.h"
|
||||||
#include "mkdir.h"
|
|
||||||
#include "mount-setup.h"
|
#include "mount-setup.h"
|
||||||
#include "os-util.h"
|
#include "os-util.h"
|
||||||
#include "pager.h"
|
#include "pager.h"
|
||||||
|
@ -2075,20 +2073,6 @@ static int initialize_runtime(
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_warning_errno(r, "Failed to set watchdog device to %s, ignoring: %m", arg_watchdog_device);
|
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)
|
if (arg_timer_slack_nsec != NSEC_INFINITY)
|
||||||
|
|
|
@ -85,8 +85,6 @@ static const MountPoint mount_table[] = {
|
||||||
#endif
|
#endif
|
||||||
{ "tmpfs", "/run", "tmpfs", "mode=755" TMPFS_LIMITS_RUN, MS_NOSUID|MS_NODEV|MS_STRICTATIME,
|
{ "tmpfs", "/run", "tmpfs", "mode=755" TMPFS_LIMITS_RUN, MS_NOSUID|MS_NODEV|MS_STRICTATIME,
|
||||||
NULL, MNT_FATAL|MNT_IN_CONTAINER },
|
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,
|
{ "cgroup2", "/sys/fs/cgroup", "cgroup2", "nsdelegate", MS_NOSUID|MS_NOEXEC|MS_NODEV,
|
||||||
cg_is_unified_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
|
cg_is_unified_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
|
||||||
{ "cgroup2", "/sys/fs/cgroup", "cgroup2", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
|
{ "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);
|
(void) mkdir_label("/run/systemd/system", 0755);
|
||||||
|
|
||||||
/* Also create /run/systemd/inaccessible nodes, so that we always have something to mount
|
/* 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
|
* inaccessible nodes from. */
|
||||||
* in /run/host/inaccessible/. Use those if we can, since tht way we likely get access to block/char
|
(void) make_inaccessible_nodes(NULL, UID_INVALID, GID_INVALID);
|
||||||
* 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -265,7 +265,7 @@ get_parent:
|
||||||
static char *format_timestamp_maybe_utc(char *buf, size_t l, usec_t t) {
|
static char *format_timestamp_maybe_utc(char *buf, size_t l, usec_t t) {
|
||||||
|
|
||||||
if (arg_utc)
|
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);
|
return format_timestamp(buf, l, t);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
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);
|
k = readv(b->input_fd, &iov, 1);
|
||||||
if (k < 0)
|
else {
|
||||||
k = -errno;
|
|
||||||
} else {
|
|
||||||
mh = (struct msghdr) {
|
mh = (struct msghdr) {
|
||||||
.msg_iov = &iov,
|
.msg_iov = &iov,
|
||||||
.msg_iovlen = 1,
|
.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);
|
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);
|
k = readv(bus->input_fd, &iov, 1);
|
||||||
if (k < 0)
|
else {
|
||||||
k = -errno;
|
|
||||||
} else {
|
|
||||||
mh = (struct msghdr) {
|
mh = (struct msghdr) {
|
||||||
.msg_iov = &iov,
|
.msg_iov = &iov,
|
||||||
.msg_iovlen = 1,
|
.msg_iovlen = 1,
|
||||||
|
|
|
@ -7,10 +7,9 @@
|
||||||
|
|
||||||
#include "bus-error.h"
|
#include "bus-error.h"
|
||||||
#include "dev-setup.h"
|
#include "dev-setup.h"
|
||||||
#include "format-util.h"
|
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
|
#include "format-util.h"
|
||||||
#include "label.h"
|
#include "label.h"
|
||||||
#include "limits-util.h"
|
|
||||||
#include "main-func.h"
|
#include "main-func.h"
|
||||||
#include "mkdir.h"
|
#include "mkdir.h"
|
||||||
#include "mountpoint-util.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");
|
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);
|
r = sd_bus_get_property_trivial(bus, "org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "RuntimeDirectorySize", &error, 't', size);
|
||||||
if (r < 0) {
|
if (r < 0)
|
||||||
log_warning_errno(r, "Failed to acquire runtime directory size, ignoring: %s", bus_error_message(&error, r));
|
return log_error_errno(r, "Failed to acquire runtime directory size: %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);
|
r = sd_bus_get_property_trivial(bus, "org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "RuntimeDirectoryInodesMax", &error, 't', inodes);
|
||||||
if (r < 0) {
|
if (r < 0)
|
||||||
log_warning_errno(r, "Failed to acquire number of inodes for runtime directory, ignoring: %s", bus_error_message(&error, r));
|
return log_error_errno(r, "Failed to acquire number of inodes for runtime directory: %s", bus_error_message(&error, r));
|
||||||
*inodes = DIV_ROUND_UP(*size, 4096);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -88,8 +83,7 @@ static int user_mkdir_runtime_path(
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_debug_errno(errno,
|
log_debug_errno(errno, "Failed to mount per-user tmpfs directory %s.\n"
|
||||||
"Failed to mount per-user tmpfs directory %s.\n"
|
|
||||||
"Assuming containerized execution, ignoring: %m", runtime_path);
|
"Assuming containerized execution, ignoring: %m", runtime_path);
|
||||||
|
|
||||||
r = chmod_and_chown(runtime_path, 0700, uid, gid);
|
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);
|
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;
|
return 0;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
|
|
@ -978,8 +978,9 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
const char *mount_inside, *q;
|
const char *mount_inside;
|
||||||
int mntfd;
|
int mntfd;
|
||||||
|
const char *q;
|
||||||
|
|
||||||
errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
|
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);
|
(void) mkdir_p(dest, 0755);
|
||||||
else {
|
else {
|
||||||
(void) mkdir_parents(dest, 0755);
|
(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) {
|
if (mount(mount_inside, dest, NULL, MS_MOVE, NULL) < 0) {
|
||||||
r = log_error_errno(errno, "Failed to mount: %m");
|
r = log_error_errno(errno, "Failed to mount: %m");
|
||||||
goto child_fail;
|
goto child_fail;
|
||||||
|
|
|
@ -101,8 +101,10 @@
|
||||||
#include "user-util.h"
|
#include "user-util.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
/* The notify socket inside the container it can use to talk to nspawn using the sd_notify(3) protocol */
|
/* nspawn is listening on the socket at the path in the constant nspawn_notify_socket_path
|
||||||
#define NSPAWN_NOTIFY_SOCKET_PATH "/run/host/notify"
|
* 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
|
#define EXIT_FORCE_RESTART 133
|
||||||
|
|
||||||
|
@ -2515,15 +2517,19 @@ static int setup_propagate(const char *root) {
|
||||||
p = strjoina("/run/systemd/nspawn/propagate/", arg_machine);
|
p = strjoina("/run/systemd/nspawn/propagate/", arg_machine);
|
||||||
(void) mkdir_p(p, 0600);
|
(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)
|
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)
|
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);
|
r = mount_verbose(LOG_ERR, p, q, NULL, MS_BIND, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
@ -2532,7 +2538,8 @@ static int setup_propagate(const char *root) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
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);
|
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);
|
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;
|
_cleanup_close_ int fd = -1;
|
||||||
union sockaddr_union sa = {
|
union sockaddr_union sa = {
|
||||||
.un.sun_family = AF_UNIX,
|
.un.sun_family = AF_UNIX,
|
||||||
|
@ -3523,7 +3530,7 @@ static int outer_child(
|
||||||
|
|
||||||
(void) dev_setup(directory, arg_uid_shift, arg_uid_shift);
|
(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);
|
(void) make_inaccessible_nodes(p, arg_uid_shift, arg_uid_shift);
|
||||||
|
|
||||||
r = setup_pts(directory);
|
r = setup_pts(directory);
|
||||||
|
@ -3564,14 +3571,6 @@ static int outer_child(
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
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) {
|
if (!arg_use_cgns) {
|
||||||
r = mount_cgroups(
|
r = mount_cgroups(
|
||||||
directory,
|
directory,
|
||||||
|
@ -3589,7 +3588,7 @@ static int outer_child(
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to move root directory: %m");
|
return log_error_errno(r, "Failed to move root directory: %m");
|
||||||
|
|
||||||
fd = setup_notify_child();
|
fd = setup_sd_notify_child();
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return fd;
|
return fd;
|
||||||
|
|
||||||
|
@ -3802,7 +3801,7 @@ static int nspawn_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t r
|
||||||
return 0;
|
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;
|
int r;
|
||||||
|
|
||||||
r = sd_event_add_io(event, notify_event_source, fd, EPOLLIN, nspawn_dispatch_notify_fd, inner_child_pid);
|
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");
|
return log_error_errno(r, "Failed to attach bus to event loop: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
r = setup_notify_parent(event, notify_socket, PID_TO_PTR(*pid), ¬ify_event_source);
|
r = setup_sd_notify_parent(event, notify_socket, PID_TO_PTR(*pid), ¬ify_event_source);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ Condition* condition_new(ConditionType type, const char *parameter, bool trigger
|
||||||
|
|
||||||
assert(type >= 0);
|
assert(type >= 0);
|
||||||
assert(type < _CONDITION_TYPE_MAX);
|
assert(type < _CONDITION_TYPE_MAX);
|
||||||
assert(parameter);
|
assert((!parameter) == (type == CONDITION_NULL));
|
||||||
|
|
||||||
c = new(Condition, 1);
|
c = new(Condition, 1);
|
||||||
if (!c)
|
if (!c)
|
||||||
|
@ -776,6 +776,15 @@ static int condition_test_file_is_executable(Condition *c, char **env) {
|
||||||
(st.st_mode & 0111));
|
(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) {
|
int condition_test(Condition *c, char **env) {
|
||||||
|
|
||||||
static int (*const condition_tests[_CONDITION_TYPE_MAX])(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_USER] = condition_test_user,
|
||||||
[CONDITION_GROUP] = condition_test_group,
|
[CONDITION_GROUP] = condition_test_group,
|
||||||
[CONDITION_CONTROL_GROUP_CONTROLLER] = condition_test_control_group_controller,
|
[CONDITION_CONTROL_GROUP_CONTROLLER] = condition_test_control_group_controller,
|
||||||
|
[CONDITION_NULL] = condition_test_null,
|
||||||
[CONDITION_CPUS] = condition_test_cpus,
|
[CONDITION_CPUS] = condition_test_cpus,
|
||||||
[CONDITION_MEMORY] = condition_test_memory,
|
[CONDITION_MEMORY] = condition_test_memory,
|
||||||
[CONDITION_ENVIRONMENT] = condition_test_environment,
|
[CONDITION_ENVIRONMENT] = condition_test_environment,
|
||||||
|
@ -849,20 +859,23 @@ bool condition_test_list(
|
||||||
r = condition_test(c, env);
|
r = condition_test(c, env);
|
||||||
|
|
||||||
if (logger) {
|
if (logger) {
|
||||||
|
const char *p = c->type == CONDITION_NULL ? "true" : c->parameter;
|
||||||
|
assert(p);
|
||||||
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
logger(userdata, LOG_WARNING, r, PROJECT_FILE, __LINE__, __func__,
|
logger(userdata, LOG_WARNING, r, PROJECT_FILE, __LINE__, __func__,
|
||||||
"Couldn't determine result for %s=%s%s%s, assuming failed: %m",
|
"Couldn't determine result for %s=%s%s%s, assuming failed: %m",
|
||||||
to_string(c->type),
|
to_string(c->type),
|
||||||
c->trigger ? "|" : "",
|
c->trigger ? "|" : "",
|
||||||
c->negate ? "!" : "",
|
c->negate ? "!" : "",
|
||||||
c->parameter);
|
p);
|
||||||
else
|
else
|
||||||
logger(userdata, LOG_DEBUG, 0, PROJECT_FILE, __LINE__, __func__,
|
logger(userdata, LOG_DEBUG, 0, PROJECT_FILE, __LINE__, __func__,
|
||||||
"%s=%s%s%s %s.",
|
"%s=%s%s%s %s.",
|
||||||
to_string(c->type),
|
to_string(c->type),
|
||||||
c->trigger ? "|" : "",
|
c->trigger ? "|" : "",
|
||||||
c->negate ? "!" : "",
|
c->negate ? "!" : "",
|
||||||
c->parameter,
|
p,
|
||||||
condition_result_to_string(c->result));
|
condition_result_to_string(c->result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -924,6 +937,7 @@ static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
|
||||||
[CONDITION_USER] = "ConditionUser",
|
[CONDITION_USER] = "ConditionUser",
|
||||||
[CONDITION_GROUP] = "ConditionGroup",
|
[CONDITION_GROUP] = "ConditionGroup",
|
||||||
[CONDITION_CONTROL_GROUP_CONTROLLER] = "ConditionControlGroupController",
|
[CONDITION_CONTROL_GROUP_CONTROLLER] = "ConditionControlGroupController",
|
||||||
|
[CONDITION_NULL] = "ConditionNull",
|
||||||
[CONDITION_CPUS] = "ConditionCPUs",
|
[CONDITION_CPUS] = "ConditionCPUs",
|
||||||
[CONDITION_MEMORY] = "ConditionMemory",
|
[CONDITION_MEMORY] = "ConditionMemory",
|
||||||
[CONDITION_ENVIRONMENT] = "ConditionEnvironment",
|
[CONDITION_ENVIRONMENT] = "ConditionEnvironment",
|
||||||
|
@ -955,6 +969,7 @@ static const char* const assert_type_table[_CONDITION_TYPE_MAX] = {
|
||||||
[CONDITION_USER] = "AssertUser",
|
[CONDITION_USER] = "AssertUser",
|
||||||
[CONDITION_GROUP] = "AssertGroup",
|
[CONDITION_GROUP] = "AssertGroup",
|
||||||
[CONDITION_CONTROL_GROUP_CONTROLLER] = "AssertControlGroupController",
|
[CONDITION_CONTROL_GROUP_CONTROLLER] = "AssertControlGroupController",
|
||||||
|
[CONDITION_NULL] = "AssertNull",
|
||||||
[CONDITION_CPUS] = "AssertCPUs",
|
[CONDITION_CPUS] = "AssertCPUs",
|
||||||
[CONDITION_MEMORY] = "AssertMemory",
|
[CONDITION_MEMORY] = "AssertMemory",
|
||||||
[CONDITION_ENVIRONMENT] = "AssertEnvironment",
|
[CONDITION_ENVIRONMENT] = "AssertEnvironment",
|
||||||
|
|
|
@ -34,6 +34,8 @@ typedef enum ConditionType {
|
||||||
CONDITION_FILE_NOT_EMPTY,
|
CONDITION_FILE_NOT_EMPTY,
|
||||||
CONDITION_FILE_IS_EXECUTABLE,
|
CONDITION_FILE_IS_EXECUTABLE,
|
||||||
|
|
||||||
|
CONDITION_NULL,
|
||||||
|
|
||||||
CONDITION_USER,
|
CONDITION_USER,
|
||||||
CONDITION_GROUP,
|
CONDITION_GROUP,
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ int dev_setup(const char *prefix, uid_t uid, gid_t gid) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int make_inaccessible_nodes(
|
int make_inaccessible_nodes(
|
||||||
const char *parent_dir,
|
const char *runtime_dir,
|
||||||
uid_t uid,
|
uid_t uid,
|
||||||
gid_t gid) {
|
gid_t gid) {
|
||||||
|
|
||||||
|
@ -65,26 +65,28 @@ int make_inaccessible_nodes(
|
||||||
const char *name;
|
const char *name;
|
||||||
mode_t mode;
|
mode_t mode;
|
||||||
} table[] = {
|
} table[] = {
|
||||||
{ "inaccessible", S_IFDIR | 0755 },
|
{ "/systemd", S_IFDIR | 0755 },
|
||||||
{ "inaccessible/reg", S_IFREG | 0000 },
|
{ "/systemd/inaccessible", S_IFDIR | 0000 },
|
||||||
{ "inaccessible/dir", S_IFDIR | 0000 },
|
{ "/systemd/inaccessible/reg", S_IFREG | 0000 },
|
||||||
{ "inaccessible/fifo", S_IFIFO | 0000 },
|
{ "/systemd/inaccessible/dir", S_IFDIR | 0000 },
|
||||||
{ "inaccessible/sock", S_IFSOCK | 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
|
/* 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
|
* 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
|
* 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
|
* fallback to use a different node then, for example <root>/inaccessible/sock, which is close
|
||||||
* enough in behaviour and semantics for most uses. */
|
* enough in behaviour and semantics for most uses. */
|
||||||
{ "inaccessible/chr", S_IFCHR | 0000 },
|
{ "/systemd/inaccessible/chr", S_IFCHR | 0000 },
|
||||||
{ "inaccessible/blk", S_IFBLK | 0000 },
|
{ "/systemd/inaccessible/blk", S_IFBLK | 0000 },
|
||||||
};
|
};
|
||||||
|
|
||||||
_cleanup_umask_ mode_t u;
|
_cleanup_umask_ mode_t u;
|
||||||
|
size_t i;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!parent_dir)
|
if (!runtime_dir)
|
||||||
parent_dir = "/run/systemd";
|
runtime_dir = "/run";
|
||||||
|
|
||||||
u = umask(0000);
|
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
|
* 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. */
|
* 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;
|
_cleanup_free_ char *path = NULL;
|
||||||
|
|
||||||
path = path_join(parent_dir, table[i].name);
|
path = path_join(runtime_dir, table[i].name);
|
||||||
if (!path)
|
if (!path)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
|
@ -105,6 +107,7 @@ int make_inaccessible_nodes(
|
||||||
else
|
else
|
||||||
r = mknod_label(path, table[i].mode, makedev(0, 0));
|
r = mknod_label(path, table[i].mode, makedev(0, 0));
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
|
if (r != -EEXIST)
|
||||||
log_debug_errno(r, "Failed to create '%s', ignoring: %m", path);
|
log_debug_errno(r, "Failed to create '%s', ignoring: %m", path);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,4 +5,4 @@
|
||||||
|
|
||||||
int dev_setup(const char *prefix, uid_t uid, gid_t gid);
|
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);
|
||||||
|
|
|
@ -1335,7 +1335,7 @@ static const char *table_data_format(Table *t, TableData *d, bool avoid_uppercas
|
||||||
if (d->type == TABLE_TIMESTAMP)
|
if (d->type == TABLE_TIMESTAMP)
|
||||||
ret = format_timestamp(p, FORMAT_TIMESTAMP_MAX, d->timestamp);
|
ret = format_timestamp(p, FORMAT_TIMESTAMP_MAX, d->timestamp);
|
||||||
else if (d->type == TABLE_TIMESTAMP_UTC)
|
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
|
else
|
||||||
ret = format_timestamp_relative(p, FORMAT_TIMESTAMP_MAX, d->timestamp);
|
ret = format_timestamp_relative(p, FORMAT_TIMESTAMP_MAX, d->timestamp);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
|
|
|
@ -368,7 +368,7 @@ static int output_timestamp_realtime(FILE *f, sd_journal *j, OutputMode mode, Ou
|
||||||
const char *k;
|
const char *k;
|
||||||
|
|
||||||
if (flags & OUTPUT_UTC)
|
if (flags & OUTPUT_UTC)
|
||||||
k = format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_UTC);
|
k = format_timestamp_utc(buf, sizeof(buf), x);
|
||||||
else
|
else
|
||||||
k = format_timestamp(buf, sizeof(buf), x);
|
k = format_timestamp(buf, sizeof(buf), x);
|
||||||
if (!k)
|
if (!k)
|
||||||
|
@ -685,8 +685,8 @@ static int output_verbose(
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to get cursor: %m");
|
return log_error_errno(r, "Failed to get cursor: %m");
|
||||||
|
|
||||||
timestamp = format_timestamp_style(ts, sizeof ts, realtime,
|
timestamp = flags & OUTPUT_UTC ? format_timestamp_us_utc(ts, sizeof ts, realtime)
|
||||||
flags & OUTPUT_UTC ? TIMESTAMP_US_UTC : TIMESTAMP_US);
|
: format_timestamp_us(ts, sizeof ts, realtime);
|
||||||
fprintf(f, "%s [%s]\n",
|
fprintf(f, "%s [%s]\n",
|
||||||
timestamp ?: "(no timestamp)",
|
timestamp ?: "(no timestamp)",
|
||||||
cursor);
|
cursor);
|
||||||
|
|
|
@ -414,6 +414,7 @@ int mode_to_inaccessible_node(
|
||||||
|
|
||||||
_cleanup_free_ char *d = NULL;
|
_cleanup_free_ char *d = NULL;
|
||||||
const char *node = NULL;
|
const char *node = NULL;
|
||||||
|
bool fallback = false;
|
||||||
|
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
|
@ -431,10 +432,12 @@ int mode_to_inaccessible_node(
|
||||||
|
|
||||||
case S_IFCHR:
|
case S_IFCHR:
|
||||||
node = "/systemd/inaccessible/chr";
|
node = "/systemd/inaccessible/chr";
|
||||||
|
fallback = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case S_IFBLK:
|
case S_IFBLK:
|
||||||
node = "/systemd/inaccessible/blk";
|
node = "/systemd/inaccessible/blk";
|
||||||
|
fallback = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case S_IFIFO:
|
case S_IFIFO:
|
||||||
|
@ -452,24 +455,7 @@ int mode_to_inaccessible_node(
|
||||||
if (!d)
|
if (!d)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* On new kernels unprivileged users are permitted to create 0:0 char device nodes (because they also
|
if (fallback && access(d, F_OK) < 0) {
|
||||||
* 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);
|
free(d);
|
||||||
d = path_join(runtime_dir, "/systemd/inaccessible/sock");
|
d = path_join(runtime_dir, "/systemd/inaccessible/sock");
|
||||||
if (!d)
|
if (!d)
|
||||||
|
|
|
@ -170,7 +170,6 @@ static bool arg_now = false;
|
||||||
static bool arg_jobs_before = false;
|
static bool arg_jobs_before = false;
|
||||||
static bool arg_jobs_after = false;
|
static bool arg_jobs_after = false;
|
||||||
static char **arg_clean_what = NULL;
|
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. */
|
/* This is a global cache that will be constructed on first use. */
|
||||||
static Hashmap *cached_id_map = NULL;
|
static Hashmap *cached_id_map = NULL;
|
||||||
|
@ -4196,7 +4195,7 @@ static void print_status_info(
|
||||||
i->active_exit_timestamp;
|
i->active_exit_timestamp;
|
||||||
|
|
||||||
s1 = format_timestamp_relative(since1, sizeof(since1), 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)
|
if (s1)
|
||||||
printf(" since %s; %s\n", s2, s1);
|
printf(" since %s; %s\n", s2, s1);
|
||||||
|
@ -4230,7 +4229,7 @@ static void print_status_info(
|
||||||
dual_timestamp_get(&nw);
|
dual_timestamp_get(&nw);
|
||||||
next_elapse = calc_next_elapse(&nw, &next);
|
next_elapse = calc_next_elapse(&nw, &next);
|
||||||
next_rel_time = format_timestamp_relative(tstamp1, sizeof tstamp1, next_elapse);
|
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)
|
if (next_time && next_rel_time)
|
||||||
printf("%s; %s\n", 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;
|
int n = 0;
|
||||||
|
|
||||||
s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
|
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",
|
printf(" Condition: start %scondition failed%s at %s%s%s\n",
|
||||||
ansi_highlight_yellow(), ansi_normal(),
|
ansi_highlight_yellow(), ansi_normal(),
|
||||||
|
@ -4277,7 +4276,7 @@ static void print_status_info(
|
||||||
|
|
||||||
if (!i->assert_result && i->assert_timestamp > 0) {
|
if (!i->assert_result && i->assert_timestamp > 0) {
|
||||||
s1 = format_timestamp_relative(since1, sizeof(since1), i->assert_timestamp);
|
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",
|
printf(" Assert: start %sassertion failed%s at %s%s%s\n",
|
||||||
ansi_highlight_red(), ansi_normal(),
|
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) {
|
while ((r = sd_bus_message_read(m, "(sst)", &base, &spec, &next_elapse)) > 0) {
|
||||||
char timestamp[FORMAT_TIMESTAMP_MAX] = "n/a";
|
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,
|
bus_print_property_valuef(name, expected_value, value,
|
||||||
"{ %s=%s ; next_elapse=%s }", base, spec, timestamp);
|
"{ %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(info.path),
|
||||||
strna(tt),
|
strna(tt),
|
||||||
strna(o),
|
strna(o),
|
||||||
strna(format_timestamp_style(timestamp1, sizeof(timestamp1), info.start_timestamp, arg_timestamp_style)),
|
strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
|
||||||
strna(format_timestamp_style(timestamp2, sizeof(timestamp2), info.exit_timestamp, arg_timestamp_style)),
|
strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
|
||||||
info.pid,
|
info.pid,
|
||||||
sigchld_code_to_string(info.code),
|
sigchld_code_to_string(info.code),
|
||||||
info.status,
|
info.status,
|
||||||
|
@ -5091,8 +5090,8 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
|
||||||
strna(info.path),
|
strna(info.path),
|
||||||
strna(tt),
|
strna(tt),
|
||||||
yes_no(info.ignore),
|
yes_no(info.ignore),
|
||||||
strna(format_timestamp_style(timestamp1, sizeof(timestamp1), info.start_timestamp, arg_timestamp_style)),
|
strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
|
||||||
strna(format_timestamp_style(timestamp2, sizeof(timestamp2), info.exit_timestamp, arg_timestamp_style)),
|
strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
|
||||||
info.pid,
|
info.pid,
|
||||||
sigchld_code_to_string(info.code),
|
sigchld_code_to_string(info.code),
|
||||||
info.status,
|
info.status,
|
||||||
|
@ -5755,7 +5754,7 @@ static int show_system_status(sd_bus *bus) {
|
||||||
printf(" Failed: %" PRIu32 " units\n", mi.n_failed_units);
|
printf(" Failed: %" PRIu32 " units\n", mi.n_failed_units);
|
||||||
|
|
||||||
printf(" Since: %s; %s\n",
|
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));
|
format_timestamp_relative(since1, sizeof(since1), mi.timestamp));
|
||||||
|
|
||||||
printf(" CGroup: %s\n", mi.control_group ?: "/");
|
printf(" CGroup: %s\n", mi.control_group ?: "/");
|
||||||
|
@ -7805,11 +7804,6 @@ static int systemctl_help(void) {
|
||||||
" --boot-loader-entry=NAME\n"
|
" --boot-loader-entry=NAME\n"
|
||||||
" Boot into a specific boot loader entry on next boot\n"
|
" Boot into a specific boot loader entry on next boot\n"
|
||||||
" --plain Print unit dependencies as a list instead of a tree\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"
|
"\nSee the %2$s for details.\n"
|
||||||
, program_invocation_short_name
|
, program_invocation_short_name
|
||||||
, link
|
, link
|
||||||
|
@ -8058,7 +8052,6 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
|
||||||
ARG_WAIT,
|
ARG_WAIT,
|
||||||
ARG_WHAT,
|
ARG_WHAT,
|
||||||
ARG_REBOOT_ARG,
|
ARG_REBOOT_ARG,
|
||||||
ARG_TIMESTAMP_STYLE,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct option options[] = {
|
static const struct option options[] = {
|
||||||
|
@ -8113,7 +8106,6 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
|
||||||
{ "show-transaction", no_argument, NULL, 'T' },
|
{ "show-transaction", no_argument, NULL, 'T' },
|
||||||
{ "what", required_argument, NULL, ARG_WHAT },
|
{ "what", required_argument, NULL, ARG_WHAT },
|
||||||
{ "reboot-argument", required_argument, NULL, ARG_REBOOT_ARG },
|
{ "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;
|
arg_reboot_argument = optarg;
|
||||||
break;
|
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 '.':
|
case '.':
|
||||||
/* Output an error mimicking getopt, and print a hint afterwards */
|
/* Output an error mimicking getopt, and print a hint afterwards */
|
||||||
log_error("%s: invalid option -- '.'", program_invocation_name);
|
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));
|
return log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s", bus_error_message(&error, r));
|
||||||
|
|
||||||
if (!arg_quiet)
|
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;
|
return 0;
|
||||||
#else
|
#else
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
|
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;
|
u = after;
|
||||||
r = calendar_spec_next_usec(c, after, &u);
|
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)
|
if (expect != (usec_t)-1)
|
||||||
assert_se(r >= 0 && u == expect);
|
assert_se(r >= 0 && u == expect);
|
||||||
else
|
else
|
||||||
|
@ -83,7 +83,7 @@ static void test_timestamp(void) {
|
||||||
|
|
||||||
x = now(CLOCK_REALTIME);
|
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);
|
printf("%s\n", buf);
|
||||||
assert_se(calendar_spec_from_string(buf, &c) >= 0);
|
assert_se(calendar_spec_from_string(buf, &c) >= 0);
|
||||||
assert_se(calendar_spec_to_string(c, &t) >= 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);
|
n = now(CLOCK_REALTIME);
|
||||||
assert_se((r = calendar_spec_next_usec(c, n, &u)) >= 0);
|
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("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_style(buf, sizeof buf, u, TIMESTAMP_US), u);
|
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);
|
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(n < u);
|
||||||
assert_se(u <= n + USEC_PER_HOUR);
|
assert_se(u <= n + USEC_PER_HOUR);
|
||||||
|
|
|
@ -438,6 +438,20 @@ static void test_condition_test_kernel_version(void) {
|
||||||
condition_free(condition);
|
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) {
|
static void test_condition_test_security(void) {
|
||||||
Condition *condition;
|
Condition *condition;
|
||||||
|
|
||||||
|
@ -854,6 +868,7 @@ int main(int argc, char *argv[]) {
|
||||||
test_condition_test_architecture();
|
test_condition_test_architecture();
|
||||||
test_condition_test_kernel_command_line();
|
test_condition_test_kernel_command_line();
|
||||||
test_condition_test_kernel_version();
|
test_condition_test_kernel_version();
|
||||||
|
test_condition_test_null();
|
||||||
test_condition_test_security();
|
test_condition_test_security();
|
||||||
print_securities();
|
print_securities();
|
||||||
test_condition_test_virtualization();
|
test_condition_test_virtualization();
|
||||||
|
|
|
@ -11,7 +11,7 @@ static void test_should_pass(const char *p) {
|
||||||
|
|
||||||
log_info("Test: %s", p);
|
log_info("Test: %s", p);
|
||||||
assert_se(parse_timestamp(p, &t) >= 0);
|
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);
|
log_info("\"%s\" → \"%s\"", p, buf);
|
||||||
|
|
||||||
assert_se(parse_timestamp(buf, &q) >= 0);
|
assert_se(parse_timestamp(buf, &q) >= 0);
|
||||||
|
@ -19,7 +19,7 @@ static void test_should_pass(const char *p) {
|
||||||
char tmp[FORMAT_TIMESTAMP_MAX];
|
char tmp[FORMAT_TIMESTAMP_MAX];
|
||||||
|
|
||||||
log_error("round-trip failed: \"%s\" → \"%s\"",
|
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);
|
assert_se(q == t);
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
#include "capability-util.h"
|
#include "capability-util.h"
|
||||||
#include "dev-setup.h"
|
#include "dev-setup.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
#include "mkdir.h"
|
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
#include "rm-rf.h"
|
#include "rm-rf.h"
|
||||||
#include "tmpfile-util.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);
|
assert_se(mkdtemp_malloc("/tmp/test-dev-setupXXXXXX", &p) >= 0);
|
||||||
|
|
||||||
f = prefix_roota(p, "/run/systemd");
|
f = prefix_roota(p, "/run");
|
||||||
assert_se(mkdir_p(f, 0755) >= 0);
|
assert_se(mkdir(f, 0755) >= 0);
|
||||||
|
|
||||||
assert_se(make_inaccessible_nodes(f, 1, 1) >= 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(parse_timestamp(buf, &y) >= 0);
|
||||||
assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
|
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);
|
log_info("%s", buf);
|
||||||
assert_se(parse_timestamp(buf, &y) >= 0);
|
assert_se(parse_timestamp(buf, &y) >= 0);
|
||||||
assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
|
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);
|
log_info("%s", buf);
|
||||||
assert_se(parse_timestamp(buf, &y) >= 0);
|
assert_se(parse_timestamp(buf, &y) >= 0);
|
||||||
assert_se(x == y);
|
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);
|
log_info("%s", buf);
|
||||||
assert_se(parse_timestamp(buf, &y) >= 0);
|
assert_se(parse_timestamp(buf, &y) >= 0);
|
||||||
assert_se(x == y);
|
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];
|
char buf[FORMAT_TIMESTAMP_MAX];
|
||||||
const char *t;
|
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));
|
assert_se(streq_ptr(t, result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,7 @@ static int clock_state_update(
|
||||||
if (tx.status & STA_NANO)
|
if (tx.status & STA_NANO)
|
||||||
tx.time.tv_usec /= 1000;
|
tx.time.tv_usec /= 1000;
|
||||||
t = timeval_load(&tx.time);
|
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)
|
if (!ts)
|
||||||
strcpy(buf, "unrepresentable");
|
strcpy(buf, "unrepresentable");
|
||||||
log_info("adjtime state %d status %x time %s", sp->adjtime_state, tx.status, ts);
|
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). */
|
/* Follows spelling in stat(1). */
|
||||||
log_debug("Directory \"%s\": modify time %s is too new.",
|
log_debug("Directory \"%s\": modify time %s is too new.",
|
||||||
sub_path,
|
sub_path,
|
||||||
format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
|
format_timestamp_us(a, sizeof(a), age));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -620,7 +620,7 @@ static int dir_cleanup(
|
||||||
char a[FORMAT_TIMESTAMP_MAX];
|
char a[FORMAT_TIMESTAMP_MAX];
|
||||||
log_debug("Directory \"%s\": access time %s is too new.",
|
log_debug("Directory \"%s\": access time %s is too new.",
|
||||||
sub_path,
|
sub_path,
|
||||||
format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
|
format_timestamp_us(a, sizeof(a), age));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -672,7 +672,7 @@ static int dir_cleanup(
|
||||||
/* Follows spelling in stat(1). */
|
/* Follows spelling in stat(1). */
|
||||||
log_debug("File \"%s\": modify time %s is too new.",
|
log_debug("File \"%s\": modify time %s is too new.",
|
||||||
sub_path,
|
sub_path,
|
||||||
format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
|
format_timestamp_us(a, sizeof(a), age));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -681,7 +681,7 @@ static int dir_cleanup(
|
||||||
char a[FORMAT_TIMESTAMP_MAX];
|
char a[FORMAT_TIMESTAMP_MAX];
|
||||||
log_debug("File \"%s\": access time %s is too new.",
|
log_debug("File \"%s\": access time %s is too new.",
|
||||||
sub_path,
|
sub_path,
|
||||||
format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
|
format_timestamp_us(a, sizeof(a), age));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -690,7 +690,7 @@ static int dir_cleanup(
|
||||||
char a[FORMAT_TIMESTAMP_MAX];
|
char a[FORMAT_TIMESTAMP_MAX];
|
||||||
log_debug("File \"%s\": change time %s is too new.",
|
log_debug("File \"%s\": change time %s is too new.",
|
||||||
sub_path,
|
sub_path,
|
||||||
format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
|
format_timestamp_us(a, sizeof(a), age));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -713,8 +713,8 @@ finish:
|
||||||
|
|
||||||
log_debug("Restoring access and modification time on \"%s\": %s, %s",
|
log_debug("Restoring access and modification time on \"%s\": %s, %s",
|
||||||
p,
|
p,
|
||||||
format_timestamp_style(a, sizeof(a), age1, TIMESTAMP_US),
|
format_timestamp_us(a, sizeof(a), age1),
|
||||||
format_timestamp_style(b, sizeof(b), age2, TIMESTAMP_US));
|
format_timestamp_us(b, sizeof(b), age2));
|
||||||
|
|
||||||
/* Restore original directory timestamps */
|
/* Restore original directory timestamps */
|
||||||
if (futimens(dirfd(d), (struct timespec[]) {
|
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",
|
log_debug("Cleanup threshold for %s \"%s\" is %s",
|
||||||
mountpoint ? "mount point" : "directory",
|
mountpoint ? "mount point" : "directory",
|
||||||
instance,
|
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,
|
return dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
|
||||||
MAX_DEPTH, i->keep_first_level);
|
MAX_DEPTH, i->keep_first_level);
|
||||||
|
|
|
@ -15,6 +15,9 @@ Documentation=https://www.freedesktop.org/wiki/Software/systemd/machined
|
||||||
Wants=machine.slice
|
Wants=machine.slice
|
||||||
After=machine.slice
|
After=machine.slice
|
||||||
RequiresMountsFor=/var/lib/machines
|
RequiresMountsFor=/var/lib/machines
|
||||||
|
ConditionNull=true
|
||||||
|
ConditionNull=
|
||||||
|
ConditionNull=|!false
|
||||||
OnFailureIsolate=false
|
OnFailureIsolate=false
|
||||||
FailureActionExitStatus=222
|
FailureActionExitStatus=222
|
||||||
FailureActionExitStatus=
|
FailureActionExitStatus=
|
||||||
|
|
|
@ -60,7 +60,7 @@ function check_norbind {
|
||||||
|
|
||||||
function check_notification_socket {
|
function check_notification_socket {
|
||||||
# https://github.com/systemd/systemd/issues/4944
|
# 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
|
# /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 /bin/sh -x -c "$_cmd"
|
||||||
systemd-nspawn $SUSE_OPTS--register=no -D /testsuite-13.nc-container -U /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