diff options
author | Adrian Szyndela <adrian.s@samsung.com> | 2020-03-26 16:03:37 +0100 |
---|---|---|
committer | Adrian Szyndela <adrian.s@samsung.com> | 2020-03-26 16:03:37 +0100 |
commit | 0dbfabccd0e6d8fecc58a19bb5b4db2842e88364 (patch) | |
tree | aaac28e9f4d8588f149f12f8a2f70e866e26ed6c /src/core/unit.c | |
parent | 6926d6fb85cdf9148d949c6e29fad3651c2efb4b (diff) | |
parent | 738ab7502afb7663d9aacdd73e79025aa7cd0a9b (diff) | |
download | systemd-0dbfabccd0e6d8fecc58a19bb5b4db2842e88364.tar.gz systemd-0dbfabccd0e6d8fecc58a19bb5b4db2842e88364.tar.bz2 systemd-0dbfabccd0e6d8fecc58a19bb5b4db2842e88364.zip |
Merge v238 into tizen
systemd 238
Diffstat (limited to 'src/core/unit.c')
-rw-r--r-- | src/core/unit.c | 297 |
1 files changed, 157 insertions, 140 deletions
diff --git a/src/core/unit.c b/src/core/unit.c index 60963638de..fe1bb028ce 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -187,7 +187,7 @@ static void unit_init(Unit *u) { 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); @@ -337,20 +337,25 @@ int unit_set_description(Unit *u, const char *description) { return 0; } -bool unit_check_gc(Unit *u) { +bool unit_may_gc(Unit *u) { UnitActiveState state; int r; assert(u); - /* Checks whether the unit is ready to be unloaded for garbage collection. Returns true, when the unit shall - * stay around, false if there's no reason to keep it loaded. */ + /* Checks whether the unit is ready to be unloaded for garbage collection. + * Returns true when the unit may be collected, and false if there's some + * reason to keep it loaded. + * + * References from other units are *not* checked here. Instead, this is done + * in unit_gc_sweep(), but using markers to properly collect dependency loops. + */ if (u->job) - return true; + return false; if (u->nop_job) - return true; + return false; state = unit_active_state(u); @@ -360,26 +365,23 @@ bool unit_check_gc(Unit *u) { UNIT_VTABLE(u)->release_resources(u); if (u->perpetual) - return true; - - if (u->refs) - return true; + return false; if (sd_bus_track_count(u->bus_track) > 0) - return true; + return false; /* But we keep the unit object around for longer when it is referenced or configured to not be gc'ed */ switch (u->collect_mode) { case COLLECT_INACTIVE: if (state != UNIT_INACTIVE) - return true; + return false; break; case COLLECT_INACTIVE_OR_FAILED: if (!IN_SET(state, UNIT_INACTIVE, UNIT_FAILED)) - return true; + return false; break; @@ -395,14 +397,13 @@ bool unit_check_gc(Unit *u) { if (r < 0) log_unit_debug_errno(u, r, "Failed to determine whether cgroup %s is empty: %m", u->cgroup_path); if (r <= 0) - return true; + return false; } - if (UNIT_VTABLE(u)->check_gc) - if (UNIT_VTABLE(u)->check_gc(u)) - return true; + if (UNIT_VTABLE(u)->may_gc && !UNIT_VTABLE(u)->may_gc(u)) + return false; - return false; + return true; } void unit_add_to_load_queue(Unit *u) { @@ -432,7 +433,7 @@ void unit_add_to_gc_queue(Unit *u) { if (u->in_gc_queue || u->in_cleanup_queue) return; - if (unit_check_gc(u)) + if (!unit_may_gc(u)) return; LIST_PREPEND(gc_queue, u->manager->gc_unit_queue, u); @@ -610,6 +611,25 @@ void unit_free(Unit *u) { 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); @@ -619,9 +639,6 @@ void unit_free(Unit *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); @@ -631,18 +648,24 @@ void unit_free(Unit *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); + safe_close(u->ip_accounting_ingress_map_fd); + safe_close(u->ip_accounting_egress_map_fd); - if (!MANAGER_IS_RELOADING(u->manager)) - unit_unlink_state_files(u); + 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); - unit_unref_uid_gid(u, false); + 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); - (void) manager_update_failed_units(u->manager, u, false); - set_remove(u->manager->startup_units, u); + condition_free_list(u->conditions); + condition_free_list(u->asserts); free(u->description); strv_free(u->documentation); @@ -655,29 +678,8 @@ void unit_free(Unit *u) { 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) - unit_ref_unset(u->refs); - - 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); } @@ -897,8 +899,8 @@ int unit_merge(Unit *u, Unit *other) { return r; /* Redirect all references */ - while (other->refs) - unit_ref_set(other->refs, u); + while (other->refs_by_target) + unit_ref_set(other->refs_by_target, other->refs_by_target->source, u); /* Merge dependencies */ for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) @@ -1120,7 +1122,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { "%s\tActive Enter Timestamp: %s\n" "%s\tActive Exit Timestamp: %s\n" "%s\tInactive Enter Timestamp: %s\n" - "%s\tGC Check Good: %s\n" + "%s\tMay GC: %s\n" "%s\tNeed Daemon Reload: %s\n" "%s\tTransient: %s\n" "%s\tPerpetual: %s\n" @@ -1138,7 +1140,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { prefix, strna(format_timestamp(timestamp2, sizeof(timestamp2), u->active_enter_timestamp.realtime)), prefix, strna(format_timestamp(timestamp3, sizeof(timestamp3), u->active_exit_timestamp.realtime)), prefix, strna(format_timestamp(timestamp4, sizeof(timestamp4), u->inactive_enter_timestamp.realtime)), - prefix, yes_no(unit_check_gc(u)), + prefix, yes_no(unit_may_gc(u)), prefix, yes_no(unit_need_daemon_reload(u)), prefix, yes_no(u->transient), prefix, yes_no(u->perpetual), @@ -1698,7 +1700,7 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) { 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 : @@ -2327,18 +2329,16 @@ static void unit_update_on_console(Unit *u) { } 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; @@ -2461,15 +2461,8 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su } } - /* 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)) { @@ -2482,8 +2475,6 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su 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) @@ -2513,17 +2504,15 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su } 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); @@ -2977,8 +2966,7 @@ int unit_set_slice(Unit *u, Unit *slice) { if (UNIT_ISSET(u->slice) && u->cgroup_realized) return -EBUSY; - unit_ref_unset(&u->slice); - unit_ref_set(&u->slice, slice); + unit_ref_set(&u->slice, u, slice); return 1; } @@ -3177,18 +3165,9 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) { assert(fds); if (unit_can_serialize(u)) { - ExecRuntime *rt; - r = UNIT_VTABLE(u)->serialize(u, f, fds); if (r < 0) return r; - - rt = unit_get_exec_runtime(u); - if (rt) { - r = exec_runtime_serialize(u, rt, f, fds); - if (r < 0) - return r; - } } dual_timestamp_serialize(f, "state-change-timestamp", &u->state_change_timestamp); @@ -3334,18 +3313,12 @@ void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *f } int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { - ExecRuntime **rt = NULL; - size_t offset; int r; assert(u); assert(f); assert(fds); - offset = UNIT_VTABLE(u)->exec_runtime_offset; - if (offset > 0) - rt = (ExecRuntime**) ((uint8_t*) u + offset); - for (;;) { char line[LINE_MAX], *l, *v; CGroupIPAccountingMetric m; @@ -3605,18 +3578,16 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { } if (unit_can_serialize(u)) { - if (rt) { - r = exec_runtime_deserialize_item(u, rt, l, v, fds); - if (r < 0) { - log_unit_warning(u, "Failed to deserialize runtime parameter '%s', ignoring.", l); - continue; - } - - /* Returns positive if key was handled by the call */ - if (r > 0) - continue; + r = exec_runtime_deserialize_compat(u, l, v, fds); + if (r < 0) { + log_unit_warning(u, "Failed to deserialize runtime parameter '%s', ignoring.", l); + continue; } + /* Returns positive if key was handled by the call */ + if (r > 0) + continue; + r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds); if (r < 0) log_unit_warning(u, "Failed to deserialize unit parameter '%s', ignoring.", l); @@ -3983,7 +3954,7 @@ UnitFileState unit_get_unit_file_state(Unit *u) { r = unit_file_get_state( u->manager->unit_file_scope, NULL, - basename(u->fragment_path), + u->id, &u->unit_file_state); if (r < 0) u->unit_file_state = UNIT_FILE_BAD; @@ -4004,30 +3975,32 @@ int unit_get_unit_file_preset(Unit *u) { return u->unit_file_preset; } -Unit* unit_ref_set(UnitRef *ref, Unit *u) { +Unit* unit_ref_set(UnitRef *ref, Unit *source, Unit *target) { assert(ref); - assert(u); + assert(source); + assert(target); - if (ref->unit) + if (ref->target) unit_ref_unset(ref); - ref->unit = u; - LIST_PREPEND(refs, u->refs, ref); - return u; + ref->source = source; + ref->target = target; + LIST_PREPEND(refs_by_target, target->refs_by_target, ref); + return target; } void unit_ref_unset(UnitRef *ref) { assert(ref); - if (!ref->unit) + if (!ref->target) return; /* We are about to drop a reference to the unit, make sure the garbage collection has a look at it as it might * be unreferenced now. */ - unit_add_to_gc_queue(ref->unit); + unit_add_to_gc_queue(ref->target); - LIST_REMOVE(refs, ref->unit->refs, ref); - ref->unit = NULL; + LIST_REMOVE(refs_by_target, ref->target->refs_by_target, ref); + ref->source = ref->target = NULL; } static int user_from_unit_name(Unit *u, char **ret) { @@ -4559,22 +4532,15 @@ int unit_kill_context( } 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) { @@ -4612,7 +4578,7 @@ int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask) 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; @@ -4649,7 +4615,7 @@ int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask) if (!x) { char *q; - 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; @@ -4685,6 +4651,7 @@ int unit_setup_exec_runtime(Unit *u) { Unit *other; Iterator i; void *v; + int r; offset = UNIT_VTABLE(u)->exec_runtime_offset; assert(offset > 0); @@ -4696,15 +4663,12 @@ int unit_setup_exec_runtime(Unit *u) { /* Try to get it from somebody else */ HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_JOINS_NAMESPACE_OF], i) { - - *rt = unit_get_exec_runtime(other); - if (*rt) { - exec_runtime_ref(*rt); - return 0; - } + r = exec_runtime_acquire(u->manager, NULL, other->id, false, rt); + if (r == 1) + return 1; } - return exec_runtime_make(rt, unit_get_exec_context(u), u->id); + return exec_runtime_acquire(u->manager, unit_get_exec_context(u), u->id, true, rt); } int unit_setup_dynamic_creds(Unit *u) { @@ -4746,7 +4710,7 @@ void unit_warn_if_dir_nonempty(Unit *u, const char* where) { assert(where); r = dir_is_empty(where); - if (r > 0) + if (r > 0 || r == -ENOTDIR) return; if (r < 0) { log_unit_warning_errno(u, r, "Failed to check directory %s: %m", where); @@ -5026,8 +4990,16 @@ void unit_set_exec_params(Unit *u, ExecParameters *p) { 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) { @@ -5376,6 +5348,51 @@ bool unit_needs_console(Unit *u) { return exec_context_may_touch_console(ec); } +const char *unit_label_path(Unit *u) { + const char *p; + + /* Returns the file system path to use for MAC access decisions, i.e. the file to read the SELinux label off + * when validating access checks. */ + + p = u->source_path ?: u->fragment_path; + if (!p) + return NULL; + + /* If a unit is masked, then don't read the SELinux label of /dev/null, as that really makes no sense */ + if (path_equal(p, "/dev/null")) + return NULL; + + 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", |