+ return r;
+}
+
+int unit_make_transient(Unit *u) {
+ int r;
+
+ assert(u);
+
+ u->load_state = UNIT_STUB;
+ u->load_error = 0;
+ u->transient = true;
+
+ free(u->fragment_path);
+ u->fragment_path = NULL;
+
+ if (u->manager->running_as == SYSTEMD_USER) {
+ _cleanup_free_ char *c = NULL;
+
+ r = user_config_home(&c);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -ENOENT;
+
+ u->fragment_path = strjoin(c, "/", u->id, NULL);
+ if (!u->fragment_path)
+ return -ENOMEM;
+
+ mkdir_p(c, 0755);
+ } else {
+ u->fragment_path = strappend("/run/systemd/system/", u->id);
+ if (!u->fragment_path)
+ return -ENOMEM;
+
+ mkdir_p("/run/systemd/system", 0755);
+ }
+
+ return write_string_file_atomic_label(u->fragment_path, "# Transient stub");
+}
+
+int unit_kill_context(
+ Unit *u,
+ KillContext *c,
+ bool sigkill,
+ pid_t main_pid,
+ pid_t control_pid,
+ bool main_pid_alien) {
+
+ int sig, wait_for_exit = 0, r;
+
+ assert(u);
+ assert(c);
+
+ if (c->kill_mode == KILL_NONE)
+ return 0;
+
+ sig = sigkill ? SIGKILL : c->kill_signal;
+
+ if (main_pid > 0) {
+ r = kill_and_sigcont(main_pid, sig);
+
+ if (r < 0 && r != -ESRCH) {
+ _cleanup_free_ char *comm = NULL;
+ get_process_comm(main_pid, &comm);
+
+ log_warning_unit(u->id, "Failed to kill main process %li (%s): %s",
+ (long) main_pid, strna(comm), strerror(-r));
+ } else {
+ wait_for_exit = !main_pid_alien;
+
+ if (c->send_sighup)
+ kill(main_pid, SIGHUP);
+ }
+ }
+
+ if (control_pid > 0) {
+ r = kill_and_sigcont(control_pid, sig);
+
+ if (r < 0 && r != -ESRCH) {
+ _cleanup_free_ char *comm = NULL;
+ get_process_comm(control_pid, &comm);
+
+ log_warning_unit(u->id,
+ "Failed to kill control process %li (%s): %s",
+ (long) control_pid, strna(comm), strerror(-r));
+ } 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;
+
+ /* 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;
+
+ 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) {
+ 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;
+ }
+