core: implement transient socket unit
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 23 Dec 2017 09:47:33 +0000 (18:47 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 23 Dec 2017 09:47:33 +0000 (18:47 +0900)
src/core/dbus-execute.c
src/core/dbus-execute.h
src/core/dbus-service.c
src/core/dbus-socket.c
src/core/socket.c

index 4b1160c..f0282f7 100644 (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,
index f30f077..3654598 100644 (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);
index 0189952..c5eba5f 100644 (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;
 }
index 930b7fa..6c5d594 100644 (file)
 #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);
 
         assert(s);
         assert(name);
         assert(message);
 
-        return bus_cgroup_set_property(u, &s->cgroup_context, name, message, flags, error);
+        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) {
index 6baaa88..553bbe9 100644 (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,