core: implement transient socket unit

This commit is contained in:
Yu Watanabe
2017-12-23 18:47:33 +09:00
parent 398ce0bc5a
commit 9c0320e7ab
5 changed files with 605 additions and 109 deletions
+115
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,
+1
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);
+2 -108
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;
}
+485 -1
View File
@@ -22,10 +22,17 @@
#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-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 +148,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 +170,457 @@ 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")) {
int32_t i;
r = sd_bus_message_read(message, "i", &i);
if (r < 0)
return r;
if (!IN_SET(i, IPPROTO_UDPLITE, IPPROTO_SCTP))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s: %i", name, i);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
s->socket_protocol = i;
unit_write_settingf(u, flags, name, "%s=%s", name, i == IPPROTO_UDPLITE ? "udplite" : "sctp");
}
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 (!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_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 +629,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) {
+2
View File
@@ -3281,6 +3281,8 @@ const UnitVTable socket_vtable = {
"Install\0",
.private_section = "Socket",
.can_transient = true,
.init = socket_init,
.done = socket_done,
.load = socket_load,