diff --git a/docs/TRANSIENT-SETTINGS.md b/docs/TRANSIENT-SETTINGS.md
index 4992acbf67..d5c9a33df8 100644
--- a/docs/TRANSIENT-SETTINGS.md
+++ b/docs/TRANSIENT-SETTINGS.md
@@ -21,88 +21,131 @@ Most generic unit settings are available for transient units.
```
✓ Description=
-✓ Documentation=
✓ SourcePath=
-✓ Requires=
-✓ Requisite=
-✓ Wants=
-✓ BindsTo=
-✓ Conflicts=
-✓ Before=
-✓ After=
-✓ OnFailure=
-✓ PropagatesReloadTo=
-✓ ReloadPropagatedFrom=
-✓ PartOf=
-✓ Upholds=
-✓ JoinsNamespaceOf=
-✓ RequiresMountsFor=
+✓ OnFailureJobMode=
+✓ JobTimeoutAction=
+✓ JobTimeoutRebootArgument=
+✓ StartLimitAction=
+✓ FailureAction=
+✓ SuccessAction=
+✓ RebootArgument=
+✓ CollectMode=
✓ StopWhenUnneeded=
✓ RefuseManualStart=
✓ RefuseManualStop=
✓ AllowIsolate=
-✓ DefaultDependencies=
-✓ OnFailureJobMode=
✓ IgnoreOnIsolate=
+✓ SurviveFinalKillSignal=
+✓ DefaultDependencies=
✓ JobTimeoutSec=
✓ JobRunningTimeoutSec=
-✓ JobTimeoutAction=
-✓ JobTimeoutRebootArgument=
✓ StartLimitIntervalSec=
✓ StartLimitBurst=
-✓ StartLimitAction=
-✓ FailureAction=
-✓ SuccessAction=
-✓ FailureActionExitStatus=
✓ SuccessActionExitStatus=
-✓ RebootArgument=
+✓ FailureActionExitStatus=
+✓ Documentation=
+✓ RequiresMountsFor=
+✓ WantsMountsFor=
+✓ Markers=
+✓ Requires=
+✓ Requisite=
+✓ Wants=
+✓ BindsTo=
+✓ PartOf=
+✓ Upholds=
+✓ RequiredBy=
+✓ RequisiteOf=
+✓ WantedBy=
+✓ BoundBy=
+✓ UpheldBy=
+✓ ConsistsOf=
+✓ Conflicts=
+✓ ConflictedBy=
+✓ Before=
+✓ After=
+✓ OnSuccess=
+✓ OnSuccessOf=
+✓ OnFailure=
+✓ OnFailureOf=
+✓ Triggers=
+✓ TriggeredBy=
+✓ PropagatesReloadTo=
+✓ ReloadPropagatedFrom=
+✓ PropagatesStopTo=
+✓ StopPropagatedFrom=
+✓ JoinsNamespaceOf=
+✓ References=
+✓ ReferencedBy=
+✓ InSlice=
+✓ SliceOf=
+✓ ConditionArchitecture=
+✓ ConditionFirmware=
+✓ ConditionVirtualization=
+✓ ConditionHost=
+✓ ConditionKernelCommandLine=
+✓ ConditionVersion=
+✓ ConditionCredential=
+✓ ConditionSecurity=
+✓ ConditionCapability=
+✓ ConditionACPower=
+✓ ConditionNeedsUpdate=
+✓ ConditionFirstBoot=
✓ ConditionPathExists=
✓ ConditionPathExistsGlob=
✓ ConditionPathIsDirectory=
✓ ConditionPathIsSymbolicLink=
✓ ConditionPathIsMountPoint=
✓ ConditionPathIsReadWrite=
+✓ ConditionPathIsEncrypted=
✓ ConditionDirectoryNotEmpty=
✓ ConditionFileNotEmpty=
✓ ConditionFileIsExecutable=
-✓ ConditionNeedsUpdate=
-✓ ConditionFirstBoot=
-✓ ConditionKernelCommandLine=
-✓ ConditionKernelVersion=
-✓ ConditionVersion=
-✓ ConditionArchitecture=
-✓ ConditionFirmware=
-✓ ConditionVirtualization=
-✓ ConditionSecurity=
-✓ ConditionCapability=
-✓ ConditionHost=
-✓ ConditionACPower=
✓ ConditionUser=
✓ ConditionGroup=
✓ ConditionControlGroupController=
+✓ ConditionCPUs=
+✓ ConditionMemory=
+✓ ConditionEnvironment=
+✓ ConditionCPUFeature=
+✓ ConditionOSRelease=
+✓ ConditionMemoryPressure=
+✓ ConditionCPUPressure=
+✓ ConditionIOPressure=
+✓ ConditionKernelModuleLoaded=
+✓ AssertArchitecture=
+✓ AssertFirmware=
+✓ AssertVirtualization=
+✓ AssertHost=
+✓ AssertKernelCommandLine=
+✓ AssertVersion=
+✓ AssertCredential=
+✓ AssertSecurity=
+✓ AssertCapability=
+✓ AssertACPower=
+✓ AssertNeedsUpdate=
+✓ AssertFirstBoot=
✓ AssertPathExists=
✓ AssertPathExistsGlob=
✓ AssertPathIsDirectory=
✓ AssertPathIsSymbolicLink=
✓ AssertPathIsMountPoint=
✓ AssertPathIsReadWrite=
+✓ AssertPathIsEncrypted=
✓ AssertDirectoryNotEmpty=
✓ AssertFileNotEmpty=
✓ AssertFileIsExecutable=
-✓ AssertNeedsUpdate=
-✓ AssertFirstBoot=
-✓ AssertKernelCommandLine=
-✓ AssertKernelVersion=
-✓ AssertArchitecture=
-✓ AssertVirtualization=
-✓ AssertSecurity=
-✓ AssertCapability=
-✓ AssertHost=
-✓ AssertACPower=
✓ AssertUser=
✓ AssertGroup=
✓ AssertControlGroupController=
-✓ CollectMode=
+✓ AssertCPUs=
+✓ AssertMemory=
+✓ AssertEnvironment=
+✓ AssertCPUFeature=
+✓ AssertOSRelease=
+✓ AssertMemoryPressure=
+✓ AssertCPUPressure=
+✓ AssertIOPressure=
+✓ AssertKernelModuleLoaded=
```
## Execution-Related Settings
@@ -236,55 +279,58 @@ All execution-related settings are available for transient units.
All cgroup/resource control settings are available for transient units
```
-✓ CPUAccounting=
+✓ DevicePolicy=
+✓ Slice=
+✓ ManagedOOMSwap=
+✓ ManagedOOMMemoryPressure=
+✓ ManagedOOMPreference=
+✓ MemoryPressureWatch=
+✓ DelegateSubgroup=
+✓ ManagedOOMMemoryPressureLimit=
+✓ MemoryAccounting=
+✓ MemoryZSwapWriteback=
+✓ IOAccounting=
+✓ TasksAccounting=
+✓ IPAccounting=
+✓ CoredumpReceive=
✓ CPUWeight=
✓ StartupCPUWeight=
-✓ CPUShares=
-✓ StartupCPUShares=
-✓ CPUQuota=
-✓ CPUQuotaPeriodSec=
+✓ IOWeight=
+✓ StartupIOWeight=
✓ AllowedCPUs=
✓ StartupAllowedCPUs=
✓ AllowedMemoryNodes=
✓ StartupAllowedMemoryNodes=
-✓ MemoryAccounting=
-✓ DefaultMemoryMin=
+✓ DisableControllers=
+✓ Delegate=
✓ MemoryMin=
✓ DefaultMemoryLow=
+✓ DefaultMemoryMin=
✓ MemoryLow=
✓ MemoryHigh=
✓ MemoryMax=
✓ MemorySwapMax=
-✓ MemoryLimit=
+✓ MemoryZSwapMax=
+✓ TasksMax=
+✓ CPUQuota=
+✓ CPUQuotaPeriodSec=
✓ DeviceAllow=
-✓ DevicePolicy=
-✓ IOAccounting=
-✓ IOWeight=
-✓ StartupIOWeight=
✓ IODeviceWeight=
+✓ IODeviceLatencyTargetSec=
+✓ IPAddressAllow=
+✓ IPAddressDeny=
+✓ IPIngressFilterPath=
+✓ IPEgressFilterPath=
+✓ BPFProgram=
+✓ SocketBindAllow=
+✓ SocketBindDeny=
+✓ MemoryPressureThresholdSec=
+✓ NFTSet=
+✓ ManagedOOMMemoryPressureDurationSec=
✓ IOReadBandwidthMax=
✓ IOWriteBandwidthMax=
✓ IOReadIOPSMax=
✓ IOWriteIOPSMax=
-✓ BlockIOAccounting=
-✓ BlockIOWeight=
-✓ StartupBlockIOWeight=
-✓ BlockIODeviceWeight=
-✓ BlockIOReadBandwidth=
-✓ BlockIOWriteBandwidth=
-✓ TasksAccounting=
-✓ TasksMax=
-✓ Delegate=
-✓ DisableControllers=
-✓ IPAccounting=
-✓ IPAddressAllow=
-✓ IPAddressDeny=
-✓ ManagedOOMSwap=
-✓ ManagedOOMMemoryPressure=
-✓ ManagedOOMMemoryPressureLimit=
-✓ ManagedOOMMemoryPressureDurationSec=
-✓ ManagedOOMPreference=
-✓ CoredumpReceive=
```
## Process Killing Settings
@@ -292,13 +338,14 @@ All cgroup/resource control settings are available for transient units
All process killing settings are available for transient units:
```
-✓ SendSIGKILL=
-✓ SendSIGHUP=
✓ KillMode=
+✓ SendSIGHUP=
+✓ SendSIGKILL=
✓ KillSignal=
✓ RestartKillSignal=
✓ FinalKillSignal=
✓ WatchdogSignal=
+✓ ReloadSignal=
```
## Service Unit Settings
@@ -306,41 +353,53 @@ All process killing settings are available for transient units:
Most service unit settings are available for transient units.
```
-✓ BusName=
-✓ ExecCondition=
-✓ ExecReload=
-✓ ExecStart=
-✓ ExecStartPost=
-✓ ExecStartPre=
-✓ ExecStop=
-✓ ExecStopPost=
-✓ ExitType=
-✓ FileDescriptorStoreMax=
-✓ GuessMainPID=
-✓ NonBlocking=
-✓ NotifyAccess=
-✓ OOMPolicy=
✓ PIDFile=
-✓ RemainAfterExit=
-✓ Restart=
-✓ RestartForceExitStatus=
-✓ RestartPreventExitStatus=
-✓ RestartSec=
-✓ RootDirectoryStartOnly=
-✓ RuntimeMaxSec=
-✓ RuntimeRandomizedExtraSec=
- Sockets=
-✓ SuccessExitStatus=
-✓ TimeoutAbortSec=
-✓ TimeoutSec=
-✓ TimeoutStartFailureMode=
-✓ TimeoutStartSec=
-✓ TimeoutStopFailureMode=
-✓ TimeoutStopSec=
✓ Type=
+✓ ExitType=
+✓ Restart=
+✓ RestartMode=
+✓ BusName=
+✓ NotifyAccess=
✓ USBFunctionDescriptors=
✓ USBFunctionStrings=
+✓ OOMPolicy=
+✓ TimeoutStartFailureMode=
+✓ TimeoutStopFailureMode=
+✓ FileDescriptorStorePreserve=
+✓ PermissionsStartOnly=
+✓ RootDirectoryStartOnly=
+✓ RemainAfterExit=
+✓ GuessMainPID=
+✓ RestartSec=
+✓ RestartMaxDelaySec=
+✓ TimeoutStartSec=
+✓ TimeoutStopSec=
+✓ TimeoutAbortSec=
+✓ RuntimeMaxSec=
+✓ RuntimeRandomizedExtraSec=
✓ WatchdogSec=
+✓ TimeoutSec=
+✓ FileDescriptorStoreMax=
+✓ RestartSteps=
+✓ ExecCondition=
+✓ ExecStartPre=
+✓ ExecStart=
+✓ ExecStartPost=
+✓ ExecConditionEx=
+✓ ExecStartPreEx=
+✓ ExecStartEx=
+✓ ExecStartPostEx=
+✓ ExecReload=
+✓ ExecStop=
+✓ ExecStopPost=
+✓ ExecReloadEx=
+✓ ExecStopEx=
+✓ ExecStopPostEx=
+✓ RestartPreventExitStatus=
+✓ RestartForceExitStatus=
+✓ SuccessExitStatus=
+✓ OpenFile=
+ Socket=
```
## Mount Unit Settings
@@ -357,7 +416,7 @@ All mount unit settings are available to transient units:
✓ SloppyOptions=
✓ LazyUnmount=
✓ ForceUnmount=
-✓ ReadWriteOnly=
+✓ ReadwriteOnly=
```
## Automount Unit Settings
@@ -366,6 +425,7 @@ All automount unit setting is available to transient units:
```
✓ Where=
+✓ ExtraOptions=
✓ DirectoryMode=
✓ TimeoutIdleSec=
```
@@ -375,21 +435,21 @@ All automount unit setting is available to transient units:
Most timer unit settings are available to transient units.
```
-✓ OnActiveSec=
-✓ OnBootSec=
-✓ OnCalendar=
-✓ OnClockChange=
-✓ OnStartupSec=
-✓ OnTimezoneChange=
-✓ OnUnitActiveSec=
-✓ OnUnitInactiveSec=
-✓ Persistent=
✓ WakeSystem=
✓ RemainAfterElapse=
-✓ AccuracySec=
-✓ RandomizedDelaySec=
+✓ Persistent=
+✓ OnTimezoneChange=
+✓ OnClockChange=
✓ FixedRandomDelay=
✓ DeferReactivation=
+✓ AccuracySec=
+✓ RandomizedDelaySec=
+✓ OnActiveSec=
+✓ OnBootSec=
+✓ OnStartupSec=
+✓ OnUnitActiveSec=
+✓ OnUnitInactiveSec=
+✓ OnCalendar=
Unit=
```
@@ -407,6 +467,9 @@ such).
✓ RuntimeMaxSec=
✓ RuntimeRandomizedExtraSec=
✓ TimeoutStopSec=
+✓ User=
+✓ Group=
+✓ OOMPolicy=
```
## Socket Unit Settings
@@ -414,65 +477,71 @@ such).
Most socket unit settings are available to transient units.
```
-✓ ListenStream=
-✓ ListenDatagram=
-✓ ListenSequentialPacket=
-✓ ListenFIFO=
-✓ ListenNetlink=
-✓ ListenSpecial=
-✓ ListenMessageQueue=
-✓ ListenUSBFunction=
-✓ SocketProtocol=
-✓ BindIPv6Only=
-✓ Backlog=
-✓ BindToDevice=
-✓ ExecStartPre=
-✓ ExecStartPost=
-✓ ExecStopPre=
-✓ ExecStopPost=
-✓ TimeoutSec=
-✓ SocketUser=
-✓ SocketGroup=
-✓ SocketMode=
-✓ DirectoryMode=
✓ Accept=
✓ FlushPending=
✓ Writable=
-✓ MaxConnections=
-✓ MaxConnectionsPerSource=
✓ KeepAlive=
-✓ KeepAliveTimeSec=
-✓ KeepAliveIntervalSec=
-✓ KeepAliveProbes=
-✓ DeferAcceptSec=
✓ NoDelay=
-✓ Priority=
-✓ ReceiveBuffer=
-✓ SendBuffer=
-✓ IPTOS=
-✓ IPTTL=
-✓ Mark=
-✓ PipeSize=
✓ FreeBind=
✓ Transparent=
✓ Broadcast=
✓ PassCredentials=
+✓ PassFileDescriptorsToExec=
✓ PassSecurity=
✓ PassPacketInfo=
-✓ TCPCongestion=
✓ ReusePort=
+✓ RemoveOnStop=
+✓ SELinuxContextFromNet=
+✓ Priority=
+✓ IPTTL=
+✓ Mark=
+✓ IPTOS=
+✓ Backlog=
+✓ MaxConnections=
+✓ MaxConnectionsPerSource=
+✓ KeepAliveProbes=
+✓ TriggerLimitBurst=
+✓ PollLimitBurst=
+✓ SocketMode=
+✓ DirectoryMode=
✓ MessageQueueMaxMessages=
✓ MessageQueueMessageSize=
-✓ RemoveOnStop=
-✓ Symlinks=
-✓ FileDescriptorName=
- Service=
+✓ TimeoutSec=
+✓ KeepAliveTimeSec=
+✓ KeepAliveIntervalSec=
+✓ DeferAcceptSec=
+✓ DeferTrigger=
+✓ DeferTriggerMaxSec=
✓ TriggerLimitIntervalSec=
-✓ TriggerLimitBurst=
+✓ PollLimitIntervalSec=
+✓ ReceiveBuffer=
+✓ SendBuffer=
+✓ PipeSize=
+✓ ExecStartPre=
+✓ ExecStartPost=
+✓ ExecReload=
+✓ ExecStopPost=
✓ SmackLabel=
✓ SmackLabelIPIn=
✓ SmackLabelIPOut=
-✓ SELinuxContextFromNet=
+✓ TCPCongestion=
+✓ BindToDevice=
+✓ BindIPv6Only=
+✓ FileDescriptorName=
+✓ SocketUser=
+✓ SocketGroup=
+✓ Timestamping=
+✓ Symlinks=
+✓ SocketProtocol=
+✓ ListenStream=
+✓ ListenDatagram=
+✓ ListenSequentialPacket=
+✓ ListenNetlink=
+✓ ListenSpecial=
+✓ ListenMessageQueue=
+✓ ListenFIFO=
+✓ ListenUSBFunction=
+ Service=
```
## Swap Unit Settings
@@ -491,14 +560,18 @@ Swap units are currently not available at all as transient units:
Most path unit settings are available to transient units.
```
+✓ MakeDirectory=
+✓ DirectoryMode=
✓ PathExists=
✓ PathExistsGlob=
✓ PathChanged=
✓ PathModified=
✓ DirectoryNotEmpty=
+✓ TriggerLimitBurst=
+✓ PollLimitBurst=
+✓ TriggerLimitIntervalSec=
+✓ PollLimitIntervalSec=
Unit=
-✓ MakeDirectory=
-✓ DirectoryMode=
```
## Install Section
diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml
index 7bdf850c60..e1c575757b 100644
--- a/man/systemd-analyze.xml
+++ b/man/systemd-analyze.xml
@@ -210,6 +210,12 @@
OPTIONS
chid
+
+ systemd-analyze
+ OPTIONS
+ transient-settings
+ TYPE
+
@@ -1121,6 +1127,39 @@ LEGEND: M → sys_vendor (LENOVO) ┄ F → product_family (ThinkPad X1 Carbon G
+
+ systemd-analyze transient-settings TYPE...
+
+ Lists properties that can be set for various unit types via command line interfaces, in
+ particular
+ systemctl1
+ set-property and /
+ options in
+ systemd-run1,
+ systemd-nspawn1, and
+ systemd-mount1.
+ Those assignments are possible for a subset of the properties that can be set in config files, see
+ systemd.unit5,
+ systemd.exec5,
+ systemd.resource-control5,
+ and the other unit-type-specific pages. The TYPE argument must be a unit
+ type ("service", "socket", …). The properties that apply to the specific types are listed.
+
+ Note: D-Bus properties documented in
+ org.freedesktop.systemd15
+ form a partially overlapping set with the lists generated by this command. Many D-Bus properties and
+ transient settings share the same names, but for example, LogRateLimitIntervalSec=
+ is described in
+ systemd.exec5 and
+ would be listed by this command, but the corresponding D-Bus property described in
+ systemd.exec5 is
+ LogRateLimitIntervalUSec.
+
+
+ This verb is intended primarily for programatic generation of shell completions.
+
+
+
diff --git a/shell-completion/bash/systemd-analyze b/shell-completion/bash/systemd-analyze
index 41a2151e12..e4ecafeddc 100644
--- a/shell-completion/bash/systemd-analyze
+++ b/shell-completion/bash/systemd-analyze
@@ -81,6 +81,7 @@ _systemd_analyze() {
[ARCHITECTURES]='architectures'
[FDSTORE]='fdstore'
[CAPABILITY]='capability'
+ [TRANSIENT_SETTINGS]='transient-settings'
)
local CONFIGS='locale.conf systemd/bootchart.conf systemd/coredump.conf systemd/journald.conf
@@ -225,6 +226,13 @@ _systemd_analyze() {
if [[ $cur = -* ]]; then
comps='--help --version --no-pager --json=off --json=pretty --json=short -m --mask'
fi
+
+ elif __contains_word "$verb" ${VERBS[TRANSIENT_SETTINGS]}; then
+ if [[ $cur = -* ]]; then
+ comps='--help --version --no-pager'
+ else
+ comps="$(systemctl --no-legend --no-pager -t help)"
+ fi
fi
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
diff --git a/shell-completion/zsh/_systemd-analyze b/shell-completion/zsh/_systemd-analyze
index 50542b3962..e03ae31afd 100644
--- a/shell-completion/zsh/_systemd-analyze
+++ b/shell-completion/zsh/_systemd-analyze
@@ -47,6 +47,13 @@
_describe 'plot options' _options
}
+(( $+functions[_systemd-analyze_transient-settings] )) ||
+ _systemd-analyze_transient-settings() {
+ local -a _types
+ _types=( $(systemctl --no-pager --no-legend -t help) )
+ _describe -t types 'unit types' _types
+ }
+
(( $+functions[_systemd-analyze_commands] )) ||
_systemd-analyze_commands(){
local -a _systemd_analyze_cmds
@@ -74,6 +81,7 @@ JSON or table format'
'security:Analyze security settings of a service'
'inspect-elf:Parse and print ELF package metadata'
'has-tpm2:Report whether TPM2 support is available'
+ 'transient-settings:List transient settings for unit types'
# log-level, log-target, service-watchdogs have been deprecated
)
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index bb5855ecc6..8745db63f5 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -12,7 +12,6 @@
#include "sd-json.h"
#include "alloc-util.h"
-#include "analyze-verify-util.h"
#include "analyze.h"
#include "analyze-architectures.h"
#include "analyze-blame.h"
@@ -46,8 +45,10 @@
#include "analyze-unit-files.h"
#include "analyze-unit-paths.h"
#include "analyze-verify.h"
+#include "analyze-verify-util.h"
#include "build.h"
#include "bus-error.h"
+#include "bus-unit-util.h"
#include "bus-util.h"
#include "calendarspec.h"
#include "dissect-image.h"
@@ -66,6 +67,7 @@
#include "string-util.h"
#include "strv.h"
#include "time-util.h"
+#include "unit-def.h"
#include "unit-name.h"
#include "verbs.h"
@@ -159,6 +161,29 @@ void time_parsing_hint(const char *p, bool calendar, bool timestamp, bool timesp
"Use 'systemd-analyze timespan \"%s\"' instead?", p);
}
+static int verb_transient_settings(int argc, char *argv[], void *userdata) {
+ assert(argc >= 2);
+
+ pager_open(arg_pager_flags);
+
+ bool first = true;
+ STRV_FOREACH(arg, strv_skip(argv, 1)) {
+ UnitType t;
+
+ t = unit_type_from_string(*arg);
+ if (t < 0)
+ return log_error_errno(t, "Invalid unit type '%s'.", *arg);
+
+ if (!first)
+ puts("");
+
+ bus_dump_transient_settings(t);
+ first = false;
+ }
+
+ return 0;
+}
+
static int help(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *link = NULL, *dot_link = NULL;
int r;
@@ -200,6 +225,7 @@ static int help(int argc, char *argv[], void *userdata) {
" architectures [NAME...] List known architectures\n"
" smbios11 List strings passed via SMBIOS Type #11\n"
" chid List local CHIDs\n"
+ " transient-settings TYPE... List transient settings for unit TYPE\n"
"\n%3$sExpression Evaluation:%4$s\n"
" condition CONDITION... Evaluate conditions and asserts\n"
" compare-versions VERSION1 [OP] VERSION2\n"
@@ -639,46 +665,47 @@ static int run(int argc, char *argv[]) {
_cleanup_(umount_and_freep) char *mounted_dir = NULL;
static const Verb verbs[] = {
- { "help", VERB_ANY, VERB_ANY, 0, help },
- { "time", VERB_ANY, 1, VERB_DEFAULT, verb_time },
- { "blame", VERB_ANY, 1, 0, verb_blame },
- { "critical-chain", VERB_ANY, VERB_ANY, 0, verb_critical_chain },
- { "plot", VERB_ANY, 1, 0, verb_plot },
- { "dot", VERB_ANY, VERB_ANY, 0, verb_dot },
+ { "help", VERB_ANY, VERB_ANY, 0, help },
+ { "time", VERB_ANY, 1, VERB_DEFAULT, verb_time },
+ { "blame", VERB_ANY, 1, 0, verb_blame },
+ { "critical-chain", VERB_ANY, VERB_ANY, 0, verb_critical_chain },
+ { "plot", VERB_ANY, 1, 0, verb_plot },
+ { "dot", VERB_ANY, VERB_ANY, 0, verb_dot },
/* ↓ The following seven verbs are deprecated, from here … ↓ */
- { "log-level", VERB_ANY, 2, 0, verb_log_control },
- { "log-target", VERB_ANY, 2, 0, verb_log_control },
- { "set-log-level", 2, 2, 0, verb_log_control },
- { "get-log-level", VERB_ANY, 1, 0, verb_log_control },
- { "set-log-target", 2, 2, 0, verb_log_control },
- { "get-log-target", VERB_ANY, 1, 0, verb_log_control },
- { "service-watchdogs", VERB_ANY, 2, 0, verb_service_watchdogs },
+ { "log-level", VERB_ANY, 2, 0, verb_log_control },
+ { "log-target", VERB_ANY, 2, 0, verb_log_control },
+ { "set-log-level", 2, 2, 0, verb_log_control },
+ { "get-log-level", VERB_ANY, 1, 0, verb_log_control },
+ { "set-log-target", 2, 2, 0, verb_log_control },
+ { "get-log-target", VERB_ANY, 1, 0, verb_log_control },
+ { "service-watchdogs", VERB_ANY, 2, 0, verb_service_watchdogs },
/* ↑ … until here ↑ */
- { "dump", VERB_ANY, VERB_ANY, 0, verb_dump },
- { "cat-config", 2, VERB_ANY, 0, verb_cat_config },
- { "unit-files", VERB_ANY, VERB_ANY, 0, verb_unit_files },
- { "unit-paths", 1, 1, 0, verb_unit_paths },
- { "exit-status", VERB_ANY, VERB_ANY, 0, verb_exit_status },
- { "syscall-filter", VERB_ANY, VERB_ANY, 0, verb_syscall_filters },
- { "capability", VERB_ANY, VERB_ANY, 0, verb_capabilities },
- { "filesystems", VERB_ANY, VERB_ANY, 0, verb_filesystems },
- { "condition", VERB_ANY, VERB_ANY, 0, verb_condition },
- { "compare-versions", 3, 4, 0, verb_compare_versions },
- { "verify", 2, VERB_ANY, 0, verb_verify },
- { "calendar", 2, VERB_ANY, 0, verb_calendar },
- { "timestamp", 2, VERB_ANY, 0, verb_timestamp },
- { "timespan", 2, VERB_ANY, 0, verb_timespan },
- { "security", VERB_ANY, VERB_ANY, 0, verb_security },
- { "inspect-elf", 2, VERB_ANY, 0, verb_elf_inspection },
- { "malloc", VERB_ANY, VERB_ANY, 0, verb_malloc },
- { "fdstore", 2, VERB_ANY, 0, verb_fdstore },
- { "image-policy", 2, 2, 0, verb_image_policy },
- { "has-tpm2", VERB_ANY, 1, 0, verb_has_tpm2 },
- { "pcrs", VERB_ANY, VERB_ANY, 0, verb_pcrs },
- { "srk", VERB_ANY, 1, 0, verb_srk },
- { "architectures", VERB_ANY, VERB_ANY, 0, verb_architectures },
- { "smbios11", VERB_ANY, 1, 0, verb_smbios11 },
- { "chid", VERB_ANY, VERB_ANY, 0, verb_chid },
+ { "dump", VERB_ANY, VERB_ANY, 0, verb_dump },
+ { "cat-config", 2, VERB_ANY, 0, verb_cat_config },
+ { "unit-files", VERB_ANY, VERB_ANY, 0, verb_unit_files },
+ { "unit-paths", 1, 1, 0, verb_unit_paths },
+ { "exit-status", VERB_ANY, VERB_ANY, 0, verb_exit_status },
+ { "syscall-filter", VERB_ANY, VERB_ANY, 0, verb_syscall_filters },
+ { "capability", VERB_ANY, VERB_ANY, 0, verb_capabilities },
+ { "filesystems", VERB_ANY, VERB_ANY, 0, verb_filesystems },
+ { "condition", VERB_ANY, VERB_ANY, 0, verb_condition },
+ { "compare-versions", 3, 4, 0, verb_compare_versions },
+ { "verify", 2, VERB_ANY, 0, verb_verify },
+ { "calendar", 2, VERB_ANY, 0, verb_calendar },
+ { "timestamp", 2, VERB_ANY, 0, verb_timestamp },
+ { "timespan", 2, VERB_ANY, 0, verb_timespan },
+ { "security", VERB_ANY, VERB_ANY, 0, verb_security },
+ { "inspect-elf", 2, VERB_ANY, 0, verb_elf_inspection },
+ { "malloc", VERB_ANY, VERB_ANY, 0, verb_malloc },
+ { "fdstore", 2, VERB_ANY, 0, verb_fdstore },
+ { "image-policy", 2, 2, 0, verb_image_policy },
+ { "has-tpm2", VERB_ANY, 1, 0, verb_has_tpm2 },
+ { "pcrs", VERB_ANY, VERB_ANY, 0, verb_pcrs },
+ { "srk", VERB_ANY, 1, 0, verb_srk },
+ { "architectures", VERB_ANY, VERB_ANY, 0, verb_architectures },
+ { "smbios11", VERB_ANY, 1, 0, verb_smbios11 },
+ { "chid", VERB_ANY, VERB_ANY, 0, verb_chid },
+ { "transient-settings", 2, VERB_ANY, 0, verb_transient_settings },
{}
};
diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c
index 8073925b4a..54d845a87b 100644
--- a/src/basic/cgroup-util.c
+++ b/src/basic/cgroup-util.c
@@ -2048,34 +2048,38 @@ int cg_has_coredump_receive(const char *path) {
}
const uint64_t cgroup_io_limit_defaults[_CGROUP_IO_LIMIT_TYPE_MAX] = {
- [CGROUP_IO_RBPS_MAX] = CGROUP_LIMIT_MAX,
- [CGROUP_IO_WBPS_MAX] = CGROUP_LIMIT_MAX,
- [CGROUP_IO_RIOPS_MAX] = CGROUP_LIMIT_MAX,
- [CGROUP_IO_WIOPS_MAX] = CGROUP_LIMIT_MAX,
+ [CGROUP_IO_RBPS_MAX] = CGROUP_LIMIT_MAX,
+ [CGROUP_IO_WBPS_MAX] = CGROUP_LIMIT_MAX,
+ [CGROUP_IO_RIOPS_MAX] = CGROUP_LIMIT_MAX,
+ [CGROUP_IO_WIOPS_MAX] = CGROUP_LIMIT_MAX,
};
static const char* const cgroup_io_limit_type_table[_CGROUP_IO_LIMIT_TYPE_MAX] = {
- [CGROUP_IO_RBPS_MAX] = "IOReadBandwidthMax",
- [CGROUP_IO_WBPS_MAX] = "IOWriteBandwidthMax",
- [CGROUP_IO_RIOPS_MAX] = "IOReadIOPSMax",
- [CGROUP_IO_WIOPS_MAX] = "IOWriteIOPSMax",
+ [CGROUP_IO_RBPS_MAX] = "IOReadBandwidthMax",
+ [CGROUP_IO_WBPS_MAX] = "IOWriteBandwidthMax",
+ [CGROUP_IO_RIOPS_MAX] = "IOReadIOPSMax",
+ [CGROUP_IO_WIOPS_MAX] = "IOWriteIOPSMax",
};
DEFINE_STRING_TABLE_LOOKUP(cgroup_io_limit_type, CGroupIOLimitType);
+void cgroup_io_limits_list(void) {
+ DUMP_STRING_TABLE(cgroup_io_limit_type, CGroupIOLimitType, _CGROUP_IO_LIMIT_TYPE_MAX);
+}
+
static const char *const cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = {
- [CGROUP_CONTROLLER_CPU] = "cpu",
- [CGROUP_CONTROLLER_CPUACCT] = "cpuacct",
- [CGROUP_CONTROLLER_CPUSET] = "cpuset",
- [CGROUP_CONTROLLER_IO] = "io",
- [CGROUP_CONTROLLER_BLKIO] = "blkio",
- [CGROUP_CONTROLLER_MEMORY] = "memory",
- [CGROUP_CONTROLLER_DEVICES] = "devices",
- [CGROUP_CONTROLLER_PIDS] = "pids",
- [CGROUP_CONTROLLER_BPF_FIREWALL] = "bpf-firewall",
- [CGROUP_CONTROLLER_BPF_DEVICES] = "bpf-devices",
- [CGROUP_CONTROLLER_BPF_FOREIGN] = "bpf-foreign",
- [CGROUP_CONTROLLER_BPF_SOCKET_BIND] = "bpf-socket-bind",
+ [CGROUP_CONTROLLER_CPU] = "cpu",
+ [CGROUP_CONTROLLER_CPUACCT] = "cpuacct",
+ [CGROUP_CONTROLLER_CPUSET] = "cpuset",
+ [CGROUP_CONTROLLER_IO] = "io",
+ [CGROUP_CONTROLLER_BLKIO] = "blkio",
+ [CGROUP_CONTROLLER_MEMORY] = "memory",
+ [CGROUP_CONTROLLER_DEVICES] = "devices",
+ [CGROUP_CONTROLLER_PIDS] = "pids",
+ [CGROUP_CONTROLLER_BPF_FIREWALL] = "bpf-firewall",
+ [CGROUP_CONTROLLER_BPF_DEVICES] = "bpf-devices",
+ [CGROUP_CONTROLLER_BPF_FOREIGN] = "bpf-foreign",
+ [CGROUP_CONTROLLER_BPF_SOCKET_BIND] = "bpf-socket-bind",
[CGROUP_CONTROLLER_BPF_RESTRICT_NETWORK_INTERFACES] = "bpf-restrict-network-interfaces",
};
diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h
index 2dea0ebdc4..ac0c7d8c41 100644
--- a/src/basic/cgroup-util.h
+++ b/src/basic/cgroup-util.h
@@ -97,6 +97,7 @@ extern const uint64_t cgroup_io_limit_defaults[_CGROUP_IO_LIMIT_TYPE_MAX];
const char* cgroup_io_limit_type_to_string(CGroupIOLimitType t) _const_;
CGroupIOLimitType cgroup_io_limit_type_from_string(const char *s) _pure_;
+void cgroup_io_limits_list(void);
/* Special values for the io.bfq.weight attribute */
#define CGROUP_BFQ_WEIGHT_INVALID UINT64_MAX
diff --git a/src/basic/macro.h b/src/basic/macro.h
index caefa7c57c..3ddc5272b8 100644
--- a/src/basic/macro.h
+++ b/src/basic/macro.h
@@ -152,7 +152,7 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
} while (false)
#define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL }))
-#define STRV_MAKE_EMPTY ((char*[1]) { NULL })
+#define STRV_EMPTY ((char*[1]) { NULL })
#define STRV_MAKE_CONST(...) ((const char* const*) ((const char*[]) { __VA_ARGS__, NULL }))
/* Pointers range from NULL to POINTER_MAX */
diff --git a/src/basic/rlimit-util.c b/src/basic/rlimit-util.c
index 803eaa09b2..22fd86301c 100644
--- a/src/basic/rlimit-util.c
+++ b/src/basic/rlimit-util.c
@@ -343,6 +343,11 @@ static const char* const rlimit_table[_RLIMIT_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(rlimit, int);
+void rlimits_list(const char *prefix) {
+ FOREACH_ELEMENT(field, rlimit_table)
+ printf("%s%s\n", strempty(prefix), *field);
+}
+
int rlimit_from_string_harder(const char *s) {
const char *suffix;
diff --git a/src/basic/rlimit-util.h b/src/basic/rlimit-util.h
index 52ec8bd320..8b600fe1d2 100644
--- a/src/basic/rlimit-util.h
+++ b/src/basic/rlimit-util.h
@@ -10,6 +10,7 @@
const char* rlimit_to_string(int i) _const_;
int rlimit_from_string(const char *s) _pure_;
int rlimit_from_string_harder(const char *s) _pure_;
+void rlimits_list(const char *prefix);
int setrlimit_closest(int resource, const struct rlimit *rlim);
int setrlimit_closest_all(const struct rlimit * const *rlim, int *which_failed);
diff --git a/src/basic/unit-def.c b/src/basic/unit-def.c
index 8bc5f56532..f98cfd4ae1 100644
--- a/src/basic/unit-def.c
+++ b/src/basic/unit-def.c
@@ -1,5 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#include
+
#include "alloc-util.h"
#include "bus-label.h"
#include "glyph-util.h"
@@ -331,6 +333,10 @@ static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(unit_dependency, UnitDependency);
+void unit_types_list(void) {
+ DUMP_STRING_TABLE(unit_dependency, UnitDependency, _UNIT_DEPENDENCY_MAX);
+}
+
static const char* const notify_access_table[_NOTIFY_ACCESS_MAX] = {
[NOTIFY_NONE] = "none",
[NOTIFY_MAIN] = "main",
diff --git a/src/basic/unit-def.h b/src/basic/unit-def.h
index fd55950ea6..7664f2881a 100644
--- a/src/basic/unit-def.h
+++ b/src/basic/unit-def.h
@@ -304,6 +304,7 @@ const char* unit_dbus_interface_from_name(const char *name);
const char* unit_type_to_string(UnitType i) _const_;
UnitType unit_type_from_string(const char *s) _pure_;
+void unit_types_list(void);
const char* unit_load_state_to_string(UnitLoadState i) _const_;
UnitLoadState unit_load_state_from_string(const char *s) _pure_;
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index cc0449dd96..c5e02a912f 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -71,7 +71,7 @@ int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
&u->job_path);
}
-static int warn_deprecated(const char *field, const char *eq) {
+static int warn_deprecated(_unused_ sd_bus_message *m, const char *field, const char *eq) {
log_warning("D-Bus property %s is deprecated, ignoring assignment: %s=%s", field, field, eq);
return 1;
}
@@ -125,6 +125,7 @@ DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string);
DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string);
DEFINE_BUS_APPEND_PARSE("i", signal_from_string);
DEFINE_BUS_APPEND_PARSE("i", parse_ip_protocol);
+DEFINE_BUS_APPEND_PARSE("i", mpol_from_string);
DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority);
DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice);
DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi);
@@ -148,7 +149,7 @@ static int bus_append_string(sd_bus_message *m, const char *field, const char *e
return 1;
}
-static int bus_append_strv(sd_bus_message *m, const char *field, const char *eq, const char *separator, ExtractFlags flags) {
+static int bus_append_strv_full(sd_bus_message *m, const char *field, const char *eq, ExtractFlags flags) {
int r;
assert(m);
@@ -173,7 +174,7 @@ static int bus_append_strv(sd_bus_message *m, const char *field, const char *eq,
for (const char *p = eq;;) {
_cleanup_free_ char *word = NULL;
- r = extract_first_word(&p, &word, separator, flags);
+ r = extract_first_word(&p, &word, /* separators= */ NULL, flags);
if (r == -ENOMEM)
return log_oom();
if (r < 0)
@@ -201,6 +202,14 @@ static int bus_append_strv(sd_bus_message *m, const char *field, const char *eq,
return 1;
}
+static int bus_append_strv(sd_bus_message *m, const char *field, const char *eq) {
+ return bus_append_strv_full(m, field, eq, EXTRACT_UNQUOTE);
+}
+
+static int bus_append_strv_cunescape(sd_bus_message *m, const char *field, const char *eq) {
+ return bus_append_strv_full(m, field, eq, EXTRACT_UNQUOTE | EXTRACT_CUNESCAPE);
+}
+
static int bus_append_byte_array(sd_bus_message *m, const char *field, const void *buf, size_t n) {
int r;
@@ -253,11 +262,15 @@ static int bus_append_parse_sec_rename(sd_bus_message *m, const char *field, con
return 1;
}
-static int bus_append_parse_size(sd_bus_message *m, const char *field, const char *eq, uint64_t base) {
+static int bus_append_parse_sec_rename_infinity(sd_bus_message *m, const char *field, const char *eq) {
+ return bus_append_parse_sec_rename(m, field, isempty(eq) ? "infinity" : eq);
+}
+
+static int bus_append_parse_size(sd_bus_message *m, const char *field, const char *eq) {
uint64_t v;
int r;
- r = parse_size(eq, base, &v);
+ r = parse_size(eq, /* base= */ 1024, &v);
if (r < 0)
return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
@@ -268,6 +281,284 @@ static int bus_append_parse_size(sd_bus_message *m, const char *field, const cha
return 1;
}
+static int bus_append_parse_permyriad(sd_bus_message *m, const char *field, const char *eq) {
+ int r;
+
+ r = parse_permyriad(eq);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
+
+ /* Pass around scaled to 2^32-1 == 100% */
+ r = sd_bus_message_append(m, "(sv)", field, "u", UINT32_SCALE_FROM_PERMYRIAD(r));
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
+static int bus_append_parse_cpu_set(sd_bus_message *m, const char *field, const char *eq) {
+ _cleanup_(cpu_set_done) CPUSet cpuset = {};
+ _cleanup_free_ uint8_t *array = NULL;
+ size_t allocated;
+ int r;
+
+ r = parse_cpu_set(eq, &cpuset);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
+
+ r = cpu_set_to_dbus(&cpuset, &array, &allocated);
+ if (r < 0)
+ return log_error_errno(r, "Failed to serialize %s: %m", field);
+
+ return bus_append_byte_array(m, field, array, allocated);
+}
+
+static int bus_append_parse_delegate(sd_bus_message *m, const char *field, const char *eq) {
+ int r;
+
+ r = parse_boolean(eq);
+ if (r < 0)
+ return bus_append_strv(m, "DelegateControllers", eq);
+
+ r = sd_bus_message_append(m, "(sv)", "Delegate", "b", r);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
+static int bus_append_parse_resource_limit(sd_bus_message *m, const char *field, const char *eq) {
+ int r;
+
+ if (isempty(eq) || streq(eq, "infinity")) {
+ uint64_t x = streq(eq, "infinity") ? CGROUP_LIMIT_MAX :
+ STR_IN_SET(field,
+ "DefaultMemoryLow",
+ "DefaultMemoryMin",
+ "MemoryLow",
+ "MemoryMin") ? CGROUP_LIMIT_MIN : CGROUP_LIMIT_MAX;
+
+ r = sd_bus_message_append(m, "(sv)", field, "t", x);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+ }
+
+ r = parse_permyriad(eq);
+ if (r >= 0) {
+ char *n;
+
+ /* When this is a percentage we'll convert this into a relative value in the range
+ * 0…UINT32_MAX and pass it in the MemoryLowScale property (and related ones). This
+ * way the physical memory size can be determined server-side. */
+
+ n = strjoina(field, "Scale");
+ r = sd_bus_message_append(m, "(sv)", n, "u", UINT32_SCALE_FROM_PERMYRIAD(r));
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+ }
+
+ if (streq(field, "TasksMax"))
+ return bus_append_safe_atou64(m, field, eq);
+
+ return bus_append_parse_size(m, field, eq);
+}
+
+static int bus_append_parse_cpu_quota(sd_bus_message *m, const char *field, const char *eq) {
+ uint64_t x;
+ int r;
+
+ if (isempty(eq))
+ x = USEC_INFINITY;
+ else {
+ r = parse_permyriad_unbounded(eq);
+ if (r == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "%s value too small.", field);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
+ x = r * USEC_PER_SEC / 10000U;
+ }
+
+ r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", x);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
+static int bus_append_parse_device_allow(sd_bus_message *m, const char *field, const char *eq) {
+ int r;
+
+ if (isempty(eq))
+ r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0);
+ else {
+ _cleanup_free_ char *_path = NULL;
+ const char *path = eq, *rwm = NULL, *e;
+
+ e = strchr(eq, ' ');
+ if (e) {
+ path = _path = strndup(eq, e - eq);
+ if (!path)
+ return log_oom();
+
+ rwm = e + 1;
+ }
+
+ r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, path, strempty(rwm));
+ }
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
+static int bus_try_append_parse_cgroup_io_limit(sd_bus_message *m, const char *field, const char *eq) {
+ int r;
+
+ if (cgroup_io_limit_type_from_string(field) < 0)
+ return 0;
+
+ if (isempty(eq))
+ r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
+ else {
+ const char *e = strchr(eq, ' ');
+ if (!e)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Failed to parse %s value %s.",
+ field, eq);
+
+ const char *bandwidth = e + 1;
+ _cleanup_free_ char *path = strndup(eq, e - eq);
+ if (!path)
+ return log_oom();
+
+ uint64_t bytes;
+ if (streq(bandwidth, "infinity"))
+ bytes = CGROUP_LIMIT_MAX;
+ else {
+ r = parse_size(bandwidth, 1000, &bytes);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse byte value %s: %m", bandwidth);
+ }
+
+ r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, bytes);
+ }
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
+static int bus_append_parse_io_device_weight(sd_bus_message *m, const char *field, const char *eq) {
+ int r;
+
+ if (isempty(eq))
+ r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
+ else {
+ const char *e = strchr(eq, ' ');
+ if (!e)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Failed to parse %s value %s.",
+ field, eq);
+
+ const char *weight = e + 1;
+ _cleanup_free_ char *path = strndup(eq, e - eq);
+ if (!path)
+ return log_oom();
+
+ uint64_t u;
+ r = safe_atou64(weight, &u);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value %s: %m", field, weight);
+
+ r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, u);
+ }
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
+static int bus_append_parse_io_device_latency(sd_bus_message *m, const char *field, const char *eq) {
+ const char *field_usec = "IODeviceLatencyTargetUSec";
+ int r;
+
+ if (isempty(eq))
+ r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", 0);
+ else {
+ const char *e = strchr(eq, ' ');
+ if (!e)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Failed to parse %s value %s.",
+ field, eq);
+
+ const char *target = e + 1;
+ _cleanup_free_ char *path = strndup(eq, e - eq);
+ if (!path)
+ return log_oom();
+
+ usec_t usec;
+ r = parse_sec(target, &usec);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value %s: %m", field, target);
+
+ r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", 1, path, usec);
+ }
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
+static int bus_append_bpf_program(sd_bus_message *m, const char *field, const char *eq) {
+ int r;
+
+ if (isempty(eq))
+ r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0);
+ else {
+ _cleanup_free_ char *word = NULL;
+
+ r = extract_first_word(&eq, &word, ":", 0);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s: %m", field);
+
+ r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, word, eq);
+ }
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
+static int bus_append_socket_filter(sd_bus_message *m, const char *field, const char *eq) {
+ int r;
+
+ if (isempty(eq))
+ r = sd_bus_message_append(m, "(sv)", field, "a(iiqq)", 0);
+ else {
+ int32_t family, ip_protocol;
+ uint16_t nr_ports, port_min;
+
+ r = parse_socket_bind_item(eq, &family, &ip_protocol, &nr_ports, &port_min);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s", field);
+
+ r = sd_bus_message_append(
+ m, "(sv)", field, "a(iiqq)", 1, family, ip_protocol, nr_ports, port_min);
+ }
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
static int bus_append_exec_command(sd_bus_message *m, const char *field, const char *eq) {
bool explicit_path = false, done = false, ambient_hack = false;
_cleanup_strv_free_ char **l = NULL, **ex_opts = NULL;
@@ -485,6 +776,141 @@ static int bus_append_ip_address_access(sd_bus_message *m, int family, const uni
return sd_bus_message_close_container(m);
}
+static int bus_append_parse_ip_address_filter(sd_bus_message *m, const char *field, const char *eq) {
+ union in_addr_union prefix = {};
+ unsigned char prefixlen;
+ int family, r;
+
+ if (isempty(eq)) {
+ r = sd_bus_message_append(m, "(sv)", field, "a(iayu)", 0);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+ }
+
+ r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'v', "a(iayu)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'a', "(iayu)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ if (streq(eq, "any")) {
+ /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
+
+ r = bus_append_ip_address_access(m, AF_INET, &prefix, 0);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = bus_append_ip_address_access(m, AF_INET6, &prefix, 0);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ } else if (is_localhost(eq)) {
+ /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
+
+ prefix.in.s_addr = htobe32(0x7f000000);
+ r = bus_append_ip_address_access(m, AF_INET, &prefix, 8);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ prefix.in6 = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
+ r = bus_append_ip_address_access(m, AF_INET6, &prefix, 128);
+ if (r < 0)
+ return r;
+
+ } else if (streq(eq, "link-local")) {
+ /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
+
+ prefix.in.s_addr = htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
+ r = bus_append_ip_address_access(m, AF_INET, &prefix, 16);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ prefix.in6 = (struct in6_addr) {
+ .s6_addr32[0] = htobe32(0xfe800000)
+ };
+ r = bus_append_ip_address_access(m, AF_INET6, &prefix, 64);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ } else if (streq(eq, "multicast")) {
+ /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
+
+ prefix.in.s_addr = htobe32((UINT32_C(224) << 24));
+ r = bus_append_ip_address_access(m, AF_INET, &prefix, 4);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ prefix.in6 = (struct in6_addr) {
+ .s6_addr32[0] = htobe32(0xff000000)
+ };
+ r = bus_append_ip_address_access(m, AF_INET6, &prefix, 8);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ } else
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+
+ r = extract_first_word(&eq, &word, NULL, 0);
+ if (r == 0)
+ break;
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s: %s", field, eq);
+
+ r = in_addr_prefix_from_string_auto(word, &family, &prefix, &prefixlen);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse IP address prefix: %s", word);
+
+ r = bus_append_ip_address_access(m, family, &prefix, prefixlen);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
+#define bus_append_trivial_array(m, field, eq, types, ...) \
+ ({ \
+ int r; \
+ \
+ if (isempty(eq)) \
+ r = sd_bus_message_append(m, "(sv)", field, types, 0); \
+ else \
+ r = sd_bus_message_append(m, "(sv)", field, types, 1, __VA_ARGS__); \
+ r < 0 ? bus_log_create_error(r) : 1; \
+ })
+
+static int bus_append_ip_filter_path(sd_bus_message *m, const char *field, const char *eq) {
+ return bus_append_trivial_array(m, field, eq,
+ "as", eq);
+}
+
static int bus_append_nft_set(sd_bus_message *m, const char *field, const char *eq) {
int r;
@@ -570,1744 +996,1104 @@ static int bus_append_nft_set(sd_bus_message *m, const char *field, const char *
return 1;
}
-static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) {
- int r;
-
- if (STR_IN_SET(field, "DevicePolicy",
- "Slice",
- "ManagedOOMSwap",
- "ManagedOOMMemoryPressure",
- "ManagedOOMPreference",
- "MemoryPressureWatch",
- "DelegateSubgroup"))
- return bus_append_string(m, field, eq);
-
- if (STR_IN_SET(field, "ManagedOOMMemoryPressureLimit")) {
- r = parse_permyriad(eq);
- if (r < 0)
- return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
-
- /* Pass around scaled to 2^32-1 == 100% */
- r = sd_bus_message_append(m, "(sv)", field, "u", UINT32_SCALE_FROM_PERMYRIAD(r));
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (STR_IN_SET(field, "MemoryAccounting",
- "MemoryZSwapWriteback",
- "IOAccounting",
- "TasksAccounting",
- "IPAccounting",
- "CoredumpReceive"))
- return bus_append_parse_boolean(m, field, eq);
-
- if (STR_IN_SET(field, "CPUWeight",
- "StartupCPUWeight"))
- return bus_append_cg_cpu_weight_parse(m, field, eq);
-
- if (STR_IN_SET(field, "IOWeight",
- "StartupIOWeight"))
- return bus_append_cg_weight_parse(m, field, eq);
-
- if (STR_IN_SET(field, "AllowedCPUs",
- "StartupAllowedCPUs",
- "AllowedMemoryNodes",
- "StartupAllowedMemoryNodes")) {
-
- _cleanup_(cpu_set_done) CPUSet cpuset = {};
- _cleanup_free_ uint8_t *array = NULL;
- size_t allocated;
-
- r = parse_cpu_set(eq, &cpuset);
- if (r < 0)
- return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
-
- r = cpu_set_to_dbus(&cpuset, &array, &allocated);
- if (r < 0)
- return log_error_errno(r, "Failed to serialize CPUSet: %m");
-
- return bus_append_byte_array(m, field, array, allocated);
- }
-
- if (streq(field, "DisableControllers"))
- return bus_append_strv(m, "DisableControllers", eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
-
- if (streq(field, "Delegate")) {
- r = parse_boolean(eq);
- if (r < 0)
- return bus_append_strv(m, "DelegateControllers", eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
-
- r = sd_bus_message_append(m, "(sv)", "Delegate", "b", r);
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (STR_IN_SET(field, "MemoryMin",
- "DefaultMemoryLow",
- "DefaultMemoryMin",
- "MemoryLow",
- "MemoryHigh",
- "MemoryMax",
- "MemorySwapMax",
- "MemoryZSwapMax",
- "TasksMax")) {
-
- if (streq(eq, "infinity")) {
- r = sd_bus_message_append(m, "(sv)", field, "t", CGROUP_LIMIT_MAX);
- if (r < 0)
- return bus_log_create_error(r);
- return 1;
- } else if (isempty(eq)) {
- uint64_t empty_value = STR_IN_SET(field,
- "DefaultMemoryLow",
- "DefaultMemoryMin",
- "MemoryLow",
- "MemoryMin") ?
- CGROUP_LIMIT_MIN :
- CGROUP_LIMIT_MAX;
-
- r = sd_bus_message_append(m, "(sv)", field, "t", empty_value);
- if (r < 0)
- return bus_log_create_error(r);
- return 1;
- }
-
- r = parse_permyriad(eq);
- if (r >= 0) {
- char *n;
-
- /* When this is a percentage we'll convert this into a relative value in the range
- * 0…UINT32_MAX and pass it in the MemoryLowScale property (and related ones). This
- * way the physical memory size can be determined server-side. */
-
- n = strjoina(field, "Scale");
- r = sd_bus_message_append(m, "(sv)", n, "u", UINT32_SCALE_FROM_PERMYRIAD(r));
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (streq(field, "TasksMax"))
- return bus_append_safe_atou64(m, field, eq);
-
- return bus_append_parse_size(m, field, eq, 1024);
- }
-
- if (streq(field, "CPUQuota")) {
- if (isempty(eq))
- r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY);
- else {
- r = parse_permyriad_unbounded(eq);
- if (r == 0)
- return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "CPU quota too small.");
- if (r < 0)
- return log_error_errno(r, "CPU quota '%s' invalid.", eq);
-
- r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r * USEC_PER_SEC) / 10000U));
- }
-
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (streq(field, "CPUQuotaPeriodSec")) {
- usec_t u = USEC_INFINITY;
-
- r = parse_sec_def_infinity(eq, &u);
- if (r < 0)
- return log_error_errno(r, "CPU quota period '%s' invalid.", eq);
-
- r = sd_bus_message_append(m, "(sv)", "CPUQuotaPeriodUSec", "t", u);
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (streq(field, "DeviceAllow")) {
- if (isempty(eq))
- r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0);
- else {
- const char *path = eq, *rwm = NULL, *e;
-
- e = strchr(eq, ' ');
- if (e) {
- path = strndupa_safe(eq, e - eq);
- rwm = e+1;
- }
-
- r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, path, strempty(rwm));
- }
-
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (cgroup_io_limit_type_from_string(field) >= 0) {
-
- if (isempty(eq))
- r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
- else {
- const char *path, *bandwidth, *e;
- uint64_t bytes;
-
- e = strchr(eq, ' ');
- if (!e)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Failed to parse %s value %s.",
- field, eq);
-
- path = strndupa_safe(eq, e - eq);
- bandwidth = e+1;
-
- if (streq(bandwidth, "infinity"))
- bytes = CGROUP_LIMIT_MAX;
- else {
- r = parse_size(bandwidth, 1000, &bytes);
- if (r < 0)
- return log_error_errno(r, "Failed to parse byte value %s: %m", bandwidth);
- }
-
- r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, bytes);
- }
-
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (streq(field, "IODeviceWeight")) {
- if (isempty(eq))
- r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
- else {
- const char *path, *weight, *e;
- uint64_t u;
-
- e = strchr(eq, ' ');
- if (!e)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Failed to parse %s value %s.",
- field, eq);
-
- path = strndupa_safe(eq, e - eq);
- weight = e+1;
-
- r = safe_atou64(weight, &u);
- if (r < 0)
- return log_error_errno(r, "Failed to parse %s value %s: %m", field, weight);
-
- r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, u);
- }
-
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (streq(field, "IODeviceLatencyTargetSec")) {
- const char *field_usec = "IODeviceLatencyTargetUSec";
-
- if (isempty(eq))
- r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", USEC_INFINITY);
- else {
- const char *path, *target, *e;
- usec_t usec;
-
- e = strchr(eq, ' ');
- if (!e)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Failed to parse %s value %s.",
- field, eq);
-
- path = strndupa_safe(eq, e - eq);
- target = e+1;
-
- r = parse_sec(target, &usec);
- if (r < 0)
- return log_error_errno(r, "Failed to parse %s value %s: %m", field, target);
-
- r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", 1, path, usec);
- }
-
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (STR_IN_SET(field, "IPAddressAllow",
- "IPAddressDeny")) {
- unsigned char prefixlen;
- union in_addr_union prefix = {};
- int family;
-
- if (isempty(eq)) {
- r = sd_bus_message_append(m, "(sv)", field, "a(iayu)", 0);
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'v', "a(iayu)");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'a', "(iayu)");
- if (r < 0)
- return bus_log_create_error(r);
-
- if (streq(eq, "any")) {
- /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
-
- r = bus_append_ip_address_access(m, AF_INET, &prefix, 0);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = bus_append_ip_address_access(m, AF_INET6, &prefix, 0);
- if (r < 0)
- return bus_log_create_error(r);
-
- } else if (is_localhost(eq)) {
- /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
-
- prefix.in.s_addr = htobe32(0x7f000000);
- r = bus_append_ip_address_access(m, AF_INET, &prefix, 8);
- if (r < 0)
- return bus_log_create_error(r);
-
- prefix.in6 = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
- r = bus_append_ip_address_access(m, AF_INET6, &prefix, 128);
- if (r < 0)
- return r;
-
- } else if (streq(eq, "link-local")) {
- /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
-
- prefix.in.s_addr = htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
- r = bus_append_ip_address_access(m, AF_INET, &prefix, 16);
- if (r < 0)
- return bus_log_create_error(r);
-
- prefix.in6 = (struct in6_addr) {
- .s6_addr32[0] = htobe32(0xfe800000)
- };
- r = bus_append_ip_address_access(m, AF_INET6, &prefix, 64);
- if (r < 0)
- return bus_log_create_error(r);
-
- } else if (streq(eq, "multicast")) {
- /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
-
- prefix.in.s_addr = htobe32((UINT32_C(224) << 24));
- r = bus_append_ip_address_access(m, AF_INET, &prefix, 4);
- if (r < 0)
- return bus_log_create_error(r);
-
- prefix.in6 = (struct in6_addr) {
- .s6_addr32[0] = htobe32(0xff000000)
- };
- r = bus_append_ip_address_access(m, AF_INET6, &prefix, 8);
- if (r < 0)
- return bus_log_create_error(r);
-
- } else {
- for (;;) {
- _cleanup_free_ char *word = NULL;
-
- r = extract_first_word(&eq, &word, NULL, 0);
- if (r == 0)
- break;
- if (r == -ENOMEM)
- return log_oom();
- if (r < 0)
- return log_error_errno(r, "Failed to parse %s: %s", field, eq);
-
- r = in_addr_prefix_from_string_auto(word, &family, &prefix, &prefixlen);
- if (r < 0)
- return log_error_errno(r, "Failed to parse IP address prefix: %s", word);
-
- r = bus_append_ip_address_access(m, family, &prefix, prefixlen);
- if (r < 0)
- return bus_log_create_error(r);
- }
- }
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (STR_IN_SET(field, "IPIngressFilterPath",
- "IPEgressFilterPath")) {
- if (isempty(eq))
- r = sd_bus_message_append(m, "(sv)", field, "as", 0);
- else
- r = sd_bus_message_append(m, "(sv)", field, "as", 1, eq);
-
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (streq(field, "BPFProgram")) {
- if (isempty(eq))
- r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0);
- else {
- _cleanup_free_ char *word = NULL;
-
- r = extract_first_word(&eq, &word, ":", 0);
- if (r == -ENOMEM)
- return log_oom();
- if (r < 0)
- return log_error_errno(r, "Failed to parse %s: %m", field);
-
- r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, word, eq);
- }
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (STR_IN_SET(field, "SocketBindAllow",
- "SocketBindDeny")) {
- if (isempty(eq))
- r = sd_bus_message_append(m, "(sv)", field, "a(iiqq)", 0);
- else {
- int32_t family, ip_protocol;
- uint16_t nr_ports, port_min;
-
- r = parse_socket_bind_item(eq, &family, &ip_protocol, &nr_ports, &port_min);
- if (r == -ENOMEM)
- return log_oom();
- if (r < 0)
- return log_error_errno(r, "Failed to parse %s", field);
-
- r = sd_bus_message_append(
- m, "(sv)", field, "a(iiqq)", 1, family, ip_protocol, nr_ports, port_min);
- }
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (streq(field, "MemoryPressureThresholdSec"))
- return bus_append_parse_sec_rename(m, field, eq);
-
- if (streq(field, "NFTSet"))
- return bus_append_nft_set(m, field, eq);
-
- if (streq(field, "ManagedOOMMemoryPressureDurationSec"))
- /* While infinity is disallowed in unit file, infinity is allowed in D-Bus API which
- * means use the default memory pressure duration from oomd.conf. */
- return bus_append_parse_sec_rename(m, field, isempty(eq) ? "infinity" : eq);
-
- if (STR_IN_SET(field,
- "MemoryLimit",
- "CPUShares",
- "StartupCPUShares",
- "BlockIOAccounting",
- "BlockIOWeight",
- "StartupBlockIOWeight",
- "BlockIODeviceWeight",
- "BlockIOReadBandwidth",
- "BlockIOWriteBandwidth",
- "CPUAccounting"))
- return warn_deprecated(field, eq);
-
- return 0;
+static int bus_append_environment_files(sd_bus_message *m, const char *field, const char *eq) {
+ return bus_append_trivial_array(m, "EnvironmentFiles", eq,
+ "a(sb)",
+ eq[0] == '-' ? eq + 1 : eq,
+ eq[0] == '-');
}
-static int bus_append_automount_property(sd_bus_message *m, const char *field, const char *eq) {
- if (STR_IN_SET(field, "Where",
- "ExtraOptions"))
- return bus_append_string(m, field, eq);
-
- if (streq(field, "DirectoryMode"))
- return bus_append_parse_mode(m, field, eq);
-
- if (streq(field, "TimeoutIdleSec"))
- return bus_append_parse_sec_rename(m, field, eq);
-
- return 0;
-}
-
-static int bus_append_execute_property(sd_bus_message *m, const char *field, const char *eq) {
- const char *suffix;
+static int bus_append_set_credential(sd_bus_message *m, const char *field, const char *eq) {
int r;
- if (STR_IN_SET(field, "User",
- "Group",
- "UtmpIdentifier",
- "UtmpMode",
- "PAMName",
- "TTYPath",
- "WorkingDirectory",
- "RootDirectory",
- "SyslogIdentifier",
- "ProtectSystem",
- "ProtectHome",
- "PrivateTmpEx",
- "PrivateUsersEx",
- "ProtectControlGroupsEx",
- "SELinuxContext",
- "RootImage",
- "RootVerity",
- "RuntimeDirectoryPreserve",
- "Personality",
- "KeyringMode",
- "ProtectProc",
- "ProcSubset",
- "NetworkNamespacePath",
- "IPCNamespacePath",
- "LogNamespace",
- "RootImagePolicy",
- "MountImagePolicy",
- "ExtensionImagePolicy",
- "PrivatePIDs"))
- return bus_append_string(m, field, eq);
-
- if (STR_IN_SET(field, "IgnoreSIGPIPE",
- "TTYVHangup",
- "TTYReset",
- "TTYVTDisallocate",
- "PrivateTmp",
- "PrivateDevices",
- "PrivateNetwork",
- "PrivateUsers",
- "PrivateMounts",
- "PrivateIPC",
- "NoNewPrivileges",
- "SyslogLevelPrefix",
- "MemoryDenyWriteExecute",
- "RestrictRealtime",
- "DynamicUser",
- "RemoveIPC",
- "ProtectKernelTunables",
- "ProtectKernelModules",
- "ProtectKernelLogs",
- "ProtectClock",
- "ProtectControlGroups",
- "MountAPIVFS",
- "BindLogSockets",
- "CPUSchedulingResetOnFork",
- "LockPersonality",
- "ProtectHostname",
- "MemoryKSM",
- "RestrictSUIDSGID",
- "RootEphemeral",
- "SetLoginEnvironment"))
- return bus_append_parse_boolean(m, field, eq);
-
- if (STR_IN_SET(field, "ReadWriteDirectories",
- "ReadOnlyDirectories",
- "InaccessibleDirectories",
- "ReadWritePaths",
- "ReadOnlyPaths",
- "InaccessiblePaths",
- "ExecPaths",
- "NoExecPaths",
- "ExecSearchPath",
- "ExtensionDirectories",
- "ConfigurationDirectory",
- "SupplementaryGroups",
- "SystemCallArchitectures"))
- return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
-
- if (STR_IN_SET(field, "SyslogLevel",
- "LogLevelMax"))
- return bus_append_log_level_from_string(m, field, eq);
-
- if (streq(field, "SyslogFacility"))
- return bus_append_log_facility_unshifted_from_string(m, field, eq);
-
- if (streq(field, "SecureBits"))
- return bus_append_secure_bits_from_string(m, field, eq);
-
- if (streq(field, "CPUSchedulingPolicy"))
- return bus_append_sched_policy_from_string(m, field, eq);
-
- if (STR_IN_SET(field, "CPUSchedulingPriority",
- "OOMScoreAdjust"))
- return bus_append_safe_atoi(m, field, eq);
-
- if (streq(field, "CoredumpFilter"))
- return bus_append_coredump_filter_mask_from_string(m, field, eq);
-
- if (streq(field, "Nice"))
- return bus_append_parse_nice(m, field, eq);
-
- if (streq(field, "SystemCallErrorNumber"))
- return bus_append_seccomp_parse_errno_or_action(m, field, eq);
-
- if (streq(field, "IOSchedulingClass"))
- return bus_append_ioprio_class_from_string(m, field, eq);
-
- if (streq(field, "IOSchedulingPriority"))
- return bus_append_ioprio_parse_priority(m, field, eq);
-
- if (STR_IN_SET(field, "RuntimeDirectoryMode",
- "StateDirectoryMode",
- "CacheDirectoryMode",
- "LogsDirectoryMode",
- "ConfigurationDirectoryMode",
- "UMask"))
- return bus_append_parse_mode(m, field, eq);
-
- if (streq(field, "TimerSlackNSec"))
- return bus_append_parse_nsec(m, field, eq);
-
- if (streq(field, "LogRateLimitIntervalSec"))
- return bus_append_parse_sec_rename(m, field, eq);
-
- if (STR_IN_SET(field, "LogRateLimitBurst",
- "TTYRows",
- "TTYColumns"))
- return bus_append_safe_atou(m, field, eq);
-
- if (streq(field, "MountFlags"))
- return bus_append_mount_propagation_flag_from_string(m, field, eq);
-
- if (STR_IN_SET(field, "Environment",
- "UnsetEnvironment",
- "PassEnvironment"))
- return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
-
- if (streq(field, "EnvironmentFile")) {
- if (isempty(eq))
- r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 0);
- else
- r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 1,
- eq[0] == '-' ? eq + 1 : eq,
- eq[0] == '-');
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (STR_IN_SET(field, "SetCredential", "SetCredentialEncrypted")) {
- r = sd_bus_message_open_container(m, 'r', "sv");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append_basic(m, 's', field);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'v', "a(say)");
- if (r < 0)
- return bus_log_create_error(r);
-
- if (isempty(eq))
- r = sd_bus_message_append(m, "a(say)", 0);
- else {
- _cleanup_free_ char *word = NULL;
- const char *p = eq;
-
- r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
- if (r == -ENOMEM)
- return log_oom();
- if (r < 0)
- return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
- if (r == 0 || !p)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
-
- r = sd_bus_message_open_container(m, 'a', "(say)");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'r', "say");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append(m, "s", word);
- if (r < 0)
- return bus_log_create_error(r);
-
- if (streq(field, "SetCredentialEncrypted")) {
- _cleanup_free_ void *decoded = NULL;
- size_t decoded_size;
-
- r = unbase64mem(p, &decoded, &decoded_size);
- if (r < 0)
- return log_error_errno(r, "Failed to base64 decode encrypted credential: %m");
-
- r = sd_bus_message_append_array(m, 'y', decoded, decoded_size);
- } else {
- _cleanup_free_ char *unescaped = NULL;
- ssize_t l;
-
- l = cunescape(p, UNESCAPE_ACCEPT_NUL, &unescaped);
- if (l < 0)
- return log_error_errno(l, "Failed to unescape %s= value: %s", field, p);
-
- r = sd_bus_message_append_array(m, 'y', unescaped, l);
- }
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- }
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (STR_IN_SET(field, "LoadCredential", "LoadCredentialEncrypted")) {
- r = sd_bus_message_open_container(m, 'r', "sv");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append_basic(m, 's', field);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'v', "a(ss)");
- if (r < 0)
- return bus_log_create_error(r);
-
- if (isempty(eq))
- r = sd_bus_message_append(m, "a(ss)", 0);
- else {
- _cleanup_free_ char *word = NULL;
- const char *p = eq;
-
- r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
- if (r == -ENOMEM)
- return log_oom();
- if (r < 0)
- return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
- if (r == 0)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
-
- if (isempty(p)) /* If only one field is specified, then this means "inherit from above" */
- p = eq;
-
- r = sd_bus_message_append(m, "a(ss)", 1, word, p);
- }
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (streq(field, "ImportCredential")) {
- if (isempty(eq))
- r = sd_bus_message_append(m, "(sv)", field, "as", 0);
- else
- r = sd_bus_message_append(m, "(sv)", field, "as", 1, eq);
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (streq(field, "ImportCredentialEx")) {
- r = sd_bus_message_open_container(m, 'r', "sv");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append_basic(m, 's', field);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'v', "a(ss)");
- if (r < 0)
- return bus_log_create_error(r);
-
- if (isempty(eq))
- r = sd_bus_message_append(m, "a(ss)", 0);
- else {
- _cleanup_free_ char *word = NULL;
- const char *p = eq;
-
- r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
- if (r == -ENOMEM)
- return log_oom();
- if (r < 0)
- return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
- if (r == 0)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
-
- r = sd_bus_message_append(m, "a(ss)", 1, word, p);
- }
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (streq(field, "LogExtraFields")) {
- r = sd_bus_message_open_container(m, 'r', "sv");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append_basic(m, 's', "LogExtraFields");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'v', "aay");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'a', "ay");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append_array(m, 'y', eq, strlen(eq));
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (streq(field, "LogFilterPatterns")) {
- r = sd_bus_message_append(m, "(sv)", "LogFilterPatterns", "a(bs)", 1,
- eq[0] != '~',
- eq[0] != '~' ? eq : eq + 1);
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (STR_IN_SET(field, "StandardInput",
- "StandardOutput",
- "StandardError")) {
- const char *n, *appended;
-
- if ((n = startswith(eq, "fd:"))) {
- appended = strjoina(field, "FileDescriptorName");
- r = sd_bus_message_append(m, "(sv)", appended, "s", n);
- } else if ((n = startswith(eq, "file:"))) {
- appended = strjoina(field, "File");
- r = sd_bus_message_append(m, "(sv)", appended, "s", n);
- } else if ((n = startswith(eq, "append:"))) {
- appended = strjoina(field, "FileToAppend");
- r = sd_bus_message_append(m, "(sv)", appended, "s", n);
- } else if ((n = startswith(eq, "truncate:"))) {
- appended = strjoina(field, "FileToTruncate");
- r = sd_bus_message_append(m, "(sv)", appended, "s", n);
- } else
- r = sd_bus_message_append(m, "(sv)", field, "s", eq);
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (streq(field, "StandardInputText")) {
- _cleanup_free_ char *unescaped = NULL;
- ssize_t l;
-
- l = cunescape(eq, 0, &unescaped);
- if (l < 0)
- return log_error_errno(l, "Failed to unescape text '%s': %m", eq);
-
- if (!strextend(&unescaped, "\n"))
+ r = sd_bus_message_open_container(m, 'r', "sv");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_basic(m, 's', field);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'v', "a(say)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ if (isempty(eq))
+ r = sd_bus_message_append(m, "a(say)", 0);
+ else {
+ _cleanup_free_ char *word = NULL;
+ const char *p = eq;
+
+ r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
+ if (r == -ENOMEM)
return log_oom();
-
- /* Note that we don't expand specifiers here, but that should be OK, as this is a
- * programmatic interface anyway */
-
- return bus_append_byte_array(m, field, unescaped, l + 1);
- }
-
- if (streq(field, "StandardInputData")) {
- _cleanup_free_ void *decoded = NULL;
- size_t sz;
-
- r = unbase64mem(eq, &decoded, &sz);
if (r < 0)
- return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq);
+ return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
+ if (r == 0 || !p)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
- return bus_append_byte_array(m, field, decoded, sz);
- }
-
- if ((suffix = startswith(field, "Limit"))) {
- int rl;
-
- rl = rlimit_from_string(suffix);
- if (rl >= 0) {
- const char *sn;
- struct rlimit l;
-
- r = rlimit_parse(rl, eq, &l);
- if (r < 0)
- return log_error_errno(r, "Failed to parse resource limit: %s", eq);
-
- r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) l.rlim_max);
- if (r < 0)
- return bus_log_create_error(r);
-
- sn = strjoina(field, "Soft");
- r = sd_bus_message_append(m, "(sv)", sn, "t", (uint64_t) l.rlim_cur);
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
- }
-
- if (STR_IN_SET(field, "AppArmorProfile",
- "SmackProcessLabel")) {
- int ignore = 0;
- const char *s = eq;
-
- if (eq[0] == '-') {
- ignore = 1;
- s = eq + 1;
- }
-
- r = sd_bus_message_append(m, "(sv)", field, "(bs)", ignore, s);
+ r = sd_bus_message_open_container(m, 'a', "(say)");
if (r < 0)
return bus_log_create_error(r);
- return 1;
- }
-
- if (STR_IN_SET(field, "CapabilityBoundingSet",
- "AmbientCapabilities")) {
- uint64_t sum = 0;
- bool invert = false;
- const char *p = eq;
-
- if (*p == '~') {
- invert = true;
- p++;
- }
-
- r = capability_set_from_string(p, &sum);
- if (r < 0)
- return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
-
- sum = invert ? ~sum : sum;
-
- r = sd_bus_message_append(m, "(sv)", field, "t", sum);
+ r = sd_bus_message_open_container(m, 'r', "say");
if (r < 0)
return bus_log_create_error(r);
- return 1;
- }
-
- if (streq(field, "CPUAffinity")) {
- _cleanup_(cpu_set_done) CPUSet cpuset = {};
- _cleanup_free_ uint8_t *array = NULL;
- size_t allocated;
-
- if (eq && streq(eq, "numa")) {
- r = sd_bus_message_append(m, "(sv)", "CPUAffinityFromNUMA", "b", true);
- if (r < 0)
- return bus_log_create_error(r);
- return r;
- }
-
- r = parse_cpu_set(eq, &cpuset);
- if (r < 0)
- return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
-
- r = cpu_set_to_dbus(&cpuset, &array, &allocated);
- if (r < 0)
- return log_error_errno(r, "Failed to serialize CPUAffinity: %m");
-
- return bus_append_byte_array(m, field, array, allocated);
- }
-
- if (streq(field, "NUMAPolicy")) {
- r = mpol_from_string(eq);
- if (r < 0)
- return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
-
- r = sd_bus_message_append(m, "(sv)", field, "i", (int32_t) r);
+ r = sd_bus_message_append(m, "s", word);
if (r < 0)
return bus_log_create_error(r);
- return 1;
- }
+ if (streq(field, "SetCredentialEncrypted")) {
+ _cleanup_free_ void *decoded = NULL;
+ size_t decoded_size;
- if (streq(field, "NUMAMask")) {
- _cleanup_(cpu_set_done) CPUSet nodes = {};
- _cleanup_free_ uint8_t *array = NULL;
- size_t allocated;
-
- if (eq && streq(eq, "all")) {
- r = numa_mask_add_all(&nodes);
+ r = unbase64mem(p, &decoded, &decoded_size);
if (r < 0)
- return log_error_errno(r, "Failed to create NUMA mask representing \"all\" NUMA nodes: %m");
+ return log_error_errno(r, "Failed to base64 decode encrypted credential: %m");
+
+ r = sd_bus_message_append_array(m, 'y', decoded, decoded_size);
} else {
- r = parse_cpu_set(eq, &nodes);
- if (r < 0)
- return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
+ _cleanup_free_ char *unescaped = NULL;
+ ssize_t l;
+
+ l = cunescape(p, UNESCAPE_ACCEPT_NUL, &unescaped);
+ if (l < 0)
+ return log_error_errno(l, "Failed to unescape %s= value: %s", field, p);
+
+ r = sd_bus_message_append_array(m, 'y', unescaped, l);
}
-
- r = cpu_set_to_dbus(&nodes, &array, &allocated);
if (r < 0)
- return log_error_errno(r, "Failed to serialize NUMAMask: %m");
+ return bus_log_create_error(r);
- return bus_append_byte_array(m, field, array, allocated);
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
}
+ if (r < 0)
+ return bus_log_create_error(r);
- if (STR_IN_SET(field, "RestrictAddressFamilies",
- "RestrictFileSystems",
- "SystemCallFilter",
- "SystemCallLog",
- "RestrictNetworkInterfaces")) {
- int allow_list = 1;
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
+static int bus_append_load_credential(sd_bus_message *m, const char *field, const char *eq) {
+ int r;
+
+ r = sd_bus_message_open_container(m, 'r', "sv");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_basic(m, 's', field);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'v', "a(ss)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ if (isempty(eq))
+ r = sd_bus_message_append(m, "a(ss)", 0);
+ else {
+ _cleanup_free_ char *word = NULL;
const char *p = eq;
- if (*p == '~') {
- allow_list = 0;
- p++;
- }
-
- r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
+ r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
+ if (r == -ENOMEM)
+ return log_oom();
if (r < 0)
- return bus_log_create_error(r);
+ return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
+ if (r == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
- r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
- if (r < 0)
- return bus_log_create_error(r);
+ if (isempty(p)) /* If only one field is specified, then this means "inherit from above" */
+ p = eq;
- r = sd_bus_message_open_container(m, 'v', "(bas)");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'r', "bas");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append_basic(m, 'b', &allow_list);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'a', "s");
- if (r < 0)
- return bus_log_create_error(r);
-
- for (;;) {
- _cleanup_free_ char *word = NULL;
-
- r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
- if (r == 0)
- break;
- if (r == -ENOMEM)
- return log_oom();
- if (r < 0)
- return log_error_errno(r, "Invalid syntax: %s", eq);
-
- r = sd_bus_message_append_basic(m, 's', word);
- if (r < 0)
- return bus_log_create_error(r);
- }
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
+ r = sd_bus_message_append(m, "a(ss)", 1, word, p);
}
+ if (r < 0)
+ return bus_log_create_error(r);
- if (STR_IN_SET(field, "RestrictNamespaces",
- "DelegateNamespaces")) {
- bool invert = false;
- unsigned long all = UPDATE_FLAG(NAMESPACE_FLAGS_ALL, CLONE_NEWUSER, !streq(field, "DelegateNamespaces"));
- unsigned long flags;
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
- r = parse_boolean(eq);
- if (r > 0)
- /* RestrictNamespaces= value gets stored into a field with reverse semantics (the
- * namespaces which are retained), so RestrictNamespaces=true means we retain no
- * access to any namespaces and vice-versa. */
- flags = streq(field, "RestrictNamespaces") ? 0 : all;
- else if (r == 0)
- flags = streq(field, "RestrictNamespaces") ? all : 0;
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
+static int bus_append_import_credential(sd_bus_message *m, const char *field, const char *eq) {
+ int r;
+
+ if (isempty(eq))
+ r = sd_bus_message_append(m, "(sv)", "ImportCredential", "as", 0);
+ else {
+ _cleanup_free_ char *word = NULL;
+ const char *p = eq;
+
+ r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
+ if (r == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
+
+ if (!p)
+ r = sd_bus_message_append(m, "(sv)", "ImportCredential", "as", 1, eq);
else {
- if (eq[0] == '~') {
- invert = true;
- eq++;
- }
-
- r = namespace_flags_from_string(eq, &flags);
- if (r < 0)
- return log_error_errno(r, "Failed to parse %s value %s.", field, eq);
- }
-
- if (invert)
- flags = (~flags) & all;
-
- r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) flags);
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (STR_IN_SET(field, "BindPaths",
- "BindReadOnlyPaths")) {
- const char *p = eq;
-
- r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'v', "a(ssbt)");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'a', "(ssbt)");
- if (r < 0)
- return bus_log_create_error(r);
-
- for (;;) {
- _cleanup_free_ char *source = NULL, *destination = NULL;
- char *s = NULL, *d = NULL;
- bool ignore_enoent = false;
- uint64_t flags = MS_REC;
-
- r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
- if (r < 0)
- return log_error_errno(r, "Failed to parse argument: %m");
- if (r == 0)
- break;
-
- s = source;
- if (s[0] == '-') {
- ignore_enoent = true;
- s++;
- }
-
- if (p && p[-1] == ':') {
- r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
- if (r < 0)
- return log_error_errno(r, "Failed to parse argument: %m");
- if (r == 0)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Missing argument after ':': %s",
- eq);
-
- d = destination;
-
- if (p && p[-1] == ':') {
- _cleanup_free_ char *options = NULL;
-
- r = extract_first_word(&p, &options, NULL, EXTRACT_UNQUOTE);
- if (r < 0)
- return log_error_errno(r, "Failed to parse argument: %m");
-
- if (isempty(options) || streq(options, "rbind"))
- flags = MS_REC;
- else if (streq(options, "norbind"))
- flags = 0;
- else
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Unknown options: %s",
- eq);
- }
- } else
- d = s;
-
- r = sd_bus_message_append(m, "(ssbt)", s, d, ignore_enoent, flags);
+ /* We need to send ImportCredentialEx */
+ r = sd_bus_message_open_container(m, 'r', "sv");
if (r < 0)
return bus_log_create_error(r);
- }
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (streq(field, "TemporaryFileSystem")) {
- const char *p = eq;
-
- r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'v', "a(ss)");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'a', "(ss)");
- if (r < 0)
- return bus_log_create_error(r);
-
- for (;;) {
- _cleanup_free_ char *word = NULL, *path = NULL;
- const char *w;
-
- r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
- if (r < 0)
- return log_error_errno(r, "Failed to parse argument: %m");
- if (r == 0)
- break;
-
- w = word;
- r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
- if (r < 0)
- return log_error_errno(r, "Failed to parse argument: %m");
- if (r == 0)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Failed to parse argument: %s",
- p);
-
- r = sd_bus_message_append(m, "(ss)", path, w);
+ r = sd_bus_message_append_basic(m, 's', "ImportCredentialEx");
if (r < 0)
return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'v', "a(ss)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(m, "a(ss)", 1, word, p);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ }
+ }
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
+static int bus_append_log_extra_fields(sd_bus_message *m, const char *field, const char *eq) {
+ int r;
+
+ r = sd_bus_message_open_container(m, 'r', "sv");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_basic(m, 's', field);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'v', "aay");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'a', "ay");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_array(m, 'y', eq, strlen(eq));
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
+static int bus_append_log_filter_patterns(sd_bus_message *m, const char *field, const char *eq) {
+ int r;
+
+ r = sd_bus_message_append(m, "(sv)", "LogFilterPatterns", "a(bs)", 1,
+ eq[0] != '~',
+ eq[0] != '~' ? eq : eq + 1);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
+static int bus_append_standard_inputs(sd_bus_message *m, const char *field, const char *eq) {
+ const char *n, *appended;
+ int r;
+
+ if ((n = startswith(eq, "fd:"))) {
+ appended = strjoina(field, "FileDescriptorName");
+ r = sd_bus_message_append(m, "(sv)", appended, "s", n);
+ } else if ((n = startswith(eq, "file:"))) {
+ appended = strjoina(field, "File");
+ r = sd_bus_message_append(m, "(sv)", appended, "s", n);
+ } else if ((n = startswith(eq, "append:"))) {
+ appended = strjoina(field, "FileToAppend");
+ r = sd_bus_message_append(m, "(sv)", appended, "s", n);
+ } else if ((n = startswith(eq, "truncate:"))) {
+ appended = strjoina(field, "FileToTruncate");
+ r = sd_bus_message_append(m, "(sv)", appended, "s", n);
+ } else
+ r = sd_bus_message_append(m, "(sv)", field, "s", eq);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
+static int bus_append_standard_input_text(sd_bus_message *m, const char *field, const char *eq) {
+ _cleanup_free_ char *unescaped = NULL;
+ ssize_t l;
+
+ l = cunescape(eq, 0, &unescaped);
+ if (l < 0)
+ return log_error_errno(l, "Failed to unescape text '%s': %m", eq);
+
+ if (!strextend(&unescaped, "\n"))
+ return log_oom();
+
+ /* Note that we don't expand specifiers here, but that should be OK, as this is a
+ * programmatic interface anyway */
+
+ return bus_append_byte_array(m, field, unescaped, l + 1);
+}
+
+static int bus_append_standard_input_data(sd_bus_message *m, const char *field, const char *eq) {
+ _cleanup_free_ void *decoded = NULL;
+ size_t sz;
+ int r;
+
+ r = unbase64mem(eq, &decoded, &sz);
+ if (r < 0)
+ return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq);
+
+ return bus_append_byte_array(m, field, decoded, sz);
+}
+
+static int bus_try_append_resource_limit(sd_bus_message *m, const char *field, const char *eq) {
+ int r;
+
+ const char *suffix = startswith(field, "Limit");
+ if (!suffix)
+ return 0;
+
+ int rl = rlimit_from_string(suffix);
+ if (rl < 0)
+ return log_error_errno(rl, "Unknown setting '%s'.", field);
+
+ struct rlimit l;
+ r = rlimit_parse(rl, eq, &l);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse resource limit: %s", eq);
+
+ r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) l.rlim_max);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ const char *sn = strjoina(field, "Soft");
+ r = sd_bus_message_append(m, "(sv)", sn, "t", (uint64_t) l.rlim_cur);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
+static void dump_resource_limits(void) {
+ rlimits_list("Limit");
+}
+
+static int bus_append_string_with_ignore(sd_bus_message *m, const char *field, const char *eq) {
+ int ignore = 0;
+ const char *s = eq;
+ int r;
+
+ if (eq[0] == '-') {
+ ignore = 1;
+ s = eq + 1;
+ }
+
+ r = sd_bus_message_append(m, "(sv)", field, "(bs)", ignore, s);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
+static int bus_append_capabilities(sd_bus_message *m, const char *field, const char *eq) {
+ uint64_t sum = 0;
+ bool invert = false;
+ const char *p = eq;
+ int r;
+
+ if (*p == '~') {
+ invert = true;
+ p++;
+ }
+
+ r = capability_set_from_string(p, &sum);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
+
+ sum = invert ? ~sum : sum;
+
+ r = sd_bus_message_append(m, "(sv)", field, "t", sum);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
+static int bus_append_cpu_affinity(sd_bus_message *m, const char *field, const char *eq) {
+ int r;
+
+ if (streq_ptr(eq, "numa")) {
+ r = sd_bus_message_append(m, "(sv)", "CPUAffinityFromNUMA", "b", true);
+ if (r < 0)
+ return bus_log_create_error(r);
+ return r;
+ }
+
+ return bus_append_parse_cpu_set(m, field, eq);
+}
+
+static int bus_append_numa_mask(sd_bus_message *m, const char *field, const char *eq) {
+ _cleanup_(cpu_set_done) CPUSet nodes = {};
+ _cleanup_free_ uint8_t *array = NULL;
+ size_t allocated;
+ int r;
+
+ if (eq && streq(eq, "all")) {
+ r = numa_mask_add_all(&nodes);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create NUMA mask representing \"all\" NUMA nodes: %m");
+ } else {
+ r = parse_cpu_set(eq, &nodes);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
+ }
+
+ r = cpu_set_to_dbus(&nodes, &array, &allocated);
+ if (r < 0)
+ return log_error_errno(r, "Failed to serialize %s: %m", field);
+
+ return bus_append_byte_array(m, field, array, allocated);
+}
+
+static int bus_append_filter_list(sd_bus_message *m, const char *field, const char *eq) {
+ int allow_list = 1;
+ const char *p = eq;
+ int r;
+
+ if (*p == '~') {
+ allow_list = 0;
+ p++;
+ }
+
+ r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'v', "(bas)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'r', "bas");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_basic(m, 'b', &allow_list);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'a', "s");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+
+ r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
+ if (r == 0)
+ break;
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0)
+ return log_error_errno(r, "Invalid syntax: %s", eq);
+
+ r = sd_bus_message_append_basic(m, 's', word);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
+static int bus_append_namespace_list(sd_bus_message *m, const char *field, const char *eq) {
+ bool invert = false;
+ unsigned long all = UPDATE_FLAG(NAMESPACE_FLAGS_ALL, CLONE_NEWUSER, !streq(field, "DelegateNamespaces"));
+ unsigned long flags;
+ int r;
+
+ r = parse_boolean(eq);
+ if (r > 0)
+ /* RestrictNamespaces= value gets stored into a field with reverse semantics (the
+ * namespaces which are retained), so RestrictNamespaces=true means we retain no
+ * access to any namespaces and vice-versa. */
+ flags = streq(field, "RestrictNamespaces") ? 0 : all;
+ else if (r == 0)
+ flags = streq(field, "RestrictNamespaces") ? all : 0;
+ else {
+ if (eq[0] == '~') {
+ invert = true;
+ eq++;
}
- r = sd_bus_message_close_container(m);
+ r = namespace_flags_from_string(eq, &flags);
if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
+ return log_error_errno(r, "Failed to parse %s value %s.", field, eq);
}
- if (streq(field, "RootHash")) {
- _cleanup_free_ void *roothash_decoded = NULL;
- size_t roothash_decoded_size = 0;
+ if (invert)
+ flags = (~flags) & all;
- /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
- if (path_is_absolute(eq))
- return bus_append_string(m, "RootHashPath", eq);
+ r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) flags);
+ if (r < 0)
+ return bus_log_create_error(r);
- /* We have a roothash to decode, eg: RootHash=012345789abcdef */
- r = unhexmem(eq, &roothash_decoded, &roothash_decoded_size);
- if (r < 0)
- return log_error_errno(r, "Failed to decode RootHash= '%s': %m", eq);
- if (roothash_decoded_size < sizeof(sd_id128_t))
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "RootHash= '%s' is too short.", eq);
+ return 1;
+}
- return bus_append_byte_array(m, field, roothash_decoded, roothash_decoded_size);
- }
+static int bus_append_bind_paths(sd_bus_message *m, const char *field, const char *eq) {
+ const char *p = eq;
+ int r;
- if (streq(field, "RootHashSignature")) {
- _cleanup_free_ void *roothash_sig_decoded = NULL;
- char *value;
- size_t roothash_sig_decoded_size = 0;
+ r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
+ if (r < 0)
+ return bus_log_create_error(r);
- /* We have the path to a roothash signature to load and decode, eg: RootHash=/foo/bar.roothash.p7s */
- if (path_is_absolute(eq))
- return bus_append_string(m, "RootHashSignaturePath", eq);
+ r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
+ if (r < 0)
+ return bus_log_create_error(r);
- if (!(value = startswith(eq, "base64:")))
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to decode RootHashSignature= '%s', not a path but doesn't start with 'base64:'.", eq);
+ r = sd_bus_message_open_container(m, 'v', "a(ssbt)");
+ if (r < 0)
+ return bus_log_create_error(r);
- /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
- r = unbase64mem(value, &roothash_sig_decoded, &roothash_sig_decoded_size);
- if (r < 0)
- return log_error_errno(r, "Failed to decode RootHashSignature= '%s': %m", eq);
+ r = sd_bus_message_open_container(m, 'a', "(ssbt)");
+ if (r < 0)
+ return bus_log_create_error(r);
- return bus_append_byte_array(m, field, roothash_sig_decoded, roothash_sig_decoded_size);
- }
+ for (;;) {
+ _cleanup_free_ char *source = NULL, *destination = NULL;
+ char *s = NULL, *d = NULL;
+ bool ignore_enoent = false;
+ uint64_t flags = MS_REC;
- if (streq(field, "RootImageOptions")) {
- _cleanup_strv_free_ char **l = NULL;
- const char *p = eq;
-
- r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'v', "a(ss)");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'a', "(ss)");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = strv_split_colon_pairs(&l, p);
+ r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
if (r < 0)
return log_error_errno(r, "Failed to parse argument: %m");
+ if (r == 0)
+ break;
- STRV_FOREACH_PAIR(first, second, l) {
- r = sd_bus_message_append(m, "(ss)",
- !isempty(*second) ? *first : "root",
- !isempty(*second) ? *second : *first);
- if (r < 0)
- return bus_log_create_error(r);
+ s = source;
+ if (s[0] == '-') {
+ ignore_enoent = true;
+ s++;
}
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (streq(field, "MountImages")) {
- const char *p = eq;
-
- r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'v', "a(ssba(ss))");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'a', "(ssba(ss))");
- if (r < 0)
- return bus_log_create_error(r);
-
- for (;;) {
- _cleanup_free_ char *first = NULL, *second = NULL, *tuple = NULL;
- const char *q = NULL, *source = NULL;
- bool permissive = false;
-
- r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
- if (r < 0)
- return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
- if (r == 0)
- break;
-
- q = tuple;
- r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second);
- if (r < 0)
- return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
- if (r == 0)
- continue;
-
- source = first;
- if (source[0] == '-') {
- permissive = true;
- source++;
- }
-
- if (isempty(second))
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Missing argument after ':': %s",
- eq);
-
- r = sd_bus_message_open_container(m, 'r', "ssba(ss)");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append(m, "ssb", source, second, permissive);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'a', "(ss)");
- if (r < 0)
- return bus_log_create_error(r);
-
- for (;;) {
- _cleanup_free_ char *partition = NULL, *mount_options = NULL;
-
- r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
- if (r < 0)
- return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
- if (r == 0)
- break;
- /* Single set of options, applying to the root partition/single filesystem */
- if (r == 1) {
- r = sd_bus_message_append(m, "(ss)", "root", partition);
- if (r < 0)
- return bus_log_create_error(r);
-
- break;
- }
-
- r = sd_bus_message_append(m, "(ss)", partition, mount_options);
- if (r < 0)
- return bus_log_create_error(r);
- }
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
- }
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (streq(field, "ExtensionImages")) {
- const char *p = eq;
-
- r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'v', "a(sba(ss))");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'a', "(sba(ss))");
- if (r < 0)
- return bus_log_create_error(r);
-
- for (;;) {
- _cleanup_free_ char *source = NULL, *tuple = NULL;
- const char *q = NULL, *s = NULL;
- bool permissive = false;
-
- r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
- if (r < 0)
- return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
- if (r == 0)
- break;
-
- q = tuple;
- r = extract_first_word(&q, &source, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
- if (r < 0)
- return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
- if (r == 0)
- continue;
-
- s = source;
- if (s[0] == '-') {
- permissive = true;
- s++;
- }
-
- r = sd_bus_message_open_container(m, 'r', "sba(ss)");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append(m, "sb", s, permissive);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'a', "(ss)");
- if (r < 0)
- return bus_log_create_error(r);
-
- for (;;) {
- _cleanup_free_ char *partition = NULL, *mount_options = NULL;
-
- r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
- if (r < 0)
- return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
- if (r == 0)
- break;
- /* Single set of options, applying to the root partition/single filesystem */
- if (r == 1) {
- r = sd_bus_message_append(m, "(ss)", "root", partition);
- if (r < 0)
- return bus_log_create_error(r);
-
- break;
- }
-
- r = sd_bus_message_append(m, "(ss)", partition, mount_options);
- if (r < 0)
- return bus_log_create_error(r);
- }
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
- }
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (STR_IN_SET(field, "StateDirectory", "RuntimeDirectory", "CacheDirectory", "LogsDirectory")) {
- _cleanup_strv_free_ char **symlinks = NULL, **symlinks_ro = NULL, **sources = NULL, **sources_ro = NULL;
- const char *p = eq;
-
- /* Adding new directories is supported from both *DirectorySymlink methods and the
- * older ones, so first parse the input, and if we are given a new-style src:dst
- * tuple use the new method, else use the old one. */
-
- for (;;) {
- _cleanup_free_ char *tuple = NULL, *source = NULL, *dest = NULL, *flags = NULL;
-
- r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE);
+ if (p && p[-1] == ':') {
+ r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
if (r < 0)
return log_error_errno(r, "Failed to parse argument: %m");
if (r == 0)
- break;
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Missing argument after ':': %s", eq);
- const char *t = tuple;
- r = extract_many_words(&t, ":", EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS, &source, &dest, &flags);
- if (r <= 0)
- return log_error_errno(r ?: SYNTHETIC_ERRNO(EINVAL), "Failed to parse argument: %m");
+ d = destination;
- path_simplify(source);
+ if (p && p[-1] == ':') {
+ _cleanup_free_ char *options = NULL;
- if (isempty(dest) && isempty(flags)) {
- r = strv_consume(&sources, TAKE_PTR(source));
+ r = extract_first_word(&p, &options, NULL, EXTRACT_UNQUOTE);
if (r < 0)
- return bus_log_create_error(r);
- } else if (isempty(flags)) {
- path_simplify(dest);
- r = strv_consume_pair(&symlinks, TAKE_PTR(source), TAKE_PTR(dest));
- if (r < 0)
- return log_oom();
- } else {
- ExecDirectoryFlags exec_directory_flags = exec_directory_flags_from_string(flags);
- if (exec_directory_flags < 0 || (exec_directory_flags & ~_EXEC_DIRECTORY_FLAGS_PUBLIC) != 0)
- return log_error_errno(r, "Failed to parse flags: %s", flags);
+ return log_error_errno(r, "Failed to parse argument: %m");
- if (!isempty(dest)) {
- path_simplify(dest);
- r = strv_consume_pair(&symlinks_ro, TAKE_PTR(source), TAKE_PTR(dest));
- } else
- r = strv_consume(&sources_ro, TAKE_PTR(source));
- if (r < 0)
- return log_oom();
+ if (isempty(options) || streq(options, "rbind"))
+ flags = MS_REC;
+ else if (streq(options, "norbind"))
+ flags = 0;
+ else
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Unknown options: %s", eq);
}
- }
+ } else
+ d = s;
- if (!strv_isempty(sources)) {
- r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'v', "as");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append_strv(m, sources);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
- }
-
- /* For State and Runtime directories we support an optional destination parameter, which
- * will be used to create a symlink to the source. But it is new so we cannot change the
- * old DBUS signatures, so append a new message type. */
- if (!strv_isempty(symlinks) || !strv_isempty(symlinks_ro) || !strv_isempty(sources_ro)) {
- const char *symlink_field;
-
- r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
- if (r < 0)
- return bus_log_create_error(r);
-
- if (streq(field, "StateDirectory"))
- symlink_field = "StateDirectorySymlink";
- else if (streq(field, "RuntimeDirectory"))
- symlink_field = "RuntimeDirectorySymlink";
- else if (streq(field, "CacheDirectory"))
- symlink_field = "CacheDirectorySymlink";
- else if (streq(field, "LogsDirectory"))
- symlink_field = "LogsDirectorySymlink";
- else
- assert_not_reached();
-
- r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, symlink_field);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'v', "a(sst)");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'a', "(sst)");
- if (r < 0)
- return bus_log_create_error(r);
-
- STRV_FOREACH_PAIR(source, destination, symlinks) {
- r = sd_bus_message_append(m, "(sst)", *source, *destination, UINT64_C(0));
- if (r < 0)
- return bus_log_create_error(r);
- }
-
- STRV_FOREACH_PAIR(source, destination, symlinks_ro) {
- r = sd_bus_message_append(m, "(sst)", *source, *destination, (uint64_t) EXEC_DIRECTORY_READ_ONLY);
- if (r < 0)
- return bus_log_create_error(r);
- }
-
- STRV_FOREACH(source, sources_ro) {
- r = sd_bus_message_append(m, "(sst)", *source, "", (uint64_t) EXEC_DIRECTORY_READ_ONLY);
- if (r < 0)
- return bus_log_create_error(r);
- }
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
- }
-
- return 1;
+ r = sd_bus_message_append(m, "(ssbt)", s, d, ignore_enoent, flags);
+ if (r < 0)
+ return bus_log_create_error(r);
}
- if (streq(field, "ProtectHostnameEx")) {
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
+static int bus_append_temporary_file_system(sd_bus_message *m, const char *field, const char *eq) {
+ const char *p = eq;
+ int r;
+
+ r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'v', "a(ss)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'a', "(ss)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ for (;;) {
+ _cleanup_free_ char *word = NULL, *path = NULL;
+ const char *w;
+
+ r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse argument: %m");
+ if (r == 0)
+ break;
+
+ w = word;
+ r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse argument: %m");
+ if (r == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Failed to parse argument: %s", p);
+
+ r = sd_bus_message_append(m, "(ss)", path, w);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
+static int bus_append_root_hash(sd_bus_message *m, const char *field, const char *eq) {
+ _cleanup_free_ void *roothash_decoded = NULL;
+ size_t roothash_decoded_size = 0;
+ int r;
+
+ /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
+ if (path_is_absolute(eq))
+ return bus_append_string(m, "RootHashPath", eq);
+
+ /* We have a roothash to decode, eg: RootHash=012345789abcdef */
+ r = unhexmem(eq, &roothash_decoded, &roothash_decoded_size);
+ if (r < 0)
+ return log_error_errno(r, "Failed to decode RootHash= '%s': %m", eq);
+ if (roothash_decoded_size < sizeof(sd_id128_t))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "RootHash= '%s' is too short.", eq);
+
+ return bus_append_byte_array(m, field, roothash_decoded, roothash_decoded_size);
+}
+
+static int bus_append_root_hash_signature(sd_bus_message *m, const char *field, const char *eq) {
+ char *value;
+ _cleanup_free_ void *roothash_sig_decoded = NULL;
+ size_t roothash_sig_decoded_size = 0;
+ int r;
+
+ /* We have the path to a roothash signature to load and decode, eg: RootHash=/foo/bar.roothash.p7s */
+ if (path_is_absolute(eq))
+ return bus_append_string(m, "RootHashSignaturePath", eq);
+
+ if (!(value = startswith(eq, "base64:")))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Failed to decode %s=%s: neither a path nor starts with 'base64:'.",
+ field, eq);
+
+ /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
+ r = unbase64mem(value, &roothash_sig_decoded, &roothash_sig_decoded_size);
+ if (r < 0)
+ return log_error_errno(r, "Failed to decode %s=%s: %m", field, eq);
+
+ return bus_append_byte_array(m, field, roothash_sig_decoded, roothash_sig_decoded_size);
+}
+
+static int bus_append_root_image_options(sd_bus_message *m, const char *field, const char *eq) {
+ _cleanup_strv_free_ char **l = NULL;
+ const char *p = eq;
+ int r;
+
+ r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'v', "a(ss)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'a', "(ss)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = strv_split_colon_pairs(&l, p);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse argument: %m");
+
+ STRV_FOREACH_PAIR(first, second, l) {
+ r = sd_bus_message_append(m, "(ss)",
+ !isempty(*second) ? *first : "root",
+ !isempty(*second) ? *second : *first);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
+static int bus_append_mount_images(sd_bus_message *m, const char *field, const char *eq) {
+ const char *p = eq;
+ int r;
+
+ r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'v', "a(ssba(ss))");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'a', "(ssba(ss))");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ for (;;) {
+ _cleanup_free_ char *first = NULL, *second = NULL, *tuple = NULL;
+ const char *q = NULL, *source = NULL;
+ bool permissive = false;
+
+ r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s property: %s", field, eq);
+ if (r == 0)
+ break;
+
+ q = tuple;
+ r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s property: %s", field, eq);
+ if (r == 0)
+ continue;
+
+ source = first;
+ if (source[0] == '-') {
+ permissive = true;
+ source++;
+ }
+
+ if (isempty(second))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Missing argument after ':' for %s: %s", field, eq);
+
+ r = sd_bus_message_open_container(m, 'r', "ssba(ss)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(m, "ssb", source, second, permissive);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'a', "(ss)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ for (;;) {
+ _cleanup_free_ char *partition = NULL, *mount_options = NULL;
+
+ r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s property: %s", field, eq);
+ if (r == 0)
+ break;
+ /* Single set of options, applying to the root partition/single filesystem */
+ if (r == 1) {
+ r = sd_bus_message_append(m, "(ss)", "root", partition);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ break;
+ }
+
+ r = sd_bus_message_append(m, "(ss)", partition, mount_options);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
+static int bus_append_extension_images(sd_bus_message *m, const char *field, const char *eq) {
+ const char *p = eq;
+ int r;
+
+ r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'v', "a(sba(ss))");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'a', "(sba(ss))");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ for (;;) {
+ _cleanup_free_ char *source = NULL, *tuple = NULL;
+ const char *q = NULL, *s = NULL;
+ bool permissive = false;
+
+ r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s property: %s", field, eq);
+ if (r == 0)
+ break;
+
+ q = tuple;
+ r = extract_first_word(&q, &source, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s property: %s", field, eq);
+ if (r == 0)
+ continue;
+
+ s = source;
+ if (s[0] == '-') {
+ permissive = true;
+ s++;
+ }
+
+ r = sd_bus_message_open_container(m, 'r', "sba(ss)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(m, "sb", s, permissive);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'a', "(ss)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ for (;;) {
+ _cleanup_free_ char *partition = NULL, *mount_options = NULL;
+
+ r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s property: %s", field, eq);
+ if (r == 0)
+ break;
+ /* Single set of options, applying to the root partition/single filesystem */
+ if (r == 1) {
+ r = sd_bus_message_append(m, "(ss)", "root", partition);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ break;
+ }
+
+ r = sd_bus_message_append(m, "(ss)", partition, mount_options);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
+static int bus_append_directory(sd_bus_message *m, const char *field, const char *eq) {
+ _cleanup_strv_free_ char **symlinks = NULL, **symlinks_ro = NULL, **sources = NULL, **sources_ro = NULL;
+ const char *p = eq;
+ int r;
+
+ /* Adding new directories is supported from both *DirectorySymlink methods and the
+ * older ones, so first parse the input, and if we are given a new-style src:dst
+ * tuple use the new method, else use the old one. */
+
+ for (;;) {
+ _cleanup_free_ char *tuple = NULL, *source = NULL, *dest = NULL, *flags = NULL;
+
+ r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse argument: %m");
+ if (r == 0)
+ break;
+
+ const char *t = tuple;
+ r = extract_many_words(&t, ":", EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS, &source, &dest, &flags);
+ if (r <= 0)
+ return log_error_errno(r ?: SYNTHETIC_ERRNO(EINVAL), "Failed to parse argument: %m");
+
+ path_simplify(source);
+
+ if (isempty(dest) && isempty(flags)) {
+ r = strv_consume(&sources, TAKE_PTR(source));
+ if (r < 0)
+ return bus_log_create_error(r);
+ } else if (isempty(flags)) {
+ path_simplify(dest);
+ r = strv_consume_pair(&symlinks, TAKE_PTR(source), TAKE_PTR(dest));
+ if (r < 0)
+ return log_oom();
+ } else {
+ ExecDirectoryFlags exec_directory_flags = exec_directory_flags_from_string(flags);
+ if (exec_directory_flags < 0 || (exec_directory_flags & ~_EXEC_DIRECTORY_FLAGS_PUBLIC) != 0)
+ return log_error_errno(r, "Failed to parse flags: %s", flags);
+
+ if (!isempty(dest)) {
+ path_simplify(dest);
+ r = strv_consume_pair(&symlinks_ro, TAKE_PTR(source), TAKE_PTR(dest));
+ } else
+ r = strv_consume(&sources_ro, TAKE_PTR(source));
+ if (r < 0)
+ return log_oom();
+ }
+ }
+
+ if (!strv_isempty(sources)) {
+ r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'v', "as");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_strv(m, sources);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ /* For State and Runtime directories we support an optional destination parameter, which
+ * will be used to create a symlink to the source. But it is new so we cannot change the
+ * old DBUS signatures, so append a new message type. */
+ if (!strv_isempty(symlinks) || !strv_isempty(symlinks_ro) || !strv_isempty(sources_ro)) {
+ const char *symlink_field;
+
+ r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ if (streq(field, "StateDirectory"))
+ symlink_field = "StateDirectorySymlink";
+ else if (streq(field, "RuntimeDirectory"))
+ symlink_field = "RuntimeDirectorySymlink";
+ else if (streq(field, "CacheDirectory"))
+ symlink_field = "CacheDirectorySymlink";
+ else if (streq(field, "LogsDirectory"))
+ symlink_field = "LogsDirectorySymlink";
+ else
+ assert_not_reached();
+
+ r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, symlink_field);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'v', "a(sst)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'a', "(sst)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ STRV_FOREACH_PAIR(source, destination, symlinks) {
+ r = sd_bus_message_append(m, "(sst)", *source, *destination, UINT64_C(0));
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ STRV_FOREACH_PAIR(source, destination, symlinks_ro) {
+ r = sd_bus_message_append(m, "(sst)", *source, *destination, (uint64_t) EXEC_DIRECTORY_READ_ONLY);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ STRV_FOREACH(source, sources_ro) {
+ r = sd_bus_message_append(m, "(sst)", *source, "", (uint64_t) EXEC_DIRECTORY_READ_ONLY);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ return 1;
+}
+
+static int bus_append_protect_hostname(sd_bus_message *m, const char *field, const char *eq) {
+ int r;
+
+ /* The command-line field is called "ProtectHostname". We also accept "ProtectHostnameEx" as the
+ * field name for backward compatibility. We set ProtectHostame or ProtectHostnameEx. */
+
+ r = parse_boolean(eq);
+ if (r >= 0)
+ r = sd_bus_message_append(m, "(sv)", "ProtectHostname", "b", r);
+ else {
const char *colon = strchr(eq, ':');
if (colon) {
if (isempty(colon + 1))
@@ -2317,632 +2103,763 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
if (!p)
return -ENOMEM;
- r = sd_bus_message_append(m, "(sv)", field, "(ss)", p, colon + 1);
+ r = sd_bus_message_append(m, "(sv)", "ProtectHostnameEx", "(ss)", p, colon + 1);
} else
- r = sd_bus_message_append(m, "(sv)", field, "(ss)", eq, NULL);
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
+ r = sd_bus_message_append(m, "(sv)", "ProtectHostnameEx", "(ss)", eq, NULL);
}
- return 0;
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
}
-static int bus_append_kill_property(sd_bus_message *m, const char *field, const char *eq) {
- if (streq(field, "KillMode"))
- return bus_append_string(m, field, eq);
-
- if (STR_IN_SET(field, "SendSIGHUP",
- "SendSIGKILL"))
- return bus_append_parse_boolean(m, field, eq);
-
- if (STR_IN_SET(field, "KillSignal",
- "RestartKillSignal",
- "FinalKillSignal",
- "WatchdogSignal",
- "ReloadSignal"))
- return bus_append_signal_from_string(m, field, eq);
-
- return 0;
+static int bus_append_paths(sd_bus_message *m, const char *field, const char *eq) {
+ return bus_append_trivial_array(m, "Paths", eq,
+ "a(ss)", field, eq);
}
-static int bus_append_mount_property(sd_bus_message *m, const char *field, const char *eq) {
-
- if (STR_IN_SET(field, "What",
- "Where",
- "Options",
- "Type"))
- return bus_append_string(m, field, eq);
-
- if (streq(field, "TimeoutSec"))
- return bus_append_parse_sec_rename(m, field, eq);
-
- if (streq(field, "DirectoryMode"))
- return bus_append_parse_mode(m, field, eq);
-
- if (STR_IN_SET(field, "SloppyOptions",
- "LazyUnmount",
- "ForceUnmount",
- "ReadwriteOnly"))
- return bus_append_parse_boolean(m, field, eq);
-
- return 0;
-}
-
-static int bus_append_path_property(sd_bus_message *m, const char *field, const char *eq) {
+static int bus_append_exit_status(sd_bus_message *m, const char *field, const char *eq) {
+ _cleanup_free_ int *status = NULL, *signal = NULL;
+ size_t n_status = 0, n_signal = 0;
int r;
- if (streq(field, "MakeDirectory"))
- return bus_append_parse_boolean(m, field, eq);
+ for (const char *p = eq;;) {
+ _cleanup_free_ char *word = NULL;
- if (streq(field, "DirectoryMode"))
- return bus_append_parse_mode(m, field, eq);
-
- if (STR_IN_SET(field, "PathExists",
- "PathExistsGlob",
- "PathChanged",
- "PathModified",
- "DirectoryNotEmpty")) {
- if (isempty(eq))
- r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 0);
- else
- r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 1, field, eq);
+ r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
+ if (r == 0)
+ break;
+ if (r == -ENOMEM)
+ return log_oom();
if (r < 0)
- return bus_log_create_error(r);
+ return log_error_errno(r, "Invalid syntax in %s: %s", field, eq);
- return 1;
+ /* We need to call exit_status_from_string() first, because we want
+ * to parse numbers as exit statuses, not signals. */
+
+ r = exit_status_from_string(word);
+ if (r >= 0) {
+ assert(r >= 0 && r < 256);
+
+ if (!GREEDY_REALLOC(status, n_status + 1))
+ return log_oom();
+
+ status[n_status++] = r;
+
+ } else if ((r = signal_from_string(word)) >= 0) {
+ if (!GREEDY_REALLOC(signal, n_signal + 1))
+ return log_oom();
+
+ signal[n_signal++] = r;
+
+ } else
+ /* original r from exit_status_to_string() */
+ return log_error_errno(r, "Invalid status or signal %s in %s: %m",
+ word, field);
}
- if (STR_IN_SET(field, "TriggerLimitBurst", "PollLimitBurst"))
- return bus_append_safe_atou(m, field, eq);
+ r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
+ if (r < 0)
+ return bus_log_create_error(r);
- if (STR_IN_SET(field, "TriggerLimitIntervalSec", "PollLimitIntervalSec"))
- return bus_append_parse_sec_rename(m, field, eq);
+ r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
+ if (r < 0)
+ return bus_log_create_error(r);
- return 0;
+ r = sd_bus_message_open_container(m, 'v', "(aiai)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'r', "aiai");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_array(m, 'i', status, n_status * sizeof(int));
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_array(m, 'i', signal, n_signal * sizeof(int));
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
}
-static int bus_append_scope_property(sd_bus_message *m, const char *field, const char *eq) {
- if (streq(field, "RuntimeMaxSec"))
- return bus_append_parse_sec_rename(m, field, eq);
+static int bus_append_action_exit_status(sd_bus_message *m, const char *field, const char *eq) {
+ int r;
- if (streq(field, "RuntimeRandomizedExtraSec"))
- return bus_append_parse_sec_rename(m, field, eq);
+ if (isempty(eq))
+ r = sd_bus_message_append(m, "(sv)", field, "i", -1);
+ else {
+ uint8_t u;
- if (streq(field, "TimeoutStopSec"))
- return bus_append_parse_sec_rename(m, field, eq);
+ r = safe_atou8(eq, &u);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s=%s", field, eq);
+
+ r = sd_bus_message_append(m, "(sv)", field, "i", (int) u);
+ }
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
+static int bus_append_listen(sd_bus_message *m, const char *field, const char *eq) {
+ const char *p = ASSERT_PTR(startswith(field, "Listen"));
+
+ return bus_append_trivial_array(m, "Listen", eq,
+ "a(ss)", p, eq);
+}
+
+static int bus_append_timers_monotonic(sd_bus_message *m, const char *field, const char *eq) {
+ int r;
+
+ if (isempty(eq))
+ r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 0);
+ else {
+ usec_t t;
+ r = parse_sec(eq, &t);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
+
+ r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t);
+ }
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
+static int bus_append_timers_calendar(sd_bus_message *m, const char *field, const char *eq) {
+ return bus_append_trivial_array(m, "TimersCalendar", eq,
+ "a(ss)", field, eq);
+}
+
+static int bus_append_timeout_sec(sd_bus_message *m, const char *field, const char *eq) {
+ int r;
+
+ r = bus_append_parse_sec_rename(m, "TimeoutStartSec", eq);
+ if (r < 0)
+ return r;
+
+ return bus_append_parse_sec_rename(m, "TimeoutStopSec", eq);
+}
+
+static int bus_try_append_condition(sd_bus_message *m, const char *field, const char *eq) {
+ ConditionType t = condition_type_from_string(field);
+ bool is_condition = t >= 0;
+
+ if (!is_condition) {
+ t = assert_type_from_string(field);
+ if (t < 0)
+ return 0;
+ }
+
+ const char *p = eq;
+
+ int trigger = p && *p == '|';
+ if (trigger)
+ p++;
+
+ int negate = p && *p == '!';
+ if (negate)
+ p++;
+
+ return bus_append_trivial_array(m,
+ is_condition ? "Conditions" : "Asserts",
+ eq,
+ "a(sbbs)",
+ field, trigger, negate, p);
+}
+
+static void dump_conditions(void) {
+ condition_types_list();
+ assert_types_list();
+}
+
+static int bus_try_append_unit_dependency(sd_bus_message *m, const char *field, const char *eq) {
+ if (unit_dependency_from_string(field) < 0)
+ return 0;
+
+ return bus_append_strv(m, field, eq);
+}
+
+typedef struct BusProperty {
+ const char *name;
+ int (*convert)(sd_bus_message *m, const char *field, const char *eq);
+ void (*dump)(void);
+} BusProperty;
+
+static const BusProperty cgroup_properties[] = {
+ { "DevicePolicy", bus_append_string },
+ { "Slice", bus_append_string },
+ { "ManagedOOMSwap", bus_append_string },
+ { "ManagedOOMMemoryPressure", bus_append_string },
+ { "ManagedOOMPreference", bus_append_string },
+ { "MemoryPressureWatch", bus_append_string },
+ { "DelegateSubgroup", bus_append_string },
+ { "ManagedOOMMemoryPressureLimit", bus_append_parse_permyriad },
+ { "MemoryAccounting", bus_append_parse_boolean },
+ { "MemoryZSwapWriteback", bus_append_parse_boolean },
+ { "IOAccounting", bus_append_parse_boolean },
+ { "TasksAccounting", bus_append_parse_boolean },
+ { "IPAccounting", bus_append_parse_boolean },
+ { "CoredumpReceive", bus_append_parse_boolean },
+ { "CPUWeight", bus_append_cg_cpu_weight_parse },
+ { "StartupCPUWeight", bus_append_cg_cpu_weight_parse },
+ { "IOWeight", bus_append_cg_weight_parse },
+ { "StartupIOWeight", bus_append_cg_weight_parse },
+ { "AllowedCPUs", bus_append_parse_cpu_set },
+ { "StartupAllowedCPUs", bus_append_parse_cpu_set },
+ { "AllowedMemoryNodes", bus_append_parse_cpu_set },
+ { "StartupAllowedMemoryNodes", bus_append_parse_cpu_set },
+ { "DisableControllers", bus_append_strv },
+ { "Delegate", bus_append_parse_delegate },
+ { "MemoryMin", bus_append_parse_resource_limit },
+ { "DefaultMemoryLow", bus_append_parse_resource_limit },
+ { "DefaultMemoryMin", bus_append_parse_resource_limit },
+ { "MemoryLow", bus_append_parse_resource_limit },
+ { "MemoryHigh", bus_append_parse_resource_limit },
+ { "MemoryMax", bus_append_parse_resource_limit },
+ { "MemorySwapMax", bus_append_parse_resource_limit },
+ { "MemoryZSwapMax", bus_append_parse_resource_limit },
+ { "TasksMax", bus_append_parse_resource_limit },
+ { "CPUQuota", bus_append_parse_cpu_quota },
+ { "CPUQuotaPeriodSec", bus_append_parse_sec_rename_infinity },
+ { "DeviceAllow", bus_append_parse_device_allow },
+ { "IODeviceWeight", bus_append_parse_io_device_weight },
+ { "IODeviceLatencyTargetSec", bus_append_parse_io_device_latency },
+ { "IPAddressAllow", bus_append_parse_ip_address_filter },
+ { "IPAddressDeny", bus_append_parse_ip_address_filter },
+ { "IPIngressFilterPath", bus_append_ip_filter_path },
+ { "IPEgressFilterPath", bus_append_ip_filter_path },
+ { "BPFProgram", bus_append_bpf_program },
+ { "SocketBindAllow", bus_append_socket_filter },
+ { "SocketBindDeny", bus_append_socket_filter },
+ { "MemoryPressureThresholdSec", bus_append_parse_sec_rename },
+ { "NFTSet", bus_append_nft_set },
+
+ /* While infinity is disallowed in unit file, infinity is allowed in D-Bus API which
+ * means use the default memory pressure duration from oomd.conf. */
+ { "ManagedOOMMemoryPressureDurationSec", bus_append_parse_sec_rename_infinity },
+
+ { "MemoryLimit", warn_deprecated },
+ { "CPUShares", warn_deprecated },
+ { "StartupCPUShares", warn_deprecated },
+ { "BlockIOAccounting", warn_deprecated },
+ { "BlockIOWeight", warn_deprecated },
+ { "StartupBlockIOWeight", warn_deprecated },
+ { "BlockIODeviceWeight", warn_deprecated },
+ { "BlockIOReadBandwidth", warn_deprecated },
+ { "BlockIOWriteBandwidth", warn_deprecated },
+ { "CPUAccounting", warn_deprecated },
+
+ { NULL, bus_try_append_parse_cgroup_io_limit, cgroup_io_limits_list },
+ {}
+};
+
+static const BusProperty automount_properties[] = {
+ { "Where", bus_append_string },
+ { "ExtraOptions", bus_append_string },
+ { "DirectoryMode", bus_append_parse_mode },
+ { "TimeoutIdleSec", bus_append_parse_sec_rename },
+ {}
+};
+
+static const BusProperty execute_properties[] = {
+ { "User", bus_append_string },
+ { "Group", bus_append_string },
+ { "UtmpIdentifier", bus_append_string },
+ { "UtmpMode", bus_append_string },
+ { "PAMName", bus_append_string },
+ { "TTYPath", bus_append_string },
+ { "WorkingDirectory", bus_append_string },
+ { "RootDirectory", bus_append_string },
+ { "SyslogIdentifier", bus_append_string },
+ { "ProtectSystem", bus_append_string },
+ { "ProtectHome", bus_append_string },
+ { "PrivateTmpEx", bus_append_string },
+ { "PrivateUsersEx", bus_append_string },
+ { "ProtectControlGroupsEx", bus_append_string },
+ { "SELinuxContext", bus_append_string },
+ { "RootImage", bus_append_string },
+ { "RootVerity", bus_append_string },
+ { "RuntimeDirectoryPreserve", bus_append_string },
+ { "Personality", bus_append_string },
+ { "KeyringMode", bus_append_string },
+ { "ProtectProc", bus_append_string },
+ { "ProcSubset", bus_append_string },
+ { "NetworkNamespacePath", bus_append_string },
+ { "IPCNamespacePath", bus_append_string },
+ { "LogNamespace", bus_append_string },
+ { "RootImagePolicy", bus_append_string },
+ { "MountImagePolicy", bus_append_string },
+ { "ExtensionImagePolicy", bus_append_string },
+ { "PrivatePIDs", bus_append_string },
+ { "IgnoreSIGPIPE", bus_append_parse_boolean },
+ { "TTYVHangup", bus_append_parse_boolean },
+ { "TTYReset", bus_append_parse_boolean },
+ { "TTYVTDisallocate", bus_append_parse_boolean },
+ { "PrivateTmp", bus_append_parse_boolean },
+ { "PrivateDevices", bus_append_parse_boolean },
+ { "PrivateNetwork", bus_append_parse_boolean },
+ { "PrivateUsers", bus_append_parse_boolean },
+ { "PrivateMounts", bus_append_parse_boolean },
+ { "PrivateIPC", bus_append_parse_boolean },
+ { "NoNewPrivileges", bus_append_parse_boolean },
+ { "SyslogLevelPrefix", bus_append_parse_boolean },
+ { "MemoryDenyWriteExecute", bus_append_parse_boolean },
+ { "RestrictRealtime", bus_append_parse_boolean },
+ { "DynamicUser", bus_append_parse_boolean },
+ { "RemoveIPC", bus_append_parse_boolean },
+ { "ProtectKernelTunables", bus_append_parse_boolean },
+ { "ProtectKernelModules", bus_append_parse_boolean },
+ { "ProtectKernelLogs", bus_append_parse_boolean },
+ { "ProtectClock", bus_append_parse_boolean },
+ { "ProtectControlGroups", bus_append_parse_boolean },
+ { "MountAPIVFS", bus_append_parse_boolean },
+ { "BindLogSockets", bus_append_parse_boolean },
+ { "CPUSchedulingResetOnFork", bus_append_parse_boolean },
+ { "LockPersonality", bus_append_parse_boolean },
+ { "MemoryKSM", bus_append_parse_boolean },
+ { "RestrictSUIDSGID", bus_append_parse_boolean },
+ { "RootEphemeral", bus_append_parse_boolean },
+ { "SetLoginEnvironment", bus_append_parse_boolean },
+ { "ReadWriteDirectories", bus_append_strv },
+ { "ReadOnlyDirectories", bus_append_strv },
+ { "InaccessibleDirectories", bus_append_strv },
+ { "ReadWritePaths", bus_append_strv },
+ { "ReadOnlyPaths", bus_append_strv },
+ { "InaccessiblePaths", bus_append_strv },
+ { "ExecPaths", bus_append_strv },
+ { "NoExecPaths", bus_append_strv },
+ { "ExecSearchPath", bus_append_strv },
+ { "ExtensionDirectories", bus_append_strv },
+ { "ConfigurationDirectory", bus_append_strv },
+ { "SupplementaryGroups", bus_append_strv },
+ { "SystemCallArchitectures", bus_append_strv },
+ { "SyslogLevel", bus_append_log_level_from_string },
+ { "LogLevelMax", bus_append_log_level_from_string },
+ { "SyslogFacility", bus_append_log_facility_unshifted_from_string },
+ { "SecureBits", bus_append_secure_bits_from_string },
+ { "CPUSchedulingPolicy", bus_append_sched_policy_from_string },
+ { "CPUSchedulingPriority", bus_append_safe_atoi },
+ { "OOMScoreAdjust", bus_append_safe_atoi },
+ { "CoredumpFilter", bus_append_coredump_filter_mask_from_string },
+ { "Nice", bus_append_parse_nice },
+ { "SystemCallErrorNumber", bus_append_seccomp_parse_errno_or_action },
+ { "IOSchedulingClass", bus_append_ioprio_class_from_string },
+ { "IOSchedulingPriority", bus_append_ioprio_parse_priority },
+ { "RuntimeDirectoryMode", bus_append_parse_mode },
+ { "StateDirectoryMode", bus_append_parse_mode },
+ { "CacheDirectoryMode", bus_append_parse_mode },
+ { "LogsDirectoryMode", bus_append_parse_mode },
+ { "ConfigurationDirectoryMode", bus_append_parse_mode },
+ { "UMask", bus_append_parse_mode },
+ { "TimerSlackNSec", bus_append_parse_nsec },
+ { "LogRateLimitIntervalSec", bus_append_parse_sec_rename },
+ { "LogRateLimitBurst", bus_append_safe_atou },
+ { "TTYRows", bus_append_safe_atou },
+ { "TTYColumns", bus_append_safe_atou },
+ { "MountFlags", bus_append_mount_propagation_flag_from_string },
+ { "Environment", bus_append_strv_cunescape },
+ { "UnsetEnvironment", bus_append_strv_cunescape },
+ { "PassEnvironment", bus_append_strv_cunescape },
+ { "EnvironmentFile", bus_append_environment_files },
+ { "SetCredential", bus_append_set_credential },
+ { "SetCredentialEncrypted", bus_append_set_credential },
+ { "LoadCredential", bus_append_load_credential },
+ { "LoadCredentialEncrypted", bus_append_load_credential },
+ { "ImportCredential", bus_append_import_credential },
+ { "ImportCredentialEx", bus_append_import_credential },
+ { "LogExtraFields", bus_append_log_extra_fields },
+ { "LogFilterPatterns", bus_append_log_filter_patterns },
+ { "StandardInput", bus_append_standard_inputs },
+ { "StandardOutput", bus_append_standard_inputs },
+ { "StandardError", bus_append_standard_inputs },
+ { "StandardInputText", bus_append_standard_input_text },
+ { "StandardInputData", bus_append_standard_input_data },
+ { "AppArmorProfile", bus_append_string_with_ignore },
+ { "SmackProcessLabel", bus_append_string_with_ignore },
+ { "CapabilityBoundingSet", bus_append_capabilities },
+ { "AmbientCapabilities", bus_append_capabilities },
+ { "CPUAffinity", bus_append_cpu_affinity },
+ { "NUMAPolicy", bus_append_mpol_from_string },
+ { "NUMAMask", bus_append_numa_mask },
+ { "RestrictAddressFamilies", bus_append_filter_list },
+ { "RestrictFileSystems", bus_append_filter_list },
+ { "SystemCallFilter", bus_append_filter_list },
+ { "SystemCallLog", bus_append_filter_list },
+ { "RestrictNetworkInterfaces", bus_append_filter_list },
+ { "RestrictNamespaces", bus_append_namespace_list },
+ { "DelegateNamespaces", bus_append_namespace_list },
+ { "BindPaths", bus_append_bind_paths },
+ { "BindReadOnlyPaths", bus_append_bind_paths },
+ { "TemporaryFileSystem", bus_append_temporary_file_system },
+ { "RootHash", bus_append_root_hash },
+ { "RootHashSignature", bus_append_root_hash_signature },
+ { "RootImageOptions", bus_append_root_image_options },
+ { "MountImages", bus_append_mount_images },
+ { "ExtensionImages", bus_append_extension_images },
+ { "StateDirectory", bus_append_directory },
+ { "RuntimeDirectory", bus_append_directory },
+ { "CacheDirectory", bus_append_directory },
+ { "LogsDirectory", bus_append_directory },
+ { "ProtectHostname", bus_append_protect_hostname },
+ { "ProtectHostnameEx", bus_append_protect_hostname },
+
+ { NULL, bus_try_append_resource_limit, dump_resource_limits },
+ {}
+};
+
+static const BusProperty kill_properties[] = {
+ { "KillMode", bus_append_string },
+ { "SendSIGHUP", bus_append_parse_boolean },
+ { "SendSIGKILL", bus_append_parse_boolean },
+ { "KillSignal", bus_append_signal_from_string },
+ { "RestartKillSignal", bus_append_signal_from_string },
+ { "FinalKillSignal", bus_append_signal_from_string },
+ { "WatchdogSignal", bus_append_signal_from_string },
+ { "ReloadSignal", bus_append_signal_from_string },
+ {}
+};
+
+static const BusProperty mount_properties[] = {
+ { "What", bus_append_string },
+ { "Where", bus_append_string },
+ { "Options", bus_append_string },
+ { "Type", bus_append_string },
+ { "TimeoutSec", bus_append_parse_sec_rename },
+ { "DirectoryMode", bus_append_parse_mode },
+ { "SloppyOptions", bus_append_parse_boolean },
+ { "LazyUnmount", bus_append_parse_boolean },
+ { "ForceUnmount", bus_append_parse_boolean },
+ { "ReadwriteOnly", bus_append_parse_boolean },
+ {}
+};
+
+static const BusProperty path_properties[] = {
+ { "MakeDirectory", bus_append_parse_boolean },
+ { "DirectoryMode", bus_append_parse_mode },
+ { "PathExists", bus_append_paths },
+ { "PathExistsGlob", bus_append_paths },
+ { "PathChanged", bus_append_paths },
+ { "PathModified", bus_append_paths },
+ { "DirectoryNotEmpty", bus_append_paths },
+ { "TriggerLimitBurst", bus_append_safe_atou },
+ { "PollLimitBurst", bus_append_safe_atou },
+ { "TriggerLimitIntervalSec", bus_append_parse_sec_rename },
+ { "PollLimitIntervalSec", bus_append_parse_sec_rename },
+ {}
+};
+
+static const BusProperty scope_properties[] = {
+ { "RuntimeMaxSec", bus_append_parse_sec_rename },
+ { "RuntimeRandomizedExtraSec", bus_append_parse_sec_rename },
+ { "TimeoutStopSec", bus_append_parse_sec_rename },
+ { "OOMPolicy", bus_append_string },
/* Scope units don't have execution context but we still want to allow setting these two,
* so let's handle them separately. */
- if (STR_IN_SET(field, "User", "Group"))
- return bus_append_string(m, field, eq);
-
- if (streq(field, "OOMPolicy"))
- return bus_append_string(m, field, eq);
-
- return 0;
-}
-
-static int bus_append_service_property(sd_bus_message *m, const char *field, const char *eq) {
- int r;
-
- if (STR_IN_SET(field, "PIDFile",
- "Type",
- "ExitType",
- "Restart",
- "RestartMode",
- "BusName",
- "NotifyAccess",
- "USBFunctionDescriptors",
- "USBFunctionStrings",
- "OOMPolicy",
- "TimeoutStartFailureMode",
- "TimeoutStopFailureMode",
- "FileDescriptorStorePreserve"))
- return bus_append_string(m, field, eq);
-
- if (STR_IN_SET(field, "PermissionsStartOnly",
- "RootDirectoryStartOnly",
- "RemainAfterExit",
- "GuessMainPID"))
- return bus_append_parse_boolean(m, field, eq);
-
- if (STR_IN_SET(field, "RestartSec",
- "RestartMaxDelaySec",
- "TimeoutStartSec",
- "TimeoutStopSec",
- "TimeoutAbortSec",
- "RuntimeMaxSec",
- "RuntimeRandomizedExtraSec",
- "WatchdogSec"))
- return bus_append_parse_sec_rename(m, field, eq);
-
- if (streq(field, "TimeoutSec")) {
- r = bus_append_parse_sec_rename(m, "TimeoutStartSec", eq);
- if (r < 0)
- return r;
-
- return bus_append_parse_sec_rename(m, "TimeoutStopSec", eq);
- }
-
- if (STR_IN_SET(field, "FileDescriptorStoreMax",
- "RestartSteps"))
- return bus_append_safe_atou(m, field, eq);
-
- if (STR_IN_SET(field, "ExecCondition",
- "ExecStartPre",
- "ExecStart",
- "ExecStartPost",
- "ExecConditionEx",
- "ExecStartPreEx",
- "ExecStartEx",
- "ExecStartPostEx",
- "ExecReload",
- "ExecStop",
- "ExecStopPost",
- "ExecReloadEx",
- "ExecStopEx",
- "ExecStopPostEx"))
- return bus_append_exec_command(m, field, eq);
-
- if (STR_IN_SET(field, "RestartPreventExitStatus",
- "RestartForceExitStatus",
- "SuccessExitStatus")) {
- _cleanup_free_ int *status = NULL, *signal = NULL;
- size_t n_status = 0, n_signal = 0;
- const char *p;
-
- for (p = eq;;) {
- _cleanup_free_ char *word = NULL;
-
- r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
- if (r == 0)
- break;
- if (r == -ENOMEM)
- return log_oom();
- if (r < 0)
- return log_error_errno(r, "Invalid syntax in %s: %s", field, eq);
-
- /* We need to call exit_status_from_string() first, because we want
- * to parse numbers as exit statuses, not signals. */
-
- r = exit_status_from_string(word);
- if (r >= 0) {
- assert(r >= 0 && r < 256);
-
- if (!GREEDY_REALLOC(status, n_status + 1))
- return log_oom();
-
- status[n_status++] = r;
-
- } else if ((r = signal_from_string(word)) >= 0) {
- if (!GREEDY_REALLOC(signal, n_signal + 1))
- return log_oom();
-
- signal[n_signal++] = r;
-
- } else
- /* original r from exit_status_to_string() */
- return log_error_errno(r, "Invalid status or signal %s in %s: %m",
- word, field);
- }
-
- r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'v', "(aiai)");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'r', "aiai");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append_array(m, 'i', status, n_status * sizeof(int));
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append_array(m, 'i', signal, n_signal * sizeof(int));
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (streq(field, "OpenFile"))
- return bus_append_open_file(m, field, eq);
-
- return 0;
-}
-
-static int bus_append_socket_property(sd_bus_message *m, const char *field, const char *eq) {
- int r;
-
- if (STR_IN_SET(field, "Accept",
- "FlushPending",
- "Writable",
- "KeepAlive",
- "NoDelay",
- "FreeBind",
- "Transparent",
- "Broadcast",
- "PassCredentials",
- "PassPIDFD",
- "PassSecurity",
- "PassPacketInfo",
- "AcceptFileDescriptors",
- "ReusePort",
- "RemoveOnStop",
- "PassFileDescriptorsToExec",
- "SELinuxContextFromNet"))
- return bus_append_parse_boolean(m, field, eq);
-
- if (STR_IN_SET(field, "Priority",
- "IPTTL",
- "Mark"))
- return bus_append_safe_atoi(m, field, eq);
-
- if (streq(field, "IPTOS"))
- return bus_append_ip_tos_from_string(m, field, eq);
-
- if (STR_IN_SET(field, "Backlog",
- "MaxConnections",
- "MaxConnectionsPerSource",
- "KeepAliveProbes",
- "TriggerLimitBurst",
- "PollLimitBurst"))
- return bus_append_safe_atou(m, field, eq);
-
- if (STR_IN_SET(field, "SocketMode",
- "DirectoryMode"))
- return bus_append_parse_mode(m, field, eq);
-
- if (STR_IN_SET(field, "MessageQueueMaxMessages",
- "MessageQueueMessageSize"))
- return bus_append_safe_atoi64(m, field, eq);
-
- if (STR_IN_SET(field, "TimeoutSec",
- "KeepAliveTimeSec",
- "KeepAliveIntervalSec",
- "DeferAcceptSec",
- "TriggerLimitIntervalSec",
- "PollLimitIntervalSec",
- "DeferTriggerMaxSec"))
- return bus_append_parse_sec_rename(m, field, eq);
-
- if (STR_IN_SET(field, "ReceiveBuffer",
- "SendBuffer",
- "PipeSize"))
- return bus_append_parse_size(m, field, eq, 1024);
-
- if (STR_IN_SET(field, "ExecStartPre",
- "ExecStartPost",
- "ExecReload",
- "ExecStopPost"))
- return bus_append_exec_command(m, field, eq);
-
- if (STR_IN_SET(field, "SmackLabel",
- "SmackLabelIPIn",
- "SmackLabelIPOut",
- "TCPCongestion",
- "BindToDevice",
- "BindIPv6Only",
- "FileDescriptorName",
- "SocketUser",
- "SocketGroup",
- "Timestamping",
- "DeferTrigger"))
- return bus_append_string(m, field, eq);
-
- if (streq(field, "Symlinks"))
- return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
-
- if (streq(field, "SocketProtocol"))
- return bus_append_parse_ip_protocol(m, field, eq);
-
- if (STR_IN_SET(field, "ListenStream",
- "ListenDatagram",
- "ListenSequentialPacket",
- "ListenNetlink",
- "ListenSpecial",
- "ListenMessageQueue",
- "ListenFIFO",
- "ListenUSBFunction")) {
- if (isempty(eq))
- r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 0);
- else
- r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 1, field + STRLEN("Listen"), eq);
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- return 0;
-}
-static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) {
- int r;
-
- if (STR_IN_SET(field, "WakeSystem",
- "RemainAfterElapse",
- "Persistent",
- "OnTimezoneChange",
- "OnClockChange",
- "FixedRandomDelay",
- "DeferReactivation"))
- return bus_append_parse_boolean(m, field, eq);
-
- if (STR_IN_SET(field, "AccuracySec",
- "RandomizedDelaySec",
- "RandomizedOffsetSec"))
- return bus_append_parse_sec_rename(m, field, eq);
-
- if (STR_IN_SET(field, "OnActiveSec",
- "OnBootSec",
- "OnStartupSec",
- "OnUnitActiveSec",
- "OnUnitInactiveSec")) {
- if (isempty(eq))
- r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 0);
- else {
- usec_t t;
- r = parse_sec(eq, &t);
- if (r < 0)
- return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
-
- r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t);
- }
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (streq(field, "OnCalendar")) {
- if (isempty(eq))
- r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 0);
- else
- r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 1, field, eq);
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- return 0;
-}
-
-static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) {
- ConditionType t = _CONDITION_TYPE_INVALID;
- bool is_condition = false;
- int r;
-
- if (STR_IN_SET(field, "Description",
- "SourcePath",
- "OnFailureJobMode",
- "JobTimeoutAction",
- "JobTimeoutRebootArgument",
- "StartLimitAction",
- "FailureAction",
- "SuccessAction",
- "RebootArgument",
- "CollectMode"))
- return bus_append_string(m, field, eq);
-
- if (STR_IN_SET(field, "StopWhenUnneeded",
- "RefuseManualStart",
- "RefuseManualStop",
- "AllowIsolate",
- "IgnoreOnIsolate",
- "SurviveFinalKillSignal",
- "DefaultDependencies"))
- return bus_append_parse_boolean(m, field, eq);
-
- if (STR_IN_SET(field, "JobTimeoutSec",
- "JobRunningTimeoutSec",
- "StartLimitIntervalSec"))
- return bus_append_parse_sec_rename(m, field, eq);
-
- if (streq(field, "StartLimitBurst"))
- return bus_append_safe_atou(m, field, eq);
-
- if (STR_IN_SET(field, "SuccessActionExitStatus",
- "FailureActionExitStatus")) {
- if (isempty(eq))
- r = sd_bus_message_append(m, "(sv)", field, "i", -1);
- else {
- uint8_t u;
-
- r = safe_atou8(eq, &u);
- if (r < 0)
- return log_error_errno(r, "Failed to parse %s=%s", field, eq);
-
- r = sd_bus_message_append(m, "(sv)", field, "i", (int) u);
- }
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- if (unit_dependency_from_string(field) >= 0 ||
- STR_IN_SET(field, "Documentation",
- "RequiresMountsFor",
- "WantsMountsFor",
- "Markers"))
- return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
-
- t = condition_type_from_string(field);
- if (t >= 0)
- is_condition = true;
- else
- t = assert_type_from_string(field);
- if (t >= 0) {
- if (isempty(eq))
- r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 0);
- else {
- const char *p = eq;
- int trigger, negate;
-
- trigger = *p == '|';
- if (trigger)
- p++;
-
- negate = *p == '!';
- if (negate)
- p++;
-
- r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 1,
- field, trigger, negate, p);
- }
- if (r < 0)
- return bus_log_create_error(r);
-
- return 1;
- }
-
- return 0;
-}
+ { "User", bus_append_string },
+ { "Group", bus_append_string },
+ {}
+};
+
+static const BusProperty service_properties[] = {
+ { "PIDFile", bus_append_string },
+ { "Type", bus_append_string },
+ { "ExitType", bus_append_string },
+ { "Restart", bus_append_string },
+ { "RestartMode", bus_append_string },
+ { "BusName", bus_append_string },
+ { "NotifyAccess", bus_append_string },
+ { "USBFunctionDescriptors", bus_append_string },
+ { "USBFunctionStrings", bus_append_string },
+ { "OOMPolicy", bus_append_string },
+ { "TimeoutStartFailureMode", bus_append_string },
+ { "TimeoutStopFailureMode", bus_append_string },
+ { "FileDescriptorStorePreserve", bus_append_string },
+ { "PermissionsStartOnly", bus_append_parse_boolean },
+ { "RootDirectoryStartOnly", bus_append_parse_boolean },
+ { "RemainAfterExit", bus_append_parse_boolean },
+ { "GuessMainPID", bus_append_parse_boolean },
+ { "RestartSec", bus_append_parse_sec_rename },
+ { "RestartMaxDelaySec", bus_append_parse_sec_rename },
+ { "TimeoutStartSec", bus_append_parse_sec_rename },
+ { "TimeoutStopSec", bus_append_parse_sec_rename },
+ { "TimeoutAbortSec", bus_append_parse_sec_rename },
+ { "RuntimeMaxSec", bus_append_parse_sec_rename },
+ { "RuntimeRandomizedExtraSec", bus_append_parse_sec_rename },
+ { "WatchdogSec", bus_append_parse_sec_rename },
+ { "TimeoutSec", bus_append_timeout_sec },
+ { "FileDescriptorStoreMax", bus_append_safe_atou },
+ { "RestartSteps", bus_append_safe_atou },
+ { "ExecCondition", bus_append_exec_command },
+ { "ExecStartPre", bus_append_exec_command },
+ { "ExecStart", bus_append_exec_command },
+ { "ExecStartPost", bus_append_exec_command },
+ { "ExecConditionEx", bus_append_exec_command },
+ { "ExecStartPreEx", bus_append_exec_command },
+ { "ExecStartEx", bus_append_exec_command },
+ { "ExecStartPostEx", bus_append_exec_command },
+ { "ExecReload", bus_append_exec_command },
+ { "ExecStop", bus_append_exec_command },
+ { "ExecStopPost", bus_append_exec_command },
+ { "ExecReloadEx", bus_append_exec_command },
+ { "ExecStopEx", bus_append_exec_command },
+ { "ExecStopPostEx", bus_append_exec_command },
+ { "RestartPreventExitStatus", bus_append_exit_status },
+ { "RestartForceExitStatus", bus_append_exit_status },
+ { "SuccessExitStatus", bus_append_exit_status },
+ { "OpenFile", bus_append_open_file },
+ {}
+};
+
+static const BusProperty socket_properties[] = {
+ { "Accept", bus_append_parse_boolean },
+ { "FlushPending", bus_append_parse_boolean },
+ { "Writable", bus_append_parse_boolean },
+ { "KeepAlive", bus_append_parse_boolean },
+ { "NoDelay", bus_append_parse_boolean },
+ { "FreeBind", bus_append_parse_boolean },
+ { "Transparent", bus_append_parse_boolean },
+ { "Broadcast", bus_append_parse_boolean },
+ { "PassCredentials", bus_append_parse_boolean },
+ { "PassFileDescriptorsToExec", bus_append_parse_boolean },
+ { "PassSecurity", bus_append_parse_boolean },
+ { "PassPacketInfo", bus_append_parse_boolean },
+ { "ReusePort", bus_append_parse_boolean },
+ { "RemoveOnStop", bus_append_parse_boolean },
+ { "SELinuxContextFromNet", bus_append_parse_boolean },
+ { "Priority", bus_append_safe_atoi },
+ { "IPTTL", bus_append_safe_atoi },
+ { "Mark", bus_append_safe_atoi },
+ { "IPTOS", bus_append_ip_tos_from_string },
+ { "Backlog", bus_append_safe_atou },
+ { "MaxConnections", bus_append_safe_atou },
+ { "MaxConnectionsPerSource", bus_append_safe_atou },
+ { "KeepAliveProbes", bus_append_safe_atou },
+ { "TriggerLimitBurst", bus_append_safe_atou },
+ { "PollLimitBurst", bus_append_safe_atou },
+ { "SocketMode", bus_append_parse_mode },
+ { "DirectoryMode", bus_append_parse_mode },
+ { "MessageQueueMaxMessages", bus_append_safe_atoi64 },
+ { "MessageQueueMessageSize", bus_append_safe_atoi64 },
+ { "TimeoutSec", bus_append_parse_sec_rename },
+ { "KeepAliveTimeSec", bus_append_parse_sec_rename },
+ { "KeepAliveIntervalSec", bus_append_parse_sec_rename },
+ { "DeferAcceptSec", bus_append_parse_sec_rename },
+ { "TriggerLimitIntervalSec", bus_append_parse_sec_rename },
+ { "PollLimitIntervalSec", bus_append_parse_sec_rename },
+ { "DeferTriggerMaxSec", bus_append_parse_sec_rename },
+ { "ReceiveBuffer", bus_append_parse_size },
+ { "SendBuffer", bus_append_parse_size },
+ { "PipeSize", bus_append_parse_size },
+ { "ExecStartPre", bus_append_exec_command },
+ { "ExecStartPost", bus_append_exec_command },
+ { "ExecReload", bus_append_exec_command },
+ { "ExecStopPost", bus_append_exec_command },
+ { "SmackLabel", bus_append_string },
+ { "SmackLabelIPIn", bus_append_string },
+ { "SmackLabelIPOut", bus_append_string },
+ { "TCPCongestion", bus_append_string },
+ { "BindToDevice", bus_append_string },
+ { "BindIPv6Only", bus_append_string },
+ { "FileDescriptorName", bus_append_string },
+ { "SocketUser", bus_append_string },
+ { "SocketGroup", bus_append_string },
+ { "Timestamping", bus_append_string },
+ { "DeferTrigger", bus_append_string },
+ { "Symlinks", bus_append_strv },
+ { "SocketProtocol", bus_append_parse_ip_protocol },
+ { "ListenStream", bus_append_listen },
+ { "ListenDatagram", bus_append_listen },
+ { "ListenSequentialPacket", bus_append_listen },
+ { "ListenNetlink", bus_append_listen },
+ { "ListenSpecial", bus_append_listen },
+ { "ListenMessageQueue", bus_append_listen },
+ { "ListenFIFO", bus_append_listen },
+ { "ListenUSBFunction", bus_append_listen },
+ {}
+};
+
+static const BusProperty timer_properties[] = {
+ { "WakeSystem", bus_append_parse_boolean },
+ { "RemainAfterElapse", bus_append_parse_boolean },
+ { "Persistent", bus_append_parse_boolean },
+ { "OnTimezoneChange", bus_append_parse_boolean },
+ { "OnClockChange", bus_append_parse_boolean },
+ { "FixedRandomDelay", bus_append_parse_boolean },
+ { "DeferReactivation", bus_append_parse_boolean },
+ { "AccuracySec", bus_append_parse_sec_rename },
+ { "RandomizedDelaySec", bus_append_parse_sec_rename },
+ { "RandomizedOffsetSec", bus_append_parse_sec_rename },
+ { "OnActiveSec", bus_append_timers_monotonic },
+ { "OnBootSec", bus_append_timers_monotonic },
+ { "OnStartupSec", bus_append_timers_monotonic },
+ { "OnUnitActiveSec", bus_append_timers_monotonic },
+ { "OnUnitInactiveSec", bus_append_timers_monotonic },
+ { "OnCalendar", bus_append_timers_calendar },
+ {}
+};
+
+static const BusProperty unit_properties[] = {
+ { "Description", bus_append_string },
+ { "SourcePath", bus_append_string },
+ { "OnFailureJobMode", bus_append_string },
+ { "JobTimeoutAction", bus_append_string },
+ { "JobTimeoutRebootArgument", bus_append_string },
+ { "StartLimitAction", bus_append_string },
+ { "FailureAction", bus_append_string },
+ { "SuccessAction", bus_append_string },
+ { "RebootArgument", bus_append_string },
+ { "CollectMode", bus_append_string },
+ { "StopWhenUnneeded", bus_append_parse_boolean },
+ { "RefuseManualStart", bus_append_parse_boolean },
+ { "RefuseManualStop", bus_append_parse_boolean },
+ { "AllowIsolate", bus_append_parse_boolean },
+ { "IgnoreOnIsolate", bus_append_parse_boolean },
+ { "SurviveFinalKillSignal", bus_append_parse_boolean },
+ { "DefaultDependencies", bus_append_parse_boolean },
+ { "JobTimeoutSec", bus_append_parse_sec_rename },
+ { "JobRunningTimeoutSec", bus_append_parse_sec_rename },
+ { "StartLimitIntervalSec", bus_append_parse_sec_rename },
+ { "StartLimitBurst", bus_append_safe_atou },
+ { "SuccessActionExitStatus", bus_append_action_exit_status },
+ { "FailureActionExitStatus", bus_append_action_exit_status },
+ { "Documentation", bus_append_strv },
+ { "RequiresMountsFor", bus_append_strv },
+ { "WantsMountsFor", bus_append_strv },
+ { "Markers", bus_append_strv },
+
+ { NULL, bus_try_append_unit_dependency, unit_types_list },
+ { NULL, bus_try_append_condition, dump_conditions },
+ {}
+};
+
+static const BusProperty* service_unit_properties[] = {
+ cgroup_properties,
+ execute_properties,
+ kill_properties,
+ service_properties,
+ unit_properties,
+ NULL,
+};
+
+static const BusProperty* socket_unit_properties[] = {
+ cgroup_properties,
+ execute_properties,
+ kill_properties,
+ socket_properties,
+ unit_properties,
+ NULL,
+};
+
+static const BusProperty* timer_unit_properties[] = {
+ timer_properties,
+ unit_properties,
+ NULL,
+};
+
+static const BusProperty* path_unit_properties[] = {
+ path_properties,
+ unit_properties,
+ NULL,
+};
+
+static const BusProperty* slice_unit_properties[] = {
+ cgroup_properties,
+ unit_properties,
+ NULL,
+};
+
+static const BusProperty* scope_unit_properties[] = {
+ cgroup_properties,
+ kill_properties,
+ scope_properties,
+ unit_properties,
+ NULL,
+};
+
+static const BusProperty* mount_unit_properties[] = {
+ cgroup_properties,
+ execute_properties,
+ kill_properties,
+ mount_properties,
+ unit_properties,
+ NULL,
+};
+
+static const BusProperty* automount_unit_properties[] = {
+ automount_properties,
+ unit_properties,
+ NULL,
+};
+
+static const BusProperty* other_unit_properties[] = {
+ unit_properties,
+ NULL,
+};
+
+static const BusProperty** unit_type_properties[_UNIT_TYPE_MAX] = {
+ [UNIT_SERVICE] = service_unit_properties,
+ [UNIT_SOCKET] = socket_unit_properties,
+ [UNIT_TIMER] = timer_unit_properties,
+ [UNIT_PATH] = path_unit_properties,
+ [UNIT_SLICE] = slice_unit_properties,
+ [UNIT_SCOPE] = scope_unit_properties,
+ [UNIT_MOUNT] = mount_unit_properties,
+ [UNIT_AUTOMOUNT] = automount_unit_properties,
+ [UNIT_TARGET] = other_unit_properties,
+ [UNIT_DEVICE] = other_unit_properties,
+ [UNIT_SWAP] = other_unit_properties,
+};
int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) {
- const char *eq, *field;
+ _cleanup_free_ char *field = NULL;
+ const char *eq;
int r;
assert(m);
assert(assignment);
+ assert(t >= 0 && t < _UNIT_TYPE_MAX);
eq = strchr(assignment, '=');
if (!eq)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Not an assignment: %s", assignment);
- field = strndupa_safe(assignment, eq - assignment);
+
+ field = strndup(assignment, eq - assignment);
+ if (!field)
+ return log_oom();
eq++;
- switch (t) {
- case UNIT_SERVICE:
- r = bus_append_cgroup_property(m, field, eq);
- if (r != 0)
- return r;
-
- r = bus_append_execute_property(m, field, eq);
- if (r != 0)
- return r;
-
- r = bus_append_kill_property(m, field, eq);
- if (r != 0)
- return r;
-
- r = bus_append_service_property(m, field, eq);
- if (r != 0)
- return r;
- break;
-
- case UNIT_SOCKET:
- r = bus_append_cgroup_property(m, field, eq);
- if (r != 0)
- return r;
-
- r = bus_append_execute_property(m, field, eq);
- if (r != 0)
- return r;
-
- r = bus_append_kill_property(m, field, eq);
- if (r != 0)
- return r;
-
- r = bus_append_socket_property(m, field, eq);
- if (r != 0)
- return r;
- break;
-
- case UNIT_TIMER:
- r = bus_append_timer_property(m, field, eq);
- if (r != 0)
- return r;
- break;
-
- case UNIT_PATH:
- r = bus_append_path_property(m, field, eq);
- if (r != 0)
- return r;
- break;
-
- case UNIT_SLICE:
- r = bus_append_cgroup_property(m, field, eq);
- if (r != 0)
- return r;
- break;
-
- case UNIT_SCOPE:
- r = bus_append_cgroup_property(m, field, eq);
- if (r != 0)
- return r;
-
- r = bus_append_kill_property(m, field, eq);
- if (r != 0)
- return r;
-
- r = bus_append_scope_property(m, field, eq);
- if (r != 0)
- return r;
- break;
-
- case UNIT_MOUNT:
- r = bus_append_cgroup_property(m, field, eq);
- if (r != 0)
- return r;
-
- r = bus_append_execute_property(m, field, eq);
- if (r != 0)
- return r;
-
- r = bus_append_kill_property(m, field, eq);
- if (r != 0)
- return r;
-
- r = bus_append_mount_property(m, field, eq);
- if (r != 0)
- return r;
-
- break;
-
- case UNIT_AUTOMOUNT:
- r = bus_append_automount_property(m, field, eq);
- if (r != 0)
- return r;
-
- break;
-
- case UNIT_TARGET:
- case UNIT_DEVICE:
- case UNIT_SWAP:
- break;
-
- default:
- assert_not_reached();
- }
-
- r = bus_append_unit_property(m, field, eq);
- if (r != 0)
- return r;
+ for (const BusProperty** tables = ASSERT_PTR(unit_type_properties[t]); *tables; tables++)
+ for (const BusProperty *item = *tables; item->convert; item++)
+ if (item->name) {
+ if (streq(item->name, field))
+ return item->convert(m, field, eq);
+ } else {
+ /* If .name is not set, the function must be a "try" helper */
+ r = item->convert(m, field, eq);
+ if (r != 0)
+ return r;
+ }
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Unknown assignment: %s", assignment);
@@ -2962,6 +2879,24 @@ int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char
return 0;
}
+void bus_dump_transient_settings(UnitType t) {
+ assert(t >= 0 && t < _UNIT_TYPE_MAX);
+
+ for (const BusProperty** tables = ASSERT_PTR(unit_type_properties[t]); *tables; tables++)
+ for (const BusProperty *item = *tables; item->convert; item++) {
+ assert(item->name || item->dump);
+
+ /* Do not print deprecated names */
+ if (item->convert == warn_deprecated)
+ continue;
+
+ if (item->name)
+ puts(item->name);
+ else
+ item->dump();
+ }
+}
+
int bus_append_scope_pidref(sd_bus_message *m, const PidRef *pidref, bool allow_pidfd) {
assert(m);
diff --git a/src/shared/bus-unit-util.h b/src/shared/bus-unit-util.h
index c6e02a01b4..c07a704414 100644
--- a/src/shared/bus-unit-util.h
+++ b/src/shared/bus-unit-util.h
@@ -51,3 +51,5 @@ int unit_freezer_new(const char *name, UnitFreezer **ret);
int unit_freezer_freeze(UnitFreezer *f);
int unit_freezer_thaw(UnitFreezer *f);
+
+void bus_dump_transient_settings(UnitType t);
diff --git a/src/shared/condition.c b/src/shared/condition.c
index 14318667ec..25c38f374b 100644
--- a/src/shared/condition.c
+++ b/src/shared/condition.c
@@ -1402,6 +1402,10 @@ ConditionType condition_type_from_string(const char *s) {
return _condition_type_from_string(s);
}
+void condition_types_list(void) {
+ DUMP_STRING_TABLE(_condition_type, ConditionType, _CONDITION_TYPE_MAX);
+}
+
static const char* const _assert_type_table[_CONDITION_TYPE_MAX] = {
[CONDITION_ARCHITECTURE] = "AssertArchitecture",
[CONDITION_FIRMWARE] = "AssertFirmware",
@@ -1453,6 +1457,10 @@ ConditionType assert_type_from_string(const char *s) {
return _assert_type_from_string(s);
}
+void assert_types_list(void) {
+ DUMP_STRING_TABLE(_assert_type, ConditionType, _CONDITION_TYPE_MAX);
+}
+
static const char* const condition_result_table[_CONDITION_RESULT_MAX] = {
[CONDITION_UNTESTED] = "untested",
[CONDITION_SUCCEEDED] = "succeeded",
diff --git a/src/shared/condition.h b/src/shared/condition.h
index a06d2a89d1..c25b9643b9 100644
--- a/src/shared/condition.h
+++ b/src/shared/condition.h
@@ -88,9 +88,11 @@ void condition_dump_list(Condition *c, FILE *f, const char *prefix, condition_to
const char* condition_type_to_string(ConditionType t) _const_;
ConditionType condition_type_from_string(const char *s) _pure_;
+void condition_types_list(void);
const char* assert_type_to_string(ConditionType t) _const_;
ConditionType assert_type_from_string(const char *s) _pure_;
+void assert_types_list(void);
const char* condition_result_to_string(ConditionResult r) _const_;
ConditionResult condition_result_from_string(const char *s) _pure_;
diff --git a/src/test/meson.build b/src/test/meson.build
index 6bb9e3f40d..286fcac5c7 100644
--- a/src/test/meson.build
+++ b/src/test/meson.build
@@ -56,6 +56,7 @@ simple_tests += files(
'test-blockdev-util.c',
'test-bootspec.c',
'test-build-path.c',
+ 'test-bus-unit-util.c',
'test-bus-util.c',
'test-calendarspec.c',
'test-cgroup-util.c',
diff --git a/src/test/test-bus-unit-util.c b/src/test/test-bus-unit-util.c
new file mode 100644
index 0000000000..a1f0104bc0
--- /dev/null
+++ b/src/test/test-bus-unit-util.c
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "bus-unit-util.h"
+#include "unit-def.h"
+#include "tests.h"
+
+TEST(bus_dump_transient_settings) {
+ /* -1 is for generic unit, natural numbers are for specific unit types */
+ for (UnitType t = 0; t < _UNIT_TYPE_MAX; t++) {
+ log_info("==================== %s ====================", t < 0 ? "unit" : unit_type_to_string(t));
+ bus_dump_transient_settings(t);
+ }
+}
+
+DEFINE_TEST_MAIN(LOG_DEBUG);
diff --git a/src/test/test-conf-parser.c b/src/test/test-conf-parser.c
index 77e321d94c..e2f9f28792 100644
--- a/src/test/test-conf-parser.c
+++ b/src/test/test-conf-parser.c
@@ -171,14 +171,14 @@ TEST(config_parse_unsigned) {
}
TEST(config_parse_strv) {
- test_config_parse_strv_one("", false, STRV_MAKE_EMPTY);
+ test_config_parse_strv_one("", false, STRV_EMPTY);
test_config_parse_strv_one("foo", false, STRV_MAKE("foo"));
test_config_parse_strv_one("foo bar foo", false, STRV_MAKE("foo", "bar", "foo"));
test_config_parse_strv_one("\"foo bar\" foo", false, STRV_MAKE("foo bar", "foo"));
test_config_parse_strv_one("\xc3\x80", false, STRV_MAKE("\xc3\x80"));
test_config_parse_strv_one("\xc3\x7f", false, STRV_MAKE("\xc3\x7f"));
- test_config_parse_strv_one("", true, STRV_MAKE_EMPTY);
+ test_config_parse_strv_one("", true, STRV_EMPTY);
test_config_parse_strv_one("foo", true, STRV_MAKE("foo"));
test_config_parse_strv_one("foo bar foo", true, STRV_MAKE("foo", "bar"));
test_config_parse_strv_one("\"foo bar\" foo", true, STRV_MAKE("foo bar", "foo"));
diff --git a/src/test/test-nulstr-util.c b/src/test/test-nulstr-util.c
index 5110435778..bb0f1b32d1 100644
--- a/src/test/test-nulstr-util.c
+++ b/src/test/test-nulstr-util.c
@@ -42,22 +42,22 @@ TEST(strv_parse_nulstr_full) {
STRV_MAKE("hoge", "hoge2", "hoge3", "", "hoge5", "", "xxx"));
strv_parse_nulstr_full_one(((const char[0]) {}), 0,
- STRV_MAKE_EMPTY, STRV_MAKE_EMPTY);
+ STRV_EMPTY, STRV_EMPTY);
strv_parse_nulstr_full_one(((const char[1]) { 0 }), 1,
- STRV_MAKE(""), STRV_MAKE_EMPTY);
+ STRV_MAKE(""), STRV_EMPTY);
strv_parse_nulstr_full_one(((const char[1]) { 'x' }), 1,
STRV_MAKE("x"), STRV_MAKE("x"));
strv_parse_nulstr_full_one(((const char[2]) { 0, 0 }), 2,
- STRV_MAKE("", ""), STRV_MAKE_EMPTY);
+ STRV_MAKE("", ""), STRV_EMPTY);
strv_parse_nulstr_full_one(((const char[2]) { 'x', 0 }), 2,
STRV_MAKE("x"), STRV_MAKE("x"));
strv_parse_nulstr_full_one(((const char[3]) { 0, 0, 0 }), 3,
- STRV_MAKE("", "", ""), STRV_MAKE_EMPTY);
+ STRV_MAKE("", "", ""), STRV_EMPTY);
strv_parse_nulstr_full_one(((const char[3]) { 'x', 0, 0 }), 3,
STRV_MAKE("x", ""), STRV_MAKE("x"));
diff --git a/src/test/test-proc-cmdline.c b/src/test/test-proc-cmdline.c
index 478974b0a9..68c4e77f75 100644
--- a/src/test/test-proc-cmdline.c
+++ b/src/test/test-proc-cmdline.c
@@ -244,7 +244,7 @@ TEST(proc_cmdline_key_startswith) {
TEST(proc_cmdline_filter_pid1_args) {
test_proc_cmdline_filter_pid1_args_one("systemd\0",
- STRV_MAKE_EMPTY);
+ STRV_EMPTY);
/* short option */
test_proc_cmdline_filter_pid1_args_one("systemd\0"
diff --git a/src/test/test-serialize.c b/src/test/test-serialize.c
index 86b1f5f2e0..bd66722456 100644
--- a/src/test/test-serialize.c
+++ b/src/test/test-serialize.c
@@ -110,7 +110,7 @@ TEST(serialize_strv) {
log_info("/* %s (%s) */", __func__, fn);
assert_se(serialize_strv(f, "strv1", NULL) == 0);
- assert_se(serialize_strv(f, "strv2", STRV_MAKE_EMPTY) == 0);
+ assert_se(serialize_strv(f, "strv2", STRV_EMPTY) == 0);
assert_se(serialize_strv(f, "strv3", strv) == 1);
assert_se(serialize_strv(f, "strv4", STRV_MAKE(long_string)) == -EINVAL);
diff --git a/src/test/test-socket-bind.c b/src/test/test-socket-bind.c
index f6f48f6723..fec8269f2b 100644
--- a/src/test/test-socket-bind.c
+++ b/src/test/test-socket-bind.c
@@ -139,7 +139,7 @@ int main(int argc, char *argv[]) {
assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "2000", STRV_MAKE("ipv6:2001-2002"), STRV_MAKE("any")) >= 0);
assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "6666", STRV_MAKE("ipv4:6666", "6667"), STRV_MAKE("any")) >= 0);
assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "6666", STRV_MAKE("6667", "6668", ""), STRV_MAKE("any")) >= 0);
- assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "7777", STRV_MAKE_EMPTY, STRV_MAKE_EMPTY) >= 0);
+ assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "7777", STRV_EMPTY, STRV_EMPTY) >= 0);
assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "8888", STRV_MAKE("any"), STRV_MAKE("any")) >= 0);
assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "8888", STRV_MAKE("ipv6:tcp:8888-8889"), STRV_MAKE("any")) >= 0);
assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "10000", STRV_MAKE("ipv6:udp:9999-10000"), STRV_MAKE("any")) >= 0);
diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c
index 2439dd12ec..90ac579707 100644
--- a/src/test/test-string-util.c
+++ b/src/test/test-string-util.c
@@ -496,7 +496,7 @@ TEST(foreach_word_quoted) {
true);
check("test\\",
- STRV_MAKE_EMPTY,
+ STRV_EMPTY,
true);
}
diff --git a/src/test/test-strv.c b/src/test/test-strv.c
index d2524fb52b..88505993cd 100644
--- a/src/test/test-strv.c
+++ b/src/test/test-strv.c
@@ -224,9 +224,9 @@ static void test_strv_unquote_one(const char *quoted, char **list) {
TEST(strv_unquote) {
test_strv_unquote_one(" foo=bar \"waldo\" zzz ", STRV_MAKE("foo=bar", "waldo", "zzz"));
- test_strv_unquote_one("", STRV_MAKE_EMPTY);
- test_strv_unquote_one(" ", STRV_MAKE_EMPTY);
- test_strv_unquote_one(" ", STRV_MAKE_EMPTY);
+ test_strv_unquote_one("", STRV_EMPTY);
+ test_strv_unquote_one(" ", STRV_EMPTY);
+ test_strv_unquote_one(" ", STRV_EMPTY);
test_strv_unquote_one(" x", STRV_MAKE("x"));
test_strv_unquote_one("x ", STRV_MAKE("x"));
test_strv_unquote_one(" x ", STRV_MAKE("x"));
@@ -774,7 +774,7 @@ TEST(strv_foreach_backwards) {
STRV_FOREACH_BACKWARDS(check, (char**) NULL)
assert_not_reached();
- STRV_FOREACH_BACKWARDS(check, STRV_MAKE_EMPTY)
+ STRV_FOREACH_BACKWARDS(check, STRV_EMPTY)
assert_not_reached();
unsigned count = 0;
@@ -1049,7 +1049,7 @@ TEST(strv_fnmatch) {
_cleanup_strv_free_ char **v = NULL;
size_t pos;
- assert_se(!strv_fnmatch(STRV_MAKE_EMPTY, "a"));
+ assert_se(!strv_fnmatch(STRV_EMPTY, "a"));
v = strv_new("xxx", "*\\*", "yyy");
assert_se(!strv_fnmatch_full(v, "\\", 0, NULL));
diff --git a/src/test/test-verbs.c b/src/test/test-verbs.c
index 03b4836e90..a28fc9b55b 100644
--- a/src/test/test-verbs.c
+++ b/src/test/test-verbs.c
@@ -43,7 +43,7 @@ TEST(verbs) {
test_dispatch_one(STRV_MAKE("copy-to", "foo", "bar", "baz", "quux", "qaax"), verbs, -EINVAL);
/* no verb, but a default is set */
- test_dispatch_one(STRV_MAKE_EMPTY, verbs, 0);
+ test_dispatch_one(STRV_EMPTY, verbs, 0);
}
TEST(verbs_no_default) {
diff --git a/test/units/TEST-07-PID1.delegate-namespaces.sh b/test/units/TEST-07-PID1.delegate-namespaces.sh
index 6d8d51caff..3fd1287fb2 100755
--- a/test/units/TEST-07-PID1.delegate-namespaces.sh
+++ b/test/units/TEST-07-PID1.delegate-namespaces.sh
@@ -45,8 +45,8 @@ testcase_pid() {
}
testcase_uts() {
- (! systemd-run -p PrivateUsersEx=self -p ProtectHostnameEx=private --wait --pipe -- hostname abc)
- systemd-run -p PrivateUsersEx=self -p ProtectHostnameEx=private -p DelegateNamespaces=uts --wait --pipe -- hostname abc
+ (! systemd-run -p PrivateUsersEx=self -p ProtectHostname=private --wait --pipe -- hostname abc)
+ systemd-run -p PrivateUsersEx=self -p ProtectHostname=private -p DelegateNamespaces=uts --wait --pipe -- hostname abc
}
testcase_implied_private_users_self() {
diff --git a/test/units/TEST-07-PID1.protect-hostname.sh b/test/units/TEST-07-PID1.protect-hostname.sh
index 4633dab57b..4a18fe5e21 100755
--- a/test/units/TEST-07-PID1.protect-hostname.sh
+++ b/test/units/TEST-07-PID1.protect-hostname.sh
@@ -22,7 +22,7 @@ testcase_yes() {
(! systemd-run --wait -p ProtectHostname=yes hostname foo)
# ProtectHostname=yes can optionally take a hostname.
- systemd-run --wait -p ProtectHostnameEx=yes:hoge \
+ systemd-run --wait -p ProtectHostname=yes:hoge \
-P bash -xec '
test "$(hostname)" = "hoge"
(! hostname foo)
@@ -50,10 +50,18 @@ EOF
systemd-run --wait -p ProtectHostname=yes -p PrivateMounts=yes \
findmnt --mountpoint /proc/sys/kernel/hostname
+
+ # Check that ProtectHostnameEx=… also works.
+ systemd-run --wait -p ProtectHostnameEx=yes:hoge \
+ -P bash -xec '
+ test "$(hostname)" = "hoge"
+ (! hostname foo)
+ test "$(hostname)" = "hoge"
+ '
}
testcase_private() {
- systemd-run --wait -p ProtectHostnameEx=private \
+ systemd-run --wait -p ProtectHostname=private \
-P bash -xec '
hostname foo
test "$(hostname)" = "foo"
@@ -64,7 +72,7 @@ testcase_private() {
test "$(hostnamectl hostname)" = "$HOSTNAME_FROM_SYSTEMD"
# ProtectHostname=private can optionally take a hostname.
- systemd-run --wait -p ProtectHostnameEx=private:hoge \
+ systemd-run --wait -p ProtectHostname=private:hoge \
-P bash -xec '
test "$(hostname)" = "hoge"
hostname foo
@@ -91,7 +99,7 @@ EOF
test "$(hostnamectl hostname)" = "$HOSTNAME_FROM_SYSTEMD"
# Verify /proc/sys/kernel/hostname is not bind mounted from host read-only.
- (! systemd-run --wait -p ProtectHostnameEx=private -p PrivateMounts=yes \
+ (! systemd-run --wait -p ProtectHostname=private -p PrivateMounts=yes \
findmnt --mountpoint /proc/sys/kernel/hostname)
}
diff --git a/test/units/TEST-07-PID1.transient-unit-container.sh b/test/units/TEST-07-PID1.transient-unit-container.sh
index f18e9ff112..60316bf2fa 100755
--- a/test/units/TEST-07-PID1.transient-unit-container.sh
+++ b/test/units/TEST-07-PID1.transient-unit-container.sh
@@ -157,7 +157,7 @@ testcase_transient_unit_container_file_write() {
-p RootDirectory="$CONTAINER_ROOT_FS" \
-p PrivatePIDs=yes \
-p PrivateUsersEx=full \
- -p ProtectHostnameEx=private \
+ -p ProtectHostname=private \
-p ProtectControlGroupsEx=private \
-p PrivateMounts=yes \
-p PrivateNetwork=yes \
diff --git a/test/units/TEST-54-CREDS.sh b/test/units/TEST-54-CREDS.sh
index dae8d6a242..7016aee85a 100755
--- a/test/units/TEST-54-CREDS.sh
+++ b/test/units/TEST-54-CREDS.sh
@@ -334,7 +334,7 @@ systemd-run -p "ImportCredential=test.creds.*" \
test ! -e '${CREDENTIALS_DIRECTORY}/test.creds.hoge:invalid'
# Check if credentials with invalid names are not imported (with renaming).
-systemd-run -p "ImportCredentialEx=test.creds.*:renamed.creds." \
+systemd-run -p "ImportCredential=test.creds.*:renamed.creds." \
--unit=test-54-ImportCredential.service \
-p DynamicUser=1 \
--wait \
@@ -352,8 +352,8 @@ systemd-run -p "ImportCredential=test.creds.*" \
'${CREDENTIALS_DIRECTORY}/test.creds.third' >/tmp/ts54-concat
cmp /tmp/ts54-concat <(echo -n abc)
-# Check that ImportCredentialEx= works without renaming.
-systemd-run -p "ImportCredentialEx=test.creds.*" \
+# Check that ImportCredential= works without renaming.
+systemd-run -p "ImportCredential=test.creds.*" \
--unit=test-54-ImportCredential.service \
-p DynamicUser=1 \
--wait \
@@ -364,7 +364,7 @@ systemd-run -p "ImportCredentialEx=test.creds.*" \
cmp /tmp/ts54-concat <(echo -n abc)
# Check that renaming with globs works as expected.
-systemd-run -p "ImportCredentialEx=test.creds.*:renamed.creds." \
+systemd-run -p "ImportCredential=test.creds.*:renamed.creds." \
--unit=test-54-ImportCredential.service \
-p DynamicUser=1 \
--wait \
@@ -375,7 +375,7 @@ systemd-run -p "ImportCredentialEx=test.creds.*:renamed.creds." \
cmp /tmp/ts54-concat <(echo -n abc)
# Check that renaming without globs works as expected.
-systemd-run -p "ImportCredentialEx=test.creds.first:renamed.creds.first" \
+systemd-run -p "ImportCredential=test.creds.first:renamed.creds.first" \
--unit=test-54-ImportCredential.service \
-p DynamicUser=1 \
--wait \
@@ -384,8 +384,8 @@ systemd-run -p "ImportCredentialEx=test.creds.first:renamed.creds.first" \
cmp /tmp/ts54-concat <(echo -n a)
# Test that multiple renames are processed in the correct order.
-systemd-run -p "ImportCredentialEx=test.creds.first:renamed.creds.first" \
- -p "ImportCredentialEx=test.creds.second:renamed.creds.first" \
+systemd-run -p "ImportCredential=test.creds.first:renamed.creds.first" \
+ -p "ImportCredential=test.creds.second:renamed.creds.first" \
--unit=test-54-ImportCredential.service \
-p DynamicUser=1 \
--wait \
@@ -394,6 +394,7 @@ systemd-run -p "ImportCredentialEx=test.creds.first:renamed.creds.first" \
cmp /tmp/ts54-concat <(echo -n a)
# Test that a credential can be imported multiple times with different names.
+# We use the deprecated name ImportCredentialEx= on purpose to check that it works.
systemd-run -p "ImportCredentialEx=test.creds.first" \
-p "ImportCredentialEx=test.creds.first:renamed.creds.first" \
-p "ImportCredentialEx=test.creds.first:renamed.creds.second" \
diff --git a/test/units/TEST-65-ANALYZE.sh b/test/units/TEST-65-ANALYZE.sh
index ac4b220ed9..468c9ed093 100755
--- a/test/units/TEST-65-ANALYZE.sh
+++ b/test/units/TEST-65-ANALYZE.sh
@@ -1105,6 +1105,17 @@ else
echo "have no tpm2"
fi
+# Test "transient-settings" verb
+
+# shellcheck disable=SC2046
+systemd-analyze --no-pager transient-settings $(systemctl --no-legend --no-pager -t help)
+systemd-analyze transient-settings service | grep NoNewPrivileges
+systemd-analyze transient-settings mount | grep CPUQuotaPeriodSec
+# make sure deprecated names are not printed
+(! systemd-analyze transient-settings service | grep CPUAccounting )
+(! systemd-analyze transient-settings service | grep ConditionKernelVersion )
+(! systemd-analyze transient-settings service | grep AssertKernelVersion )
+
systemd-analyze log-level info
touch /testok