/* Frees the hashmap and makes sure we are dropped from the inverse pointers */
HASHMAP_FOREACH_KEY(v, other, h, i) {
- UnitDependency d;
-
- for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
+ for (UnitDependency d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
hashmap_remove(other->dependencies[d], u);
unit_add_to_gc_queue(other);
}
void unit_free(Unit *u) {
- UnitDependency d;
Iterator i;
char *t;
job_free(j);
}
- for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
+ for (UnitDependency d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
bidi_set_free(u, u->dependencies[d]);
if (u->on_console)
assert(d < _UNIT_DEPENDENCY_MAX);
/* Fix backwards pointers. Let's iterate through all dependent units of the other unit. */
- HASHMAP_FOREACH_KEY(v, back, other->dependencies[d], i) {
- UnitDependency k;
-
- /* Let's now iterate through the dependencies of that dependencies of the other units, looking for
- * pointers back, and let's fix them up, to instead point to 'u'. */
+ HASHMAP_FOREACH_KEY(v, back, other->dependencies[d], i)
- for (k = 0; k < _UNIT_DEPENDENCY_MAX; k++) {
+ /* Let's now iterate through the dependencies of that dependencies of the other units,
+ * looking for pointers back, and let's fix them up, to instead point to 'u'. */
+ for (UnitDependency k = 0; k < _UNIT_DEPENDENCY_MAX; k++)
if (back == u) {
/* Do not add dependencies between u and itself. */
if (hashmap_remove(back->dependencies[k], other))
maybe_warn_about_dependency(u, other_id, k);
} else {
- UnitDependencyInfo di_u, di_other, di_merged;
+ UnitDependencyInfo di_u, di_other;
/* Let's drop this dependency between "back" and "other", and let's create it between
* "back" and "u" instead. Let's merge the bit masks of the dependency we are moving,
di_u.data = hashmap_get(back->dependencies[k], u);
- di_merged = (UnitDependencyInfo) {
+ UnitDependencyInfo di_merged = {
.origin_mask = di_u.origin_mask | di_other.origin_mask,
.destination_mask = di_u.destination_mask | di_other.destination_mask,
};
/* assert_se(hashmap_remove_and_replace(back->dependencies[k], other, u, di_merged.data) >= 0); */
}
- }
-
- }
/* Also do not move dependencies on u to itself */
back = hashmap_remove(other->dependencies[d], u);
}
int unit_merge(Unit *u, Unit *other) {
- UnitDependency d;
const char *other_id = NULL;
int r;
other_id = strdupa(other->id);
/* Make reservations to ensure merge_dependencies() won't fail */
- for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) {
+ for (UnitDependency 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
unit_ref_set(other->refs_by_target, other->refs_by_target->source, u);
/* Merge dependencies */
- for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
+ for (UnitDependency d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
merge_dependencies(u, other, other_id, d);
other->load_state = UNIT_MERGED;
if (!IN_SET(c->std_output,
EXEC_OUTPUT_JOURNAL, EXEC_OUTPUT_JOURNAL_AND_CONSOLE,
- EXEC_OUTPUT_KMSG, EXEC_OUTPUT_KMSG_AND_CONSOLE,
- EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_SYSLOG_AND_CONSOLE) &&
+ EXEC_OUTPUT_KMSG, EXEC_OUTPUT_KMSG_AND_CONSOLE) &&
!IN_SET(c->std_error,
EXEC_OUTPUT_JOURNAL, EXEC_OUTPUT_JOURNAL_AND_CONSOLE,
- EXEC_OUTPUT_KMSG, EXEC_OUTPUT_KMSG_AND_CONSOLE,
- EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_SYSLOG_AND_CONSOLE) &&
+ EXEC_OUTPUT_KMSG, EXEC_OUTPUT_KMSG_AND_CONSOLE) &&
!c->log_namespace)
return 0;
void unit_dump(Unit *u, FILE *f, const char *prefix) {
char *t, **j;
- UnitDependency d;
Iterator i;
const char *prefix2;
char timestamp[5][FORMAT_TIMESTAMP_MAX], timespan[FORMAT_TIMESPAN_MAX];
prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->assert_timestamp.realtime)),
prefix, yes_no(u->assert_result));
- for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) {
+ for (UnitDependency d = 0; d < _UNIT_DEPENDENCY_MAX; d++) {
UnitDependencyInfo di;
Unit *other;
* target unit needlessly. But we cannot be sure which drops-ins have already
* been loaded and which not, at least without doing complicated book-keeping,
* so let's always reread all drop-ins. */
- return unit_load_dropin(unit_follow_merge(u));
+ r = unit_load_dropin(unit_follow_merge(u));
+ if (r < 0)
+ return r;
+
+ if (u->source_path) {
+ struct stat st;
+
+ if (stat(u->source_path, &st) >= 0)
+ u->source_mtime = timespec_load(&st.st_mtim);
+ else
+ u->source_mtime = 0;
+ }
+
+ return 0;
}
void unit_add_to_target_deps_queue(Unit *u) {
}
static int unit_add_slice_dependencies(Unit *u) {
- UnitDependencyMask mask;
assert(u);
if (!UNIT_HAS_CGROUP_CONTEXT(u))
/* Slice units are implicitly ordered against their parent slices (as this relationship is encoded in the
name), while all other units are ordered based on configuration (as in their case Slice= configures the
relationship). */
- mask = u->type == UNIT_SLICE ? UNIT_DEPENDENCY_IMPLICIT : UNIT_DEPENDENCY_FILE;
+ UnitDependencyMask mask = u->type == UNIT_SLICE ? UNIT_DEPENDENCY_IMPLICIT : UNIT_DEPENDENCY_FILE;
if (UNIT_ISSET(u->slice))
return unit_add_two_dependencies(u, UNIT_AFTER, UNIT_REQUIRES, UNIT_DEREF(u->slice), true, mask);
}
static bool unit_test_condition(Unit *u) {
+ _cleanup_strv_free_ char **env = NULL;
+ int r;
+
assert(u);
dual_timestamp_get(&u->condition_timestamp);
- u->condition_result = condition_test_list(u->conditions, condition_type_to_string, log_unit_internal, u);
- unit_add_to_dbus_queue(u);
+ r = manager_get_effective_environment(u->manager, &env);
+ if (r < 0) {
+ log_unit_error_errno(u, r, "Failed to determine effective environment: %m");
+ u->condition_result = CONDITION_ERROR;
+ } else
+ u->condition_result = condition_test_list(
+ u->conditions,
+ env,
+ condition_type_to_string,
+ log_unit_internal,
+ u);
+ unit_add_to_dbus_queue(u);
return u->condition_result;
}
static bool unit_test_assert(Unit *u) {
+ _cleanup_strv_free_ char **env = NULL;
+ int r;
+
assert(u);
dual_timestamp_get(&u->assert_timestamp);
- u->assert_result = condition_test_list(u->asserts, assert_type_to_string, log_unit_internal, u);
- unit_add_to_dbus_queue(u);
+ r = manager_get_effective_environment(u->manager, &env);
+ if (r < 0) {
+ log_unit_error_errno(u, r, "Failed to determine effective environment: %m");
+ u->assert_result = CONDITION_ERROR;
+ } else
+ u->assert_result = condition_test_list(
+ u->asserts,
+ env,
+ assert_type_to_string,
+ log_unit_internal,
+ u);
+ unit_add_to_dbus_queue(u);
return u->assert_result;
}
if (m == 0) {
/* The array is now empty, remove the entire entry */
- assert(hashmap_remove(u->manager->watch_pids, PID_TO_PTR(-pid)) == array);
+ assert_se(hashmap_remove(u->manager->watch_pids, PID_TO_PTR(-pid)) == array);
free(array);
}
}
return 0;
}
- if (d == UNIT_AFTER && UNIT_VTABLE(u)->refuse_after) {
- log_unit_warning(u, "Requested dependency After=%s ignored (%s units cannot be delayed).", other->id, unit_type_to_string(u->type));
- return 0;
- }
-
- if (d == UNIT_BEFORE && UNIT_VTABLE(other)->refuse_after) {
- log_unit_warning(u, "Requested dependency Before=%s ignored (%s units cannot be delayed).", other->id, unit_type_to_string(other->type));
+ /* Note that ordering a device unit after a unit is permitted since it
+ * allows to start its job running timeout at a specific time. */
+ if (d == UNIT_BEFORE && other->type == UNIT_DEVICE) {
+ log_unit_warning(u, "Dependency Before=%s ignored (.device units cannot be delayed)", other->id);
return 0;
}
return unit_dbus_path_from_name(u->invocation_id_string);
}
+static int unit_set_invocation_id(Unit *u, sd_id128_t id) {
+ int r;
+
+ assert(u);
+
+ /* Set the invocation ID for this unit. If we cannot, this will not roll back, but reset the whole thing. */
+
+ if (sd_id128_equal(u->invocation_id, id))
+ return 0;
+
+ if (!sd_id128_is_null(u->invocation_id))
+ (void) hashmap_remove_value(u->manager->units_by_invocation_id, &u->invocation_id, u);
+
+ if (sd_id128_is_null(id)) {
+ r = 0;
+ goto reset;
+ }
+
+ r = hashmap_ensure_allocated(&u->manager->units_by_invocation_id, &id128_hash_ops);
+ if (r < 0)
+ goto reset;
+
+ u->invocation_id = id;
+ sd_id128_to_string(id, u->invocation_id_string);
+
+ r = hashmap_put(u->manager->units_by_invocation_id, &u->invocation_id, u);
+ if (r < 0)
+ goto reset;
+
+ return 0;
+
+reset:
+ u->invocation_id = SD_ID128_NULL;
+ u->invocation_id_string[0] = 0;
+ return r;
+}
+
int unit_set_slice(Unit *u, Unit *slice) {
assert(u);
assert(slice);
u->unit_file_preset = unit_file_query_preset(
u->manager->unit_file_scope,
NULL,
- basename(u->fragment_path));
+ basename(u->fragment_path),
+ NULL);
return u->unit_file_preset;
}
/* Make sure the drop-in dir is registered in our path cache. This way we don't need to stupidly
* recreate the cache after every drop-in we write. */
if (u->manager->unit_path_cache) {
- r = set_put_strdup(u->manager->unit_path_cache, p);
+ r = set_put_strdup(&u->manager->unit_path_cache, p);
if (r < 0)
return r;
}
if (!pid_set)
return -ENOMEM;
- cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path,
- SIGHUP,
- CGROUP_IGNORE_SELF,
- pid_set,
- NULL, NULL);
+ (void) cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path,
+ SIGHUP,
+ CGROUP_IGNORE_SELF,
+ pid_set,
+ NULL, NULL);
}
}
}
unit_add_to_dbus_queue(u);
}
-int unit_set_invocation_id(Unit *u, sd_id128_t id) {
- int r;
-
- assert(u);
-
- /* Set the invocation ID for this unit. If we cannot, this will not roll back, but reset the whole thing. */
-
- if (sd_id128_equal(u->invocation_id, id))
- return 0;
-
- if (!sd_id128_is_null(u->invocation_id))
- (void) hashmap_remove_value(u->manager->units_by_invocation_id, &u->invocation_id, u);
-
- if (sd_id128_is_null(id)) {
- r = 0;
- goto reset;
- }
-
- r = hashmap_ensure_allocated(&u->manager->units_by_invocation_id, &id128_hash_ops);
- if (r < 0)
- goto reset;
-
- u->invocation_id = id;
- sd_id128_to_string(id, u->invocation_id_string);
-
- r = hashmap_put(u->manager->units_by_invocation_id, &u->invocation_id, u);
- if (r < 0)
- goto reset;
-
- return 0;
-
-reset:
- u->invocation_id = SD_ID128_NULL;
- u->invocation_id_string[0] = 0;
- return r;
-}
-
int unit_acquire_invocation_id(Unit *u) {
sd_id128_t id;
int r;
}
void unit_remove_dependencies(Unit *u, UnitDependencyMask mask) {
- UnitDependency d;
-
assert(u);
/* Removes all dependencies u has on other units marked for ownership by 'mask'. */
if (mask == 0)
return;
- for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) {
+ for (UnitDependency d = 0; d < _UNIT_DEPENDENCY_MAX; d++) {
bool done;
do {
done = true;
HASHMAP_FOREACH_KEY(di.data, other, u->dependencies[d], i) {
- UnitDependency q;
-
if ((di.origin_mask & ~mask) == di.origin_mask)
continue;
di.origin_mask &= ~mask;
* all dependency types on the other unit and delete all those which point to us and
* have the right mask set. */
- for (q = 0; q < _UNIT_DEPENDENCY_MAX; q++) {
+ for (UnitDependency q = 0; q < _UNIT_DEPENDENCY_MAX; q++) {
UnitDependencyInfo dj;
dj.data = hashmap_get(other->dependencies[q], u);
return 0;
}
-static int log_leftover(pid_t pid, int sig, void *userdata) {
+static bool ignore_leftover_process(const char *comm) {
+ return comm && comm[0] == '('; /* Most likely our own helper process (PAM?), ignore */
+}
+
+int unit_log_leftover_process_start(pid_t pid, int sig, void *userdata) {
_cleanup_free_ char *comm = NULL;
(void) get_process_comm(pid, &comm);
- if (comm && comm[0] == '(') /* Most likely our own helper process (PAM?), ignore */
+ if (ignore_leftover_process(comm))
return 0;
+ /* During start we print a warning */
+
log_unit_warning(userdata,
"Found left-over process " PID_FMT " (%s) in control group while starting unit. Ignoring.\n"
"This usually indicates unclean termination of a previous run, or service implementation deficiencies.",
return 1;
}
-int unit_warn_leftover_processes(Unit *u) {
+int unit_log_leftover_process_stop(pid_t pid, int sig, void *userdata) {
+ _cleanup_free_ char *comm = NULL;
+
+ (void) get_process_comm(pid, &comm);
+
+ if (ignore_leftover_process(comm))
+ return 0;
+
+ /* During stop we only print an informational message */
+
+ log_unit_info(userdata,
+ "Unit process " PID_FMT " (%s) remains running after unit stopped.",
+ pid, strna(comm));
+
+ return 1;
+}
+
+int unit_warn_leftover_processes(Unit *u, cg_kill_log_func_t log_func) {
assert(u);
(void) unit_pick_cgroup_path(u);
if (!u->cgroup_path)
return 0;
- return cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, 0, 0, NULL, log_leftover, u);
+ return cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, 0, 0, NULL, log_func, u);
}
bool unit_needs_console(Unit *u) {