Merge pull request #7695 from yuwata/transient-socket

DBus-API: implement transient socket unit
This commit is contained in:
Lennart Poettering 2017-12-23 19:20:29 +01:00 committed by GitHub
commit 7785da68e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 2272 additions and 1577 deletions

View File

@ -2,8 +2,8 @@
Our intention is to make all settings that are available as unit file settings
also available for transient units, through the D-Bus API. At the moment, some
unit types (socket, swap, path) are not supported at all via unit types, but
most others are pretty well supported, with some notable omissions.
unit types (device, swap, target) are not supported at all via unit types,
but most others are pretty well supported, with some notable omissions.
The lists below contain all settings currently available in unit files. The
ones currently available in transient units are prefixed with `✓`.
@ -68,6 +68,7 @@ Only the most important generic unit settings are available for transient units.
ConditionACPower=
ConditionUser=
ConditionGroup=
ConditionControlGroupController=
AssertPathExists=
AssertPathExistsGlob=
AssertPathIsDirectory=
@ -88,6 +89,7 @@ Only the most important generic unit settings are available for transient units.
AssertACPower=
AssertUser=
AssertGroup=
AssertControlGroupController=
✓ CollectMode=
```
@ -341,71 +343,71 @@ of their own beyond the generic unit and resource control settings.
## Scope Unit Settings
Scope units are fully supported as transient units (in fact they only exist as
such), but they have no settings of their own beyond the generic unit and
resource control settings.
such), but they have no settings of their own beyond the generic unit,
resource control, and process killing settings.
## Socket Unit Settings
Socket units are currently not available at all as transient units:
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=
Writable=
MaxConnections=
MaxConnectionsPerSource=
KeepAlive=
KeepAliveTimeSec=
KeepAliveIntervalSec=
KeepAliveProbes=
DeferAcceptSec=
NoDelay=
Priority=
ReceiveBuffer=
SendBuffer=
IPTOS=
IPTTL=
Mark=
PipeSize=
FreeBind=
Transparent=
Broadcast=
PassCredentials=
PassSecurity=
TCPCongestion=
ReusePort=
MessageQueueMaxMessages=
MessageQueueMessageSize=
RemoveOnStop=
Symlinks=
FileDescriptorName=
ListenStream=
ListenDatagram=
ListenSequentialPacket=
ListenFIFO=
ListenNetlink=
ListenSpecial=
ListenMessageQueue=
ListenUSBFunction=
SocketProtocol=
BindIPv6Only=
Backlog=
BindToDevice=
ExecStartPre=
ExecStartPost=
ExecStopPre=
ExecStopPost=
TimeoutSec=
SocketUser=
SocketGroup=
SocketMode=
DirectoryMode=
Accept=
Writable=
MaxConnections=
MaxConnectionsPerSource=
KeepAlive=
KeepAliveTimeSec=
KeepAliveIntervalSec=
KeepAliveProbes=
DeferAcceptSec=
NoDelay=
Priority=
ReceiveBuffer=
SendBuffer=
IPTOS=
IPTTL=
Mark=
PipeSize=
FreeBind=
Transparent=
Broadcast=
PassCredentials=
PassSecurity=
TCPCongestion=
ReusePort=
MessageQueueMaxMessages=
MessageQueueMessageSize=
RemoveOnStop=
Symlinks=
FileDescriptorName=
Service=
TriggerLimitIntervalSec=
TriggerLimitBurst=
SmackLabel=
SmackLabelIPIn=
SmackLabelIPOut=
SELinuxContextFromNet=
TriggerLimitIntervalSec=
TriggerLimitBurst=
SmackLabel=
SmackLabelIPIn=
SmackLabelIPOut=
SELinuxContextFromNet=
```
## Swap Unit Settings

View File

@ -47,7 +47,7 @@
<refnamediv>
<refname>systemd-run</refname>
<refpurpose>Run programs in transient scope units, service units, or timer-scheduled service units</refpurpose>
<refpurpose>Run programs in transient scope units, service units, or path-, socket-, or timer-triggered service units</refpurpose>
</refnamediv>
<refsynopsisdiv>
@ -58,6 +58,20 @@
<arg choice="opt" rep="repeat">ARGS</arg>
</arg>
</cmdsynopsis>
<cmdsynopsis>
<command>systemd-run</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
<arg choice="opt" rep="repeat">PATH OPTIONS</arg>
<arg choice="req"><replaceable>COMMAND</replaceable></arg>
<arg choice="opt" rep="repeat">ARGS</arg>
</cmdsynopsis>
<cmdsynopsis>
<command>systemd-run</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
<arg choice="opt" rep="repeat">SOCKET OPTIONS</arg>
<arg choice="req"><replaceable>COMMAND</replaceable></arg>
<arg choice="opt" rep="repeat">ARGS</arg>
</cmdsynopsis>
<cmdsynopsis>
<command>systemd-run</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
@ -72,8 +86,8 @@
<para><command>systemd-run</command> may be used to create and start a transient <filename>.service</filename> or
<filename>.scope</filename> unit and run the specified <replaceable>COMMAND</replaceable> in it. It may also be
used to create and start a transient <filename>.timer</filename> unit, that activates a
<filename>.service</filename> unit when elapsing.</para>
used to create and start a transient <filename>.path</filename>, <filename>.socket</filename>, or
<filename>.timer</filename> unit, that activates a <filename>.service</filename> unit when elapsing.</para>
<para>If a command is run as transient service unit, it will be started and managed by the service manager like any
other service, and thus shows up in the output of <command>systemctl list-units</command> like any other unit. It
@ -88,12 +102,13 @@
list-units</command>. Execution in this case is synchronous, and will return only when the command finishes. This
mode is enabled via the <option>--scope</option> switch (see below). </para>
<para>If a command is run with timer options such as <option>--on-calendar=</option> (see below), a transient timer
unit is created alongside the service unit for the specified command. Only the transient timer unit is started
immediately, the transient service unit will be started when the timer elapses. If the <option>--unit=</option>
option is specified, the <replaceable>COMMAND</replaceable> may be omitted. In this case,
<command>systemd-run</command> creates only a <filename>.timer</filename> unit that invokes the specified unit when
elapsing.</para>
<para>If a command is run with path, socket, or timer options such as <option>--on-calendar=</option> (see below),
a transient path, socket, or timer unit is created alongside the service unit for the specified command. Only the
transient path, socket, or timer unit is started immediately, the transient service unit will be triggered by the
path, socket, or timer unit. If the <option>--unit=</option> option is specified, the
<replaceable>COMMAND</replaceable> may be omitted. In this case, <command>systemd-run</command> creates only a
<filename>.path</filename>, <filename>.socket</filename>, or <filename>.timer</filename> unit that triggers the
specified unit.</para>
</refsect1>
<refsect1>
@ -140,8 +155,8 @@
<varlistentry>
<term><option>--description=</option></term>
<listitem><para>Provide a description for the service, scope or timer unit. If not specified, the command
itself will be used as a description. See <varname>Description=</varname> in
<listitem><para>Provide a description for the service, scope, path, socket, or timer unit. If not specified,
the command itself will be used as a description. See <varname>Description=</varname> in
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
</para></listitem>
</varlistentry>
@ -278,7 +293,8 @@
command. See <varname>OnActiveSec=</varname>, <varname>OnBootSec=</varname>, <varname>OnStartupSec=</varname>,
<varname>OnUnitActiveSec=</varname> and <varname>OnUnitInactiveSec=</varname> in
<citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
details. These options may not be combined with <option>--scope</option> or <option>--pty</option>.</para>
details. These options are shortcuts for <command>--timer-property=</command> with the relevant properties.
These options may not be combined with <option>--scope</option> or <option>--pty</option>.</para>
</listitem>
</varlistentry>
@ -287,20 +303,23 @@
<listitem><para>Defines a calendar timer for starting the specified command. See <varname>OnCalendar=</varname>
in <citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>. This
option may not be combined with <option>--scope</option> or <option>--pty</option>.</para>
option is a shortcut for <command>--timer-property=OnCalendar=</command>. This option may not be combined with
<option>--scope</option> or <option>--pty</option>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--path-property=</option></term>
<term><option>--socket-property=</option></term>
<term><option>--timer-property=</option></term>
<listitem><para>Sets a property on the timer unit that is created. This option is similar to
<option>--property=</option> but applies to the transient timer unit rather than the transient service unit
created. This option only has an effect in conjunction with <option>--on-active=</option>,
<option>--on-boot=</option>, <option>--on-startup=</option>, <option>--on-unit-active=</option>,
<option>--on-unit-inactive=</option> or <option>--on-calendar=</option>. This option takes an assignment in the
same format as <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
<command>set-property</command> command.</para> </listitem>
<listitem><para>Sets a property on the path, socket, or timer unit that is created. This option is similar to
<option>--property=</option> but applies to the transient path, socket, or timer unit rather than the
transient service unit created. This option takes an assignment in the same format as
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
<command>set-property</command> command. These options may not be combined with
<option>--scope</option> or <option>--pty</option>.</para>
</listitem>
</varlistentry>
<varlistentry>
@ -323,7 +342,7 @@
completed). On exit, terse information about the unit's runtime is shown, including total runtime (as well as
CPU usage, if <option>--property=CPUAccounting=1</option> was set) and the exit code and status of the main
process. This output may be suppressed with <option>--quiet</option>. This option may not be combined with
<option>--no-block</option>, <option>--scope</option> or the various timer options.</para></listitem>
<option>--no-block</option>, <option>--scope</option> or the various path, socket, or timer options.</para></listitem>
</varlistentry>
<varlistentry>

View File

@ -0,0 +1,5 @@
#!/bin/sh -eu
$1 -dM -include netinet/in.h - </dev/null | \
awk '/^#define[ \t]+IPPROTO_[^ \t]+[ \t]+[^ \t]/ { print $2; }' | \
sed -e 's/IPPROTO_//'

View File

