diff options
-rw-r--r-- | meta-agl/recipes-core/systemd/systemd/backport-v234-e266c06.patch | 315 | ||||
-rw-r--r-- | meta-agl/recipes-core/systemd/systemd_%.bbappend | 3 |
2 files changed, 317 insertions, 1 deletions
diff --git a/meta-agl/recipes-core/systemd/systemd/backport-v234-e266c06.patch b/meta-agl/recipes-core/systemd/systemd/backport-v234-e266c06.patch new file mode 100644 index 000000000..1f4a23ea7 --- /dev/null +++ b/meta-agl/recipes-core/systemd/systemd/backport-v234-e266c06.patch @@ -0,0 +1,315 @@ +commit e266c068b5597e18b2299f9c9d3ee6cf04198c41 +Author: Michal Sekletar <msekleta@redhat.com> +Date: Mon Jan 23 17:12:35 2017 +0100 + + service: serialize information about currently executing command + + Stored information will help us to resume execution after the + daemon-reload. + + This commit implements following scheme, + + * On serialization: + - we count rank of the currently executing command + - we store command type, its rank and command line arguments + + * On deserialization: + - configuration is parsed and loaded + - we deserialize stored data, command type, rank and arguments + - we look at the given rank in the list and if command there has same + arguments then we restore execution at that point + - otherwise we search respective command list and we look for command + that has the same arguments + - if both methods fail we do not do not resume execution at all + + To better illustrate how does above scheme works, please consider + following cases (<<< denotes position where we resume execution after reload) + + ; Original unit file + [Service] + ExecStart=/bin/true <<< + ExecStart=/bin/false + + ; Swapped commands + ; Second command is not going to be executed + [Service] + ExecStart=/bin/false + ExecStart=/bin/true <<< + + ; Commands added before + ; Same commands are problematic and execution could be restarted at wrong place + [Service] + ExecStart=/bin/foo + ExecStart=/bin/bar + ExecStart=/bin/true <<< + ExecStart=/bin/false + + ; Commands added after + ; Same commands are not an issue in this case + [Service] + ExecStart=/bin/true <<< + ExecStart=/bin/false + ExecStart=/bin/foo + ExecStart=/bin/bar + + ; New commands interleaved with old commands + ; Some new commands will be executed while others won't + ExecStart=/bin/foo + ExecStart=/bin/true <<< + ExecStart=/bin/bar + ExecStart=/bin/false + + As you can see, above scheme has some drawbacks. However, in most + cases (we assume that in most common case unit file command list is not + changed while some other command is running for the same unit) it + should cause that systemd does the right thing, which is restoring + execution exactly at the point we were before daemon-reload. + + Fixes #518 + +Signed-off-by: Scott Murray <scott.murray@konsulko.com> + +Upstream-Status: backport + +diff --git a/src/core/service.c b/src/core/service.c +index 74054887b..5e681fb71 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -45,6 +45,7 @@ + #include "service.h" + #include "signal-util.h" + #include "special.h" ++#include "stdio-util.h" + #include "string-table.h" + #include "string-util.h" + #include "strv.h" +@@ -2140,6 +2141,80 @@ _pure_ static bool service_can_reload(Unit *u) { + return !!s->exec_command[SERVICE_EXEC_RELOAD]; + } + ++static unsigned service_exec_command_index(Unit *u, ServiceExecCommand id, ExecCommand *current) { ++ Service *s = SERVICE(u); ++ unsigned idx = 0; ++ ExecCommand *first, *c; ++ ++ assert(s); ++ ++ first = s->exec_command[id]; ++ ++ /* Figure out where we are in the list by walking back to the beginning */ ++ for (c = current; c != first; c = c->command_prev) ++ idx++; ++ ++ return idx; ++} ++ ++static int service_serialize_exec_command(Unit *u, FILE *f, ExecCommand *command) { ++ Service *s = SERVICE(u); ++ ServiceExecCommand id; ++ unsigned idx; ++ const char *type; ++ char **arg; ++ _cleanup_strv_free_ char **escaped_args = NULL; ++ _cleanup_free_ char *args = NULL, *p = NULL; ++ size_t allocated = 0, length = 0; ++ ++ assert(s); ++ assert(f); ++ ++ if (!command) ++ return 0; ++ ++ if (command == s->control_command) { ++ type = "control"; ++ id = s->control_command_id; ++ } else { ++ type = "main"; ++ id = SERVICE_EXEC_START; ++ } ++ ++ idx = service_exec_command_index(u, id, command); ++ ++ STRV_FOREACH(arg, command->argv) { ++ size_t n; ++ _cleanup_free_ char *e = NULL; ++ ++ e = xescape(*arg, WHITESPACE); ++ if (!e) ++ return -ENOMEM; ++ ++ n = strlen(e); ++ if (!GREEDY_REALLOC(args, allocated, length + 1 + n + 1)) ++ return -ENOMEM; ++ ++ if (length > 0) ++ args[length++] = ' '; ++ ++ memcpy(args + length, e, n); ++ length += n; ++ } ++ ++ if (!GREEDY_REALLOC(args, allocated, length + 1)) ++ return -ENOMEM; ++ args[length++] = 0; ++ ++ p = xescape(command->path, WHITESPACE); ++ if (!p) ++ return -ENOMEM; ++ ++ fprintf(f, "%s-command=%s %u %s %s\n", type, service_exec_command_to_string(id), idx, p, args); ++ ++ return 0; ++} ++ + static int service_serialize(Unit *u, FILE *f, FDSet *fds) { + Service *s = SERVICE(u); + ServiceFDStore *fs; +@@ -2167,11 +2242,8 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) { + if (r < 0) + return r; + +- /* FIXME: There's a minor uncleanliness here: if there are +- * multiple commands attached here, we will start from the +- * first one again */ +- if (s->control_command_id >= 0) +- unit_serialize_item(u, f, "control-command", service_exec_command_to_string(s->control_command_id)); ++ service_serialize_exec_command(u, f, s->control_command); ++ service_serialize_exec_command(u, f, s->main_command); + + r = unit_serialize_item_fd(u, f, fds, "stdin-fd", s->stdin_fd); + if (r < 0) +@@ -2227,6 +2299,106 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) { + return 0; + } + ++static int service_deserialize_exec_command(Unit *u, const char *key, const char *value) { ++ Service *s = SERVICE(u); ++ int r; ++ unsigned idx = 0, i; ++ bool control, found = false; ++ ServiceExecCommand id = _SERVICE_EXEC_COMMAND_INVALID; ++ ExecCommand *command = NULL; ++ _cleanup_free_ char *args = NULL, *path = NULL; ++ _cleanup_strv_free_ char **argv = NULL; ++ ++ enum ExecCommandState { ++ STATE_EXEC_COMMAND_TYPE, ++ STATE_EXEC_COMMAND_INDEX, ++ STATE_EXEC_COMMAND_PATH, ++ STATE_EXEC_COMMAND_ARGS, ++ _STATE_EXEC_COMMAND_MAX, ++ _STATE_EXEC_COMMAND_INVALID = -1, ++ } state; ++ ++ assert(s); ++ assert(key); ++ assert(value); ++ ++ control = streq(key, "control-command"); ++ ++ state = STATE_EXEC_COMMAND_TYPE; ++ ++ for (;;) { ++ _cleanup_free_ char *arg = NULL; ++ ++ r = extract_first_word(&value, &arg, NULL, EXTRACT_CUNESCAPE); ++ if (r == 0) ++ break; ++ else if (r < 0) ++ return r; ++ ++ switch (state) { ++ case STATE_EXEC_COMMAND_TYPE: ++ id = service_exec_command_from_string(arg); ++ if (id < 0) ++ return -EINVAL; ++ ++ state = STATE_EXEC_COMMAND_INDEX; ++ break; ++ case STATE_EXEC_COMMAND_INDEX: ++ r = safe_atou(arg, &idx); ++ if (r < 0) ++ return -EINVAL; ++ ++ state = STATE_EXEC_COMMAND_PATH; ++ break; ++ case STATE_EXEC_COMMAND_PATH: ++ path = arg; ++ arg = NULL; ++ state = STATE_EXEC_COMMAND_ARGS; ++ ++ if (!path_is_absolute(path)) ++ return -EINVAL; ++ break; ++ case STATE_EXEC_COMMAND_ARGS: ++ r = strv_extend(&argv, arg); ++ if (r < 0) ++ return -ENOMEM; ++ break; ++ default: ++ assert_not_reached("Unknown error at deserialization of exec command"); ++ break; ++ } ++ } ++ ++ if (state != STATE_EXEC_COMMAND_ARGS) ++ return -EINVAL; ++ ++ /* Let's check whether exec command on given offset matches data that we just deserialized */ ++ for (command = s->exec_command[id], i = 0; command; command = command->command_next, i++) { ++ if (i != idx) ++ continue; ++ ++ found = strv_equal(argv, command->argv) && streq(command->path, path); ++ break; ++ } ++ ++ if (!found) { ++ /* Command at the index we serialized is different, let's look for command that exactly ++ * matches but is on different index. If there is no such command we will not resume execution. */ ++ for (command = s->exec_command[id]; command; command = command->command_next) ++ if (strv_equal(command->argv, argv) && streq(command->path, path)) ++ break; ++ } ++ ++ if (command && control) ++ s->control_command = command; ++ else if (command) ++ s->main_command = command; ++ else ++ log_unit_warning(u, "Current command vanished from the unit file, execution of the command list won't be resumed."); ++ ++ return 0; ++} ++ + static int service_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { + Service *s = SERVICE(u); + int r; +@@ -2309,16 +2481,6 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, + s->status_text = t; + } + +- } else if (streq(key, "control-command")) { +- ServiceExecCommand id; +- +- id = service_exec_command_from_string(value); +- if (id < 0) +- log_unit_debug(u, "Failed to parse exec-command value: %s", value); +- else { +- s->control_command_id = id; +- s->control_command = s->exec_command[id]; +- } + } else if (streq(key, "accept-socket")) { + Unit *socket; + +@@ -2437,6 +2599,10 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, + s->watchdog_override_enable = true; + s->watchdog_override_usec = watchdog_override_usec; + } ++ } else if (STR_IN_SET(key, "main-command", "control-command")) { ++ r = service_deserialize_exec_command(u, key, value); ++ if (r < 0) ++ log_unit_debug_errno(u, r, "Failed to parse serialized command \"%s\": %m", value); + } else + log_unit_debug(u, "Unknown serialization key: %s", key); + diff --git a/meta-agl/recipes-core/systemd/systemd_%.bbappend b/meta-agl/recipes-core/systemd/systemd_%.bbappend index 487892d50..354464c12 100644 --- a/meta-agl/recipes-core/systemd/systemd_%.bbappend +++ b/meta-agl/recipes-core/systemd/systemd_%.bbappend @@ -1,6 +1,7 @@ FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" -SRC_URI += "file://e2fsck.conf \ +SRC_URI += "file://backport-v234-e266c06.patch \ + file://e2fsck.conf \ ${@bb.utils.contains('VIRTUAL-RUNTIME_net_manager','systemd','file://wired.network','',d)} \ " |