u->id = s;
u->instance = i;
- LIST_PREPEND(Unit, units_by_type, u->manager->units_by_type[t], u);
+ LIST_PREPEND(units_by_type, u->manager->units_by_type[t], u);
if (UNIT_VTABLE(u)->init)
UNIT_VTABLE(u)->init(u);
}
int unit_choose_id(Unit *u, const char *name) {
- char *s, *t = NULL, *i;
+ char *s, *i;
+ _cleanup_free_ char *t = NULL;
int r;
assert(u);
/* Selects one of the names of this unit as the id */
s = set_get(u->names, (char*) name);
- free(t);
if (!s)
return -ENOENT;
if (u->load_state != UNIT_STUB || u->in_load_queue)
return;
- LIST_PREPEND(Unit, load_queue, u->manager->load_queue, u);
+ LIST_PREPEND(load_queue, u->manager->load_queue, u);
u->in_load_queue = true;
}
if (u->in_cleanup_queue)
return;
- LIST_PREPEND(Unit, cleanup_queue, u->manager->cleanup_queue, u);
+ LIST_PREPEND(cleanup_queue, u->manager->cleanup_queue, u);
u->in_cleanup_queue = true;
}
if (unit_check_gc(u))
return;
- LIST_PREPEND(Unit, gc_queue, u->manager->gc_queue, u);
+ LIST_PREPEND(gc_queue, u->manager->gc_queue, u);
u->in_gc_queue = true;
u->manager->n_in_gc_queue ++;
return;
}
- LIST_PREPEND(Unit, dbus_queue, u->manager->dbus_unit_queue, u);
+ LIST_PREPEND(dbus_queue, u->manager->dbus_unit_queue, u);
u->in_dbus_queue = true;
}
}
}
+static void unit_free_requires_mounts_for(Unit *u) {
+ char **j;
+
+ STRV_FOREACH(j, u->requires_mounts_for) {
+ char s[strlen(*j) + 1];
+
+ PATH_FOREACH_PREFIX_MORE(s, *j) {
+ char *y;
+ Set *x;
+
+ x = hashmap_get2(u->manager->units_requiring_mounts_for, s, (void**) &y);
+ if (!x)
+ continue;
+
+ set_remove(x, u);
+
+ if (set_isempty(x)) {
+ hashmap_remove(u->manager->units_requiring_mounts_for, y);
+ free(y);
+ set_free(x);
+ }
+ }
+ }
+
+ strv_free(u->requires_mounts_for);
+ u->requires_mounts_for = NULL;
+}
+
void unit_free(Unit *u) {
UnitDependency d;
Iterator i;
if (UNIT_VTABLE(u)->done)
UNIT_VTABLE(u)->done(u);
+ unit_free_requires_mounts_for(u);
+
SET_FOREACH(t, u->names, i)
hashmap_remove_value(u->manager->units, t, u);
for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
bidi_set_free(u, u->dependencies[d]);
- if (u->requires_mounts_for) {
- LIST_REMOVE(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
- strv_free(u->requires_mounts_for);
- }
-
if (u->type != _UNIT_TYPE_INVALID)
- LIST_REMOVE(Unit, units_by_type, u->manager->units_by_type[u->type], u);
+ LIST_REMOVE(units_by_type, u->manager->units_by_type[u->type], u);
if (u->in_load_queue)
- LIST_REMOVE(Unit, load_queue, u->manager->load_queue, u);
+ LIST_REMOVE(load_queue, u->manager->load_queue, u);
if (u->in_dbus_queue)
- LIST_REMOVE(Unit, dbus_queue, u->manager->dbus_unit_queue, u);
+ LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
if (u->in_cleanup_queue)
- LIST_REMOVE(Unit, cleanup_queue, u->manager->cleanup_queue, u);
+ LIST_REMOVE(cleanup_queue, u->manager->cleanup_queue, u);
if (u->in_gc_queue) {
- LIST_REMOVE(Unit, gc_queue, u->manager->gc_queue, u);
+ LIST_REMOVE(gc_queue, u->manager->gc_queue, u);
u->manager->n_in_gc_queue--;
}
if (u->in_cgroup_queue)
- LIST_REMOVE(Unit, cgroup_queue, u->manager->cgroup_queue, u);
+ LIST_REMOVE(cgroup_queue, u->manager->cgroup_queue, u);
if (u->cgroup_path) {
hashmap_remove(u->manager->cgroup_unit, u->cgroup_path);
int unit_merge_by_name(Unit *u, const char *name) {
Unit *other;
int r;
- char *s = NULL;
+ _cleanup_free_ char *s = NULL;
assert(u);
assert(name);
else
r = unit_merge(u, other);
- free(s);
return r;
}
char *t, **j;
UnitDependency d;
Iterator i;
- char *p2;
+ _cleanup_free_ char *p2 = NULL;
const char *prefix2;
char
timestamp1[FORMAT_TIMESTAMP_MAX],
if (u->nop_job)
job_dump(u->nop_job, f, prefix2);
- free(p2);
}
/* Common implementation for multiple backends */
assert(u);
if (u->in_load_queue) {
- LIST_REMOVE(Unit, load_queue, u->manager->load_queue, u);
+ LIST_REMOVE(load_queue, u->manager->load_queue, u);
u->in_load_queue = false;
}
assert(u);
dual_timestamp_get(&u->condition_timestamp);
- u->condition_result = condition_test_list(u->conditions);
+ u->condition_result = condition_test_list(u->id, u->conditions);
return u->condition_result;
}
}
/* Forward to the main object, if we aren't it. */
- if ((following = unit_following(u))) {
+ following = unit_following(u);
+ if (following) {
log_debug_unit(u->id, "Redirecting start request from %s to %s.",
u->id, following->id);
return unit_start(following);
int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference) {
Unit *other;
int r;
- char *s;
+ _cleanup_free_ char *s = NULL;
assert(u);
assert(name || path);
return -ENOMEM;
if ((r = manager_load_unit(u->manager, name, path, NULL, &other)) < 0)
- goto finish;
+ return r;
r = unit_add_two_dependencies(u, d, e, other, add_reference);
-finish:
- free(s);
return r;
}
int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) {
Unit *other;
int r;
- char *s;
+ _cleanup_free_ char *s = NULL;
assert(u);
assert(name || path);
return -ENOMEM;
if ((r = manager_load_unit(u->manager, name, path, NULL, &other)) < 0)
- goto finish;
+ return r;
r = unit_add_dependency(other, d, u, add_reference);
-finish:
- free(s);
return r;
}
int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference) {
Unit *other;
int r;
- char *s;
+ _cleanup_free_ char *s = NULL;
assert(u);
assert(name || path);
return -ENOMEM;
if ((r = manager_load_unit(u->manager, name, path, NULL, &other)) < 0)
- goto finish;
+ return r;
if ((r = unit_add_two_dependencies(other, d, e, u, add_reference)) < 0)
- goto finish;
+ return r;
-finish:
- free(s);
return r;
}
if (u->instance) {
_cleanup_free_ char *prefix = NULL, *escaped = NULL;
- ;
+
/* Implicitly place all instantiated units in their
* own per-template slice */
free(u->cgroup_path);
u->cgroup_path = s;
- hashmap_put(u->manager->cgroup_unit, s, u);
+ assert(hashmap_put(u->manager->cgroup_unit, s, u) == 1);
continue;
}
int unit_add_node_link(Unit *u, const char *what, bool wants) {
Unit *device;
- char *e;
+ _cleanup_free_ char *e = NULL;
int r;
assert(u);
return -ENOMEM;
r = manager_load_unit(u->manager, e, NULL, NULL, &device);
- free(e);
+
if (r < 0)
return r;
return UNIT_VTABLE(u)->kill(u, w, signo, error);
}
+static Set *unit_pid_set(pid_t main_pid, pid_t control_pid) {
+ Set *pid_set;
+ int r;
+
+ pid_set = set_new(trivial_hash_func, trivial_compare_func);
+ if (!pid_set)
+ return NULL;
+
+ /* Exclude the main/control pids from being killed via the cgroup */
+ if (main_pid > 0) {
+ r = set_put(pid_set, LONG_TO_PTR(main_pid));
+ if (r < 0)
+ goto fail;
+ }
+
+ if (control_pid > 0) {
+ r = set_put(pid_set, LONG_TO_PTR(control_pid));
+ if (r < 0)
+ goto fail;
+ }
+
+ return pid_set;
+
+fail:
+ set_free(pid_set);
+ return NULL;
+}
+
int unit_kill_common(
Unit *u,
KillWho who,
_cleanup_set_free_ Set *pid_set = NULL;
int q;
- pid_set = set_new(trivial_hash_func, trivial_compare_func);
+ /* Exclude the main/control pids from being killed via the cgroup */
+ pid_set = unit_pid_set(main_pid, control_pid);
if (!pid_set)
return -ENOMEM;
- /* Exclude the control/main pid from being killed via the cgroup */
- if (control_pid > 0) {
- q = set_put(pid_set, LONG_TO_PTR(control_pid));
- if (q < 0)
- return q;
- }
-
- if (main_pid > 0) {
- q = set_put(pid_set, LONG_TO_PTR(main_pid));
- if (q < 0)
- return q;
- }
-
q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, false, true, false, pid_set);
if (q < 0 && q != -EAGAIN && q != -ESRCH && q != -ENOENT)
r = q;
unit_ref_unset(ref);
ref->unit = u;
- LIST_PREPEND(UnitRef, refs, u->refs, ref);
+ LIST_PREPEND(refs, u->refs, ref);
return u;
}
if (!ref->unit)
return;
- LIST_REMOVE(UnitRef, refs, ref->unit->refs, ref);
+ LIST_REMOVE(refs, ref->unit->refs, ref);
ref->unit = NULL;
}
-int unit_add_one_mount_link(Unit *u, Mount *m) {
+int unit_add_mount_links(Unit *u) {
char **i;
+ int r;
assert(u);
- assert(m);
-
- if (u->load_state != UNIT_LOADED ||
- UNIT(m)->load_state != UNIT_LOADED)
- return 0;
STRV_FOREACH(i, u->requires_mounts_for) {
+ char prefix[strlen(*i) + 1];
- if (UNIT(m) == u)
- continue;
+ PATH_FOREACH_PREFIX_MORE(prefix, *i) {
+ Unit *m;
- if (!path_startswith(*i, m->where))
- continue;
-
- return unit_add_two_dependencies(u, UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true);
- }
+ r = manager_get_unit_by_path(u->manager, prefix, ".mount", &m);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ continue;
+ if (m == u)
+ continue;
- return 0;
-}
+ if (m->load_state != UNIT_LOADED)
+ continue;
-int unit_add_mount_links(Unit *u) {
- Unit *other;
- int r;
-
- assert(u);
+ r = unit_add_dependency(u, UNIT_AFTER, m, true);
+ if (r < 0)
+ return r;
- LIST_FOREACH(units_by_type, other, u->manager->units_by_type[UNIT_MOUNT]) {
- r = unit_add_one_mount_link(u, MOUNT(other));
- if (r < 0)
- return r;
+ if (m->fragment_path) {
+ r = unit_add_dependency(u, UNIT_REQUIRES, m, true);
+ if (r < 0)
+ return r;
+ }
+ }
}
return 0;
return 0;
r = drop_in_file(u, mode, name, &p, &q);
+ if (r < 0)
+ return r;
+
if (unlink(q) < 0)
r = errno == ENOENT ? 0 : -errno;
else
log_warning_unit(u->id, "Failed to kill main process %li (%s): %s",
(long) main_pid, strna(comm), strerror(-r));
- } else
+ } else {
wait_for_exit = !main_pid_alien;
+
+ if (c->send_sighup)
+ kill(main_pid, SIGHUP);
+ }
}
if (control_pid > 0) {
log_warning_unit(u->id,
"Failed to kill control process %li (%s): %s",
(long) control_pid, strna(comm), strerror(-r));
- } else
+ } else {
wait_for_exit = true;
+
+ if (c->send_sighup)
+ kill(control_pid, SIGHUP);
+ }
}
if (c->kill_mode == KILL_CONTROL_GROUP && u->cgroup_path) {
_cleanup_set_free_ Set *pid_set = NULL;
- pid_set = set_new(trivial_hash_func, trivial_compare_func);
+ /* Exclude the main/control pids from being killed via the cgroup */
+ pid_set = unit_pid_set(main_pid, control_pid);
if (!pid_set)
return -ENOMEM;
- /* Exclude the main/control pids from being killed via the cgroup */
- if (main_pid > 0) {
- r = set_put(pid_set, LONG_TO_PTR(main_pid));
- if (r < 0)
- return r;
- }
-
- if (control_pid > 0) {
- r = set_put(pid_set, LONG_TO_PTR(control_pid));
- if (r < 0)
- return r;
- }
-
r = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, sig, true, true, false, pid_set);
if (r < 0) {
if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
log_warning_unit(u->id, "Failed to kill control group: %s", strerror(-r));
- } else if (r > 0)
+ } else if (r > 0) {
wait_for_exit = true;
+ if (c->send_sighup) {
+ set_free(pid_set);
+
+ pid_set = unit_pid_set(main_pid, control_pid);
+ if (!pid_set)
+ return -ENOMEM;
+
+ cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, SIGHUP, true, true, false, pid_set);
+ }
+ }
}
return wait_for_exit;
}
+int unit_require_mounts_for(Unit *u, const char *path) {
+ char prefix[strlen(path) + 1], *p;
+ int r;
+
+ assert(u);
+ assert(path);
+
+ /* Registers a unit for requiring a certain path and all its
+ * prefixes. We keep a simple array of these paths in the
+ * unit, since its usually short. However, we build a prefix
+ * table for all possible prefixes so that new appearing mount
+ * units can easily determine which units to make themselves a
+ * dependency of. */
+
+ p = strdup(path);
+ if (!p)
+ return -ENOMEM;
+
+ path_kill_slashes(p);
+
+ if (!path_is_absolute(p)) {
+ free(p);
+ return -EINVAL;
+ }
+
+ if (!path_is_safe(p)) {
+ free(p);
+ return -EPERM;
+ }
+
+ if (strv_contains(u->requires_mounts_for, p)) {
+ free(p);
+ return 0;
+ }
+
+ r = strv_push(&u->requires_mounts_for, p);
+ if (r < 0) {
+ free(p);
+ return r;
+ }
+
+ PATH_FOREACH_PREFIX_MORE(prefix, p) {
+ Set *x;
+
+ x = hashmap_get(u->manager->units_requiring_mounts_for, prefix);
+ if (!x) {
+ char *q;
+
+ if (!u->manager->units_requiring_mounts_for) {
+ u->manager->units_requiring_mounts_for = hashmap_new(string_hash_func, string_compare_func);
+ if (!u->manager->units_requiring_mounts_for)
+ return -ENOMEM;
+ }
+
+ q = strdup(prefix);
+ if (!q)
+ return -ENOMEM;
+
+ x = set_new(NULL, NULL);
+ if (!x) {
+ free(q);
+ return -ENOMEM;
+ }
+
+ r = hashmap_put(u->manager->units_requiring_mounts_for, q, x);
+ if (r < 0) {
+ free(q);
+ set_free(x);
+ return r;
+ }
+ }
+
+ r = set_put(x, u);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = {
[UNIT_ACTIVE] = "active",
[UNIT_RELOADING] = "reloading",