From 586290017d09a1081bfcd328098022a933d40888 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 15 Dec 2017 16:36:35 +0900 Subject: [PATCH 01/25] tree-wide: use !strv_isempty() instead of strv_length() > 0 --- src/core/execute.c | 6 +++--- src/notify/notify.c | 2 +- src/shared/ask-password-api.c | 2 +- src/shared/bus-unit-util.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/core/execute.c b/src/core/execute.c index b91f654994..aa9120b2ed 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -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); diff --git a/src/notify/notify.c b/src/notify/notify.c index 3e511b7e47..4a34e1e9db 100644 --- a/src/notify/notify.c +++ b/src/notify/notify.c @@ -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; } diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c index 17928a9732..346d8c9d24 100644 --- a/src/shared/ask-password-api.c +++ b/src/shared/ask-password-api.c @@ -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; diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 8af738d8ce..372e431d63 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1269,7 +1269,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen if (r < 0) return r; - if (strv_length(l) > 0) { + if (!strv_isempty(l)) { r = sd_bus_message_open_container(m, 'r', "sasb"); if (r < 0) From 5976f1ca769f67288a0dbfce20dd529fc75c9458 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 15 Dec 2017 21:22:01 +0900 Subject: [PATCH 02/25] core: fix wrong validity check --- src/core/dbus-execute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index be25b6e987..35407d19eb 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -1573,7 +1573,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)) { From e7bcff4ec4eeb1f04e2f35cecea4e50698dddb00 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 15 Dec 2017 21:25:00 +0900 Subject: [PATCH 03/25] core: move path_kill_slashes() to manager --- src/core/dbus-execute.c | 4 +++- src/shared/bus-unit-util.c | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 35407d19eb..e4a31e1d3e 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -2323,7 +2323,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 +2333,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)) { diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 372e431d63..092c1768c7 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1008,8 +1008,6 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen return -EINVAL; } - path_kill_slashes(word + offset); - r = sd_bus_message_append_basic(m, 's', word); if (r < 0) return bus_log_create_error(r); From 898748d8b97194e43f909e6edf27c100ecaad1be Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 23 Dec 2017 18:45:32 +0900 Subject: [PATCH 04/25] core,seccomp: fix logic to parse syscall filter in dbus-execute.c If multiple SystemCallFilter= settings, some of them are whitelist and the others are blacklist, are sent to bus, then the parse result was corrupted. This fixes the parse logic, now it is the same as one used in load-fragment.c --- src/core/dbus-execute.c | 69 +++++++++++++++------------------------ src/core/load-fragment.c | 58 ++------------------------------ src/shared/seccomp-util.c | 59 +++++++++++++++++++++++++++++++++ src/shared/seccomp-util.h | 18 ++++++++++ 4 files changed, 105 insertions(+), 99 deletions(-) diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index e4a31e1d3e..a3d601b1e9 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -1361,59 +1361,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, " "); diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index d6c616502b..469b2fc2b4 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2891,60 +2891,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 +2939,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 +2966,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; } diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index b8f2b30a71..14ebe01a39 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -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; diff --git a/src/shared/seccomp-util.h b/src/shared/seccomp-util.h index ad2ab7f6b5..0b30cdf388 100644 --- a/src/shared/seccomp-util.h +++ b/src/shared/seccomp-util.h @@ -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); From 9ee896d5dd98ee9fba7c0ee40784a1266661cd5f Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 19 Dec 2017 11:05:43 +0900 Subject: [PATCH 05/25] core,seccomp: fix logic to parse RestrictAddressFamilies= in dbus-execute.c If multiple RestrictAddressFamilies= settings, some of them are whitelist and the others are blacklist, are sent to bus, then parsing result was corrupted. This fixes the parse logic, now it is the same as one used in load-fragment.c --- src/core/dbus-execute.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index a3d601b1e9..4b1160cab4 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -1490,30 +1490,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, " "); From 836bb1cd4226e28839260cbbae87a85c572c119d Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 19 Dec 2017 22:14:07 +0900 Subject: [PATCH 06/25] core:socket: fix string in socket_exec_command_table --- src/core/socket.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/socket.c b/src/core/socket.c index 7e3630ada7..99b1440a92 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -3227,11 +3227,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); From 038ed5a4b6f391d5646e55f3dfce7011a6a5d799 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 23 Dec 2017 16:29:40 +0900 Subject: [PATCH 07/25] core/socket: add socket_port_type_from_string() --- src/core/socket.c | 17 +++++++++++++++++ src/core/socket.h | 5 +++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/core/socket.c b/src/core/socket.c index 99b1440a92..6baaa8840e 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -2780,6 +2780,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(t, "Stream", "Datagram", "SequentialPacket", "Netlink")) + return = SOCKET_SOCKET; + else if (streq(t, "Special")) + return = SOCKET_SPECIAL; + else if (streq(t, "MessageQueue")) + return = SOCKET_MQUEUE; + else if (streq(t, "FIFO")) + return = SOCKET_FIFO; + else if (streq(t, "USBFunction")) + return = SOCKET_USB_FUNCTION; + else + return _SOCKET_TYPE_INVALID; +} + _pure_ static bool socket_check_gc(Unit *u) { Socket *s = SOCKET(u); diff --git a/src/core/socket.h b/src/core/socket.h index e9e560e57e..9c528fb39c 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -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_; From 398ce0bc5a0e1aad57223a62dcbcc8854e103c90 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 23 Dec 2017 16:55:36 +0900 Subject: [PATCH 08/25] socket-util: add socket_address_type_{from,to}_string() --- src/basic/socket-util.c | 11 +++++++++++ src/basic/socket-util.h | 3 +++ 2 files changed, 14 insertions(+) diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index a458fc2902..fa74465b92 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -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; diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index 272e74b0cc..0f84a5e93e 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -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); From 9c0320e7abda82f78c448c2b173d2809dac6bfb1 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 23 Dec 2017 18:47:33 +0900 Subject: [PATCH 09/25] core: implement transient socket unit --- src/core/dbus-execute.c | 115 ++++++++++ src/core/dbus-execute.h | 1 + src/core/dbus-service.c | 110 +-------- src/core/dbus-socket.c | 486 +++++++++++++++++++++++++++++++++++++++- src/core/socket.c | 2 + 5 files changed, 605 insertions(+), 109 deletions(-) diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 4b1160cab4..f0282f7750 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -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, diff --git a/src/core/dbus-execute.h b/src/core/dbus-execute.h index f30f0774cd..3654598f4b 100644 --- a/src/core/dbus-execute.h +++ b/src/core/dbus-execute.h @@ -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); diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c index 0189952124..c5eba5f4e5 100644 --- a/src/core/dbus-service.c +++ b/src/core/dbus-service.c @@ -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; } diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index 930b7fa87d..6c5d5944fc 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -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) { diff --git a/src/core/socket.c b/src/core/socket.c index 6baaa8840e..553bbe9f76 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -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, From 89ada3ba0867fb1330a470ea17ae698c81d8762e Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 23 Dec 2017 16:59:56 +0900 Subject: [PATCH 10/25] bus-unit-util: add socket unit related options Also, split bus_append_unit_property_assignment(). --- src/mount/mount-tool.c | 9 +- src/nspawn/nspawn-register.c | 4 +- src/run/run.c | 11 +- src/shared/bus-unit-util.c | 2034 ++++++++++++++++++---------------- src/shared/bus-unit-util.h | 10 +- src/systemctl/systemctl.c | 10 +- 6 files changed, 1092 insertions(+), 986 deletions(-) diff --git a/src/mount/mount-tool.c b/src/mount/mount-tool.c index f82e9dac44..131f160b50 100644 --- a/src/mount/mount-tool.c +++ b/src/mount/mount-tool.c @@ -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; diff --git a/src/nspawn/nspawn-register.c b/src/nspawn/nspawn-register.c index ef9db31df7..07d68242c6 100644 --- a/src/nspawn/nspawn-register.c +++ b/src/nspawn/nspawn-register.c @@ -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; diff --git a/src/run/run.c b/src/run/run.c index 5d7441ac93..510b6aba00 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -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" @@ -462,7 +463,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 +476,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 +522,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 +695,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 +719,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; diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 092c1768c7..805ad30c7a 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -45,6 +45,7 @@ #include "string-util.h" #include "syslog-util.h" #include "terminal-util.h" +#include "unit-def.h" #include "user-util.h" #include "utf8.h" #include "util.h" @@ -70,6 +71,292 @@ int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) { &u->job_path); } +#define DEFINE_BUS_APPEND_PARSE_PTR(bus_type, cast_type, type, parse_func) \ + static int bus_append_##parse_func(sd_bus_message *m, const char *field, const char *eq) { \ + type val; \ + int r; \ + \ + r = parse_func(eq, &val); \ + if (r < 0) \ + return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); \ + \ + r = sd_bus_message_append(m, "(sv)", field, bus_type, (cast_type) val); \ + if (r < 0) \ + return bus_log_create_error(r); \ + \ + return 1; \ + } + +#define DEFINE_BUS_APPEND_PARSE(bus_type, parse_func) \ + static int bus_append_##parse_func(sd_bus_message *m, const char *field, const char *eq) { \ + int r; \ + \ + r = parse_func(eq); \ + if (r < 0) { \ + log_error("Failed to parse %s: %s", field, eq); \ + return -EINVAL; \ + } \ + \ + r = sd_bus_message_append(m, "(sv)", field, bus_type, (int32_t) r); \ + if (r < 0) \ + return bus_log_create_error(r); \ + \ + return 1; \ + } + +DEFINE_BUS_APPEND_PARSE("b", parse_boolean) +DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string) +DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string) +DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string) +DEFINE_BUS_APPEND_PARSE("i", log_level_from_string) +DEFINE_BUS_APPEND_PARSE("i", parse_errno) +DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string) +DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string) +DEFINE_BUS_APPEND_PARSE("i", signal_from_string_try_harder) +DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority) +DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice) +DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi) +DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, nsec_t, parse_nsec) +DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_blkio_weight_parse) +DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_shares_parse) +DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse) +DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flags_from_string) +DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, usec_t, parse_sec) +DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t, parse_mode) +DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou) +DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64) + +static inline int bus_append_string(sd_bus_message *m, const char *field, const char *eq) { + int r; + + r = sd_bus_message_append(m, "(sv)", field, "s", eq); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + +static int bus_append_strv(sd_bus_message *m, const char *field, const char *eq, ExtractFlags flags) { + const char *p; + int r; + + r = sd_bus_message_open_container(m, 'r', "sv"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(m, 's', field); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'v', "as"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'a', "s"); + if (r < 0) + return bus_log_create_error(r); + + for (p = eq;;) { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&p, &word, NULL, flags); + if (r == 0) + break; + if (r == -ENOMEM) + return log_oom(); + if (r < 0) + return log_error_errno(r, "Invalid syntax: %s", eq); + + r = sd_bus_message_append_basic(m, 's', word); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + +static int bus_append_byte_array(sd_bus_message *m, const char *field, const void *buf, size_t n) { + int r; + + r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'v', "ay"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_array(m, 'y', buf, n); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + +static int bus_append_parse_sec_rename(sd_bus_message *m, const char *field, const char *eq) { + char *n; + usec_t t; + size_t l; + int r; + + r = parse_sec(eq, &t); + if (r < 0) + return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); + + l = strlen(field); + n = newa(char, l + 2); + /* Change suffix Sec → USec */ + strcpy(mempcpy(n, field, l - 3), "USec"); + + r = sd_bus_message_append(m, "(sv)", n, "t", t); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + +static int bus_append_parse_iec_size(sd_bus_message *m, const char *field, const char *eq) { + uint64_t v; + int r; + + r = parse_size(eq, 1024, &v); + if (r < 0 || (uint64_t) (size_t) v != v) + return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); + + r = sd_bus_message_append(m, "(sv)", field, "t", v); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + +static int bus_append_exec_command(sd_bus_message *m, const char *field, const char *eq) { + bool ignore_failure = false, explicit_path = false, done = false; + _cleanup_strv_free_ char **l = NULL; + _cleanup_free_ char *path = NULL; + int r; + + do { + switch (*eq) { + + case '-': + if (ignore_failure) + done = true; + else { + ignore_failure = true; + eq++; + } + break; + + case '@': + if (explicit_path) + done = true; + else { + explicit_path = true; + eq++; + } + break; + + case '+': + case '!': + /* The bus API doesn't support +, ! and !! currently, unfortunately. :-( */ + log_error("Sorry, but +, ! and !! are currently not supported for transient services."); + return -EOPNOTSUPP; + + default: + done = true; + break; + } + } while (!done); + + if (explicit_path) { + r = extract_first_word(&eq, &path, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE); + if (r < 0) + return log_error_errno(r, "Failed to parse path: %m"); + } + + r = strv_split_extract(&l, eq, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE); + if (r < 0) + return log_error_errno(r, "Failed to parse command line: %m"); + + r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'v', "a(sasb)"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'a', "(sasb)"); + if (r < 0) + return bus_log_create_error(r); + + if (!strv_isempty(l)) { + + r = sd_bus_message_open_container(m, 'r', "sasb"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append(m, "s", path ?: l[0]); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_strv(m, l); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append(m, "b", ignore_failure); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + return 1; +} + static int bus_append_ip_address_access(sd_bus_message *m, int family, const union in_addr_union *prefix, unsigned char prefixlen) { int r; @@ -95,31 +382,89 @@ static int bus_append_ip_address_access(sd_bus_message *m, int family, const uni return sd_bus_message_close_container(m); } -int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) { - const char *eq, *field; - UnitDependency dep; - int r, rl; +static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) { + int r; - assert(m); - assert(assignment); + if (STR_IN_SET(field, "DevicePolicy", "Slice")) - eq = strchr(assignment, '='); - if (!eq) { - log_error("Not an assignment: %s", assignment); - return -EINVAL; + return bus_append_string(m, field, eq); + + if (STR_IN_SET(field, + "CPUAccounting", "MemoryAccounting", "IOAccounting", "BlockIOAccounting", + "TasksAccounting", "IPAccounting")) + + return bus_append_parse_boolean(m, field, eq); + + if (STR_IN_SET(field, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight")) + + return bus_append_cg_weight_parse(m, field, eq); + + if (STR_IN_SET(field, "CPUShares", "StartupCPUShares")) + + return bus_append_cg_cpu_shares_parse(m, field, eq); + + if (STR_IN_SET(field, "BlockIOWeight", "StartupBlockIOWeight")) + + return bus_append_cg_blkio_weight_parse(m, field, eq); + + if (streq(field, "Delegate")) { + + r = parse_boolean(eq); + if (r < 0) + return bus_append_strv(m, "DelegateControllers", eq, EXTRACT_QUOTES); + + r = sd_bus_message_append(m, "(sv)", "Delegate", "b", r); + if (r < 0) + return bus_log_create_error(r); + + return 1; } - r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); - if (r < 0) - return bus_log_create_error(r); + if (STR_IN_SET(field, "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit", "TasksMax")) { + uint64_t val; - field = strndupa(assignment, eq - assignment); - eq++; + if (isempty(eq) || streq(eq, "infinity")) { + r = sd_bus_message_append(m, "(sv)", field, "t", CGROUP_LIMIT_MAX); + if (r < 0) + return bus_log_create_error(r); + return 1; + } + + r = parse_percent(eq); + if (r >= 0) { + char *n; + + /* When this is a percentage we'll convert this into a relative value in the range + * 0…UINT32_MAX and pass it in the MemoryLowScale property (and related + * ones). This way the physical memory size can be determined server-side */ + + n = strjoina(field, "Scale"); + r = sd_bus_message_append(m, "(sv)", n, "u", (uint32_t) (((uint64_t) UINT32_MAX * r) / 100U)); + if (r < 0) + return bus_log_create_error(r); + + return 1; + } + + if (streq(field, "TasksMax")) + r = safe_atou64(eq, &val); + else + r = parse_size(eq, 1024, &val); + + if (r < 0) + return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); + + r = sd_bus_message_append(m, "(sv)", field, "t", val); + if (r < 0) + return bus_log_create_error(r); + + return 1; + } if (streq(field, "CPUQuota")) { if (isempty(eq)) - r = sd_bus_message_append(m, "sv", "CPUQuotaPerSecUSec", "t", USEC_INFINITY); + r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY); else { r = parse_percent_unbounded(eq); if (r <= 0) { @@ -127,378 +472,19 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen return -EINVAL; } - r = sd_bus_message_append(m, "sv", "CPUQuotaPerSecUSec", "t", (usec_t) r * USEC_PER_SEC / 100U); + r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", (usec_t) r * USEC_PER_SEC / 100U); } - goto finish; - - } else if (streq(field, "EnvironmentFile")) { - - if (isempty(eq)) - r = sd_bus_message_append(m, "sv", "EnvironmentFiles", "a(sb)", 0); - else - r = sd_bus_message_append(m, "sv", "EnvironmentFiles", "a(sb)", 1, - eq[0] == '-' ? eq + 1 : eq, - eq[0] == '-'); - goto finish; - - } else if (STR_IN_SET(field, "AccuracySec", "RandomizedDelaySec", "RuntimeMaxSec")) { - char *n; - usec_t t; - size_t l; - - r = parse_sec(eq, &t); - if (r < 0) - return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq); - - l = strlen(field); - n = newa(char, l + 2); - - /* Change suffix Sec → USec */ - strcpy(mempcpy(n, field, l - 3), "USec"); - r = sd_bus_message_append(m, "sv", n, "t", t); - goto finish; - - } else if (streq(field, "LogExtraFields")) { - - r = sd_bus_message_append(m, "s", "LogExtraFields"); - if (r < 0) - goto finish; - - r = sd_bus_message_open_container(m, 'v', "aay"); - if (r < 0) - goto finish; - - r = sd_bus_message_open_container(m, 'a', "ay"); - if (r < 0) - goto finish; - - r = sd_bus_message_append_array(m, 'y', eq, strlen(eq)); - if (r < 0) - goto finish; - - r = sd_bus_message_close_container(m); - if (r < 0) - goto finish; - - r = sd_bus_message_close_container(m); - goto finish; - - } else if (STR_IN_SET(field, "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit")) { - uint64_t bytes; - - if (isempty(eq) || streq(eq, "infinity")) - bytes = CGROUP_LIMIT_MAX; - else { - r = parse_percent(eq); - if (r >= 0) { - char *n; - - /* When this is a percentage we'll convert this into a relative value in the range - * 0…UINT32_MAX and pass it in the MemoryLowScale property (and related - * ones). This way the physical memory size can be determined server-side */ - - n = strjoina(field, "Scale"); - r = sd_bus_message_append(m, "sv", n, "u", (uint32_t) (((uint64_t) UINT32_MAX * r) / 100U)); - goto finish; - - } else { - r = parse_size(eq, 1024, &bytes); - if (r < 0) - return log_error_errno(r, "Failed to parse bytes specification %s", assignment); - } - } - - r = sd_bus_message_append(m, "sv", field, "t", bytes); - goto finish; - - } else if (streq(field, "Delegate")) { - - r = parse_boolean(eq); - if (r < 0) { - const char *p = eq; - - r = sd_bus_message_append(m, "s", "DelegateControllers"); - if (r < 0) - goto finish; - - r = sd_bus_message_open_container(m, 'v', "as"); - if (r < 0) - goto finish; - - r = sd_bus_message_open_container(m, 'a', "s"); - if (r < 0) - goto finish; - - for (;;) { - _cleanup_free_ char *word = NULL; - - r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); - if (r == 0) - break; - if (r == -ENOMEM) - return log_oom(); - if (r < 0) - return log_error_errno(r, "Invalid syntax: %s", eq); - - r = sd_bus_message_append(m, "s", word); - if (r < 0) - goto finish; - } - - r = sd_bus_message_close_container(m); - if (r < 0) - goto finish; - - r = sd_bus_message_close_container(m); - } else - r = sd_bus_message_append(m, "sv", "Delegate", "b", r); - - goto finish; - - } else if (streq(field, "TasksMax")) { - uint64_t t; - - if (isempty(eq) || streq(eq, "infinity")) - t = (uint64_t) -1; - else { - r = parse_percent(eq); - if (r >= 0) { - r = sd_bus_message_append(m, "sv", "TasksMaxScale", "u", (uint32_t) (((uint64_t) UINT32_MAX * r) / 100U)); - goto finish; - } else { - r = safe_atou64(eq, &t); - if (r < 0) - return log_error_errno(r, "Failed to parse maximum tasks specification %s", assignment); - } - - } - - r = sd_bus_message_append(m, "sv", "TasksMax", "t", t); - goto finish; - - } else if (STR_IN_SET(field, "StandardInput", "StandardOutput", "StandardError")) { - const char *n, *appended; - - n = startswith(eq, "fd:"); - if (n) { - appended = strjoina(field, "FileDescriptorName"); - r = sd_bus_message_append(m, "sv", appended, "s", n); - - } else if ((n = startswith(eq, "file:"))) { - appended = strjoina(field, "File"); - r = sd_bus_message_append(m, "sv", appended, "s", n); - } else - r = sd_bus_message_append(m, "sv", field, "s", eq); - - goto finish; - - } else if (streq(field, "StandardInputText")) { - _cleanup_free_ char *unescaped = NULL; - - r = cunescape(eq, 0, &unescaped); - if (r < 0) - return log_error_errno(r, "Failed to unescape text '%s': %m", eq); - - if (!strextend(&unescaped, "\n", NULL)) - return log_oom(); - - /* Note that we don't expand specifiers here, but that should be OK, as this is a programmatic - * interface anyway */ - - r = sd_bus_message_append(m, "s", "StandardInputData"); if (r < 0) return bus_log_create_error(r); - r = sd_bus_message_open_container(m, 'v', "ay"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append_array(m, 'y', unescaped, strlen(unescaped)); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - goto finish; + return 1; } - r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); - if (r < 0) - return bus_log_create_error(r); - - rl = rlimit_from_string(field); - if (rl >= 0) { - const char *sn; - struct rlimit l; - - r = rlimit_parse(rl, eq, &l); - if (r < 0) - return log_error_errno(r, "Failed to parse resource limit: %s", eq); - - r = sd_bus_message_append(m, "v", "t", l.rlim_max); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); - if (r < 0) - return bus_log_create_error(r); - - sn = strjoina(field, "Soft"); - r = sd_bus_message_append(m, "sv", sn, "t", l.rlim_cur); - - } else if (STR_IN_SET(field, - "CPUAccounting", "MemoryAccounting", "IOAccounting", "BlockIOAccounting", - "TasksAccounting", "IPAccounting", "SendSIGHUP", "SendSIGKILL", "WakeSystem", - "DefaultDependencies", "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate", - "RemainAfterExit", "PrivateTmp", "PrivateDevices", "PrivateNetwork", "PrivateUsers", - "NoNewPrivileges", "SyslogLevelPrefix", "RemainAfterElapse", "Persistent", - "MemoryDenyWriteExecute", "RestrictRealtime", "DynamicUser", "RemoveIPC", - "ProtectKernelTunables", "ProtectKernelModules", "ProtectControlGroups", "MountAPIVFS", - "CPUSchedulingResetOnFork", "LockPersonality", "MakeDirectory")) { - - r = parse_boolean(eq); - if (r < 0) - return log_error_errno(r, "Failed to parse boolean assignment %s.", assignment); - - r = sd_bus_message_append(m, "v", "b", r); - - } else if (STR_IN_SET(field, "CPUWeight", "StartupCPUWeight")) { - uint64_t u; - - r = cg_weight_parse(eq, &u); - if (r < 0) - return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq); - - r = sd_bus_message_append(m, "v", "t", u); - - } else if (STR_IN_SET(field, "CPUShares", "StartupCPUShares")) { - uint64_t u; - - r = cg_cpu_shares_parse(eq, &u); - if (r < 0) - return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq); - - r = sd_bus_message_append(m, "v", "t", u); - - } else if (STR_IN_SET(field, "IOWeight", "StartupIOWeight")) { - uint64_t u; - - r = cg_weight_parse(eq, &u); - if (r < 0) - return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq); - - r = sd_bus_message_append(m, "v", "t", u); - - } else if (STR_IN_SET(field, "BlockIOWeight", "StartupBlockIOWeight")) { - uint64_t u; - - r = cg_blkio_weight_parse(eq, &u); - if (r < 0) - return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq); - - r = sd_bus_message_append(m, "v", "t", u); - - } else if (STR_IN_SET(field, - "User", "Group", "DevicePolicy", "KillMode", - "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath", - "Description", "Slice", "Type", "WorkingDirectory", - "RootDirectory", "SyslogIdentifier", "ProtectSystem", - "ProtectHome", "SELinuxContext", "Restart", "RootImage", - "NotifyAccess", "RuntimeDirectoryPreserve", "Personality", - "KeyringMode", "CollectMode", "FailureAction", "SuccessAction", - "OnCalendar")) - - r = sd_bus_message_append(m, "v", "s", eq); - - else if (streq(field, "StandardInputData")) { - _cleanup_free_ void *decoded = NULL; - size_t sz; - - r = unbase64mem(eq, (size_t) -1, &decoded, &sz); - if (r < 0) - return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq); - - r = sd_bus_message_open_container(m, 'v', "ay"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append_array(m, 'y', decoded, sz); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - - } else if (STR_IN_SET(field, "AppArmorProfile", "SmackProcessLabel")) { - bool ignore; - const char *s; - - if (eq[0] == '-') { - ignore = true; - s = eq + 1; - } else { - ignore = false; - s = eq; - } - - r = sd_bus_message_append(m, "v", "(bs)", ignore, s); - - } else if (STR_IN_SET(field, "SyslogLevel", "LogLevelMax")) { - int level; - - level = log_level_from_string(eq); - if (level < 0) { - log_error("Failed to parse %s value %s.", field, eq); - return -EINVAL; - } - - r = sd_bus_message_append(m, "v", "i", level); - - } else if (streq(field, "SyslogFacility")) { - int facility; - - facility = log_facility_unshifted_from_string(eq); - if (facility < 0) { - log_error("Failed to parse %s value %s.", field, eq); - return -EINVAL; - } - - r = sd_bus_message_append(m, "v", "i", facility); - - } else if (streq(field, "SecureBits")) { - - r = secure_bits_from_string(eq); - if (r < 0) - return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq); - - r = sd_bus_message_append(m, "v", "i", r); - - } else if (STR_IN_SET(field, "CapabilityBoundingSet", "AmbientCapabilities")) { - uint64_t sum = 0; - bool invert = false; - const char *p; - - p = eq; - if (*p == '~') { - invert = true; - p++; - } - - r = capability_set_from_string(p, &sum); - if (r < 0) - return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq); - - sum = invert ? ~sum : sum; - - r = sd_bus_message_append(m, "v", "t", sum); - - } else if (streq(field, "DeviceAllow")) { + if (streq(field, "DeviceAllow")) { if (isempty(eq)) - r = sd_bus_message_append(m, "v", "a(ss)", 0); + r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0); else { const char *path, *rwm, *e; @@ -516,13 +502,19 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen return -EINVAL; } - r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm); + r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, path, rwm); } - } else if (cgroup_io_limit_type_from_string(field) >= 0 || STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) { + if (r < 0) + return bus_log_create_error(r); + + return 1; + } + + if (cgroup_io_limit_type_from_string(field) >= 0 || STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) { if (isempty(eq)) - r = sd_bus_message_append(m, "v", "a(st)", 0); + r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0); else { const char *path, *bandwidth, *e; uint64_t bytes; @@ -549,13 +541,19 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen return log_error_errno(r, "Failed to parse byte value %s: %m", bandwidth); } - r = sd_bus_message_append(m, "v", "a(st)", 1, path, bytes); + r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, bytes); } - } else if (STR_IN_SET(field, "IODeviceWeight", "BlockIODeviceWeight")) { + if (r < 0) + return bus_log_create_error(r); + + return 1; + } + + if (STR_IN_SET(field, "IODeviceWeight", "BlockIODeviceWeight")) { if (isempty(eq)) - r = sd_bus_message_append(m, "v", "a(st)", 0); + r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0); else { const char *path, *weight, *e; uint64_t u; @@ -578,269 +576,393 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen if (r < 0) return log_error_errno(r, "Failed to parse %s value %s: %m", field, weight); - r = sd_bus_message_append(m, "v", "a(st)", 1, path, u); + r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, u); } - } else if (STR_IN_SET(field, "IPAddressAllow", "IPAddressDeny")) { + if (r < 0) + return bus_log_create_error(r); + + return 1; + } + + if (STR_IN_SET(field, "IPAddressAllow", "IPAddressDeny")) { + unsigned char prefixlen; + union in_addr_union prefix = {}; + int family; + + if (isempty(eq)) { + r = sd_bus_message_append(m, "(sv)", field, "a(iayu)", 0); + if (r < 0) + return bus_log_create_error(r); + + return 1; + } + + r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'v', "a(iayu)"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'a', "(iayu)"); + if (r < 0) + return bus_log_create_error(r); + + if (streq(eq, "any")) { + /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */ + + r = bus_append_ip_address_access(m, AF_INET, &prefix, 0); + if (r < 0) + return bus_log_create_error(r); + + r = bus_append_ip_address_access(m, AF_INET6, &prefix, 0); + if (r < 0) + return bus_log_create_error(r); + + } else if (is_localhost(eq)) { + /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */ + + prefix.in.s_addr = htobe32(0x7f000000); + r = bus_append_ip_address_access(m, AF_INET, &prefix, 8); + if (r < 0) + return bus_log_create_error(r); + + prefix.in6 = (struct in6_addr) IN6ADDR_LOOPBACK_INIT; + r = bus_append_ip_address_access(m, AF_INET6, &prefix, 128); + if (r < 0) + return r; + + } else if (streq(eq, "link-local")) { + /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */ + + prefix.in.s_addr = htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16)); + r = bus_append_ip_address_access(m, AF_INET, &prefix, 16); + if (r < 0) + return bus_log_create_error(r); + + prefix.in6 = (struct in6_addr) { + .s6_addr32[0] = htobe32(0xfe800000) + }; + r = bus_append_ip_address_access(m, AF_INET6, &prefix, 64); + if (r < 0) + return bus_log_create_error(r); + + } else if (streq(eq, "multicast")) { + /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */ + + prefix.in.s_addr = htobe32((UINT32_C(224) << 24)); + r = bus_append_ip_address_access(m, AF_INET, &prefix, 4); + if (r < 0) + return bus_log_create_error(r); + + prefix.in6 = (struct in6_addr) { + .s6_addr32[0] = htobe32(0xff000000) + }; + r = bus_append_ip_address_access(m, AF_INET6, &prefix, 8); + if (r < 0) + return bus_log_create_error(r); + + } else { + r = in_addr_prefix_from_string_auto(eq, &family, &prefix, &prefixlen); + if (r < 0) + return log_error_errno(r, "Failed to parse IP address prefix: %s", eq); + + r = bus_append_ip_address_access(m, family, &prefix, prefixlen); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + return 1; + } + + return 0; +} + +static int bus_append_execute_property(sd_bus_message *m, const char *field, const char *eq) { + int r, rl; + + if (STR_IN_SET(field, + "User", "Group", + "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath", + "WorkingDirectory", "RootDirectory", "SyslogIdentifier", + "ProtectSystem", "ProtectHome", "SELinuxContext", "RootImage", + "RuntimeDirectoryPreserve", "Personality", "KeyringMode")) + + return bus_append_string(m, field, eq); + + if (STR_IN_SET(field, + "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate", + "PrivateTmp", "PrivateDevices", "PrivateNetwork", "PrivateUsers", + "NoNewPrivileges", "SyslogLevelPrefix", + "MemoryDenyWriteExecute", "RestrictRealtime", "DynamicUser", "RemoveIPC", + "ProtectKernelTunables", "ProtectKernelModules", "ProtectControlGroups", + "MountAPIVFS", "CPUSchedulingResetOnFork", "LockPersonality")) + + return bus_append_parse_boolean(m, field, eq); + + if (STR_IN_SET(field, + "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories", + "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths", + "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory", + "SupplementaryGroups", "SystemCallArchitectures")) + + return bus_append_strv(m, field, eq, EXTRACT_QUOTES); + + if (STR_IN_SET(field, "SyslogLevel", "LogLevelMax")) + + return bus_append_log_level_from_string(m, field, eq); + + if (streq(field, "SyslogFacility")) + + return bus_append_log_facility_unshifted_from_string(m, field, eq); + + if (streq(field, "SecureBits")) + + return bus_append_secure_bits_from_string(m, field, eq); + + if (streq(field, "CPUSchedulingPolicy")) + + return bus_append_sched_policy_from_string(m, field, eq); + + if (STR_IN_SET(field, "CPUSchedulingPriority", "OOMScoreAdjust")) + + return bus_append_safe_atoi(m, field, eq); + + if (streq(field, "Nice")) + + return bus_append_parse_nice(m, field, eq); + + if (streq(field, "SystemCallErrorNumber")) + + return bus_append_parse_errno(m, field, eq); + + if (streq(field, "IOSchedulingClass")) + + return bus_append_ioprio_class_from_string(m, field, eq); + + if (streq(field, "IOSchedulingPriority")) + + return bus_append_ioprio_parse_priority(m, field, eq); + + if (STR_IN_SET(field, + "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode", + "LogsDirectoryMode", "ConfigurationDirectoryMode", "UMask")) + + return bus_append_parse_mode(m, field, eq); + + if (streq(field, "TimerSlackNSec")) + + return bus_append_parse_nsec(m, field, eq); + + if (streq(field, "MountFlags")) + + return bus_append_mount_propagation_flags_from_string(m, field, eq); + + if (STR_IN_SET(field, "Environment", "UnsetEnvironment", "PassEnvironment")) + + return bus_append_strv(m, field, eq, EXTRACT_QUOTES|EXTRACT_CUNESCAPE); + + if (streq(field, "EnvironmentFile")) { if (isempty(eq)) - r = sd_bus_message_append(m, "v", "a(iayu)", 0); - else { - unsigned char prefixlen; - union in_addr_union prefix = {}; - int family; - - r = sd_bus_message_open_container(m, 'v', "a(iayu)"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'a', "(iayu)"); - if (r < 0) - return bus_log_create_error(r); - - if (streq(eq, "any")) { - /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */ - - r = bus_append_ip_address_access(m, AF_INET, &prefix, 0); - if (r < 0) - return bus_log_create_error(r); - - r = bus_append_ip_address_access(m, AF_INET6, &prefix, 0); - if (r < 0) - return bus_log_create_error(r); - - } else if (is_localhost(eq)) { - /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */ - - prefix.in.s_addr = htobe32(0x7f000000); - r = bus_append_ip_address_access(m, AF_INET, &prefix, 8); - if (r < 0) - return bus_log_create_error(r); - - prefix.in6 = (struct in6_addr) IN6ADDR_LOOPBACK_INIT; - r = bus_append_ip_address_access(m, AF_INET6, &prefix, 128); - if (r < 0) - return r; - - } else if (streq(eq, "link-local")) { - - /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */ - - prefix.in.s_addr = htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16)); - r = bus_append_ip_address_access(m, AF_INET, &prefix, 16); - if (r < 0) - return bus_log_create_error(r); - - prefix.in6 = (struct in6_addr) { - .s6_addr32[0] = htobe32(0xfe800000) - }; - r = bus_append_ip_address_access(m, AF_INET6, &prefix, 64); - if (r < 0) - return bus_log_create_error(r); - - } else if (streq(eq, "multicast")) { - - /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */ - - prefix.in.s_addr = htobe32((UINT32_C(224) << 24)); - r = bus_append_ip_address_access(m, AF_INET, &prefix, 4); - if (r < 0) - return bus_log_create_error(r); - - prefix.in6 = (struct in6_addr) { - .s6_addr32[0] = htobe32(0xff000000) - }; - r = bus_append_ip_address_access(m, AF_INET6, &prefix, 8); - if (r < 0) - return bus_log_create_error(r); - - } else { - r = in_addr_prefix_from_string_auto(eq, &family, &prefix, &prefixlen); - if (r < 0) - return log_error_errno(r, "Failed to parse IP address prefix: %s", eq); - - r = bus_append_ip_address_access(m, family, &prefix, prefixlen); - if (r < 0) - return bus_log_create_error(r); - } - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - } - - } else if (streq(field, "CPUSchedulingPolicy")) { - int n; - - n = sched_policy_from_string(eq); - if (n < 0) - return log_error_errno(r, "Failed to parse CPUSchedulingPolicy: %s", eq); - - r = sd_bus_message_append(m, "v", "i", (int32_t) n); - - } else if (streq(field, "CPUSchedulingPriority")) { - int n; - - r = safe_atoi(eq, &n); - if (r < 0) - return log_error_errno(r, "Failed to parse CPUSchedulingPriority: %s", eq); - if (!sched_priority_is_valid(n)) - return log_error_errno(r, "Invalid CPUSchedulingPriority: %s", eq); - - r = sd_bus_message_append(m, "v", "i", (int32_t) n); - - } else if (streq(field, "CPUAffinity")) { - _cleanup_cpu_free_ cpu_set_t *cpuset = NULL; - int ncpus; - - ncpus = parse_cpu_set(eq, &cpuset); - if (ncpus < 0) - return log_error_errno(r, "Failed to parse %s value: %s", field, eq); - - r = sd_bus_message_open_container(m, 'v', "ay"); + r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 0); + else + r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 1, + eq[0] == '-' ? eq + 1 : eq, + eq[0] == '-'); if (r < 0) return bus_log_create_error(r); - r = sd_bus_message_append_array(m, 'y', cpuset, CPU_ALLOC_SIZE(ncpus)); + return 1; + } + + if (streq(field, "LogExtraFields")) { + + r = sd_bus_message_open_container(m, 'r', "sv"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(m, 's', "LogExtraFields"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'v', "aay"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'a', "ay"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_array(m, 'y', eq, strlen(eq)); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_close_container(m); - - } else if (streq(field, "Nice")) { - int n; - - r = parse_nice(eq, &n); if (r < 0) - return log_error_errno(r, "Failed to parse nice value: %s", eq); + return bus_log_create_error(r); - r = sd_bus_message_append(m, "v", "i", (int32_t) n); + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); - } else if (streq(field, "SystemCallFilter")) { - int whitelist; - _cleanup_strv_free_ char **l = NULL; - const char *p; + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); - p = eq; - if (*p == '~') { - whitelist = 0; - p++; + return 1; + } + + if (STR_IN_SET(field, "StandardInput", "StandardOutput", "StandardError")) { + const char *n, *appended; + + if ((n = startswith(eq, "fd:"))) { + appended = strjoina(field, "FileDescriptorName"); + r = sd_bus_message_append(m, "(sv)", appended, "s", n); + } else if ((n = startswith(eq, "file:"))) { + appended = strjoina(field, "File"); + r = sd_bus_message_append(m, "(sv)", appended, "s", n); } else - whitelist = 1; + r = sd_bus_message_append(m, "(sv)", field, "s", eq); - if (whitelist != 0) { - r = strv_extend(&l, "@default"); - if (r < 0) - return log_oom(); + if (r < 0) + return bus_log_create_error(r); + + return 1; + } + + if (streq(field, "StandardInputText")) { + _cleanup_free_ char *unescaped = NULL; + + r = cunescape(eq, 0, &unescaped); + if (r < 0) + return log_error_errno(r, "Failed to unescape text '%s': %m", eq); + + if (!strextend(&unescaped, "\n", NULL)) + return log_oom(); + + /* Note that we don't expand specifiers here, but that should be OK, as this is a programmatic + * interface anyway */ + + return bus_append_byte_array(m, field, unescaped, strlen(unescaped)); + } + + if (streq(field, "StandardInputData")) { + _cleanup_free_ void *decoded = NULL; + size_t sz; + + r = unbase64mem(eq, (size_t) -1, &decoded, &sz); + if (r < 0) + return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq); + + return bus_append_byte_array(m, field, decoded, sz); + } + + rl = rlimit_from_string(field); + if (rl >= 0) { + const char *sn; + struct rlimit l; + + r = rlimit_parse(rl, eq, &l); + if (r < 0) + return log_error_errno(r, "Failed to parse resource limit: %s", eq); + + r = sd_bus_message_append(m, "(sv)", field, "t", l.rlim_max); + if (r < 0) + return bus_log_create_error(r); + + sn = strjoina(field, "Soft"); + r = sd_bus_message_append(m, "(sv)", sn, "t", l.rlim_cur); + if (r < 0) + return bus_log_create_error(r); + + return 1; + } + + if (STR_IN_SET(field, "AppArmorProfile", "SmackProcessLabel")) { + int ignore = 0; + const char *s = eq; + + if (eq[0] == '-') { + ignore = 1; + s = eq + 1; } - for (;;) { - _cleanup_free_ char *word = NULL; + r = sd_bus_message_append(m, "(sv)", field, "(bs)", ignore, s); + if (r < 0) + return bus_log_create_error(r); - r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); - if (r < 0) - return log_error_errno(r, "Failed to parse %s value: %s", field, eq); - if (r == 0) - break; + return 1; + } - r = strv_extend(&l, word); - if (r < 0) - return log_oom(); + if (STR_IN_SET(field, "CapabilityBoundingSet", "AmbientCapabilities")) { + uint64_t sum = 0; + bool invert = false; + const char *p = eq; + + if (*p == '~') { + invert = true; + p++; } - r = sd_bus_message_open_container(m, 'v', "(bas)"); + r = capability_set_from_string(p, &sum); + if (r < 0) + return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq); + + sum = invert ? ~sum : sum; + + r = sd_bus_message_append(m, "(sv)", field, "t", sum); if (r < 0) return bus_log_create_error(r); - r = sd_bus_message_open_container(m, 'r', "bas"); + return 1; + } + + if (streq(field, "CPUAffinity")) { + _cleanup_cpu_free_ cpu_set_t *cpuset = NULL; + + r = parse_cpu_set(eq, &cpuset); if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append_basic(m, 'b', &whitelist); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append_strv(m, l); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - } else if (streq(field, "SystemCallArchitectures")) { - const char *p; - - r = sd_bus_message_open_container(m, 'v', "as"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'a', "s"); - if (r < 0) - return bus_log_create_error(r); - - for (p = eq;;) { - _cleanup_free_ char *word = NULL; - - r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); - if (r < 0) - return log_error_errno(r, "Failed to parse %s value: %s", field, eq); - if (r == 0) - break; - - r = sd_bus_message_append_basic(m, 's', word); - if (r < 0) - return bus_log_create_error(r); - } - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - - } else if (streq(field, "SystemCallErrorNumber")) { - int n; - - n = parse_errno(eq); - if (n <= 0) return log_error_errno(r, "Failed to parse %s value: %s", field, eq); - r = sd_bus_message_append(m, "v", "i", (int32_t) n); + return bus_append_byte_array(m, field, cpuset, CPU_ALLOC_SIZE(r)); + } - } else if (streq(field, "RestrictAddressFamilies")) { - int whitelist; - _cleanup_strv_free_ char **l = NULL; + if (STR_IN_SET(field, "RestrictAddressFamilies", "SystemCallFilter")) { + int whitelist = 1; const char *p = eq; if (*p == '~') { whitelist = 0; p++; - } else - whitelist = 1; - - for (;;) { - _cleanup_free_ char *word = NULL; - - r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); - if (r < 0) - return log_error_errno(r, "Failed to parse %s value: %s", field, eq); - if (r == 0) - break; - - r = strv_extend(&l, word); - if (r < 0) - return log_oom(); } + r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); + if (r < 0) + return bus_log_create_error(r); + r = sd_bus_message_open_container(m, 'v', "(bas)"); if (r < 0) return bus_log_create_error(r); @@ -853,179 +975,6 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen if (r < 0) return bus_log_create_error(r); - r = sd_bus_message_append_strv(m, l); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - } else if (streq(field, "FileDescriptorStoreMax")) { - unsigned u; - - r = safe_atou(eq, &u); - if (r < 0) - return log_error_errno(r, "Failed to parse file descriptor store limit: %s", eq); - - r = sd_bus_message_append(m, "v", "u", (uint32_t) u); - - } else if (streq(field, "IOSchedulingClass")) { - int c; - - c = ioprio_class_from_string(eq); - if (c < 0) - return log_error_errno(r, "Failed to parse IO scheduling class: %s", eq); - - r = sd_bus_message_append(m, "v", "i", (int32_t) c); - - } else if (streq(field, "IOSchedulingPriority")) { - int q; - - r = ioprio_parse_priority(eq, &q); - if (r < 0) - return log_error_errno(r, "Failed to parse IO scheduling priority: %s", eq); - - r = sd_bus_message_append(m, "v", "i", (int32_t) q); - - } else if (STR_IN_SET(field, "Environment", "UnsetEnvironment", "PassEnvironment")) { - const char *p; - - r = sd_bus_message_open_container(m, 'v', "as"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'a', "s"); - if (r < 0) - return bus_log_create_error(r); - - for (p = eq;;) { - _cleanup_free_ char *word = NULL; - - r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE); - if (r < 0) - return log_error_errno(r, "Failed to parse Environment value %s: %m", eq); - if (r == 0) - break; - - if (streq(field, "Environment")) { - if (!env_assignment_is_valid(word)) { - log_error("Invalid environment assignment: %s", word); - return -EINVAL; - } - } else if (streq(field, "UnsetEnvironment")) { - if (!env_assignment_is_valid(word) && !env_name_is_valid(word)) { - log_error("Invalid environment name or assignment: %s", word); - return -EINVAL; - } - } else { /* PassEnvironment */ - if (!env_name_is_valid(word)) { - log_error("Invalid environment variable name: %s", word); - return -EINVAL; - } - } - - r = sd_bus_message_append_basic(m, 's', word); - if (r < 0) - return bus_log_create_error(r); - } - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - - } else if (streq(field, "KillSignal")) { - int sig; - - sig = signal_from_string_try_harder(eq); - if (sig < 0) { - log_error("Failed to parse %s value %s.", field, eq); - return -EINVAL; - } - - r = sd_bus_message_append(m, "v", "i", sig); - - } else if (streq(field, "TimerSlackNSec")) { - nsec_t n; - - r = parse_nsec(eq, &n); - if (r < 0) - return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq); - - r = sd_bus_message_append(m, "v", "t", n); - } else if (streq(field, "OOMScoreAdjust")) { - int oa; - - r = safe_atoi(eq, &oa); - if (r < 0) - return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq); - - if (!oom_score_adjust_is_valid(oa)) { - log_error("OOM score adjust value out of range"); - return -EINVAL; - } - - r = sd_bus_message_append(m, "v", "i", oa); - - } else if (STR_IN_SET(field, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories", - "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths")) { - const char *p; - - r = sd_bus_message_open_container(m, 'v', "as"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'a', "s"); - if (r < 0) - return bus_log_create_error(r); - - for (p = eq;;) { - _cleanup_free_ char *word = NULL; - size_t offset; - - r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); - if (r < 0) - return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq); - if (r == 0) - break; - - if (!utf8_is_valid(word)) { - log_error("Failed to parse %s value %s", field, eq); - return -EINVAL; - } - - offset = word[0] == '-'; - offset += word[offset] == '+'; - - if (!path_is_absolute(word + offset)) { - log_error("Path specified by %s is not absolute: %s", field, eq); - return -EINVAL; - } - - r = sd_bus_message_append_basic(m, 's', word); - if (r < 0) - return bus_log_create_error(r); - } - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - - } else if (streq(field, "SupplementaryGroups")) { - const char *p; - - r = sd_bus_message_open_container(m, 'v', "as"); - if (r < 0) - return bus_log_create_error(r); - r = sd_bus_message_open_container(m, 'a', "s"); if (r < 0) return bus_log_create_error(r); @@ -1034,60 +983,12 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen _cleanup_free_ char *word = NULL; r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); - if (r < 0) - return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq); if (r == 0) break; - - if (!valid_user_group_name_or_id(word)) { - log_error("Invalid group name or id is specified by %s: %s", field, eq); - return -EINVAL; - } - - r = sd_bus_message_append_basic(m, 's', word); - if (r < 0) - return bus_log_create_error(r); - } - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - - } else if (STR_IN_SET(field, - "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode", - "LogsDirectoryMode", "ConfigurationDirectoryMode", "UMask", - "DirectoryMode")) { - mode_t mode; - - r = parse_mode(eq, &mode); - if (r < 0) - return log_error_errno(r, "Failed to parse %s value %s", field, eq); - - r = sd_bus_message_append(m, "v", "u", mode); - - } else if (STR_IN_SET(field, "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory")) { - const char *p; - - r = sd_bus_message_open_container(m, 'v', "as"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'a', "s"); - if (r < 0) - return bus_log_create_error(r); - - for (p = eq;;) { - _cleanup_free_ char *word = NULL; - - r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); if (r == -ENOMEM) return log_oom(); if (r < 0) - return log_error_errno(r, "Failed to parse %s value %s", field, eq); - if (r == 0) - break; + return log_error_errno(r, "Invalid syntax: %s", eq); r = sd_bus_message_append_basic(m, 's', word); if (r < 0) @@ -1099,8 +1000,21 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen return bus_log_create_error(r); r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); - } else if (streq(field, "RestrictNamespaces")) { + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + return 1; + } + + if (streq(field, "RestrictNamespaces")) { bool invert = false; unsigned long flags = 0; @@ -1123,31 +1037,31 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen if (invert) flags = (~flags) & NAMESPACE_FLAGS_ALL; - r = sd_bus_message_append(m, "v", "t", (uint64_t) flags); - - } else if ((dep = unit_dependency_from_string(field)) >= 0) - - r = sd_bus_message_append(m, "v", "as", 1, eq); - - else if (streq(field, "MountFlags")) { - unsigned long f; - - r = mount_propagation_flags_from_string(eq, &f); + r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) flags); if (r < 0) - return log_error_errno(r, "Failed to parse mount propagation flags: %s", eq); + return bus_log_create_error(r); - r = sd_bus_message_append(m, "v", "t", (uint64_t) f); + return 1; + } - } else if (STR_IN_SET(field, "BindPaths", "BindReadOnlyPaths")) { + if (STR_IN_SET(field, "BindPaths", "BindReadOnlyPaths")) { const char *p = eq; + r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); + if (r < 0) + return bus_log_create_error(r); + r = sd_bus_message_open_container(m, 'v', "a(ssbt)"); if (r < 0) - return r; + return bus_log_create_error(r); r = sd_bus_message_open_container(m, 'a', "(ssbt)"); if (r < 0) - return r; + return bus_log_create_error(r); for (;;) { _cleanup_free_ char *source = NULL, *destination = NULL; @@ -1200,148 +1114,330 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "(ssbt)", s, d, ignore_enoent, flags); if (r < 0) - return r; + return bus_log_create_error(r); } r = sd_bus_message_close_container(m); if (r < 0) - return r; - - r = sd_bus_message_close_container(m); - - } else if (STR_IN_SET(field, "ExecStartPre", "ExecStart", "ExecStartPost", - "ExecReload", "ExecStop", "ExecStopPost")) { - - bool ignore_failure = false, explicit_path = false, done = false; - _cleanup_strv_free_ char **l = NULL; - _cleanup_free_ char *path = NULL; - - do { - switch (*eq) { - - case '-': - if (ignore_failure) - done = true; - else { - ignore_failure = true; - eq++; - } - break; - - case '@': - if (explicit_path) - done = true; - else { - explicit_path = true; - eq++; - } - break; - - case '+': - case '!': - /* The bus API doesn't support +, ! and !! currently, unfortunately. :-( */ - log_error("Sorry, but +, ! and !! are currently not supported for transient services."); - return -EOPNOTSUPP; - - default: - done = true; - break; - } - } while (!done); - - if (explicit_path) { - r = extract_first_word(&eq, &path, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE); - if (r < 0) - return log_error_errno(r, "Failed to parse path: %m"); - } - - r = strv_split_extract(&l, eq, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE); - if (r < 0) - return log_error_errno(r, "Failed to parse command line: %m"); - - r = sd_bus_message_open_container(m, 'v', "a(sasb)"); - if (r < 0) - return r; - - r = sd_bus_message_open_container(m, 'a', "(sasb)"); - if (r < 0) - return r; - - if (!strv_isempty(l)) { - - r = sd_bus_message_open_container(m, 'r', "sasb"); - if (r < 0) - return r; - - r = sd_bus_message_append(m, "s", path ?: l[0]); - if (r < 0) - return r; - - r = sd_bus_message_append_strv(m, l); - if (r < 0) - return r; - - r = sd_bus_message_append(m, "b", ignore_failure); - if (r < 0) - return r; - - r = sd_bus_message_close_container(m); - if (r < 0) - return r; - } + return bus_log_create_error(r); r = sd_bus_message_close_container(m); if (r < 0) - return r; + return bus_log_create_error(r); r = sd_bus_message_close_container(m); - - } else if (STR_IN_SET(field, - "OnActiveSec", "OnBootSec", "OnStartupSec", - "OnUnitActiveSec","OnUnitInactiveSec")) { - usec_t t; - - r = parse_sec(eq, &t); if (r < 0) - return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq); + return bus_log_create_error(r); - r = sd_bus_message_append(m, "v", "t", t); - - } else if (STR_IN_SET(field, - "PathExists", "PathExistsGlob", "PathChanged", - "PathModified", "DirectoryNotEmpty")) { - - if (!path_is_absolute(eq)) { - log_error("Path specified by %s= is not absolute: %s", field, eq); - return -EINVAL; - } - - r = sd_bus_message_append(m, "v", "s", eq); - - } else { - log_error("Unknown assignment: %s", assignment); - return -EINVAL; + return 1; } -finish: - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - return 0; } -int bus_append_unit_property_assignment_many(sd_bus_message *m, char **l) { +static int bus_append_kill_property(sd_bus_message *m, const char *field, const char *eq) { + + if (streq(field, "KillMode")) + + return bus_append_string(m, field, eq); + + if (STR_IN_SET(field, "SendSIGHUP", "SendSIGKILL")) + + return bus_append_parse_boolean(m, field, eq); + + if (streq(field, "KillSignal")) + + return bus_append_signal_from_string_try_harder(m, field, eq); + + return 0; +} + +static int bus_append_path_property(sd_bus_message *m, const char *field, const char *eq) { + + if (STR_IN_SET(field, + "PathExists", "PathExistsGlob", "PathChanged", + "PathModified", "DirectoryNotEmpty")) + + return bus_append_string(m, field, eq); + + if (streq(field, "MakeDirectory")) + + return bus_append_parse_boolean(m, field, eq); + + if (streq(field, "DirectoryMode")) + + return bus_append_parse_mode(m, field, eq); + + return 0; +} + +static int bus_append_service_property(sd_bus_message *m, const char *field, const char *eq) { + + if (STR_IN_SET(field, "Type", "Restart", "NotifyAccess")) + + return bus_append_string(m, field, eq); + + if (streq(field, "RemainAfterExit")) + + return bus_append_parse_boolean(m, field, eq); + + if (streq(field, "RuntimeMaxSec")) + + return bus_append_parse_sec_rename(m, field, eq); + + if (streq(field, "FileDescriptorStoreMax")) + + return bus_append_safe_atou(m, field, eq); + + if (STR_IN_SET(field, + "ExecStartPre", "ExecStart", "ExecStartPost", + "ExecReload", "ExecStop", "ExecStopPost")) + + return bus_append_exec_command(m, field, eq); + + return 0; +} + +static int bus_append_socket_property(sd_bus_message *m, const char *field, const char *eq) { + int r; + + if (STR_IN_SET(field, + "Accept", "Writable", "KeepAlive", "NoDelay", "FreeBind", "Transparent", "Broadcast", + "PassCredentials", "PassSecurity", "ReusePort", "RemoveOnStop", "SELinuxContextFromNet")) + + return bus_append_parse_boolean(m, field, eq); + + if (STR_IN_SET(field, "Priority", "IPTTL", "Mark")) + + return bus_append_safe_atoi(m, field, eq); + + if (streq(field, "IPTOS")) + + return bus_append_ip_tos_from_string(m, field, eq); + + if (STR_IN_SET(field, "Backlog", "MaxConnections", "MaxConnectionsPerSource", "KeepAliveProbes", "TriggerLimitBurst")) + + return bus_append_safe_atou(m, field, eq); + + if (STR_IN_SET(field, "SocketMode", "DirectoryMode")) + + return bus_append_parse_mode(m, field, eq); + + if (STR_IN_SET(field, "MessageQueueMaxMessages", "MessageQueueMessageSize")) + + return bus_append_safe_atoi64(m, field, eq); + + if (STR_IN_SET(field, "TimeoutSec", "KeepAliveTimeSec", "KeepAliveIntervalSec", "DeferAcceptSec", "TriggerLimitIntervalSec")) + + return bus_append_parse_sec_rename(m, field, eq); + + if (STR_IN_SET(field, "ReceiveBuffer", "SendBuffer", "PipeSize")) + + return bus_append_parse_iec_size(m, field, eq); + + if (STR_IN_SET(field, "ExecStartPre", "ExecStartPost", "ExecReload", "ExecStopPost")) + + return bus_append_exec_command(m, field, eq); + + if (STR_IN_SET(field, + "SmackLabel", "SmackLabelIPIn", "SmackLabelIPOut", "TCPCongestion", + "BindToDevice", "BindIPv6Only", "FileDescriptorName", + "SocketUser", "SocketGroup")) + + return bus_append_string(m, field, eq); + + if (streq(field, "Symlinks")) + + return bus_append_strv(m, field, eq, EXTRACT_QUOTES); + + if (streq(field, "SocketProtocol")) { + + if (streq(eq, "udplite")) + r = sd_bus_message_append(m, "(sv)", field, "i", IPPROTO_UDPLITE); + else if (streq(eq, "sctp")) + r = sd_bus_message_append(m, "(sv)", field, "i", IPPROTO_SCTP); + else { + log_error("Unsupported Socket protocol: %s", eq); + return -EINVAL; + } + if (r < 0) + return bus_log_create_error(r); + + return 1; + } + + if (STR_IN_SET(field, + "ListenStream", "ListenDatagram", "ListenSequentialPacket", "ListenNetlink", + "ListenSpecial", "ListenMessageQueue", "ListenFIFO", "ListenUSBFunction")) { + + r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 1, field + strlen("Listen"), eq); + if (r < 0) + return bus_log_create_error(r); + + return 1; + } + + return 0; +} +static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) { + + if (streq(field, "OnCalendar")) + + return bus_append_string(m, field, eq); + + if (STR_IN_SET(field, "WakeSystem", "RemainAfterElapse", "Persistent")) + + return bus_append_parse_boolean(m, field, eq); + + if (STR_IN_SET(field, + "OnActiveSec", "OnBootSec", "OnStartupSec", + "OnUnitActiveSec","OnUnitInactiveSec")) + + return bus_append_parse_sec(m, field, eq); + + if (STR_IN_SET(field, "AccuracySec", "RandomizedDelaySec")) + + return bus_append_parse_sec_rename(m, field, eq); + + return 0; +} + +static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) { + UnitDependency dep; + int r; + + if (STR_IN_SET(field, "Description", "CollectMode", "FailureAction", "SuccessAction")) + + return bus_append_string(m, field, eq); + + if (streq(field, "DefaultDependencies")) + + return bus_append_parse_boolean(m, field, eq); + + if ((dep = unit_dependency_from_string(field)) >= 0) { + + r = sd_bus_message_append(m, "(sv)", field, "as", 1, eq); + if (r < 0) + return bus_log_create_error(r); + + return 1; + } + + return 0; +} + +int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) { + const char *eq, *field; + int r; + + assert(m); + assert(assignment); + + eq = strchr(assignment, '='); + if (!eq) { + log_error("Not an assignment: %s", assignment); + return -EINVAL; + } + + field = strndupa(assignment, eq - assignment); + eq++; + + switch (t) { + case UNIT_SERVICE: + r = bus_append_cgroup_property(m, field, eq); + if (r != 0) + return r; + + r = bus_append_execute_property(m, field, eq); + if (r != 0) + return r; + + r = bus_append_kill_property(m, field, eq); + if (r != 0) + return r; + + r = bus_append_service_property(m, field, eq); + if (r != 0) + return r; + break; + + case UNIT_SOCKET: + r = bus_append_cgroup_property(m, field, eq); + if (r != 0) + return r; + + r = bus_append_execute_property(m, field, eq); + if (r != 0) + return r; + + r = bus_append_kill_property(m, field, eq); + if (r != 0) + return r; + + r = bus_append_socket_property(m, field, eq); + if (r != 0) + return r; + break; + + case UNIT_TIMER: + r = bus_append_timer_property(m, field, eq); + if (r != 0) + return r; + break; + + case UNIT_PATH: + r = bus_append_path_property(m, field, eq); + if (r != 0) + return r; + break; + + case UNIT_SLICE: + r = bus_append_cgroup_property(m, field, eq); + if (r != 0) + return r; + break; + + case UNIT_SCOPE: + r = bus_append_cgroup_property(m, field, eq); + if (r != 0) + return r; + + r = bus_append_kill_property(m, field, eq); + if (r != 0) + return r; + break; + + case UNIT_MOUNT: + case UNIT_AUTOMOUNT: + break; + + case UNIT_TARGET: + case UNIT_DEVICE: + case UNIT_SWAP: + log_error("Not supported unit type"); + return -EINVAL; + + default: + log_error("Invalid unit type"); + return -EINVAL; + } + + r = bus_append_unit_property(m, field, eq); + if (r != 0) + return r; + + log_error("Unknown assignment: %s", assignment); + return -EINVAL; +} + +int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char **l) { char **i; int r; assert(m); STRV_FOREACH(i, l) { - r = bus_append_unit_property_assignment(m, *i); + r = bus_append_unit_property_assignment(m, t, *i); if (r < 0) return r; } diff --git a/src/shared/bus-unit-util.h b/src/shared/bus-unit-util.h index 1a137e8b84..514e6edb76 100644 --- a/src/shared/bus-unit-util.h +++ b/src/shared/bus-unit-util.h @@ -20,10 +20,10 @@ along with systemd; If not, see . ***/ -#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; diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 6d3adc5803..50a10ace77 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -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; From d59ef3e24362aa7a9e209ed07db5feca1a2cdb8e Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 18 Dec 2017 23:46:45 +0900 Subject: [PATCH 11/25] run: add support to create transient path and socket unit --- src/run/run.c | 86 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 66 insertions(+), 20 deletions(-) diff --git a/src/run/run.c b/src/run/run.c index 510b6aba00..b018d1547e 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -69,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; @@ -102,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" @@ -153,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, @@ -189,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); @@ -369,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; @@ -388,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 @@ -398,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; } @@ -418,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; } @@ -433,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; } @@ -449,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; } @@ -1283,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; @@ -1309,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; @@ -1329,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"); @@ -1340,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"); } @@ -1360,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); @@ -1369,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; @@ -1415,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; } @@ -1428,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); } @@ -1489,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; From 624dd009732dd18ca5e0d43a064958930366512f Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 19 Dec 2017 00:07:11 +0900 Subject: [PATCH 12/25] man: add explanation about transient path or socket units in systemd-run --- man/systemd-run.xml | 61 +++++++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/man/systemd-run.xml b/man/systemd-run.xml index 7bcea9bc30..4f47ef8191 100644 --- a/man/systemd-run.xml +++ b/man/systemd-run.xml @@ -47,7 +47,7 @@ systemd-run - Run programs in transient scope units, service units, or timer-scheduled service units + Run programs in transient scope units, service units, or path-, socket-, or timer-triggered service units @@ -58,6 +58,20 @@ ARGS + + systemd-run + OPTIONS + PATH OPTIONS + COMMAND + ARGS + + + systemd-run + OPTIONS + SOCKET OPTIONS + COMMAND + ARGS + systemd-run OPTIONS @@ -72,8 +86,8 @@ systemd-run may be used to create and start a transient .service or .scope unit and run the specified COMMAND in it. It may also be - used to create and start a transient .timer unit, that activates a - .service unit when elapsing. + used to create and start a transient .path, .socket, or + .timer unit, that activates a .service unit when elapsing. 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 systemctl list-units like any other unit. It @@ -88,12 +102,13 @@ list-units. Execution in this case is synchronous, and will return only when the command finishes. This mode is enabled via the switch (see below). - If a command is run with timer options such as (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 is specified, the COMMAND may be omitted. In this case, - systemd-run creates only a .timer unit that invokes the specified unit when - elapsing. + If a command is run with path, socket, or timer options such as (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 is specified, the + COMMAND may be omitted. In this case, systemd-run creates only a + .path, .socket, or .timer unit that triggers the + specified unit. @@ -140,8 +155,8 @@ - Provide a description for the service, scope or timer unit. If not specified, the command - itself will be used as a description. See Description= in + 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 Description= in systemd.unit5. @@ -278,7 +293,8 @@ command. See OnActiveSec=, OnBootSec=, OnStartupSec=, OnUnitActiveSec= and OnUnitInactiveSec= in systemd.timer5 for - details. These options may not be combined with or . + details. These options are shortcuts for --timer-property= with the relevant properties. + These options may not be combined with or . @@ -287,20 +303,23 @@ Defines a calendar timer for starting the specified command. See OnCalendar= in systemd.timer5. This - option may not be combined with or . + option is a shortcut for --timer-property=OnCalendar=. This option may not be combined with + or . + + - Sets a property on the timer unit that is created. This option is similar to - but applies to the transient timer unit rather than the transient service unit - created. This option only has an effect in conjunction with , - , , , - or . This option takes an assignment in the - same format as systemctl1's - set-property command. + Sets a property on the path, socket, or timer unit that is created. This option is similar to + 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 + systemctl1's + set-property command. These options may not be combined with + or . + @@ -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 was set) and the exit code and status of the main process. This output may be suppressed with . This option may not be combined with - , or the various timer options. + , or the various path, socket, or timer options. From 8a211c8edb3ce536ea342ec656c995d946b8bc77 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 19 Dec 2017 10:53:38 +0900 Subject: [PATCH 13/25] doc: update TRANSIENT-SETTINGS.md --- TRANSIENT-SETTINGS.md | 122 +++++++++++++++++++++--------------------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/TRANSIENT-SETTINGS.md b/TRANSIENT-SETTINGS.md index 789ffe0dcf..8e9798ba3a 100644 --- a/TRANSIENT-SETTINGS.md +++ b/TRANSIENT-SETTINGS.md @@ -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 `✓`. @@ -341,71 +341,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 From e045e325df676108a5689231259bd6ecdae72909 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 23 Dec 2017 19:32:04 +0900 Subject: [PATCH 14/25] basic: introduce socket_protocol_{from,to}_name() And use them where they can be applicable. --- src/basic/generate-socket-protocol-list.sh | 5 ++ src/basic/meson.build | 12 ++++- src/basic/socket-protocol-list.c | 57 ++++++++++++++++++++++ src/basic/socket-protocol-list.h | 26 ++++++++++ src/basic/socket-protocol-to-name.awk | 9 ++++ src/core/dbus-socket.c | 12 +++-- src/core/load-fragment.c | 14 ++++-- src/core/socket.c | 21 ++++---- src/shared/bus-unit-util.c | 18 ++----- 9 files changed, 141 insertions(+), 33 deletions(-) create mode 100755 src/basic/generate-socket-protocol-list.sh create mode 100644 src/basic/socket-protocol-list.c create mode 100644 src/basic/socket-protocol-list.h create mode 100644 src/basic/socket-protocol-to-name.awk diff --git a/src/basic/generate-socket-protocol-list.sh b/src/basic/generate-socket-protocol-list.sh new file mode 100755 index 0000000000..18a540f32b --- /dev/null +++ b/src/basic/generate-socket-protocol-list.sh @@ -0,0 +1,5 @@ +#!/bin/sh -eu + +$1 -dM -include netinet/in.h - . +***/ + +#include +#include + +#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); +} diff --git a/src/basic/socket-protocol-list.h b/src/basic/socket-protocol-list.h new file mode 100644 index 0000000000..12fd053382 --- /dev/null +++ b/src/basic/socket-protocol-list.h @@ -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 . +***/ + +const char *socket_protocol_to_name(int id); +int socket_protocol_from_name(const char *name); + +int socket_protocol_max(void); diff --git a/src/basic/socket-protocol-to-name.awk b/src/basic/socket-protocol-to-name.awk new file mode 100644 index 0000000000..4848a7631a --- /dev/null +++ b/src/basic/socket-protocol-to-name.awk @@ -0,0 +1,9 @@ +BEGIN{ + print "static const char* const socket_protocol_names[] = { " +} +!/HOPOPTS/ { + printf " [IPPROTO_%s] = \"%s\",\n", $1, tolower($1) +} +END{ + print "};" +} diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index 6c5d5944fc..26ab6b9ea5 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -28,6 +28,7 @@ #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" @@ -268,18 +269,23 @@ static int bus_socket_set_transient_property( 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; - if (!IN_SET(i, IPPROTO_UDPLITE, IPPROTO_SCTP)) + 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, i == IPPROTO_UDPLITE ? "udplite" : "sctp"); + unit_write_settingf(u, flags, name, "%s=%s", name, p); } return 1; @@ -557,7 +563,7 @@ static int bus_socket_set_transient_property( if (!p) return log_oom(); - p->type = socket_type_from_string(t); + 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); diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 469b2fc2b4..28920e4a4f 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -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" @@ -454,6 +455,7 @@ int config_parse_socket_protocol(const char *unit, void *data, void *userdata) { Socket *s; + int r; assert(filename); assert(lvalue); @@ -462,15 +464,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; } diff --git a/src/core/socket.c b/src/core/socket.c index 553bbe9f76..d45b528985 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -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" @@ -2783,16 +2784,16 @@ const char* socket_port_type_to_string(SocketPort *p) { SocketType socket_port_type_from_string(const char *s) { assert(s); - if (STR_IN_SET(t, "Stream", "Datagram", "SequentialPacket", "Netlink")) - return = SOCKET_SOCKET; - else if (streq(t, "Special")) - return = SOCKET_SPECIAL; - else if (streq(t, "MessageQueue")) - return = SOCKET_MQUEUE; - else if (streq(t, "FIFO")) - return = SOCKET_FIFO; - else if (streq(t, "USBFunction")) - return = SOCKET_USB_FUNCTION; + 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; } diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 805ad30c7a..b9224bb23c 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -42,6 +42,7 @@ #include "rlimit-util.h" #include "securebits-util.h" #include "signal-util.h" +#include "socket-protocol-list.h" #include "string-util.h" #include "syslog-util.h" #include "terminal-util.h" @@ -113,6 +114,7 @@ DEFINE_BUS_APPEND_PARSE("i", parse_errno) DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string) DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string) DEFINE_BUS_APPEND_PARSE("i", signal_from_string_try_harder) +DEFINE_BUS_APPEND_PARSE("i", socket_protocol_from_name) DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority) DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice) DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi) @@ -1250,21 +1252,9 @@ static int bus_append_socket_property(sd_bus_message *m, const char *field, cons return bus_append_strv(m, field, eq, EXTRACT_QUOTES); - if (streq(field, "SocketProtocol")) { + if (streq(field, "SocketProtocol")) - if (streq(eq, "udplite")) - r = sd_bus_message_append(m, "(sv)", field, "i", IPPROTO_UDPLITE); - else if (streq(eq, "sctp")) - r = sd_bus_message_append(m, "(sv)", field, "i", IPPROTO_SCTP); - else { - log_error("Unsupported Socket protocol: %s", eq); - return -EINVAL; - } - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + return bus_append_socket_protocol_from_name(m, field, eq); if (STR_IN_SET(field, "ListenStream", "ListenDatagram", "ListenSequentialPacket", "ListenNetlink", From b48e508db310306b9a17bf9f37c87feca7ef0d87 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 19 Dec 2017 15:30:59 +0900 Subject: [PATCH 15/25] dbus-socket: move truncation check to bus_socket_set_transient_property() --- src/core/dbus-socket.c | 3 +++ src/shared/bus-unit-util.c | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index 26ab6b9ea5..e73ae9ddfa 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -381,6 +381,9 @@ static int bus_socket_set_transient_property( 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; diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index b9224bb23c..92a7de8341 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -241,12 +241,12 @@ static int bus_append_parse_sec_rename(sd_bus_message *m, const char *field, con return 1; } -static int bus_append_parse_iec_size(sd_bus_message *m, const char *field, const char *eq) { +static int bus_append_parse_size(sd_bus_message *m, const char *field, const char *eq, uint64_t base) { uint64_t v; int r; - r = parse_size(eq, 1024, &v); - if (r < 0 || (uint64_t) (size_t) v != v) + r = parse_size(eq, base, &v); + if (r < 0) return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); r = sd_bus_message_append(m, "(sv)", field, "t", v); @@ -1235,7 +1235,7 @@ static int bus_append_socket_property(sd_bus_message *m, const char *field, cons if (STR_IN_SET(field, "ReceiveBuffer", "SendBuffer", "PipeSize")) - return bus_append_parse_iec_size(m, field, eq); + return bus_append_parse_size(m, field, eq, 1024); if (STR_IN_SET(field, "ExecStartPre", "ExecStartPost", "ExecReload", "ExecStopPost")) From eae194a51b2b4d2cea4d4f0897063b45f6787688 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 19 Dec 2017 15:32:11 +0900 Subject: [PATCH 16/25] bus-unit-util: make dependency settings can take multiple units This allows people to specify multiple units in dependency settings e.g. `Requires=foo.service baz.service`. --- src/shared/bus-unit-util.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 92a7de8341..b9f8f69bf3 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1293,8 +1293,6 @@ static int bus_append_timer_property(sd_bus_message *m, const char *field, const } static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) { - UnitDependency dep; - int r; if (STR_IN_SET(field, "Description", "CollectMode", "FailureAction", "SuccessAction")) @@ -1304,14 +1302,9 @@ static int bus_append_unit_property(sd_bus_message *m, const char *field, const return bus_append_parse_boolean(m, field, eq); - if ((dep = unit_dependency_from_string(field)) >= 0) { + if (unit_dependency_from_string(field) >= 0) - r = sd_bus_message_append(m, "(sv)", field, "as", 1, eq); - if (r < 0) - return bus_log_create_error(r); - - return 1; - } + return bus_append_strv(m, field, eq, EXTRACT_QUOTES); return 0; } From 62b749a9810d0484e05603ba905aeb77a3f5e1ea Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 19 Dec 2017 15:33:20 +0900 Subject: [PATCH 17/25] bus-unit-util: simplify bus_append_cgroup_property() --- src/shared/bus-unit-util.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index b9f8f69bf3..b406bdd11b 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -124,6 +124,7 @@ DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_shares_parse) DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse) DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flags_from_string) DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, usec_t, parse_sec) +DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64) DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t, parse_mode) DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou) DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64) @@ -423,7 +424,6 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons } if (STR_IN_SET(field, "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit", "TasksMax")) { - uint64_t val; if (isempty(eq) || streq(eq, "infinity")) { r = sd_bus_message_append(m, "(sv)", field, "t", CGROUP_LIMIT_MAX); @@ -449,18 +449,10 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons } if (streq(field, "TasksMax")) - r = safe_atou64(eq, &val); - else - r = parse_size(eq, 1024, &val); + return bus_append_safe_atou64(m, field, eq); - if (r < 0) - return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); + return bus_append_parse_size(m, field, eq, 1024); - r = sd_bus_message_append(m, "(sv)", field, "t", val); - if (r < 0) - return bus_log_create_error(r); - - return 1; } if (streq(field, "CPUQuota")) { From d9f7305fd73718f7e33de96b18efc639cb13b0bf Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 19 Dec 2017 15:34:04 +0900 Subject: [PATCH 18/25] cgroup: move path checking logic to dbus-cgroup.c --- src/core/dbus-cgroup.c | 18 ++++++++++++++---- src/shared/bus-unit-util.c | 34 ++++++++-------------------------- 2 files changed, 22 insertions(+), 30 deletions(-) diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index abca4e112d..70dca6cf1b 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -630,6 +630,9 @@ int bus_cgroup_set_property( while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) { + if (!path_startswith(path, "/dev")) + 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 +717,9 @@ int bus_cgroup_set_property( while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) { + if (!path_startswith(path, "/dev")) + 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"); @@ -855,6 +861,9 @@ int bus_cgroup_set_property( while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) { + if (!path_startswith(path, "/dev")) + 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 +960,9 @@ int bus_cgroup_set_property( while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) { + if (!path_startswith(path, "/dev")) + 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"); @@ -1170,10 +1182,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"); diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index b406bdd11b..6940f35482 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -480,23 +480,15 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons if (isempty(eq)) r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0); else { - const char *path, *rwm, *e; + const char *path = eq, *rwm = NULL, *e; e = strchr(eq, ' '); if (e) { path = strndupa(eq, e - eq); rwm = e+1; - } else { - path = eq; - rwm = ""; } - if (!is_deviceallow_pattern(path)) { - log_error("%s is not a device file in /dev.", path); - return -EINVAL; - } - - r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, path, rwm); + r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, path, strempty(rwm)); } if (r < 0) @@ -514,18 +506,13 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons uint64_t bytes; e = strchr(eq, ' '); - if (e) { - path = strndupa(eq, e - eq); - bandwidth = e+1; - } else { + if (!e) { log_error("Failed to parse %s value %s.", field, eq); return -EINVAL; } - if (!path_startswith(path, "/dev")) { - log_error("%s is not a device file in /dev.", path); - return -EINVAL; - } + path = strndupa(eq, e - eq); + bandwidth = e+1; if (streq(bandwidth, "infinity")) { bytes = CGROUP_LIMIT_MAX; @@ -553,18 +540,13 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons uint64_t u; e = strchr(eq, ' '); - if (e) { - path = strndupa(eq, e - eq); - weight = e+1; - } else { + if (!e) { log_error("Failed to parse %s value %s.", field, eq); return -EINVAL; } - if (!path_startswith(path, "/dev")) { - log_error("%s is not a device file in /dev.", path); - return -EINVAL; - } + path = strndupa(eq, e - eq); + weight = e+1; r = safe_atou64(weight, &u); if (r < 0) From f50ab33faf726ec18d803441da3c1d96457b731a Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 19 Dec 2017 15:36:36 +0900 Subject: [PATCH 19/25] doc: add {Condition,Assert}ControlGroupController= to TRANSIENT-SETTINGS.md Follow-up for e16647c39d195804711a006667d5bce49c0ef73d. --- TRANSIENT-SETTINGS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/TRANSIENT-SETTINGS.md b/TRANSIENT-SETTINGS.md index 8e9798ba3a..cbdf83f24c 100644 --- a/TRANSIENT-SETTINGS.md +++ b/TRANSIENT-SETTINGS.md @@ -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= ``` From d6ff82d37cae5910a0c62bf830e3cfa70df1e23f Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 19 Dec 2017 16:49:37 +0900 Subject: [PATCH 20/25] dbus-execute: use empty_to_null() where it can be applicable --- src/core/dbus-execute.c | 86 ++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 52 deletions(-) diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index f0282f7750..55e8349fc5 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -1169,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); @@ -1177,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; @@ -1254,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); } @@ -1823,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; @@ -1857,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)) { @@ -1865,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; @@ -1946,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; @@ -1962,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; @@ -1972,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; @@ -1990,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; @@ -2006,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; @@ -2016,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; @@ -2635,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)); } From 13ec20d42a7b7abfbcbca5c6f1ec487fd3e3def8 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 19 Dec 2017 18:14:39 +0900 Subject: [PATCH 21/25] dbus-cgroup: merge several blocks which operate almost same tasks --- src/core/dbus-cgroup.c | 208 ++++++++++------------------------------- 1 file changed, 47 insertions(+), 161 deletions(-) diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index 70dca6cf1b..30e8f16efd 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -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; @@ -802,7 +748,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); @@ -810,38 +756,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; @@ -1046,7 +974,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); @@ -1062,8 +990,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); @@ -1075,7 +1005,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; @@ -1098,10 +1028,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, @@ -1110,48 +1042,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; @@ -1460,12 +1350,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; } From 827d9bf29795de615410122e195e7d56ff809fe6 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 23 Dec 2017 18:53:36 +0900 Subject: [PATCH 22/25] core/socket: dump more settings --- src/core/socket.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/core/socket.c b/src/core/socket.c index d45b528985..eb1c0bfa32 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -656,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); @@ -681,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), @@ -716,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, @@ -844,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); From 845001221d6bf2e4aff3a923376e845b8dcca9ec Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 19 Dec 2017 20:12:01 +0900 Subject: [PATCH 23/25] core/socket: shorten socket_fdname() --- src/core/socket.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/core/socket.c b/src/core/socket.c index eb1c0bfa32..d2c469433d 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -3250,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) { From 32048f5414d70192c85dda6133e02c4ad1a1c56c Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 23 Dec 2017 19:10:24 +0900 Subject: [PATCH 24/25] cgroup: IODeviceWeight= or friends can take device node files in /run/systemd/inaccessible/ systemd creates several device nodes in /run/systemd/inaccessible/. This makes CGroup's settings related to IO can take device node files in the directory. --- src/core/dbus-cgroup.c | 12 ++++++++---- src/core/load-fragment.c | 15 ++++++++++----- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index 30e8f16efd..755b66ef8f 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -576,7 +576,8 @@ int bus_cgroup_set_property( while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) { - if (!path_startswith(path, "/dev")) + 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)) { @@ -663,7 +664,8 @@ int bus_cgroup_set_property( while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) { - if (!path_startswith(path, "/dev")) + 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) @@ -789,7 +791,8 @@ int bus_cgroup_set_property( while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) { - if (!path_startswith(path, "/dev")) + 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)) { @@ -888,7 +891,8 @@ int bus_cgroup_set_property( while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) { - if (!path_startswith(path, "/dev")) + 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) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 28920e4a4f..e1e8333c8d 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -3525,7 +3525,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; } @@ -3625,7 +3626,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; } @@ -3698,7 +3700,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; } @@ -3812,7 +3815,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; } @@ -3886,7 +3890,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; } From 533f8a677113b8532bcda422f881709f083db897 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 23 Dec 2017 19:16:49 +0900 Subject: [PATCH 25/25] load-fragment: simplify list insertion logic LIST_FIND_TAIL and LIST_INSERT_AFTER can work for empty list. --- src/core/load-fragment.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index e1e8333c8d..f9c2acc53a 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -434,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;