strv_free(u->dropin_paths);
free(u->instance);
+ free(u->job_timeout_reboot_arg);
+
set_free_free(u->names);
unit_unwatch_all_pids(u);
return UNIT_VTABLE(u)->sub_state_to_string(u);
}
-static void complete_move(Set **s, Set **other) {
+static int complete_move(Set **s, Set **other) {
+ int r;
+
assert(s);
assert(other);
if (!*other)
- return;
+ return 0;
- if (*s)
- set_move(*s, *other);
- else {
+ if (*s) {
+ r = set_move(*s, *other);
+ if (r < 0)
+ return r;
+ } else {
*s = *other;
*other = NULL;
}
+
+ return 0;
}
-static void merge_names(Unit *u, Unit *other) {
+static int merge_names(Unit *u, Unit *other) {
char *t;
Iterator i;
+ int r;
assert(u);
assert(other);
- complete_move(&u->names, &other->names);
+ r = complete_move(&u->names, &other->names);
+ if (r < 0)
+ return r;
set_free_free(other->names);
other->names = NULL;
SET_FOREACH(t, u->names, i)
assert_se(hashmap_replace(u->manager->units, t, u) == 0);
+
+ return 0;
+}
+
+static int reserve_dependencies(Unit *u, Unit *other, UnitDependency d) {
+ unsigned n_reserve;
+
+ assert(u);
+ assert(other);
+ assert(d < _UNIT_DEPENDENCY_MAX);
+
+ /*
+ * If u does not have this dependency set allocated, there is no need
+ * to reserve anything. In that case other's set will be transfered
+ * as a whole to u by complete_move().
+ */
+ if (!u->dependencies[d])
+ return 0;
+
+ /* merge_dependencies() will skip a u-on-u dependency */
+ n_reserve = set_size(other->dependencies[d]) - !!set_get(other->dependencies[d], u);
+
+ return set_reserve(u->dependencies[d], n_reserve);
}
static void merge_dependencies(Unit *u, Unit *other, const char *other_id, UnitDependency d) {
if (back)
maybe_warn_about_dependency(u->id, other_id, d);
- complete_move(&u->dependencies[d], &other->dependencies[d]);
+ /* The move cannot fail. The caller must have performed a reservation. */
+ assert_se(complete_move(&u->dependencies[d], &other->dependencies[d]) == 0);
set_free(other->dependencies[d]);
other->dependencies[d] = NULL;
int unit_merge(Unit *u, Unit *other) {
UnitDependency d;
const char *other_id = NULL;
+ int r;
assert(u);
assert(other);
if (other->id)
other_id = strdupa(other->id);
+ /* Make reservations to ensure merge_dependencies() won't fail */
+ for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) {
+ r = reserve_dependencies(u, other, d);
+ /*
+ * We don't rollback reservations if we fail. We don't have
+ * a way to undo reservations. A reservation is not a leak.
+ */
+ if (r < 0)
+ return r;
+ }
+
/* Merge names */
- merge_names(u, other);
+ r = merge_names(u, other);
+ if (r < 0)
+ return r;
/* Redirect all references */
while (other->refs)
if (u->job_timeout > 0)
fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout, 0));
+ if (u->job_timeout_action != FAILURE_ACTION_NONE)
+ fprintf(f, "%s\tJob Timeout Action: %s\n", prefix, failure_action_to_string(u->job_timeout_action));
+
+ if (u->job_timeout_reboot_arg)
+ fprintf(f, "%s\tJob Timeout Reboot Argument: %s\n", prefix, u->job_timeout_reboot_arg);
+
condition_dump_list(u->conditions, f, prefix);
if (dual_timestamp_is_set(&u->condition_timestamp))
void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) {
DISABLE_WARNING_FORMAT_NONLITERAL;
- manager_status_printf(u->manager, false, status, unit_status_msg_format, unit_description(u));
+ manager_status_printf(u->manager, STATUS_TYPE_NORMAL,
+ status, unit_status_msg_format, unit_description(u));
REENABLE_WARNING;
}
int unit_kill_context(
Unit *u,
KillContext *c,
- bool sigkill,
+ KillOperation k,
pid_t main_pid,
pid_t control_pid,
bool main_pid_alien) {
if (c->kill_mode == KILL_NONE)
return 0;
- sig = sigkill ? SIGKILL : c->kill_signal;
+ switch (k) {
+ case KILL_KILL:
+ sig = SIGKILL;
+ break;
+ case KILL_ABORT:
+ sig = SIGABRT;
+ break;
+ case KILL_TERMINATE:
+ sig = c->kill_signal;
+ break;
+ default:
+ assert_not_reached("KillOperation unknown");
+ }
if (main_pid > 0) {
r = kill_and_sigcont(main_pid, sig);
if (!main_pid_alien)
wait_for_exit = true;
- if (c->send_sighup && !sigkill)
+ if (c->send_sighup && k != KILL_KILL)
kill(main_pid, SIGHUP);
}
}
} else {
wait_for_exit = true;
- if (c->send_sighup && !sigkill)
+ if (c->send_sighup && k != KILL_KILL)
kill(control_pid, SIGHUP);
}
}
- if ((c->kill_mode == KILL_CONTROL_GROUP || (c->kill_mode == KILL_MIXED && sigkill)) && u->cgroup_path) {
+ if ((c->kill_mode == KILL_CONTROL_GROUP || (c->kill_mode == KILL_MIXED && k == KILL_KILL)) && u->cgroup_path) {
_cleanup_set_free_ Set *pid_set = NULL;
/* Exclude the main/control pids from being killed via the cgroup */
/* wait_for_exit = true; */
- if (c->send_sighup && !sigkill) {
+ if (c->send_sighup && k != KILL_KILL) {
set_free(pid_set);
pid_set = unit_pid_set(main_pid, control_pid);