From af2a7ac568af7b8ecf1002023dd9d07135c3c9c2 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 25 Apr 2024 04:54:54 +0200 Subject: Merging upstream version 255.5. Signed-off-by: Daniel Baumann --- src/core/bpf-socket-bind.c | 9 +++ src/core/bpf/socket_bind/socket-bind-api.bpf.h | 7 +- src/core/bpf/socket_bind/socket-bind.bpf.c | 3 + src/core/dynamic-user.c | 4 +- src/core/exec-invoke.c | 4 +- src/core/main.c | 2 +- src/core/manager-serialize.c | 3 + src/core/mount.c | 89 +++++++++++++++----------- src/core/scope.c | 2 + src/core/service.c | 18 ++++-- src/core/show-status.c | 15 +++-- src/core/socket.c | 5 +- src/core/swap.c | 4 +- 13 files changed, 109 insertions(+), 56 deletions(-) (limited to 'src/core') diff --git a/src/core/bpf-socket-bind.c b/src/core/bpf-socket-bind.c index 9f290ab..88ab487 100644 --- a/src/core/bpf-socket-bind.c +++ b/src/core/bpf-socket-bind.c @@ -32,6 +32,15 @@ static int update_rules_map( assert(map_fd >= 0); + if (!head) { + static const struct socket_bind_rule val = { + .address_family = SOCKET_BIND_RULE_AF_MATCH_NOTHING, + }; + + if (sym_bpf_map_update_elem(map_fd, &i, &val, BPF_ANY) != 0) + return -errno; + } + LIST_FOREACH(socket_bind_items, item, head) { struct socket_bind_rule val = { .address_family = (uint32_t) item->address_family, diff --git a/src/core/bpf/socket_bind/socket-bind-api.bpf.h b/src/core/bpf/socket_bind/socket-bind-api.bpf.h index 277b9bb..4fe08f1 100644 --- a/src/core/bpf/socket_bind/socket-bind-api.bpf.h +++ b/src/core/bpf/socket_bind/socket-bind-api.bpf.h @@ -7,13 +7,17 @@ */ #include +#include /* * Bind rule is matched with socket fields accessible to cgroup/bind{4,6} hook * through bpf_sock_addr struct. - * 'address_family' is expected to be one of AF_UNSPEC, AF_INET or AF_INET6. + * 'address_family' is expected to be one of AF_UNSPEC, AF_INET, AF_INET6 or the + * magic SOCKET_BIND_RULE_AF_MATCH_NOTHING. * Matching by family is bypassed for rules with AF_UNSPEC set, which makes the * rest of a rule applicable for both IPv4 and IPv6 addresses. + * If SOCKET_BIND_RULE_AF_MATCH_NOTHING is set the rule fails unconditionally + * and other checks are skipped. * If matching by family is either successful or bypassed, a rule and a socket * are matched by ip protocol. * If 'protocol' is 0, matching is bypassed. @@ -49,3 +53,4 @@ struct socket_bind_rule { }; #define SOCKET_BIND_MAX_RULES 128 +#define SOCKET_BIND_RULE_AF_MATCH_NOTHING UINT32_MAX diff --git a/src/core/bpf/socket_bind/socket-bind.bpf.c b/src/core/bpf/socket_bind/socket-bind.bpf.c index b7972a8..da9f9d1 100644 --- a/src/core/bpf/socket_bind/socket-bind.bpf.c +++ b/src/core/bpf/socket_bind/socket-bind.bpf.c @@ -55,6 +55,9 @@ static __always_inline bool match( __u32 protocol, __u16 port, const struct socket_bind_rule *r) { + if (r->address_family == SOCKET_BIND_RULE_AF_MATCH_NOTHING) + return false; + return match_af(address_family, r) && match_protocol(protocol, r) && match_user_port(port, r); diff --git a/src/core/dynamic-user.c b/src/core/dynamic-user.c index 12724c6..2bf9094 100644 --- a/src/core/dynamic-user.c +++ b/src/core/dynamic-user.c @@ -337,8 +337,10 @@ static int dynamic_user_pop(DynamicUser *d, uid_t *ret_uid, int *ret_lock_fd) { * the lock on the socket taken. */ k = receive_one_fd_iov(d->storage_socket[0], &iov, 1, MSG_DONTWAIT, &lock_fd); - if (k < 0) + if (k < 0) { + assert(errno_is_valid(-k)); return (int) k; + } *ret_uid = uid; *ret_lock_fd = lock_fd; diff --git a/src/core/exec-invoke.c b/src/core/exec-invoke.c index 28d6142..8e6de15 100644 --- a/src/core/exec-invoke.c +++ b/src/core/exec-invoke.c @@ -3459,7 +3459,7 @@ static int close_remaining_fds( const int *fds, size_t n_fds) { size_t n_dont_close = 0; - int dont_close[n_fds + 14]; + int dont_close[n_fds + 15]; assert(params); @@ -3495,6 +3495,8 @@ static int close_remaining_fds( if (params->user_lookup_fd >= 0) dont_close[n_dont_close++] = params->user_lookup_fd; + assert(n_dont_close <= ELEMENTSOF(dont_close)); + return close_all_fds(dont_close, n_dont_close); } diff --git a/src/core/main.c b/src/core/main.c index 3f71cc0..1ed968d 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -627,7 +627,7 @@ static int parse_config_file(void) { { "Manager", "CPUAffinity", config_parse_cpu_affinity2, 0, &arg_cpu_affinity }, { "Manager", "NUMAPolicy", config_parse_numa_policy, 0, &arg_numa_policy.type }, { "Manager", "NUMAMask", config_parse_numa_mask, 0, &arg_numa_policy }, - { "Manager", "JoinControllers", config_parse_warn_compat, DISABLED_CONFIGURATION, NULL }, + { "Manager", "JoinControllers", config_parse_warn_compat, DISABLED_LEGACY, NULL }, { "Manager", "RuntimeWatchdogSec", config_parse_watchdog_sec, 0, &arg_runtime_watchdog }, { "Manager", "RuntimeWatchdogPreSec", config_parse_watchdog_sec, 0, &arg_pretimeout_watchdog }, { "Manager", "RebootWatchdogSec", config_parse_watchdog_sec, 0, &arg_reboot_watchdog }, diff --git a/src/core/manager-serialize.c b/src/core/manager-serialize.c index e9d567a..1ac2636 100644 --- a/src/core/manager-serialize.c +++ b/src/core/manager-serialize.c @@ -153,6 +153,7 @@ int manager_serialize( } (void) serialize_ratelimit(f, "dump-ratelimit", &m->dump_ratelimit); + (void) serialize_ratelimit(f, "reload-ratelimit", &m->reload_ratelimit); bus_track_serialize(m->subscribed, f, "subscribed"); @@ -515,6 +516,8 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { (void) varlink_server_deserialize_one(m->varlink_server, val, fds); } else if ((val = startswith(l, "dump-ratelimit="))) deserialize_ratelimit(&m->dump_ratelimit, "dump-ratelimit", val); + else if ((val = startswith(l, "reload-ratelimit="))) + deserialize_ratelimit(&m->reload_ratelimit, "reload-ratelimit", val); else { ManagerTimestamp q; diff --git a/src/core/mount.c b/src/core/mount.c index ded322d..3c4971c 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -55,7 +55,7 @@ static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = { static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata); static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata); -static void mount_enter_dead(Mount *m, MountResult f); +static void mount_enter_dead(Mount *m, MountResult f, bool flush_result); static void mount_enter_mounted(Mount *m, MountResult f); static void mount_cycle_clear(Mount *m); static int mount_process_proc_self_mountinfo(Manager *m); @@ -846,7 +846,7 @@ static void mount_catchup(Unit *u) { break; case MOUNT_MOUNTED: assert(!pidref_is_set(&m->control_pid)); - mount_enter_dead(m, MOUNT_SUCCESS); + mount_enter_dead(m, MOUNT_SUCCESS, /* flush_result = */ false); break; default: break; @@ -952,10 +952,10 @@ static int mount_spawn(Mount *m, ExecCommand *c, PidRef *ret_pid) { return 0; } -static void mount_enter_dead(Mount *m, MountResult f) { +static void mount_enter_dead(Mount *m, MountResult f, bool flush_result) { assert(m); - if (m->result == MOUNT_SUCCESS) + if (m->result == MOUNT_SUCCESS || flush_result) m->result = f; unit_log_result(UNIT(m), m->result == MOUNT_SUCCESS, mount_result_to_string(m->result)); @@ -983,17 +983,20 @@ static void mount_enter_mounted(Mount *m, MountResult f) { mount_set_state(m, MOUNT_MOUNTED); } -static void mount_enter_dead_or_mounted(Mount *m, MountResult f) { +static void mount_enter_dead_or_mounted(Mount *m, MountResult f, bool flush_result) { assert(m); - /* Enter DEAD or MOUNTED state, depending on what the kernel currently says about the mount point. We use this - * whenever we executed an operation, so that our internal state reflects what the kernel says again, after all - * ultimately we just mirror the kernel's internal state on this. */ + /* Enter DEAD or MOUNTED state, depending on what the kernel currently says about the mount point. + * We use this whenever we executed an operation, so that our internal state reflects what + * the kernel says again, after all ultimately we just mirror the kernel's internal state on this. + * + * Note that flush_result only applies to mount_enter_dead(), since that's when the result gets + * turned into unit end state. */ if (m->from_proc_self_mountinfo) mount_enter_mounted(m, f); else - mount_enter_dead(m, f); + mount_enter_dead(m, f, flush_result); } static int state_to_kill_operation(MountState state) { @@ -1049,12 +1052,12 @@ static void mount_enter_signal(Mount *m, MountState state, MountResult f) { else if (state == MOUNT_UNMOUNTING_SIGTERM && m->kill_context.send_sigkill) mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, MOUNT_SUCCESS); else - mount_enter_dead_or_mounted(m, MOUNT_SUCCESS); + mount_enter_dead_or_mounted(m, MOUNT_SUCCESS, /* flush_result = */ false); return; fail: - mount_enter_dead_or_mounted(m, MOUNT_FAILURE_RESOURCES); + mount_enter_dead_or_mounted(m, MOUNT_FAILURE_RESOURCES, /* flush_result = */ false); } static int mount_set_umount_command(Mount *m, ExecCommand *c) { @@ -1116,7 +1119,7 @@ static void mount_enter_unmounting(Mount *m) { return; fail: - mount_enter_dead_or_mounted(m, MOUNT_FAILURE_RESOURCES); + mount_enter_dead_or_mounted(m, MOUNT_FAILURE_RESOURCES, /* flush_result = */ false); } static int mount_set_mount_command(Mount *m, ExecCommand *c, const MountParameters *p) { @@ -1232,7 +1235,7 @@ static void mount_enter_mounting(Mount *m) { return; fail: - mount_enter_dead_or_mounted(m, MOUNT_FAILURE_RESOURCES); + mount_enter_dead_or_mounted(m, MOUNT_FAILURE_RESOURCES, /* flush_result = */ false); } static void mount_set_reload_result(Mount *m, MountResult result) { @@ -1298,7 +1301,7 @@ static void mount_enter_remounting(Mount *m) { fail: mount_set_reload_result(m, MOUNT_FAILURE_RESOURCES); - mount_enter_dead_or_mounted(m, MOUNT_SUCCESS); + mount_enter_dead_or_mounted(m, MOUNT_SUCCESS, /* flush_result = */ false); } static void mount_cycle_clear(Mount *m) { @@ -1472,8 +1475,8 @@ static int mount_deserialize_item(Unit *u, const char *key, const char *value, F } else if (streq(key, "control-pid")) { - pidref_done(&m->control_pid); - (void) deserialize_pidref(fds, value, &m->control_pid); + if (!pidref_is_set(&m->control_pid)) + (void) deserialize_pidref(fds, value, &m->control_pid); } else if (streq(key, "control-command")) { MountExecCommand id; @@ -1555,7 +1558,8 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) { if (IN_SET(m->state, MOUNT_REMOUNTING, MOUNT_REMOUNTING_SIGKILL, MOUNT_REMOUNTING_SIGTERM)) mount_set_reload_result(m, f); - else if (m->result == MOUNT_SUCCESS) + else if (m->result == MOUNT_SUCCESS && !IN_SET(m->state, MOUNT_MOUNTING, MOUNT_UNMOUNTING)) + /* MOUNT_MOUNTING and MOUNT_UNMOUNTING states need to be patched, see below. */ m->result = f; if (m->control_command) { @@ -1578,15 +1582,15 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) { switch (m->state) { case MOUNT_MOUNTING: - /* Our mount point has not appeared in mountinfo. Something went wrong. */ + /* Our mount point has not appeared in mountinfo. Something went wrong. */ if (f == MOUNT_SUCCESS) { - /* Either /bin/mount has an unexpected definition of success, - * or someone raced us and we lost. */ + /* Either /bin/mount has an unexpected definition of success, or someone raced us + * and we lost. */ log_unit_warning(UNIT(m), "Mount process finished, but there is no mount."); f = MOUNT_FAILURE_PROTOCOL; } - mount_enter_dead(m, f); + mount_enter_dead(m, f, /* flush_result = */ false); break; case MOUNT_MOUNTING_DONE: @@ -1596,13 +1600,11 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) { case MOUNT_REMOUNTING: case MOUNT_REMOUNTING_SIGTERM: case MOUNT_REMOUNTING_SIGKILL: - mount_enter_dead_or_mounted(m, MOUNT_SUCCESS); + mount_enter_dead_or_mounted(m, MOUNT_SUCCESS, /* flush_result = */ false); break; case MOUNT_UNMOUNTING: - if (f == MOUNT_SUCCESS && m->from_proc_self_mountinfo) { - /* Still a mount point? If so, let's try again. Most likely there were multiple mount points * stacked on top of each other. We might exceed the timeout specified by the user overall, * but we will stop as soon as any one umount times out. */ @@ -1613,23 +1615,33 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) { mount_enter_unmounting(m); } else { log_unit_warning(u, "Mount still present after %u attempts to unmount, giving up.", m->n_retry_umount); - mount_enter_mounted(m, f); + mount_enter_mounted(m, MOUNT_FAILURE_PROTOCOL); } + } else if (f == MOUNT_FAILURE_EXIT_CODE && !m->from_proc_self_mountinfo) { + /* Hmm, umount process spawned by us failed, but the mount disappeared anyway? + * Maybe someone else is trying to unmount at the same time. */ + log_unit_notice(u, "Mount disappeared even though umount process failed, continuing."); + mount_enter_dead(m, MOUNT_SUCCESS, /* flush_result = */ true); } else - mount_enter_dead_or_mounted(m, f); + /* At this point, either the unmount succeeded or unexpected error occurred. We usually + * remember the first error in 'result', but here let's update that forcibly, since + * there could previous failed attempts yet we only care about the most recent + * attempt. IOW, if we eventually managed to unmount the stuff, don't enter failed + * end state. */ + mount_enter_dead_or_mounted(m, f, /* flush_result = */ true); break; - case MOUNT_UNMOUNTING_SIGKILL: case MOUNT_UNMOUNTING_SIGTERM: - mount_enter_dead_or_mounted(m, f); + case MOUNT_UNMOUNTING_SIGKILL: + mount_enter_dead_or_mounted(m, f, /* flush_result = */ false); break; case MOUNT_CLEANING: if (m->clean_result == MOUNT_SUCCESS) m->clean_result = f; - mount_enter_dead(m, MOUNT_SUCCESS); + mount_enter_dead(m, MOUNT_SUCCESS, /* flush_result = */ false); break; default: @@ -1668,7 +1680,7 @@ static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *user mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, MOUNT_SUCCESS); } else { log_unit_warning(UNIT(m), "Remounting timed out. Skipping SIGKILL. Ignoring."); - mount_enter_dead_or_mounted(m, MOUNT_SUCCESS); + mount_enter_dead_or_mounted(m, MOUNT_SUCCESS, /* flush_result = */ false); } break; @@ -1676,7 +1688,7 @@ static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *user mount_set_reload_result(m, MOUNT_FAILURE_TIMEOUT); log_unit_warning(UNIT(m), "Mount process still around after SIGKILL. Ignoring."); - mount_enter_dead_or_mounted(m, MOUNT_SUCCESS); + mount_enter_dead_or_mounted(m, MOUNT_SUCCESS, /* flush_result = */ false); break; case MOUNT_UNMOUNTING: @@ -1690,13 +1702,13 @@ static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *user mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT); } else { log_unit_warning(UNIT(m), "Mount process timed out. Skipping SIGKILL. Ignoring."); - mount_enter_dead_or_mounted(m, MOUNT_FAILURE_TIMEOUT); + mount_enter_dead_or_mounted(m, MOUNT_FAILURE_TIMEOUT, /* flush_result = */ false); } break; case MOUNT_UNMOUNTING_SIGKILL: log_unit_warning(UNIT(m), "Mount process still around after SIGKILL. Ignoring."); - mount_enter_dead_or_mounted(m, MOUNT_FAILURE_TIMEOUT); + mount_enter_dead_or_mounted(m, MOUNT_FAILURE_TIMEOUT, /* flush_result = */ false); break; case MOUNT_CLEANING: @@ -2157,8 +2169,11 @@ static int mount_process_proc_self_mountinfo(Manager *m) { switch (mount->state) { case MOUNT_MOUNTED: - /* This has just been unmounted by somebody else, follow the state change. */ - mount_enter_dead(mount, MOUNT_SUCCESS); + /* This has just been unmounted by somebody else, follow the state change. + * Also explicitly override the result (see the comment in mount_sigchld_event()), + * but more aggressively here since the state change is extrinsic. */ + mount_cycle_clear(mount); + mount_enter_dead(mount, MOUNT_SUCCESS, /* flush_result = */ true); break; case MOUNT_MOUNTING_DONE: @@ -2166,7 +2181,7 @@ static int mount_process_proc_self_mountinfo(Manager *m) { * then remove it because of an internal error. E.g., fuse.sshfs seems * to do that when the connection fails. See #17617. To handle such the * case, let's once set the state back to mounting. Then, the unit can - * correctly enter the failed state later in mount_sigchld(). */ + * correctly enter the failed state later in mount_sigchld_event(). */ mount_set_state(mount, MOUNT_MOUNTING); break; @@ -2330,7 +2345,7 @@ static int mount_can_start(Unit *u) { r = unit_test_start_limit(u); if (r < 0) { - mount_enter_dead(m, MOUNT_FAILURE_START_LIMIT_HIT); + mount_enter_dead(m, MOUNT_FAILURE_START_LIMIT_HIT, /* flush_result = */ false); return r; } diff --git a/src/core/scope.c b/src/core/scope.c index e4c27da..2841280 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -586,6 +586,8 @@ static int scope_deserialize_item(Unit *u, const char *key, const char *value, F } else if (streq(key, "pids")) { _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL; + /* We don't check if we already received the pid before here because unit_watch_pidref() + * does this check internally and discards the new pidref if we already received it before. */ if (deserialize_pidref(fds, value, &pidref) >= 0) { r = unit_watch_pidref(u, &pidref, /* exclusive= */ false); if (r < 0) diff --git a/src/core/service.c b/src/core/service.c index 060ac08..ffe92d2 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -3174,14 +3174,14 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, s->reload_result = f; } else if (streq(key, "control-pid")) { - pidref_done(&s->control_pid); - (void) deserialize_pidref(fds, value, &s->control_pid); + if (!pidref_is_set(&s->control_pid)) + (void) deserialize_pidref(fds, value, &s->control_pid); } else if (streq(key, "main-pid")) { _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL; - if (deserialize_pidref(fds, value, &pidref) >= 0) + if (!pidref_is_set(&s->main_pid) && deserialize_pidref(fds, value, &pidref) >= 0) (void) service_set_main_pidref(s, &pidref); } else if (streq(key, "main-pid-known")) { @@ -3589,8 +3589,10 @@ static void service_notify_cgroup_empty_event(Unit *u) { break; } - if (s->exit_type == SERVICE_EXIT_CGROUP && main_pid_good(s) <= 0) - service_enter_start_post(s); + if (s->exit_type == SERVICE_EXIT_CGROUP && main_pid_good(s) <= 0) { + service_enter_stop_post(s, SERVICE_SUCCESS); + break; + } _fallthrough_; case SERVICE_START_POST: @@ -3861,11 +3863,13 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { default: assert_not_reached(); } - } else if (s->exit_type == SERVICE_EXIT_CGROUP && s->state == SERVICE_START) + } else if (s->exit_type == SERVICE_EXIT_CGROUP && s->state == SERVICE_START && + !IN_SET(s->type, SERVICE_NOTIFY, SERVICE_NOTIFY_RELOAD, SERVICE_DBUS)) /* If a main process exits very quickly, this function might be executed * before service_dispatch_exec_io(). Since this function disabled IO events * to monitor the main process above, we need to update the state here too. - * Let's consider the process is successfully launched and exited. */ + * Let's consider the process is successfully launched and exited, but + * only when we're not expecting a readiness notification or dbus name. */ service_enter_start_post(s); } diff --git a/src/core/show-status.c b/src/core/show-status.c index 606237e..5b003ba 100644 --- a/src/core/show-status.c +++ b/src/core/show-status.c @@ -38,6 +38,8 @@ int parse_show_status(const char *v, ShowStatus *ret) { int status_vprintf(const char *status, ShowStatusFlags flags, const char *format, va_list ap) { static const char status_indent[] = " "; /* "[" STATUS "] " */ + static int dumb = -1; + _cleanup_free_ char *s = NULL; _cleanup_close_ int fd = -EBADF; struct iovec iovec[7] = {}; @@ -46,6 +48,9 @@ int status_vprintf(const char *status, ShowStatusFlags flags, const char *format assert(format); + if (dumb < 0) + dumb = getenv_terminal_is_dumb(); + /* This is independent of logging, as status messages are * optional and go exclusively to the console. */ @@ -61,7 +66,7 @@ int status_vprintf(const char *status, ShowStatusFlags flags, const char *format if (fd < 0) return fd; - if (FLAGS_SET(flags, SHOW_STATUS_ELLIPSIZE)) { + if (FLAGS_SET(flags, SHOW_STATUS_ELLIPSIZE) && !dumb) { char *e; size_t emax, sl; int c; @@ -81,7 +86,7 @@ int status_vprintf(const char *status, ShowStatusFlags flags, const char *format free_and_replace(s, e); } - if (prev_ephemeral) + if (prev_ephemeral && !dumb) iovec[n++] = IOVEC_MAKE_STRING(ANSI_REVERSE_LINEFEED "\r" ANSI_ERASE_TO_END_OF_LINE); if (status) { @@ -94,9 +99,11 @@ int status_vprintf(const char *status, ShowStatusFlags flags, const char *format } iovec[n++] = IOVEC_MAKE_STRING(s); - iovec[n++] = IOVEC_MAKE_STRING("\r\n"); /* use CRNL instead of just NL, to be robust towards TTYs in raw mode */ + /* use CRNL instead of just NL, to be robust towards TTYs in raw mode. If we're writing to a dumb + * terminal, use NL as CRNL might be interpreted as a double newline. */ + iovec[n++] = IOVEC_MAKE_STRING(dumb ? "\n" : "\r\n"); - if (prev_ephemeral && !FLAGS_SET(flags, SHOW_STATUS_EPHEMERAL)) + if (prev_ephemeral && !FLAGS_SET(flags, SHOW_STATUS_EPHEMERAL) && !dumb) iovec[n++] = IOVEC_MAKE_STRING(ANSI_ERASE_TO_END_OF_LINE); prev_ephemeral = FLAGS_SET(flags, SHOW_STATUS_EPHEMERAL); diff --git a/src/core/socket.c b/src/core/socket.c index 388be62..9adae16 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -2634,8 +2634,9 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value, else s->n_refused += k; } else if (streq(key, "control-pid")) { - pidref_done(&s->control_pid); - (void) deserialize_pidref(fds, value, &s->control_pid); + + if (!pidref_is_set(&s->control_pid)) + (void) deserialize_pidref(fds, value, &s->control_pid); } else if (streq(key, "control-command")) { SocketExecCommand id; diff --git a/src/core/swap.c b/src/core/swap.c index 488b171..682c2b9 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -989,8 +989,8 @@ static int swap_deserialize_item(Unit *u, const char *key, const char *value, FD s->result = f; } else if (streq(key, "control-pid")) { - pidref_done(&s->control_pid); - (void) deserialize_pidref(fds, value, &s->control_pid); + if (!pidref_is_set(&s->control_pid)) + (void) deserialize_pidref(fds, value, &s->control_pid); } else if (streq(key, "control-command")) { SwapExecCommand id; -- cgit v1.2.3