@ -176,6 +176,8 @@ basic_sources_plain = files('''
smack-util.c
smack-util.h
socket-label.c
socket-protocol-list.c
socket-protocol-list.h
socket-util.c
socket-util.h
sparse-endian.h
@ -255,11 +257,19 @@ errno_list_txt = custom_target(
command : [generate_errno_list, cpp],
capture : true)
generate_socket_protocol_list = find_program('generate-socket-protocol-list.sh')
socket_protocol_list_txt = custom_target(
'socket-protocol-list.txt',
output : 'socket-protocol-list.txt',
command : [generate_socket_protocol_list, cpp],
capture : true)
generated_gperf_headers = []
foreach item : [['af', af_list_txt, 'af', ''],
['arphrd', arphrd_list_txt, 'arphrd', 'ARPHRD_'],
['cap', cap_list_txt, 'capability', ''],
['errno', errno_list_txt, 'errno', '']]
['errno', errno_list_txt, 'errno', ''],
['socket-protocol', socket_protocol_list_txt, 'socket_protocol', 'IPPROTO_']]
fname = '@0@-from-name.gperf'.format(item[0])
gperf_file = custom_target(

View File

@ -0,0 +1,57 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
Copyright 2014 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <netinet/in.h>
#include <string.h>
#include "socket-protocol-list.h"
#include "macro.h"
static const struct socket_protocol_name* lookup_socket_protocol(register const char *str, register GPERF_LEN_TYPE len);
#include "socket-protocol-from-name.h"
#include "socket-protocol-to-name.h"
const char *socket_protocol_to_name(int id) {
if (id < 0)
return NULL;
if (id >= (int) ELEMENTSOF(socket_protocol_names))
return NULL;
return socket_protocol_names[id];
}
int socket_protocol_from_name(const char *name) {
const struct socket_protocol_name *sc;
assert(name);
sc = lookup_socket_protocol(name, strlen(name));
if (!sc)
return 0;
return sc->id;
}
int socket_protocol_max(void) {
return ELEMENTSOF(socket_protocol_names);
}

View File

@ -0,0 +1,26 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
This file is part of systemd.
Copyright 2014 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
const char *socket_protocol_to_name(int id);
int socket_protocol_from_name(const char *name);
int socket_protocol_max(void);

View File

@ -0,0 +1,9 @@
BEGIN{
print "static const char* const socket_protocol_names[] = { "
}
!/HOPOPTS/ {
printf " [IPPROTO_%s] = \"%s\",\n", $1, tolower($1)
}
END{
print "};"
}

View File

@ -55,6 +55,17 @@
# define IDN_FLAGS 0
#endif
static const char* const socket_address_type_table[] = {
[SOCK_STREAM] = "Stream",
[SOCK_DGRAM] = "Datagram",
[SOCK_RAW] = "Raw",
[SOCK_RDM] = "ReliableDatagram",
[SOCK_SEQPACKET] = "SequentialPacket",
[SOCK_DCCP] = "DatagramCongestionControl",
};
DEFINE_STRING_TABLE_LOOKUP(socket_address_type, int);
int socket_address_parse(SocketAddress *a, const char *s) {
char *e, *n;
unsigned u;

View File

@ -72,6 +72,9 @@ typedef enum SocketAddressBindIPv6Only {
#define socket_address_family(a) ((a)->sockaddr.sa.sa_family)
const char* socket_address_type_to_string(int t) _const_;
int socket_address_type_from_string(const char *s) _pure_;
int socket_address_parse(SocketAddress *a, const char *s);
int socket_address_parse_and_warn(SocketAddress *a, const char *s);
int socket_address_parse_netlink(SocketAddress *a, const char *s);

View File

@ -446,7 +446,7 @@ int bus_cgroup_set_property(
return 1;
} else if (streq(name, "CPUWeight")) {
} else if (STR_IN_SET(name, "CPUWeight", "StartupCPUWeight")) {
uint64_t weight;
r = sd_bus_message_read(message, "t", &weight);
@ -454,43 +454,25 @@ int bus_cgroup_set_property(
return r;
if (!CGROUP_WEIGHT_IS_OK(weight))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "CPUWeight= value out of range");
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= value out of range", name);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
c->cpu_weight = weight;
if (streq(name, "CPUWeight"))
c->cpu_weight = weight;
else /* "StartupCPUWeight" */
c->startup_cpu_weight = weight;
unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
if (weight == CGROUP_WEIGHT_INVALID)
unit_write_setting(u, flags, name, "CPUWeight=");
unit_write_settingf(u, flags, name, "%s=", name);
else
unit_write_settingf(u, flags, name, "CPUWeight=%" PRIu64, weight);
unit_write_settingf(u, flags, name, "%s=%" PRIu64, name, weight);
}
return 1;
} else if (streq(name, "StartupCPUWeight")) {
uint64_t weight;
r = sd_bus_message_read(message, "t", &weight);
if (r < 0)
return r;
if (!CGROUP_WEIGHT_IS_OK(weight))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "StartupCPUWeight= value out of range");
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
c->startup_cpu_weight = weight;
unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
if (weight == CGROUP_CPU_SHARES_INVALID)
unit_write_setting(u, flags, name, "StartupCPUWeight=");
else
unit_write_settingf(u, flags, name, "StartupCPUWeight=%" PRIu64, weight);
}
return 1;
} else if (streq(name, "CPUShares")) {
} else if (STR_IN_SET(name, "CPUShares", "StartupCPUShares")) {
uint64_t shares;
r = sd_bus_message_read(message, "t", &shares);
@ -498,38 +480,20 @@ int bus_cgroup_set_property(
return r;
if (!CGROUP_CPU_SHARES_IS_OK(shares))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "CPUShares= value out of range");
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= value out of range", name);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
c->cpu_shares = shares;
if (streq(name, "CPUShares"))
c->cpu_shares = shares;
else /* "StartupCPUShares" */
c->startup_cpu_shares = shares;
unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
if (shares == CGROUP_CPU_SHARES_INVALID)
unit_write_setting(u, flags, name, "CPUShares=");
unit_write_settingf(u, flags, name, "%s=", name);
else
unit_write_settingf(u, flags, name, "CPUShares=%" PRIu64, shares);
}
return 1;
} else if (streq(name, "StartupCPUShares")) {
uint64_t shares;
r = sd_bus_message_read(message, "t", &shares);
if (r < 0)
return r;
if (!CGROUP_CPU_SHARES_IS_OK(shares))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "StartupCPUShares= value out of range");
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
c->startup_cpu_shares = shares;
unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
if (shares == CGROUP_CPU_SHARES_INVALID)
unit_write_setting(u, flags, name, "StartupCPUShares=");
else
unit_write_settingf(u, flags, name, "StartupCPUShares=%" PRIu64, shares);
unit_write_settingf(u, flags, name, "%s=%" PRIu64, name, shares);
}
return 1;
@ -575,7 +539,7 @@ int bus_cgroup_set_property(
return 1;
} else if (streq(name, "IOWeight")) {
} else if (STR_IN_SET(name, "IOWeight", "StartupIOWeight")) {
uint64_t weight;
r = sd_bus_message_read(message, "t", &weight);
@ -583,38 +547,20 @@ int bus_cgroup_set_property(
return r;
if (!CGROUP_WEIGHT_IS_OK(weight))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "IOWeight= value out of range");
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= value out of range", name);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
c->io_weight = weight;
if (streq(name, "IOWeight"))
c->io_weight = weight;
else /* "StartupIOWeight" */
c->startup_io_weight = weight;
unit_invalidate_cgroup(u, CGROUP_MASK_IO);
if (weight == CGROUP_WEIGHT_INVALID)
unit_write_setting(u, flags, name, "IOWeight=");
unit_write_settingf(u, flags, name, "%s=", name);
else
unit_write_settingf(u, flags, name, "IOWeight=%" PRIu64, weight);
}
return 1;
} else if (streq(name, "StartupIOWeight")) {
uint64_t weight;
r = sd_bus_message_read(message, "t", &weight);
if (r < 0)
return r;
if (CGROUP_WEIGHT_IS_OK(weight))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "StartupIOWeight= value out of range");
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
c->startup_io_weight = weight;
unit_invalidate_cgroup(u, CGROUP_MASK_IO);
if (weight == CGROUP_WEIGHT_INVALID)
unit_write_setting(u, flags, name, "StartupIOWeight=");
else
unit_write_settingf(u, flags, name, "StartupIOWeight=%" PRIu64, weight);
unit_write_settingf(u, flags, name, "%s=%" PRIu64, name, weight);
}
return 1;
@ -630,6 +576,10 @@ int bus_cgroup_set_property(
while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
if (!path_startswith(path, "/dev") &&
!path_startswith(path, "/run/systemd/inaccessible/"))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s specified in %s= is not a device file in /dev", name, path);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
CGroupIODeviceLimit *a = NULL, *b;
@ -714,6 +664,10 @@ int bus_cgroup_set_property(
while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
if (!path_startswith(path, "/dev") &&
!path_startswith(path, "/run/systemd/inaccessible/"))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s specified in %s= is not a device file in /dev", name, path);
if (!CGROUP_WEIGHT_IS_OK(weight) || weight == CGROUP_WEIGHT_INVALID)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "IODeviceWeight= value out of range");
@ -796,7 +750,7 @@ int bus_cgroup_set_property(
return 1;
} else if (streq(name, "BlockIOWeight")) {
} else if (STR_IN_SET(name, "BlockIOWeight", "StartupBlockIOWeight")) {
uint64_t weight;
r = sd_bus_message_read(message, "t", &weight);
@ -804,38 +758,20 @@ int bus_cgroup_set_property(
return r;
if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "BlockIOWeight= value out of range");
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= value out of range", name);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
c->blockio_weight = weight;
if (streq(name, "BlockIOWeight"))
c->blockio_weight = weight;
else /* "StartupBlockIOWeight" */
c->startup_blockio_weight = weight;
unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
if (weight == CGROUP_BLKIO_WEIGHT_INVALID)
unit_write_setting(u, flags, name, "BlockIOWeight=");
unit_write_settingf(u, flags, name, "%s=", name);
else
unit_write_settingf(u, flags, name, "BlockIOWeight=%" PRIu64, weight);
}
return 1;
} else if (streq(name, "StartupBlockIOWeight")) {
uint64_t weight;
r = sd_bus_message_read(message, "t", &weight);
if (r < 0)
return r;
if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "StartupBlockIOWeight= value out of range");
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
c->startup_blockio_weight = weight;
unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
if (weight == CGROUP_BLKIO_WEIGHT_INVALID)
unit_write_setting(u, flags, name, "StartupBlockIOWeight=");
else
unit_write_settingf(u, flags, name, "StartupBlockIOWeight=%" PRIu64, weight);
unit_write_settingf(u, flags, name, "%s=%" PRIu64, name, weight);
}
return 1;
@ -855,6 +791,10 @@ int bus_cgroup_set_property(
while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
if (!path_startswith(path, "/dev") &&
!path_startswith(path, "/run/systemd/inaccessible/"))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s specified in %s= is not a device file in /dev", name, path);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
CGroupBlockIODeviceBandwidth *a = NULL, *b;
@ -951,6 +891,10 @@ int bus_cgroup_set_property(
while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
if (!path_startswith(path, "/dev") &&
!path_startswith(path, "/run/systemd/inaccessible/"))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s specified in %s= is not a device file in /dev", name, path);
if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight) || weight == CGROUP_BLKIO_WEIGHT_INVALID)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "BlockIODeviceWeight= out of range");
@ -1034,7 +978,7 @@ int bus_cgroup_set_property(
return 1;
} else if (STR_IN_SET(name, "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax")) {
} else if (STR_IN_SET(name, "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit")) {
uint64_t v;
r = sd_bus_message_read(message, "t", &v);
@ -1050,8 +994,10 @@ int bus_cgroup_set_property(
c->memory_high = v;
else if (streq(name, "MemorySwapMax"))
c->memory_swap_max = v;
else
else if (streq(name, "MemoryMax"))
c->memory_max = v;
else /* "MemoryLimit" */
c->memory_limit = v;
unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
@ -1063,7 +1009,7 @@ int bus_cgroup_set_property(
return 1;
} else if (STR_IN_SET(name, "MemoryLowScale", "MemoryHighScale", "MemoryMaxScale", "MemorySwapMaxScale")) {
} else if (STR_IN_SET(name, "MemoryLowScale", "MemoryHighScale", "MemoryMaxScale", "MemorySwapMaxScale", "MemoryLimitScale")) {
uint32_t raw;
uint64_t v;
@ -1086,10 +1032,12 @@ int bus_cgroup_set_property(
c->memory_low = v;
else if (streq(name, "MemoryHigh"))
c->memory_high = v;
else if (streq(name, "MemorySwapMaxScale"))
else if (streq(name, "MemorySwapMax"))
c->memory_swap_max = v;
else /* MemoryMax */
else if (streq(name, "MemoryMax"))
c->memory_max = v;
else /* "MemoryLimit" */
c->memory_limit = v;
unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
unit_write_settingf(u, flags, name, "%s=%" PRIu32 "%%", name,
@ -1098,48 +1046,6 @@ int bus_cgroup_set_property(
return 1;
} else if (streq(name, "MemoryLimit")) {
uint64_t limit;
r = sd_bus_message_read(message, "t", &limit);
if (r < 0)
return r;
if (limit <= 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= is too small", name);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
c->memory_limit = limit;
unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
if (limit == CGROUP_LIMIT_MAX)
unit_write_setting(u, flags, name, "MemoryLimit=infinity");
else
unit_write_settingf(u, flags, name, "MemoryLimit=%" PRIu64, limit);
}
return 1;
} else if (streq(name, "MemoryLimitScale")) {
uint64_t limit;
uint32_t raw;
r = sd_bus_message_read(message, "u", &raw);
if (r < 0)
return r;
limit = physical_memory_scale(raw, UINT32_MAX);
if (limit <= 0 || limit == UINT64_MAX)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= is out of range", name);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
c->memory_limit = limit;
unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
unit_write_settingf(u, flags, "MemoryLimit", "MemoryLimit=%" PRIu32 "%%",
(uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX)));
}
return 1;
} else if (streq(name, "DevicePolicy")) {
const char *policy;
CGroupDevicePolicy p;
@ -1170,10 +1076,8 @@ int bus_cgroup_set_property(
while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
if ((!path_startswith(path, "/dev/") &&
!path_startswith(path, "/run/systemd/inaccessible/") &&
!startswith(path, "block-") &&
!startswith(path, "char-")) ||
if ((!is_deviceallow_pattern(path) &&
!path_startswith(path, "/run/systemd/inaccessible/")) ||
strpbrk(path, WHITESPACE))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "DeviceAllow= requires device node");
@ -1450,12 +1354,8 @@ int bus_cgroup_set_property(
return 1;
}
if (u->transient && u->load_state == UNIT_STUB) {
r = bus_cgroup_set_transient_property(u, c, name, message, flags, error);
if (r != 0)
return r;
}
if (u->transient && u->load_state == UNIT_STUB)
return bus_cgroup_set_transient_property(u, c, name, message, flags, error);
return 0;
}

View File

@ -1036,6 +1036,121 @@ int bus_property_get_exec_command_list(
return sd_bus_message_close_container(reply);
}
int bus_exec_command_set_transient_property(
Unit *u,
const char *name,
ExecCommand **exec_command,
sd_bus_message *message,
UnitWriteFlags flags,
sd_bus_error *error) {
unsigned n = 0;
int r;
r = sd_bus_message_enter_container(message, 'a', "(sasb)");
if (r < 0)
return r;
while ((r = sd_bus_message_enter_container(message, 'r', "sasb")) > 0) {
_cleanup_strv_free_ char **argv = NULL;
const char *path;
int b;
r = sd_bus_message_read(message, "s", &path);
if (r < 0)
return r;
if (!path_is_absolute(path))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not absolute.", path);
r = sd_bus_message_read_strv(message, &argv);
if (r < 0)
return r;
r = sd_bus_message_read(message, "b", &b);
if (r < 0)
return r;
r = sd_bus_message_exit_container(message);
if (r < 0)
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
ExecCommand *c;
c = new0(ExecCommand, 1);
if (!c)
return -ENOMEM;
c->path = strdup(path);
if (!c->path) {
free(c);
return -ENOMEM;
}
c->argv = argv;
argv = NULL;
c->flags = b ? EXEC_COMMAND_IGNORE_FAILURE : 0;
path_kill_slashes(c->path);
exec_command_append_list(exec_command, c);
}
n++;
}
if (r < 0)
return r;
r = sd_bus_message_exit_container(message);
if (r < 0)
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
_cleanup_free_ char *buf = NULL;
_cleanup_fclose_ FILE *f = NULL;
ExecCommand *c;
size_t size = 0;
if (n == 0)
*exec_command = exec_command_free_list(*exec_command);
f = open_memstream(&buf, &size);
if (!f)
return -ENOMEM;
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
fputs("ExecStart=\n", f);
LIST_FOREACH(command, c, *exec_command) {
_cleanup_free_ char *a = NULL, *t = NULL;
const char *p;
p = unit_escape_setting(c->path, UNIT_ESCAPE_C|UNIT_ESCAPE_SPECIFIERS, &t);
if (!p)
return -ENOMEM;
a = unit_concat_strv(c->argv, UNIT_ESCAPE_C|UNIT_ESCAPE_SPECIFIERS);
if (!a)
return -ENOMEM;
fprintf(f, "%s=%s@%s %s\n",
name,
c->flags & EXEC_COMMAND_IGNORE_FAILURE ? "-" : "",
p,
a);
}
r = fflush_and_check(f);
if (r < 0)
return r;
unit_write_setting(u, flags, name, buf);
}
return 1;
}
int bus_exec_context_set_transient_property(
Unit *u,
ExecContext *c,
@ -1054,7 +1169,7 @@ int bus_exec_context_set_transient_property(
flags |= UNIT_PRIVATE;
if (streq(name, "User")) {
if (STR_IN_SET(name, "User", "Group")) {
const char *uu;
r = sd_bus_message_read(message, "s", &uu);
@ -1062,36 +1177,18 @@ int bus_exec_context_set_transient_property(
return r;
if (!isempty(uu) && !valid_user_group_name_or_id(uu))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user name: %s", uu);
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s: %s", name, uu);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
r = free_and_strdup(&c->user, empty_to_null(uu));
if (streq(name, "User"))
r = free_and_strdup(&c->user, empty_to_null(uu));
else /* "Group" */
r = free_and_strdup(&c->group, empty_to_null(uu));
if (r < 0)
return r;
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "User=%s", uu);
}
return 1;
} else if (streq(name, "Group")) {
const char *gg;
r = sd_bus_message_read(message, "s", &gg);
if (r < 0)
return r;
if (!isempty(gg) && !valid_user_group_name_or_id(gg))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group name: %s", gg);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
r = free_and_strdup(&c->group, empty_to_null(gg));
if (r < 0)
return r;
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "Group=%s", gg);
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, uu);
}
return 1;
@ -1139,10 +1236,9 @@ int bus_exec_context_set_transient_property(
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
if (isempty(id))
c->syslog_identifier = mfree(c->syslog_identifier);
else if (free_and_strdup(&c->syslog_identifier, id) < 0)
return -ENOMEM;
r = free_and_strdup(&c->syslog_identifier, empty_to_null(id));
if (r < 0)
return r;
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "SyslogIdentifier=%s", id);
}
@ -1361,59 +1457,42 @@ int bus_exec_context_set_transient_property(
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
_cleanup_free_ char *joined = NULL;
bool invert = !whitelist;
char **s;
if (strv_isempty(l)) {
c->syscall_whitelist = false;
c->syscall_filter = hashmap_free(c->syscall_filter);
} else {
char **s;
unit_write_settingf(u, flags, name, "SystemCallFilter=");
return 1;
}
if (!c->syscall_filter) {
c->syscall_filter = hashmap_new(NULL);
if (!c->syscall_filter)
return log_oom();
c->syscall_whitelist = whitelist;
r = hashmap_ensure_allocated(&c->syscall_filter, NULL);
if (c->syscall_whitelist) {
r = seccomp_parse_syscall_filter(invert, "@default", -1, c->syscall_filter, true);
if (r < 0)
return r;
}
}
STRV_FOREACH(s, l) {
_cleanup_free_ char *n = NULL;
int e;
r = parse_syscall_and_errno(*s, &n, &e);
if (r < 0)
return r;
STRV_FOREACH(s, l) {
_cleanup_free_ char *n = NULL;
int e;
r = parse_syscall_and_errno(*s, &n, &e);
if (r < 0)
return r;
if (*n == '@') {
const SyscallFilterSet *set;
const char *i;
set = syscall_filter_set_find(n);
if (!set)
return -EINVAL;
NULSTR_FOREACH(i, set->value) {
int id;
id = seccomp_syscall_resolve_name(i);
if (id == __NR_SCMP_ERROR)
return -EINVAL;
r = hashmap_put(c->syscall_filter, INT_TO_PTR(id + 1), INT_TO_PTR(e));
if (r < 0)
return r;
}
} else {
int id;
id = seccomp_syscall_resolve_name(n);
if (id == __NR_SCMP_ERROR)
return -EINVAL;
r = hashmap_put(c->syscall_filter, INT_TO_PTR(id + 1), INT_TO_PTR(e));
if (r < 0)
return r;
}
}
r = seccomp_parse_syscall_filter(invert, n, e, c->syscall_filter, c->syscall_whitelist);
if (r < 0)
return r;
}
joined = strv_join(l, " ");
@ -1507,30 +1586,38 @@ int bus_exec_context_set_transient_property(
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
_cleanup_free_ char *joined = NULL;
bool invert = !whitelist;
char **s;
if (strv_isempty(l)) {
c->address_families_whitelist = false;
c->address_families = set_free(c->address_families);
} else {
char **s;
unit_write_settingf(u, flags, name, "RestrictAddressFamilies=");
return 1;
}
if (!c->address_families) {
c->address_families = set_new(NULL);
if (!c->address_families)
return log_oom();
c->address_families_whitelist = whitelist;
}
r = set_ensure_allocated(&c->address_families, NULL);
if (r < 0)
return r;
STRV_FOREACH(s, l) {
int af;
STRV_FOREACH(s, l) {
int af;
af = af_from_name(*s);
if (af <= 0)
return -EINVAL;
af = af_from_name(*s);
if (af <= 0)
return -EINVAL;
if (!invert == c->address_families_whitelist) {
r = set_put(c->address_families, INT_TO_PTR(af));
if (r < 0)
return r;
}
} else
(void) set_remove(c->address_families, INT_TO_PTR(af));
}
joined = strv_join(l, " ");
@ -1573,7 +1660,7 @@ int bus_exec_context_set_transient_property(
if (r < 0)
return r;
if (!ioprio_priority_is_valid(n))
if (!sched_priority_is_valid(n))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid CPU scheduling priority");
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
@ -1717,17 +1804,17 @@ int bus_exec_context_set_transient_property(
if (r < 0)
return r;
if (!path_is_absolute(s))
if (!isempty(s) && !path_is_absolute(s))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s takes an absolute path", name);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
if (streq(name, "TTYPath"))
r = free_and_strdup(&c->tty_path, s);
r = free_and_strdup(&c->tty_path, empty_to_null(s));
else if (streq(name, "RootImage"))
r = free_and_strdup(&c->root_image, s);
r = free_and_strdup(&c->root_image, empty_to_null(s));
else {
assert(streq(name, "RootDirectory"));
r = free_and_strdup(&c->root_directory, s);
r = free_and_strdup(&c->root_directory, empty_to_null(s));
}
if (r < 0)
return r;
@ -1751,7 +1838,7 @@ int bus_exec_context_set_transient_property(
} else
missing_ok = false;
if (!streq(s, "~") && !path_is_absolute(s))
if (!isempty(s) && !streq(s, "~") && !path_is_absolute(s))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "WorkingDirectory= expects an absolute path or '~'");
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
@ -1759,7 +1846,7 @@ int bus_exec_context_set_transient_property(
c->working_directory = mfree(c->working_directory);
c->working_directory_home = true;
} else {
r = free_and_strdup(&c->working_directory, s);
r = free_and_strdup(&c->working_directory, empty_to_null(s));
if (r < 0)
return r;
@ -1840,15 +1927,13 @@ int bus_exec_context_set_transient_property(
if (r < 0)
return r;
if (isempty(s))
s = NULL;
else if (!fdname_is_valid(s))
if (!isempty(s) && !fdname_is_valid(s))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid file descriptor name");
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
if (streq(name, "StandardInputFileDescriptorName")) {
r = free_and_strdup(c->stdio_fdname + STDIN_FILENO, s);
r = free_and_strdup(c->stdio_fdname + STDIN_FILENO, empty_to_null(s));
if (r < 0)
return r;
@ -1856,7 +1941,7 @@ int bus_exec_context_set_transient_property(
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardInput=fd:%s", exec_context_fdname(c, STDIN_FILENO));
} else if (streq(name, "StandardOutputFileDescriptorName")) {
r = free_and_strdup(c->stdio_fdname + STDOUT_FILENO, s);
r = free_and_strdup(c->stdio_fdname + STDOUT_FILENO, empty_to_null(s));
if (r < 0)
return r;
@ -1866,7 +1951,7 @@ int bus_exec_context_set_transient_property(
} else {
assert(streq(name, "StandardErrorFileDescriptorName"));
r = free_and_strdup(&c->stdio_fdname[STDERR_FILENO], s);
r = free_and_strdup(&c->stdio_fdname[STDERR_FILENO], empty_to_null(s));
if (r < 0)
return r;
@ -1884,15 +1969,17 @@ int bus_exec_context_set_transient_property(
if (r < 0)
return r;
if (!path_is_absolute(s))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not absolute", s);
if (!path_is_normalized(s))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not normalized", s);
if (!isempty(s)) {
if (!path_is_absolute(s))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not absolute", s);
if (!path_is_normalized(s))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not normalized", s);
}
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
if (streq(name, "StandardInputFile")) {
r = free_and_strdup(&c->stdio_file[STDIN_FILENO], s);
r = free_and_strdup(&c->stdio_file[STDIN_FILENO], empty_to_null(s));
if (r < 0)
return r;
@ -1900,7 +1987,7 @@ int bus_exec_context_set_transient_property(
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardInput=file:%s", s);
} else if (streq(name, "StandardOutputFile")) {
r = free_and_strdup(&c->stdio_file[STDOUT_FILENO], s);
r = free_and_strdup(&c->stdio_file[STDOUT_FILENO], empty_to_null(s));
if (r < 0)
return r;
@ -1910,7 +1997,7 @@ int bus_exec_context_set_transient_property(
} else {
assert(streq(name, "StandardErrorFile"));
r = free_and_strdup(&c->stdio_file[STDERR_FILENO], s);
r = free_and_strdup(&c->stdio_file[STDERR_FILENO], empty_to_null(s));
if (r < 0)
return r;
@ -2323,7 +2410,7 @@ int bus_exec_context_set_transient_property(
return r;
STRV_FOREACH(p, l) {
const char *i = *p;
char *i = *p;
size_t offset;
if (!utf8_is_valid(i))
@ -2333,6 +2420,8 @@ int bus_exec_context_set_transient_property(
offset += i[offset] == '+';
if (!path_is_absolute(i + offset))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s", name);
path_kill_slashes(i + offset);
}
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
@ -2527,15 +2616,16 @@ int bus_exec_context_set_transient_property(
} else if (streq(name, "SELinuxContext")) {
const char *s;
r = sd_bus_message_read(message, "s", &s);
if (r < 0)
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
if (isempty(s))
c->selinux_context = mfree(c->selinux_context);
else if (free_and_strdup(&c->selinux_context, s) < 0)
return -ENOMEM;
r = free_and_strdup(&c->selinux_context, empty_to_null(s));
if (r < 0)
return r;
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, strempty(s));
}

View File

@ -44,3 +44,4 @@ int bus_property_get_exec_command(sd_bus *bus, const char *path, const char *int
int bus_property_get_exec_command_list(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *ret_error);
int bus_exec_context_set_transient_property(Unit *u, ExecContext *c, const char *name, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
int bus_exec_command_set_transient_property(Unit *u, const char *name, ExecCommand **exec_command, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);

View File

@ -239,114 +239,8 @@ static int bus_service_set_transient_property(
return 1;
} else if ((ci = service_exec_command_from_string(name)) >= 0) {
unsigned n = 0;
r = sd_bus_message_enter_container(message, 'a', "(sasb)");
if (r < 0)
return r;
while ((r = sd_bus_message_enter_container(message, 'r', "sasb")) > 0) {
_cleanup_strv_free_ char **argv = NULL;
const char *path;
int b;
r = sd_bus_message_read(message, "s", &path);
if (r < 0)
return r;
if (!path_is_absolute(path))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not absolute.", path);
r = sd_bus_message_read_strv(message, &argv);
if (r < 0)
return r;
r = sd_bus_message_read(message, "b", &b);
if (r < 0)
return r;
r = sd_bus_message_exit_container(message);
if (r < 0)
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
ExecCommand *c;
c = new0(ExecCommand, 1);
if (!c)
return -ENOMEM;
c->path = strdup(path);
if (!c->path) {
free(c);
return -ENOMEM;
}
c->argv = argv;
argv = NULL;
c->flags = b ? EXEC_COMMAND_IGNORE_FAILURE : 0;
path_kill_slashes(c->path);
exec_command_append_list(&s->exec_command[ci], c);
}
n++;
}
if (r < 0)
return r;
r = sd_bus_message_exit_container(message);
if (r < 0)
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
_cleanup_free_ char *buf = NULL;
_cleanup_fclose_ FILE *f = NULL;
ExecCommand *c;
size_t size = 0;
if (n == 0)
s->exec_command[ci] = exec_command_free_list(s->exec_command[ci]);
f = open_memstream(&buf, &size);
if (!f)
return -ENOMEM;
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
fputs("ExecStart=\n", f);
LIST_FOREACH(command, c, s->exec_command[ci]) {
_cleanup_free_ char *a = NULL, *t = NULL;
const char *p;
p = unit_escape_setting(c->path, UNIT_ESCAPE_C|UNIT_ESCAPE_SPECIFIERS, &t);
if (!p)
return -ENOMEM;
a = unit_concat_strv(c->argv, UNIT_ESCAPE_C|UNIT_ESCAPE_SPECIFIERS);
if (!a)
return -ENOMEM;
fprintf(f, "%s=%s@%s %s\n",
name,
c->flags & EXEC_COMMAND_IGNORE_FAILURE ? "-" : "",
p,
a);
}
r = fflush_and_check(f);
if (r < 0)
return r;
unit_write_setting(UNIT(s), flags, name, buf);
}
return 1;
}
} else if ((ci = service_exec_command_from_string(name)) >= 0)
return bus_exec_command_set_transient_property(UNIT(s), name, &s->exec_command[ci], message, flags, error);
return 0;
}

View File

@ -22,10 +22,18 @@
#include "bus-util.h"
#include "dbus-cgroup.h"
#include "dbus-execute.h"
#include "dbus-kill.h"
#include "dbus-socket.h"
#include "fd-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "socket.h"
#include "socket-protocol-list.h"
#include "socket-util.h"
#include "string-util.h"
#include "unit.h"
#include "user-util.h"
#include "utf8.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, socket_result, SocketResult);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_bind_ipv6_only, socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
@ -141,6 +149,7 @@ const sd_bus_vtable bus_socket_vtable[] = {
SD_BUS_PROPERTY("MaxConnectionsPerSource", "u", bus_property_get_unsigned, offsetof(Socket, max_connections_per_source), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("MessageQueueMaxMessages", "x", bus_property_get_long, offsetof(Socket, mq_maxmsg), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("MessageQueueMessageSize", "x", bus_property_get_long, offsetof(Socket, mq_msgsize), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("TCPCongestion", "s", NULL, offsetof(Socket, tcp_congestion), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ReusePort", "b", bus_property_get_bool, offsetof(Socket, reuse_port), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SmackLabel", "s", NULL, offsetof(Socket, smack), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SmackLabelIPIn", "s", NULL, offsetof(Socket, smack_ip_in), SD_BUS_VTABLE_PROPERTY_CONST),
@ -162,6 +171,465 @@ const sd_bus_vtable bus_socket_vtable[] = {
SD_BUS_VTABLE_END
};
static int bus_socket_set_transient_property(
Socket *s,
const char *name,
sd_bus_message *message,
UnitWriteFlags flags,
sd_bus_error *error) {
SocketExecCommand ci;
Unit *u = UNIT(s);
int r;
assert(s);
assert(name);
assert(message);
flags |= UNIT_PRIVATE;
if (STR_IN_SET(name,
"Accept", "Writable", "KeepAlive", "NoDelay", "FreeBind", "Transparent", "Broadcast",
"PassCredentials", "PassSecurity", "ReusePort", "RemoveOnStop", "SELinuxContextFromNet")) {
int b;
r = sd_bus_message_read(message, "b", &b);
if (r < 0)
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
if (streq(name, "Accept"))
s->accept = b;
else if (streq(name, "Writable"))
s->writable = b;
else if (streq(name, "KeepAlive"))
s->keep_alive = b;
else if (streq(name, "NoDelay"))
s->no_delay = b;
else if (streq(name, "FreeBind"))
s->free_bind = b;
else if (streq(name, "Transparent"))
s->transparent = b;
else if (streq(name, "Broadcast"))
s->broadcast = b;
else if (streq(name, "PassCredentials"))
s->pass_cred = b;
else if (streq(name, "PassSecurity"))
s->pass_sec = b;
else if (streq(name, "ReusePort"))
s->reuse_port = b;
else if (streq(name, "RemoveOnStop"))
s->remove_on_stop = b;
else /* "SELinuxContextFromNet" */
s->selinux_context_from_net = b;
unit_write_settingf(u, flags, name, "%s=%s", name, yes_no(b));
}
return 1;
} else if (STR_IN_SET(name, "Priority", "IPTTL", "Mark")) {
int32_t i;
r = sd_bus_message_read(message, "i", &i);
if (r < 0)
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
if (streq(name, "Priority"))
s->priority = i;
else if (streq(name, "IPTTL"))
s->ip_ttl = i;
else /* "Mark" */
s->mark = i;
unit_write_settingf(u, flags, name, "%s=%i", name, i);
}
return 1;
} else if (streq(name, "IPTOS")) {
_cleanup_free_ char *str = NULL;
int32_t i;
r = sd_bus_message_read(message, "i", &i);
if (r < 0)
return r;
r = ip_tos_to_string_alloc(i, &str);
if (r < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s: %i", name, i);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
s->ip_tos = i;
unit_write_settingf(u, flags, name, "%s=%s", name, str);
}
return 1;
} else if (streq(name, "SocketProtocol")) {
const char *p;
int32_t i;
r = sd_bus_message_read(message, "i", &i);
if (r < 0)
return r;
p = socket_protocol_to_name(i);
if (!p)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s: %i", name, i);
if (!IN_SET(i, IPPROTO_UDPLITE, IPPROTO_SCTP))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unsupported socket protocol: %s", p);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
s->socket_protocol = i;
unit_write_settingf(u, flags, name, "%s=%s", name, p);
}
return 1;
} else if (STR_IN_SET(name, "Backlog", "MaxConnections", "MaxConnectionsPerSource", "KeepAliveProbes", "TriggerLimitBurst")) {
uint32_t n;
r = sd_bus_message_read(message, "u", &n);
if (r < 0)
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
if (streq(name, "Backlog"))
s->backlog = n;
else if (streq(name, "MaxConnections"))
s->max_connections = n;
else if (streq(name, "MaxConnectionsPerSource"))
s->max_connections_per_source = n;
else if (streq(name, "KeepAliveProbes"))
s->keep_alive_cnt = n;
else /* "TriggerLimitBurst" */
s->trigger_limit.burst = n;
unit_write_settingf(u, flags, name, "%s=%u", name, n);
}
return 1;
} else if (STR_IN_SET(name, "SocketMode", "DirectoryMode")) {
mode_t m;
r = sd_bus_message_read(message, "u", &m);
if (r < 0)
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
if (streq(name, "SocketMode"))
s->socket_mode = m;
else /* "DirectoryMode" */
s->directory_mode = m;
unit_write_settingf(u, flags, name, "%s=%040o", name, m);
}
return 1;
} else if (STR_IN_SET(name, "MessageQueueMaxMessages", "MessageQueueMessageSize")) {
int64_t n;
r = sd_bus_message_read(message, "x", &n);
if (r < 0)
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
if (streq(name, "MessageQueueMaxMessages"))
s->mq_maxmsg = (long) n;
else /* "MessageQueueMessageSize" */
s->mq_msgsize = (long) n;
unit_write_settingf(u, flags, name, "%s=%" PRIi64, name, n);
}
return 1;
} else if (STR_IN_SET(name, "TimeoutUSec", "KeepAliveTimeUSec", "KeepAliveIntervalUSec", "DeferAcceptUSec", "TriggerLimitIntervalUSec")) {
usec_t t;
r = sd_bus_message_read(message, "t", &t);
if (r < 0)
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
if (streq(name, "TimeoutUSec"))
s->timeout_usec = t ?: USEC_INFINITY;
else if (streq(name, "KeepAliveTimeUSec"))
s->keep_alive_time = t;
else if (streq(name, "KeepAliveIntervalUSec"))
s->keep_alive_interval = t;
else if (streq(name, "DeferAcceptUSec"))
s->defer_accept = t;
else /* "TriggerLimitIntervalUSec" */
s->trigger_limit.interval = t;
unit_write_settingf(u, flags, name, "%s=" USEC_FMT, name, t);
}
return 1;
} else if (STR_IN_SET(name, "ReceiveBuffer", "SendBuffer", "PipeSize")) {
uint64_t t;
r = sd_bus_message_read(message, "t", &t);
if (r < 0)
return r;
if ((uint64_t) (size_t) t != t)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s: %" PRIu64, name, t);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
if (streq(name, "ReceiveBuffer"))
s->receive_buffer = t;
else if (streq(name, "SendBuffer"))
s->send_buffer = t;
else /* "PipeSize" */
s->pipe_size = t;
unit_write_settingf(u, flags, name, "%s=%" PRIu64, name, t);
}
return 1;
} else if (STR_IN_SET(name, "SmackLabel", "SmackLabelIPIn", "SmackLabelIPOut", "TCPCongestion")) {
const char *n;
r = sd_bus_message_read(message, "s", &n);
if (r < 0)
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
if (streq(name, "SmackLabel"))
r = free_and_strdup(&s->smack, empty_to_null(n));
else if (streq(name, "SmackLabelIPin"))
r = free_and_strdup(&s->smack_ip_in, empty_to_null(n));
else if (streq(name, "SmackLabelIPOut"))
r = free_and_strdup(&s->smack_ip_out, empty_to_null(n));
else /* "TCPCongestion" */
r = free_and_strdup(&s->tcp_congestion, empty_to_null(n));
if (r < 0)
return r;
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, strempty(n));
}
return 1;
} else if (streq(name, "BindToDevice")) {
const char *n;
r = sd_bus_message_read(message, "s", &n);
if (r < 0)
return r;
if (n[0] && !streq(n, "*")) {
if (!ifname_valid(n))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface name for %s: %s", name, n);
} else
n = NULL;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
r = free_and_strdup(&s->bind_to_device, empty_to_null(n));
if (r < 0)
return r;
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, strempty(n));
}
return 1;
} else if (streq(name, "BindIPv6Only")) {
SocketAddressBindIPv6Only b;
const char *n;
r = sd_bus_message_read(message, "s", &n);
if (r < 0)
return r;
b = socket_address_bind_ipv6_only_from_string(n);
if (b < 0) {
r = parse_boolean(n);
if (r < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s: %s", name, n);
b = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
}
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
s->bind_ipv6_only = b;
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, n);
}
return 1;
} else if (streq(name, "FileDescriptorName")) {
const char *n;
r = sd_bus_message_read(message, "s", &n);
if (r < 0)
return r;
if (!isempty(n) && !fdname_is_valid(n))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s: %s", name, n);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
r = free_and_strdup(&s->fdname, empty_to_null(n));
if (r < 0)
return r;
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, strempty(n));
}
return 1;
} else if (STR_IN_SET(name, "SocketUser", "SocketGroup")) {
const char *n;
r = sd_bus_message_read(message, "s", &n);
if (r < 0)
return r;
if (!isempty(n) && !valid_user_group_name_or_id(n))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s: %s", name, n);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
if (streq(name, "SocketUser"))
r = free_and_strdup(&s->user, empty_to_null(n));
else /* "SocketGroup" */
r = free_and_strdup(&s->user, empty_to_null(n));
if (r < 0)
return r;
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, strempty(n));
}
return 1;
} else if (streq(name, "Symlinks")) {
_cleanup_strv_free_ char **l = NULL;
char **p;
r = sd_bus_message_read_strv(message, &l);
if (r < 0)
return r;
STRV_FOREACH(p, l) {
if (!utf8_is_valid(*p))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "String is not UTF-8 clean, ignoring assignment: %s", *p);
if (!path_is_absolute(*p))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Symlink path is not absolute: %s", *p);
}
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
if (strv_isempty(l)) {
s->symlinks = strv_free(s->symlinks);
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=", name);
} else {
_cleanup_free_ char *joined = NULL;
r = strv_extend_strv(&s->symlinks, l, true);
if (r < 0)
return -ENOMEM;
joined = strv_join(l, " ");
if (!joined)
return -ENOMEM;
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, joined);
}
}
return 1;
} else if (streq(name, "Listen")) {
const char *t, *a;
bool empty = true;
r = sd_bus_message_enter_container(message, 'a', "(ss)");
if (r < 0)
return r;
while ((r = sd_bus_message_read(message, "(ss)", &t, &a)) > 0) {
_cleanup_free_ SocketPort *p = NULL;
p = new0(SocketPort, 1);
if (!p)
return log_oom();
p->type = socket_port_type_from_string(t);
if (p->type < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown Socket type: %s", t);
if (p->type != SOCKET_SOCKET) {
p->path = strdup(a);
path_kill_slashes(p->path);
} else if (streq(t, "Netlink")) {
r = socket_address_parse_netlink(&p->address, a);
if (r < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid netlink address: %s", a);
} else {
r = socket_address_parse(&p->address, a);
if (r < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address: %s", a);
p->address.type = socket_address_type_from_string(t);
if (p->address.type < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address type: %s", t);
if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Address family not supported: %s", a);
}
p->fd = -1;
p->auxiliary_fds = NULL;
p->n_auxiliary_fds = 0;
p->socket = s;
empty = false;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
SocketPort *tail;
LIST_FIND_TAIL(port, s->ports, tail);
LIST_INSERT_AFTER(port, s->ports, tail, p);
p = NULL;
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "Listen%s=%s", t, a);
}
}
if (r < 0)
return r;
r = sd_bus_message_exit_container(message);
if (r < 0)
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags) && empty) {
socket_free_ports(s);
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "ListenStream=");
}
return 1;
} else if ((ci = socket_exec_command_from_string(name)) >= 0)
return bus_exec_command_set_transient_property(UNIT(s), name, &s->exec_command[ci], message, flags, error);
return 0;
}
int bus_socket_set_property(
Unit *u,
const char *name,
@ -170,12 +638,37 @@ int bus_socket_set_property(
sd_bus_error *error) {
Socket *s = SOCKET(u);
int r;
assert(s);
assert(name);
assert(message);
return bus_cgroup_set_property(u, &s->cgroup_context, name, message, flags, error);
assert(s);
assert(name);
assert(message);
r = bus_cgroup_set_property(u, &s->cgroup_context, name, message, flags, error);
if (r != 0)
return r;
if (u->transient && u->load_state == UNIT_STUB) {
/* This is a transient unit, let's load a little more */
r = bus_socket_set_transient_property(s, name, message, flags, error);
if (r != 0)
return r;
r = bus_exec_context_set_transient_property(u, &s->exec_context, name, message, flags, error);
if (r != 0)
return r;
r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, flags, error);
if (r != 0)
return r;
}
return 0;
}
int bus_socket_commit_properties(Unit *u) {

View File

@ -4162,19 +4162,19 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
if (c->pam_name)
fprintf(f, "%sPAMName: %s\n", prefix, c->pam_name);
if (strv_length(c->read_write_paths) > 0) {
if (!strv_isempty(c->read_write_paths)) {
fprintf(f, "%sReadWritePaths:", prefix);
strv_fprintf(f, c->read_write_paths);
fputs("\n", f);
}
if (strv_length(c->read_only_paths) > 0) {
if (!strv_isempty(c->read_only_paths)) {
fprintf(f, "%sReadOnlyPaths:", prefix);
strv_fprintf(f, c->read_only_paths);
fputs("\n", f);
}
if (strv_length(c->inaccessible_paths) > 0) {
if (!strv_isempty(c->inaccessible_paths)) {
fprintf(f, "%sInaccessiblePaths:", prefix);
strv_fprintf(f, c->inaccessible_paths);
fputs("\n", f);

View File

@ -64,6 +64,7 @@
#include "securebits.h"
#include "securebits-util.h"
#include "signal-util.h"
#include "socket-protocol-list.h"
#include "stat-util.h"
#include "string-util.h"
#include "strv.h"
@ -433,11 +434,9 @@ int config_parse_socket_listen(const char *unit,
p->n_auxiliary_fds = 0;
p->socket = s;
if (s->ports) {
LIST_FIND_TAIL(port, s->ports, tail);
LIST_INSERT_AFTER(port, s->ports, tail, p);
} else
LIST_PREPEND(port, s->ports, p);
LIST_FIND_TAIL(port, s->ports, tail);
LIST_INSERT_AFTER(port, s->ports, tail, p);
p = NULL;
return 0;
@ -454,6 +453,7 @@ int config_parse_socket_protocol(const char *unit,
void *data,
void *userdata) {
Socket *s;
int r;
assert(filename);
assert(lvalue);
@ -462,15 +462,17 @@ int config_parse_socket_protocol(const char *unit,
s = SOCKET(data);
if (streq(rvalue, "udplite"))
s->socket_protocol = IPPROTO_UDPLITE;
else if (streq(rvalue, "sctp"))
s->socket_protocol = IPPROTO_SCTP;
else {
r = socket_protocol_from_name(rvalue);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid socket protocol, ignoring: %s", rvalue);
return 0;
} else if (!IN_SET(r, IPPROTO_UDPLITE, IPPROTO_SCTP)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Socket protocol not supported, ignoring: %s", rvalue);
return 0;
}
s->socket_protocol = r;
return 0;
}
@ -2891,60 +2893,6 @@ int config_parse_documentation(const char *unit,
}
#if HAVE_SECCOMP
static int syscall_filter_parse_one(
const char *unit,
const char *filename,
unsigned line,
ExecContext *c,
bool invert,
const char *t,
bool warn,
int errno_num) {
int r;
if (t[0] == '@') {
const SyscallFilterSet *set;
const char *i;
set = syscall_filter_set_find(t);
if (!set) {
if (warn)
log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown system call group, ignoring: %s", t);
return 0;
}
NULSTR_FOREACH(i, set->value) {
r = syscall_filter_parse_one(unit, filename, line, c, invert, i, false, errno_num);
if (r < 0)
return r;
}
} else {
int id;
id = seccomp_syscall_resolve_name(t);
if (id == __NR_SCMP_ERROR) {
if (warn)
log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse system call, ignoring: %s", t);
return 0;
}
/* If we previously wanted to forbid a syscall and now
* we want to allow it, then remove it from the list.
*/
if (!invert == c->syscall_whitelist) {
r = hashmap_put(c->syscall_filter, INT_TO_PTR(id + 1), INT_TO_PTR(errno_num));
if (r == 0)
return 0;
if (r < 0)
return log_oom();
} else
(void) hashmap_remove(c->syscall_filter, INT_TO_PTR(id + 1));
}
return 0;
}
int config_parse_syscall_filter(
const char *unit,
const char *filename,
@ -2993,7 +2941,7 @@ int config_parse_syscall_filter(
c->syscall_whitelist = true;
/* Accept default syscalls if we are on a whitelist */
r = syscall_filter_parse_one(unit, filename, line, c, false, "@default", false, -1);
r = seccomp_parse_syscall_filter(false, "@default", -1, c->syscall_filter, true);
if (r < 0)
return r;
}
@ -3020,7 +2968,7 @@ int config_parse_syscall_filter(
continue;
}
r = syscall_filter_parse_one(unit, filename, line, c, invert, name, true, num);
r = seccomp_parse_syscall_filter_and_warn(invert, name, num, c->syscall_filter, c->syscall_whitelist, unit, filename, line);
if (r < 0)
return r;
}
@ -3575,7 +3523,8 @@ int config_parse_device_allow(
if (!path)
return log_oom();
if (!is_deviceallow_pattern(path)) {
if (!is_deviceallow_pattern(path) &&
!path_startswith(path, "/run/systemd/inaccessible/")) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
return 0;
}
@ -3675,7 +3624,8 @@ int config_parse_io_device_weight(
if (!path)
return log_oom();
if (!path_startswith(path, "/dev")) {
if (!path_startswith(path, "/dev") &&
!path_startswith(path, "/run/systemd/inaccessible/")) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
return 0;
}
@ -3748,7 +3698,8 @@ int config_parse_io_limit(
if (!path)
return log_oom();
if (!path_startswith(path, "/dev")) {
if (!path_startswith(path, "/dev") &&
!path_startswith(path, "/run/systemd/inaccessible/")) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
return 0;
}
@ -3862,7 +3813,8 @@ int config_parse_blockio_device_weight(
if (!path)
return log_oom();
if (!path_startswith(path, "/dev")) {
if (!path_startswith(path, "/dev") &&
!path_startswith(path, "/run/systemd/inaccessible/")) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
return 0;
}
@ -3936,7 +3888,8 @@ int config_parse_blockio_bandwidth(
if (!path)
return log_oom();
if (!path_startswith(path, "/dev")) {
if (!path_startswith(path, "/dev") &&
!path_startswith(path, "/run/systemd/inaccessible/")) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
return 0;
}

View File

@ -53,6 +53,7 @@
#include "signal-util.h"
#include "smack-util.h"
#include "socket.h"
#include "socket-protocol-list.h"
#include "special.h"
#include "string-table.h"
#include "string-util.h"
@ -655,7 +656,7 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
SocketExecCommand c;
Socket *s = SOCKET(u);
SocketPort *p;
const char *prefix2;
const char *prefix2, *str;
assert(s);
assert(f);
@ -680,7 +681,7 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
"%sTCPCongestion: %s\n"
"%sRemoveOnStop: %s\n"
"%sWritable: %s\n"
"%sFDName: %s\n"
"%sFileDescriptorName: %s\n"
"%sSELinuxContextFromNet: %s\n",
prefix, socket_state_to_string(s->state),
prefix, socket_result_to_string(s->result),
@ -715,10 +716,12 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
fprintf(f,
"%sAccepted: %u\n"
"%sNConnections: %u\n"
"%sMaxConnections: %u\n",
"%sMaxConnections: %u\n"
"%sMaxConnectionsPerSource: %u\n",
prefix, s->n_accepted,
prefix, s->n_connections,
prefix, s->max_connections);
prefix, s->max_connections,
prefix, s->max_connections_per_source);
if (s->priority >= 0)
fprintf(f,
@ -843,6 +846,24 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
prefix, format_timespan(time_string, FORMAT_TIMESPAN_MAX, s->trigger_limit.interval, USEC_PER_SEC),
prefix, s->trigger_limit.burst);
str = socket_protocol_to_name(s->socket_protocol);
if (str)
fprintf(f, "%sSocketProtocol: %s\n", prefix, str);
if (!strv_isempty(s->symlinks)) {
char **q;
fprintf(f, "%sSymlinks:", prefix);
STRV_FOREACH(q, s->symlinks)
fprintf(f, " %s", *q);
fprintf(f, "\n");
}
fprintf(f,
"%sTimeoutSec: %s\n",
prefix, format_timespan(time_string, FORMAT_TIMESPAN_MAX, s->timeout_usec, USEC_PER_SEC));
exec_context_dump(&s->exec_context, f, prefix);
kill_context_dump(&s->kill_context, f, prefix);
@ -2780,6 +2801,23 @@ const char* socket_port_type_to_string(SocketPort *p) {
}
}
SocketType socket_port_type_from_string(const char *s) {
assert(s);
if (STR_IN_SET(s, "Stream", "Datagram", "SequentialPacket", "Netlink"))
return SOCKET_SOCKET;
else if (streq(s, "Special"))
return SOCKET_SPECIAL;
else if (streq(s, "MessageQueue"))
return SOCKET_MQUEUE;
else if (streq(s, "FIFO"))
return SOCKET_FIFO;
else if (streq(s, "USBFunction"))
return SOCKET_USB_FUNCTION;
else
return _SOCKET_TYPE_INVALID;
}
_pure_ static bool socket_check_gc(Unit *u) {
Socket *s = SOCKET(u);
@ -3212,10 +3250,7 @@ char *socket_fdname(Socket *s) {
* didn't specify anything specifically, use the socket unit's
* name as fallback. */
if (s->fdname)
return s->fdname;
return UNIT(s)->id;
return s->fdname ?: UNIT(s)->id;
}
static int socket_control_pid(Unit *u) {
@ -3227,11 +3262,11 @@ static int socket_control_pid(Unit *u) {
}
static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = {
[SOCKET_EXEC_START_PRE] = "StartPre",
[SOCKET_EXEC_START_CHOWN] = "StartChown",
[SOCKET_EXEC_START_POST] = "StartPost",
[SOCKET_EXEC_STOP_PRE] = "StopPre",
[SOCKET_EXEC_STOP_POST] = "StopPost"
[SOCKET_EXEC_START_PRE] = "ExecStartPre",
[SOCKET_EXEC_START_CHOWN] = "ExecStartChown",
[SOCKET_EXEC_START_POST] = "ExecStartPost",
[SOCKET_EXEC_STOP_PRE] = "ExecStopPre",
[SOCKET_EXEC_STOP_POST] = "ExecStopPost"
};
DEFINE_STRING_TABLE_LOOKUP(socket_exec_command, SocketExecCommand);
@ -3264,6 +3299,8 @@ const UnitVTable socket_vtable = {
"Install\0",
.private_section = "Socket",
.can_transient = true,
.init = socket_init,
.done = socket_done,
.load = socket_load,

View File

@ -43,8 +43,8 @@ typedef enum SocketType {
SOCKET_SPECIAL,
SOCKET_MQUEUE,
SOCKET_USB_FUNCTION,
_SOCKET_FIFO_MAX,
_SOCKET_FIFO_INVALID = -1
_SOCKET_TYPE_MAX,
_SOCKET_TYPE_INVALID = -1
} SocketType;
typedef enum SocketResult {
@ -194,3 +194,4 @@ const char* socket_result_to_string(SocketResult i) _const_;
SocketResult socket_result_from_string(const char *s) _pure_;
const char* socket_port_type_to_string(SocketPort *p) _pure_;
SocketType socket_port_type_from_string(const char *p) _pure_;

View File

@ -40,6 +40,7 @@
#include "stat-util.h"
#include "strv.h"
#include "udev-util.h"
#include "unit-def.h"
#include "unit-name.h"
#include "user-util.h"
#include "terminal-util.h"
@ -403,7 +404,7 @@ static int parse_argv(int argc, char *argv[]) {
return 1;
}
static int transient_unit_set_properties(sd_bus_message *m, char **properties) {
static int transient_unit_set_properties(sd_bus_message *m, UnitType t, char **properties) {
int r;
if (!isempty(arg_description)) {
@ -432,7 +433,7 @@ static int transient_unit_set_properties(sd_bus_message *m, char **properties) {
return r;
}
r = bus_append_unit_property_assignment_many(m, properties);
r = bus_append_unit_property_assignment_many(m, t, properties);
if (r < 0)
return r;
@ -445,7 +446,7 @@ static int transient_mount_set_properties(sd_bus_message *m) {
assert(m);
r = transient_unit_set_properties(m, arg_property);
r = transient_unit_set_properties(m, UNIT_MOUNT, arg_property);
if (r < 0)
return r;
@ -503,7 +504,7 @@ static int transient_automount_set_properties(sd_bus_message *m) {
assert(m);
r = transient_unit_set_properties(m, arg_automount_property);
r = transient_unit_set_properties(m, UNIT_AUTOMOUNT, arg_automount_property);
if (r < 0)
return r;

View File

@ -179,7 +179,7 @@ int main(int argc, char* argv[]) {
goto finish;
}
if (strv_length(final_env) <= 0) {
if (strv_isempty(final_env)) {
r = 0;
goto finish;
}

View File

@ -203,7 +203,7 @@ int register_machine(
if (r < 0)
return r;
r = bus_append_unit_property_assignment_many(m, properties);
r = bus_append_unit_property_assignment_many(m, UNIT_SERVICE, properties);
if (r < 0)
return r;
@ -339,7 +339,7 @@ int allocate_scope(
if (r < 0)
return r;
r = bus_append_unit_property_assignment_many(m, properties);
r = bus_append_unit_property_assignment_many(m, UNIT_SCOPE, properties);
if (r < 0)
return r;

View File

@ -40,6 +40,7 @@
#include "spawn-polkit-agent.h"
#include "strv.h"
#include "terminal-util.h"
#include "unit-def.h"
#include "unit-name.h"
#include "user-util.h"
@ -68,6 +69,8 @@ static enum {
ARG_STDIO_DIRECT, /* Directly pass our stdin/stdout/stderr to the activated service, useful for usage in shell pipelines, requested by --pipe */
ARG_STDIO_AUTO, /* If --pipe and --pty are used together we use --pty when invoked on a TTY, and --pipe otherwise */
} arg_stdio = ARG_STDIO_NONE;
static char **arg_path_property = NULL;
static char **arg_socket_property = NULL;
static char **arg_timer_property = NULL;
static bool with_timer = false;
static bool arg_quiet = false;
@ -101,6 +104,10 @@ static void help(void) {
" -P --pipe Pass STDIN/STDOUT/STDERR directly to service\n"
" -q --quiet Suppress information messages during runtime\n"
" -G --collect Unload unit after it ran, even when failed\n\n"
"Path options:\n"
" --path-property=NAME=VALUE Set path unit property\n\n"
"Socket options:\n"
" --socket-property=NAME=VALUE Set socket unit property\n\n"
"Timer options:\n"
" --on-active=SECONDS Run after SECONDS delay\n"
" --on-boot=SECONDS Run SECONDS after machine was booted up\n"
@ -152,6 +159,8 @@ static int parse_argv(int argc, char *argv[]) {
ARG_ON_UNIT_INACTIVE,
ARG_ON_CALENDAR,
ARG_TIMER_PROPERTY,
ARG_PATH_PROPERTY,
ARG_SOCKET_PROPERTY,
ARG_NO_BLOCK,
ARG_NO_ASK_PASSWORD,
ARG_WAIT,
@ -188,12 +197,15 @@ static int parse_argv(int argc, char *argv[]) {
{ "on-unit-inactive", required_argument, NULL, ARG_ON_UNIT_INACTIVE },
{ "on-calendar", required_argument, NULL, ARG_ON_CALENDAR },
{ "timer-property", required_argument, NULL, ARG_TIMER_PROPERTY },
{ "path-property", required_argument, NULL, ARG_PATH_PROPERTY },
{ "socket-property", required_argument, NULL, ARG_SOCKET_PROPERTY },
{ "no-block", no_argument, NULL, ARG_NO_BLOCK },
{ "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
{ "collect", no_argument, NULL, 'G' },
{},
};
bool with_trigger = false;
int r, c;
assert(argc >= 0);
@ -368,6 +380,20 @@ static int parse_argv(int argc, char *argv[]) {
!!startswith(optarg, "OnCalendar=");
break;
case ARG_PATH_PROPERTY:
if (strv_extend(&arg_path_property, optarg) < 0)
return log_oom();
break;
case ARG_SOCKET_PROPERTY:
if (strv_extend(&arg_socket_property, optarg) < 0)
return log_oom();
break;
case ARG_NO_BLOCK:
arg_no_block = true;
break;
@ -387,6 +413,13 @@ static int parse_argv(int argc, char *argv[]) {
assert_not_reached("Unhandled option");
}
with_trigger = !!arg_path_property || !!arg_socket_property || with_timer;
/* currently, only single trigger (path, socket, timer) unit can be created simultaneously */
if ((int) !!arg_path_property + (int) !!arg_socket_property + (int) with_timer > 1) {
log_error("Only single trigger (path, socket, timer) unit can be created.");
return -EINVAL;
}
if (arg_stdio == ARG_STDIO_AUTO) {
/* If we both --pty and --pipe are specified we'll automatically pick --pty if we are connected fully
@ -397,7 +430,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_STDIO_DIRECT;
}
if ((optind >= argc) && (!arg_unit || !with_timer)) {
if ((optind >= argc) && (!arg_unit || !with_trigger)) {
log_error("Command line to execute required.");
return -EINVAL;
}
@ -417,7 +450,7 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
if (arg_stdio != ARG_STDIO_NONE && (with_timer || arg_scope)) {
if (arg_stdio != ARG_STDIO_NONE && (with_trigger || arg_scope)) {
log_error("--pty/--pipe is not compatible in timer or --scope mode.");
return -EINVAL;
}
@ -432,8 +465,8 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
if (arg_scope && with_timer) {
log_error("Timer options are not supported in --scope mode.");
if (arg_scope && with_trigger) {
log_error("Path, socket or timer options are not supported in --scope mode.");
return -EINVAL;
}
@ -448,8 +481,8 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
if (with_timer) {
log_error("--wait may not be combined with timer operations.");
if (with_trigger) {
log_error("--wait may not be combined with path, socket or timer operations.");
return -EINVAL;
}
@ -462,7 +495,7 @@ static int parse_argv(int argc, char *argv[]) {
return 1;
}
static int transient_unit_set_properties(sd_bus_message *m, char **properties) {
static int transient_unit_set_properties(sd_bus_message *m, UnitType t, char **properties) {
int r;
r = sd_bus_message_append(m, "(sv)", "Description", "s", arg_description);
@ -475,7 +508,7 @@ static int transient_unit_set_properties(sd_bus_message *m, char **properties) {
return bus_log_create_error(r);
}
r = bus_append_unit_property_assignment_many(m, properties);
r = bus_append_unit_property_assignment_many(m, t, properties);
if (r < 0)
return r;
@ -521,7 +554,7 @@ static int transient_service_set_properties(sd_bus_message *m, char **argv, cons
assert(m);
r = transient_unit_set_properties(m, arg_property);
r = transient_unit_set_properties(m, UNIT_SERVICE, arg_property);
if (r < 0)
return r;
@ -694,7 +727,7 @@ static int transient_scope_set_properties(sd_bus_message *m) {
assert(m);
r = transient_unit_set_properties(m, arg_property);
r = transient_unit_set_properties(m, UNIT_SCOPE, arg_property);
if (r < 0)
return r;
@ -718,7 +751,7 @@ static int transient_timer_set_properties(sd_bus_message *m) {
assert(m);
r = transient_unit_set_properties(m, arg_timer_property);
r = transient_unit_set_properties(m, UNIT_TIMER, arg_timer_property);
if (r < 0)
return r;
@ -1282,14 +1315,15 @@ static int start_transient_scope(
return log_error_errno(errno, "Failed to execute: %m");
}
static int start_transient_timer(
static int start_transient_trigger(
sd_bus *bus,
char **argv) {
char **argv,
const char *suffix) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
_cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
_cleanup_free_ char *timer = NULL, *service = NULL;
_cleanup_free_ char *trigger = NULL, *service = NULL;
const char *object = NULL;
int r;
@ -1308,17 +1342,17 @@ static int start_transient_timer(
if (!service)
return log_oom();
r = unit_name_change_suffix(service, ".timer", &timer);
r = unit_name_change_suffix(service, suffix, &trigger);
if (r < 0)
return log_error_errno(r, "Failed to change unit suffix: %m");
break;
case UNIT_TIMER:
timer = strdup(arg_unit);
if (!timer)
trigger = strdup(arg_unit);
if (!trigger)
return log_oom();
r = unit_name_change_suffix(timer, ".service", &service);
r = unit_name_change_suffix(trigger, ".service", &service);
if (r < 0)
return log_error_errno(r, "Failed to change unit suffix: %m");
break;
@ -1328,7 +1362,7 @@ static int start_transient_timer(
if (r < 0)
return log_error_errno(r, "Failed to mangle unit name: %m");
r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".timer", &timer);
r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, suffix, &trigger);
if (r < 0)
return log_error_errno(r, "Failed to mangle unit name: %m");
@ -1339,7 +1373,7 @@ static int start_transient_timer(
if (r < 0)
return r;
r = unit_name_change_suffix(service, ".timer", &timer);
r = unit_name_change_suffix(service, suffix, &trigger);
if (r < 0)
return log_error_errno(r, "Failed to change unit suffix: %m");
}
@ -1359,7 +1393,7 @@ static int start_transient_timer(
return bus_log_create_error(r);
/* Name and Mode */
r = sd_bus_message_append(m, "ss", timer, "fail");
r = sd_bus_message_append(m, "ss", trigger, "fail");
if (r < 0)
return bus_log_create_error(r);
@ -1368,7 +1402,14 @@ static int start_transient_timer(
if (r < 0)
return bus_log_create_error(r);
r = transient_timer_set_properties(m);
if (streq(suffix, ".path"))
r = transient_unit_set_properties(m, UNIT_PATH, arg_path_property);
else if (streq(suffix, ".socket"))
r = transient_unit_set_properties(m, UNIT_SOCKET, arg_socket_property);
else if (streq(suffix, ".timer"))
r = transient_timer_set_properties(m);
else
assert_not_reached("Invalid suffix");
if (r < 0)
return r;
@ -1414,7 +1455,7 @@ static int start_transient_timer(
r = sd_bus_call(bus, m, 0, &error, &reply);
if (r < 0) {
log_error("Failed to start transient timer unit: %s", bus_error_message(&error, -r));
log_error("Failed to start transient %s unit: %s", suffix + 1, bus_error_message(&error, -r));
return r;
}
@ -1427,7 +1468,7 @@ static int start_transient_timer(
return r;
if (!arg_quiet) {
log_info("Running timer as unit: %s", timer);
log_info("Running %s as unit: %s", suffix + 1, trigger);
if (argv[0])
log_info("Will run service as unit: %s", service);
}
@ -1488,14 +1529,20 @@ int main(int argc, char* argv[]) {
if (arg_scope)
r = start_transient_scope(bus, argv + optind);
else if (arg_path_property)
r = start_transient_trigger(bus, argv + optind, ".path");
else if (arg_socket_property)
r = start_transient_trigger(bus, argv + optind, ".socket");
else if (with_timer)
r = start_transient_timer(bus, argv + optind);
r = start_transient_trigger(bus, argv + optind, ".timer");
else
r = start_transient_service(bus, argv + optind, &retval);
finish:
strv_free(arg_environment);
strv_free(arg_property);
strv_free(arg_path_property);
strv_free(arg_socket_property);
strv_free(arg_timer_property);
return r < 0 ? EXIT_FAILURE : retval;

View File

@ -656,7 +656,7 @@ int ask_password_agent(
goto finish;
}
if (strv_length(l) <= 0) {
if (strv_isempty(l)) {
l = strv_free(l);
log_debug("Invalid packet");
continue;

File diff suppressed because it is too large Load Diff

View File

@ -20,10 +20,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include "sd-bus.h"
#include "output-mode.h"
#include "install.h"
#include "output-mode.h"
#include "sd-bus.h"
#include "unit-def.h"
typedef struct UnitInfo {
const char *machine;
@ -41,8 +41,8 @@ typedef struct UnitInfo {
int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u);
int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment);
int bus_append_unit_property_assignment_many(sd_bus_message *m, char **l);
int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment);
int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char **l);
typedef struct BusWaitForJobs BusWaitForJobs;

View File

@ -950,6 +950,65 @@ int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* set, u
return 0;
}
int seccomp_parse_syscall_filter_internal(
bool invert,
const char *name,
int errno_num,
Hashmap *filter,
bool whitelist,
bool warn,
const char *unit,
const char *filename,
unsigned line) {
int r;
assert(name);
assert(filter);
if (name[0] == '@') {
const SyscallFilterSet *set;
const char *i;
set = syscall_filter_set_find(name);
if (!set) {
if (warn) {
log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown system call group, ignoring: %s", name);
return 0;
} else
return -EINVAL;
}
NULSTR_FOREACH(i, set->value) {
r = seccomp_parse_syscall_filter_internal(invert, i, errno_num, filter, whitelist, warn, unit, filename, line);
if (r < 0)
return r;
}
} else {
int id;
id = seccomp_syscall_resolve_name(name);
if (id == __NR_SCMP_ERROR) {
if (warn) {
log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse system call, ignoring: %s", name);
return 0;
} else
return -EINVAL;
}
/* If we previously wanted to forbid a syscall and now
* we want to allow it, then remove it from the list. */
if (!invert == whitelist) {
r = hashmap_put(filter, INT_TO_PTR(id + 1), INT_TO_PTR(errno_num));
if (r < 0)
return warn ? log_oom() : -ENOMEM;
} else
(void) hashmap_remove(filter, INT_TO_PTR(id + 1));
}
return 0;
}
int seccomp_restrict_namespaces(unsigned long retain) {
uint32_t arch;
int r;

View File

@ -81,6 +81,24 @@ int seccomp_add_syscall_filter_item(scmp_filter_ctx *ctx, const char *name, uint
int seccomp_load_syscall_filter_set(uint32_t default_action, const SyscallFilterSet *set, uint32_t action);
int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* set, uint32_t action);
int seccomp_parse_syscall_filter_internal(
bool invert, const char *name, int errno_num, Hashmap *filter, bool whitelist,
bool warn, const char *unit, const char *filename, unsigned line);
static inline int seccomp_parse_syscall_filter_and_warn(
bool invert, const char *name, int errno_num, Hashmap *filter, bool whitelist,
const char *unit, const char *filename, unsigned line) {
assert(unit);
assert(filename);
return seccomp_parse_syscall_filter_internal(invert, name, errno_num, filter, whitelist, true, unit, filename, line);
}
static inline int seccomp_parse_syscall_filter(
bool invert, const char *name, int errno_num, Hashmap *filter, bool whitelist) {
return seccomp_parse_syscall_filter_internal(invert, name, errno_num, filter, whitelist, false, NULL, NULL, 0);
}
int seccomp_restrict_archs(Set *archs);
int seccomp_restrict_namespaces(unsigned long retain);
int seccomp_protect_sysctl(void);

View File

@ -84,6 +84,7 @@
#include "stat-util.h"
#include "strv.h"
#include "terminal-util.h"
#include "unit-def.h"
#include "unit-name.h"
#include "user-util.h"
#include "util.h"
@ -5582,6 +5583,7 @@ static int set_property(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_free_ char *n = NULL;
UnitType t;
sd_bus *bus;
int r;
@ -5605,6 +5607,12 @@ static int set_property(int argc, char *argv[], void *userdata) {
if (r < 0)
return log_error_errno(r, "Failed to mangle unit name: %m");
t = unit_name_to_type(n);
if (t < 0) {
log_error("Invalid unit type: %s", n);
return -EINVAL;
}
r = sd_bus_message_append(m, "sb", n, arg_runtime);
if (r < 0)
return bus_log_create_error(r);
@ -5613,7 +5621,7 @@ static int set_property(int argc, char *argv[], void *userdata) {
if (r < 0)
return bus_log_create_error(r);
r = bus_append_unit_property_assignment_many(m, strv_skip(argv, 2));
r = bus_append_unit_property_assignment_many(m, t, strv_skip(argv, 2));
if (r < 0)
return r;