}
int unit_new_for_name(Manager *m, size_t size, const char *name, Unit **ret) {
- Unit *u;
+ _cleanup_(unit_freep) Unit *u = NULL;
int r;
u = unit_new(m, size);
return -ENOMEM;
r = unit_add_name(u, name);
- if (r < 0) {
- unit_free(u);
+ if (r < 0)
return r;
- }
- *ret = u;
+ *ret = TAKE_PTR(u);
+
return r;
}
exec_context_init(ec);
ec->keyring_mode = MANAGER_IS_SYSTEM(u->manager) ?
- EXEC_KEYRING_PRIVATE : EXEC_KEYRING_INHERIT;
+ EXEC_KEYRING_SHARED : EXEC_KEYRING_INHERIT;
}
kc = unit_get_kill_context(u);
if (u->type == _UNIT_TYPE_INVALID) {
u->type = t;
u->id = s;
- u->instance = i;
+ u->instance = TAKE_PTR(i);
LIST_PREPEND(units_by_type, u->manager->units_by_type[t], u);
unit_init(u);
-
- i = NULL;
}
s = NULL;
for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
bidi_set_free(u, u->dependencies[d]);
+ if (u->on_console)
+ manager_unref_console(u->manager);
+
+ unit_release_cgroup(u);
+
+ if (!MANAGER_IS_RELOADING(u->manager))
+ unit_unlink_state_files(u);
+
+ unit_unref_uid_gid(u, false);
+
+ (void) manager_update_failed_units(u->manager, u, false);
+ set_remove(u->manager->startup_units, u);
+
+ unit_unwatch_all_pids(u);
+
+ unit_ref_unset(&u->slice);
+ while (u->refs_by_target)
+ unit_ref_unset(u->refs_by_target);
+
if (u->type != _UNIT_TYPE_INVALID)
LIST_REMOVE(units_by_type, u->manager->units_by_type[u->type], u);
if (u->in_dbus_queue)
LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
- if (u->in_cleanup_queue)
- LIST_REMOVE(cleanup_queue, u->manager->cleanup_queue, u);
-
if (u->in_gc_queue)
LIST_REMOVE(gc_queue, u->manager->gc_unit_queue, u);
if (u->in_cgroup_empty_queue)
LIST_REMOVE(cgroup_empty_queue, u->manager->cgroup_empty_queue, u);
- if (u->on_console)
- manager_unref_console(u->manager);
+ if (u->in_cleanup_queue)
+ LIST_REMOVE(cleanup_queue, u->manager->cleanup_queue, u);
- unit_release_cgroup(u);
+ if (u->in_target_deps_queue)
+ LIST_REMOVE(target_deps_queue, u->manager->target_deps_queue, u);
- if (!MANAGER_IS_RELOADING(u->manager))
- unit_unlink_state_files(u);
+ safe_close(u->ip_accounting_ingress_map_fd);
+ safe_close(u->ip_accounting_egress_map_fd);
- unit_unref_uid_gid(u, false);
+ safe_close(u->ipv4_allow_map_fd);
+ safe_close(u->ipv6_allow_map_fd);
+ safe_close(u->ipv4_deny_map_fd);
+ safe_close(u->ipv6_deny_map_fd);
- (void) manager_update_failed_units(u->manager, u, false);
- set_remove(u->manager->startup_units, u);
+ bpf_program_unref(u->ip_bpf_ingress);
+ bpf_program_unref(u->ip_bpf_ingress_installed);
+ bpf_program_unref(u->ip_bpf_egress);
+ bpf_program_unref(u->ip_bpf_egress_installed);
+
+ condition_free_list(u->conditions);
+ condition_free_list(u->asserts);
free(u->description);
strv_free(u->documentation);
set_free_free(u->names);
- unit_unwatch_all_pids(u);
-
- condition_free_list(u->conditions);
- condition_free_list(u->asserts);
-
free(u->reboot_arg);
- unit_ref_unset(&u->slice);
- while (u->refs_by_target)
- unit_ref_unset(u->refs_by_target);
-
- safe_close(u->ip_accounting_ingress_map_fd);
- safe_close(u->ip_accounting_egress_map_fd);
-
- safe_close(u->ipv4_allow_map_fd);
- safe_close(u->ipv6_allow_map_fd);
- safe_close(u->ipv4_deny_map_fd);
- safe_close(u->ipv6_deny_map_fd);
-
- bpf_program_unref(u->ip_bpf_ingress);
- bpf_program_unref(u->ip_bpf_egress);
-
free(u);
}
if (*s)
return set_move(*s, *other);
- else {
- *s = *other;
- *other = NULL;
- }
+ else
+ *s = TAKE_PTR(*other);
return 0;
}
if (*s)
return hashmap_move(*s, *other);
- else {
- *s = *other;
- *other = NULL;
- }
+ else
+ *s = TAKE_PTR(*other);
return 0;
}
return unit_load_dropin(unit_follow_merge(u));
}
+void unit_add_to_target_deps_queue(Unit *u) {
+ Manager *m = u->manager;
+
+ assert(u);
+
+ if (u->in_target_deps_queue)
+ return;
+
+ LIST_PREPEND(target_deps_queue, m->target_deps_queue, u);
+ u->in_target_deps_queue = true;
+}
+
int unit_add_default_target_dependency(Unit *u, Unit *target) {
assert(u);
assert(target);
return unit_add_dependency(target, UNIT_AFTER, u, true, UNIT_DEPENDENCY_DEFAULT);
}
-static int unit_add_target_dependencies(Unit *u) {
-
- static const UnitDependency deps[] = {
- UNIT_REQUIRED_BY,
- UNIT_REQUISITE_OF,
- UNIT_WANTED_BY,
- UNIT_BOUND_BY
- };
-
- unsigned k;
- int r = 0;
-
- assert(u);
-
- for (k = 0; k < ELEMENTSOF(deps); k++) {
- Unit *target;
- Iterator i;
- void *v;
-
- HASHMAP_FOREACH_KEY(v, target, u->dependencies[deps[k]], i) {
- r = unit_add_default_target_dependency(u, target);
- if (r < 0)
- return r;
- }
- }
-
- return r;
-}
-
static int unit_add_slice_dependencies(Unit *u) {
UnitDependencyMask mask;
assert(u);
}
if (u->load_state == UNIT_LOADED) {
-
- r = unit_add_target_dependencies(u);
- if (r < 0)
- goto fail;
+ unit_add_to_target_deps_queue(u);
r = unit_add_slice_dependencies(u);
if (r < 0)
format = unit_get_status_message_format(u, t);
DISABLE_WARNING_FORMAT_NONLITERAL;
- xsprintf(buf, format, unit_description(u));
+ (void) snprintf(buf, sizeof buf, format, unit_description(u));
REENABLE_WARNING;
mid = t == JOB_START ? "MESSAGE_ID=" SD_MESSAGE_UNIT_STARTING_STR :
}
void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success) {
- Manager *m;
bool unexpected;
+ Manager *m;
assert(u);
assert(os < _UNIT_ACTIVE_STATE_MAX);
assert(ns < _UNIT_ACTIVE_STATE_MAX);
- /* Note that this is called for all low-level state changes,
- * even if they might map to the same high-level
- * UnitActiveState! That means that ns == os is an expected
- * behavior here. For example: if a mount point is remounted
- * this function will be called too! */
+ /* Note that this is called for all low-level state changes, even if they might map to the same high-level
+ * UnitActiveState! That means that ns == os is an expected behavior here. For example: if a mount point is
+ * remounted this function will be called too! */
m = u->manager;
}
}
- /* Some names are special */
if (UNIT_IS_ACTIVE_OR_RELOADING(ns)) {
- if (unit_has_name(u, SPECIAL_DBUS_SERVICE))
- /* The bus might have just become available,
- * hence try to connect to it, if we aren't
- * yet connected. */
- bus_init(m, true);
-
if (u->type == UNIT_SERVICE &&
!UNIT_IS_ACTIVE_OR_RELOADING(os) &&
!MANAGER_IS_RELOADING(m)) {
manager_send_unit_plymouth(m, u);
} else {
- /* We don't care about D-Bus going down here, since we'll get an asynchronous notification for it
- * anyway. */
if (UNIT_IS_INACTIVE_OR_FAILED(ns) &&
!UNIT_IS_INACTIVE_OR_FAILED(os)
}
manager_recheck_journal(m);
+ manager_recheck_dbus(m);
+
unit_trigger_notify(u);
if (!MANAGER_IS_RELOADING(u->manager)) {
- /* Maybe we finished startup and are now ready for
- * being stopped because unneeded? */
+ /* Maybe we finished startup and are now ready for being stopped because unneeded? */
unit_check_unneeded(u);
- /* Maybe we finished startup, but something we needed
- * has vanished? Let's die then. (This happens when
- * something BindsTo= to a Type=oneshot unit, as these
- * units go directly from starting to inactive,
+ /* Maybe we finished startup, but something we needed has vanished? Let's die then. (This happens when
+ * something BindsTo= to a Type=oneshot unit, as these units go directly from starting to inactive,
* without ever entering started.) */
unit_check_binds_to(u);
return r;
if (valid_user_group_name(n)) {
- *ret = n;
- n = NULL;
+ *ret = TAKE_PTR(n);
return 0;
}
char* unit_concat_strv(char **l, UnitWriteFlags flags) {
_cleanup_free_ char *result = NULL;
size_t n = 0, allocated = 0;
- char **i, *ret;
+ char **i;
/* Takes a list of strings, escapes them, and concatenates them. This may be used to format command lines in a
* way suitable for ExecStart= stanzas */
result[n] = 0;
- ret = result;
- result = NULL;
-
- return ret;
+ return TAKE_PTR(result);
}
int unit_write_setting(Unit *u, UnitWriteFlags flags, const char *name, const char *data) {
} else if (r > 0) {
- /* FIXME: For now, on the legacy hierarchy, we
- * will not wait for the cgroup members to die
- * if we are running in a container or if this
- * is a delegation unit, simply because cgroup
- * notification is unreliable in these
- * cases. It doesn't work at all in
- * containers, and outside of containers it
- * can be confused easily by left-over
- * directories in the cgroup — which however
- * should not exist in non-delegated units. On
- * the unified hierarchy that's different,
- * there we get proper events. Hence rely on
- * them. */
+ /* FIXME: For now, on the legacy hierarchy, we will not wait for the cgroup members to die if
+ * we are running in a container or if this is a delegation unit, simply because cgroup
+ * notification is unreliable in these cases. It doesn't work at all in containers, and outside
+ * of containers it can be confused easily by left-over directories in the cgroup — which
+ * however should not exist in non-delegated units. On the unified hierarchy that's different,
+ * there we get proper events. Hence rely on them. */
if (cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER) > 0 ||
- (detect_container() == 0 && !UNIT_CGROUP_BOOL(u, delegate)))
+ (detect_container() == 0 && !unit_cgroup_delegate(u)))
wait_for_exit = true;
if (send_sighup) {
}
int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask) {
- char prefix[strlen(path) + 1], *p;
+ _cleanup_free_ char *p = NULL;
+ char *prefix;
UnitDependencyInfo di;
int r;
if (!path_is_absolute(path))
return -EINVAL;
- r = hashmap_ensure_allocated(&u->requires_mounts_for, &string_hash_ops);
+ r = hashmap_ensure_allocated(&u->requires_mounts_for, &path_hash_ops);
if (r < 0)
return r;
if (!p)
return -ENOMEM;
- path_kill_slashes(p);
+ path = path_kill_slashes(p);
- if (!path_is_normalized(p)) {
- free(p);
+ if (!path_is_normalized(path))
return -EPERM;
- }
- if (hashmap_contains(u->requires_mounts_for, p)) {
- free(p);
+ if (hashmap_contains(u->requires_mounts_for, path))
return 0;
- }
di = (UnitDependencyInfo) {
.origin_mask = mask
};
- r = hashmap_put(u->requires_mounts_for, p, di.data);
- if (r < 0) {
- free(p);
+ r = hashmap_put(u->requires_mounts_for, path, di.data);
+ if (r < 0)
return r;
- }
+ p = NULL;
- PATH_FOREACH_PREFIX_MORE(prefix, p) {
+ prefix = alloca(strlen(path) + 1);
+ PATH_FOREACH_PREFIX_MORE(prefix, path) {
Set *x;
x = hashmap_get(u->manager->units_requiring_mounts_for, prefix);
if (!x) {
- char *q;
+ _cleanup_free_ char *q = NULL;
- r = hashmap_ensure_allocated(&u->manager->units_requiring_mounts_for, &string_hash_ops);
+ r = hashmap_ensure_allocated(&u->manager->units_requiring_mounts_for, &path_hash_ops);
if (r < 0)
return r;
return -ENOMEM;
x = set_new(NULL);
- if (!x) {
- free(q);
+ if (!x)
return -ENOMEM;
- }
r = hashmap_put(u->manager->units_requiring_mounts_for, q, x);
if (r < 0) {
- free(q);
set_free(x);
return r;
}
+ q = NULL;
}
r = set_put(x, u);
assert(u);
assert(p);
+ /* Copy parameters from manager */
+ p->environment = u->manager->environment;
+ p->confirm_spawn = manager_get_confirm_spawn(u->manager);
+ p->cgroup_supported = u->manager->cgroup_supported;
+ p->prefix = u->manager->prefix;
+ SET_FLAG(p->flags, EXEC_PASS_LOG_UNIT|EXEC_CHOWN_DIRECTORIES, MANAGER_IS_SYSTEM(u->manager));
+
+ /* Copy paramaters from unit */
p->cgroup_path = u->cgroup_path;
- SET_FLAG(p->flags, EXEC_CGROUP_DELEGATE, UNIT_CGROUP_BOOL(u, delegate));
+ SET_FLAG(p->flags, EXEC_CGROUP_DELEGATE, unit_cgroup_delegate(u));
}
int unit_fork_helper_process(Unit *u, const char *name, pid_t *ret) {
return p;
}
+int unit_pid_attachable(Unit *u, pid_t pid, sd_bus_error *error) {
+ int r;
+
+ assert(u);
+
+ /* Checks whether the specified PID is generally good for attaching, i.e. a valid PID, not our manager itself,
+ * and not a kernel thread either */
+
+ /* First, a simple range check */
+ if (!pid_is_valid(pid))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Process identifier " PID_FMT " is not valid.", pid);
+
+ /* Some extra safety check */
+ if (pid == 1 || pid == getpid_cached())
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Process " PID_FMT " is a manager processs, refusing.", pid);
+
+ /* Don't even begin to bother with kernel threads */
+ r = is_kernel_thread(pid);
+ if (r == -ESRCH)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_UNIX_PROCESS_ID_UNKNOWN, "Process with ID " PID_FMT " does not exist.", pid);
+ if (r < 0)
+ return sd_bus_error_set_errnof(error, r, "Failed to determine whether process " PID_FMT " is a kernel thread: %m", pid);
+ if (r > 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Process " PID_FMT " is a kernel thread, refusing.", pid);
+
+ return 0;
+}
+
static const char* const collect_mode_table[_COLLECT_MODE_MAX] = {
[COLLECT_INACTIVE] = "inactive",
[COLLECT_INACTIVE_OR_FAILED] = "inactive-or-failed",