#include "log.h"
#include "macro.h"
#include "missing_audit.h"
-#include "mkdir.h"
+#include "mkdir-label.h"
#include "path-util.h"
#include "process-util.h"
#include "rm-rf.h"
return 0;
}
+static bool unit_success_failure_handler_has_jobs(Unit *unit) {
+ Unit *other;
+
+ UNIT_FOREACH_DEPENDENCY(other, unit, UNIT_ATOM_ON_SUCCESS)
+ if (other->job || other->nop_job)
+ return true;
+
+ UNIT_FOREACH_DEPENDENCY(other, unit, UNIT_ATOM_ON_FAILURE)
+ if (other->job || other->nop_job)
+ return true;
+
+ return false;
+}
+
bool unit_may_gc(Unit *u) {
UnitActiveState state;
int r;
* in unit_gc_sweep(), but using markers to properly collect dependency loops.
*/
- if (u->job)
- return false;
-
- if (u->nop_job)
+ if (u->job || u->nop_job)
return false;
state = unit_active_state(u);
assert_not_reached();
}
+ /* Check if any OnFailure= or on Success= jobs may be pending */
+ if (unit_success_failure_handler_has_jobs(u))
+ return false;
+
if (u->cgroup_path) {
/* If the unit has a cgroup, then check whether there's anything in it. If so, we should stay
* around. Units with active processes should never be collected. */
return unit_start(following);
}
- /* Check start rate limiting early so that failure conditions don't cause us to enter a busy loop. */
- if (UNIT_VTABLE(u)->test_start_limit) {
- r = UNIT_VTABLE(u)->test_start_limit(u);
+ /* Check our ability to start early so that failure conditions don't cause us to enter a busy loop. */
+ if (UNIT_VTABLE(u)->can_start) {
+ r = UNIT_VTABLE(u)->can_start(u);
if (r < 0)
return r;
}
continue;
if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
- if (*ret_culprit)
+ if (ret_culprit)
*ret_culprit = other;
return true;
UnitDependencyAtom atom,
JobMode job_mode) {
- bool logged = false;
+ int n_jobs = -1;
Unit *other;
int r;
UNIT_FOREACH_DEPENDENCY(other, u, atom) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- if (!logged) {
+ if (n_jobs < 0) {
log_unit_info(u, "Triggering %s dependencies.", dependency_name);
- logged = true;
+ n_jobs = 0;
}
r = manager_add_job(u->manager, JOB_START, other, job_mode, NULL, &error, NULL);
log_unit_warning_errno(
u, r, "Failed to enqueue %s job, ignoring: %s",
dependency_name, bus_error_message(&error, r));
+ n_jobs ++;
}
- if (logged)
- log_unit_debug(u, "Triggering %s dependencies done.", dependency_name);
+ if (n_jobs >= 0)
+ log_unit_debug(u, "Triggering %s dependencies done (%u %s).",
+ dependency_name, n_jobs, n_jobs == 1 ? "job" : "jobs");
}
void unit_trigger_notify(Unit *u) {
message_parts[n_message_parts++] = t;
log_level = raise_level(log_level,
- nsec > NOTICEWORTHY_CPU_NSEC,
- nsec > MENTIONWORTHY_CPU_NSEC);
+ nsec > MENTIONWORTHY_CPU_NSEC,
+ nsec > NOTICEWORTHY_CPU_NSEC);
}
for (CGroupIOAccountingMetric k = 0; k < _CGROUP_IO_ACCOUNTING_METRIC_MAX; k++) {
UnitDependencyMask mask) {
static const UnitDependency inverse_table[_UNIT_DEPENDENCY_MAX] = {
- [UNIT_REQUIRES] = UNIT_REQUIRED_BY,
- [UNIT_REQUISITE] = UNIT_REQUISITE_OF,
- [UNIT_WANTS] = UNIT_WANTED_BY,
- [UNIT_BINDS_TO] = UNIT_BOUND_BY,
- [UNIT_PART_OF] = UNIT_CONSISTS_OF,
- [UNIT_UPHOLDS] = UNIT_UPHELD_BY,
- [UNIT_REQUIRED_BY] = UNIT_REQUIRES,
- [UNIT_REQUISITE_OF] = UNIT_REQUISITE,
- [UNIT_WANTED_BY] = UNIT_WANTS,
- [UNIT_BOUND_BY] = UNIT_BINDS_TO,
- [UNIT_CONSISTS_OF] = UNIT_PART_OF,
- [UNIT_UPHELD_BY] = UNIT_UPHOLDS,
- [UNIT_CONFLICTS] = UNIT_CONFLICTED_BY,
- [UNIT_CONFLICTED_BY] = UNIT_CONFLICTS,
- [UNIT_BEFORE] = UNIT_AFTER,
- [UNIT_AFTER] = UNIT_BEFORE,
- [UNIT_ON_SUCCESS] = UNIT_ON_SUCCESS_OF,
- [UNIT_ON_SUCCESS_OF] = UNIT_ON_SUCCESS,
- [UNIT_ON_FAILURE] = UNIT_ON_FAILURE_OF,
- [UNIT_ON_FAILURE_OF] = UNIT_ON_FAILURE,
- [UNIT_TRIGGERS] = UNIT_TRIGGERED_BY,
- [UNIT_TRIGGERED_BY] = UNIT_TRIGGERS,
- [UNIT_PROPAGATES_RELOAD_TO] = UNIT_RELOAD_PROPAGATED_FROM,
+ [UNIT_REQUIRES] = UNIT_REQUIRED_BY,
+ [UNIT_REQUISITE] = UNIT_REQUISITE_OF,
+ [UNIT_WANTS] = UNIT_WANTED_BY,
+ [UNIT_BINDS_TO] = UNIT_BOUND_BY,
+ [UNIT_PART_OF] = UNIT_CONSISTS_OF,
+ [UNIT_UPHOLDS] = UNIT_UPHELD_BY,
+ [UNIT_REQUIRED_BY] = UNIT_REQUIRES,
+ [UNIT_REQUISITE_OF] = UNIT_REQUISITE,
+ [UNIT_WANTED_BY] = UNIT_WANTS,
+ [UNIT_BOUND_BY] = UNIT_BINDS_TO,
+ [UNIT_CONSISTS_OF] = UNIT_PART_OF,
+ [UNIT_UPHELD_BY] = UNIT_UPHOLDS,
+ [UNIT_CONFLICTS] = UNIT_CONFLICTED_BY,
+ [UNIT_CONFLICTED_BY] = UNIT_CONFLICTS,
+ [UNIT_BEFORE] = UNIT_AFTER,
+ [UNIT_AFTER] = UNIT_BEFORE,
+ [UNIT_ON_SUCCESS] = UNIT_ON_SUCCESS_OF,
+ [UNIT_ON_SUCCESS_OF] = UNIT_ON_SUCCESS,
+ [UNIT_ON_FAILURE] = UNIT_ON_FAILURE_OF,
+ [UNIT_ON_FAILURE_OF] = UNIT_ON_FAILURE,
+ [UNIT_TRIGGERS] = UNIT_TRIGGERED_BY,
+ [UNIT_TRIGGERED_BY] = UNIT_TRIGGERS,
+ [UNIT_PROPAGATES_RELOAD_TO] = UNIT_RELOAD_PROPAGATED_FROM,
[UNIT_RELOAD_PROPAGATED_FROM] = UNIT_PROPAGATES_RELOAD_TO,
- [UNIT_PROPAGATES_STOP_TO] = UNIT_STOP_PROPAGATED_FROM,
- [UNIT_STOP_PROPAGATED_FROM] = UNIT_PROPAGATES_STOP_TO,
- [UNIT_JOINS_NAMESPACE_OF] = UNIT_JOINS_NAMESPACE_OF, /* symmetric! 👓 */
- [UNIT_REFERENCES] = UNIT_REFERENCED_BY,
- [UNIT_REFERENCED_BY] = UNIT_REFERENCES,
- [UNIT_IN_SLICE] = UNIT_SLICE_OF,
- [UNIT_SLICE_OF] = UNIT_IN_SLICE,
+ [UNIT_PROPAGATES_STOP_TO] = UNIT_STOP_PROPAGATED_FROM,
+ [UNIT_STOP_PROPAGATED_FROM] = UNIT_PROPAGATES_STOP_TO,
+ [UNIT_JOINS_NAMESPACE_OF] = UNIT_JOINS_NAMESPACE_OF, /* symmetric! 👓 */
+ [UNIT_REFERENCES] = UNIT_REFERENCED_BY,
+ [UNIT_REFERENCED_BY] = UNIT_REFERENCES,
+ [UNIT_IN_SLICE] = UNIT_SLICE_OF,
+ [UNIT_SLICE_OF] = UNIT_IN_SLICE,
};
Unit *original_u = u, *original_other = other;
UnitDependencyAtom a;
int set_unit_path(const char *p) {
/* This is mostly for debug purposes */
- if (setenv("SYSTEMD_UNIT_PATH", p, 1) < 0)
- return -errno;
-
- return 0;
+ return RET_NERRNO(setenv("SYSTEMD_UNIT_PATH", p, 1));
}
char *unit_dbus_path(Unit *u) {
return r;
}
-int unit_set_slice(Unit *u, Unit *slice, UnitDependencyMask mask) {
+int unit_set_slice(Unit *u, Unit *slice) {
int r;
assert(u);
if (UNIT_GET_SLICE(u) && u->cgroup_realized)
return -EBUSY;
- r = unit_add_dependency(u, UNIT_IN_SLICE, slice, true, mask);
+ /* Remove any slices assigned prior; we should only have one UNIT_IN_SLICE dependency */
+ if (UNIT_GET_SLICE(u))
+ unit_remove_dependencies(u, UNIT_DEPENDENCY_SLICE_PROPERTY);
+
+ r = unit_add_dependency(u, UNIT_IN_SLICE, slice, true, UNIT_DEPENDENCY_SLICE_PROPERTY);
if (r < 0)
return r;
if (r < 0)
return r;
- return unit_set_slice(u, slice, UNIT_DEPENDENCY_FILE);
+ return unit_set_slice(u, slice);
}
const char *unit_slice_name(Unit *u) {
e = sd_bus_message_get_error(message);
if (e) {
- if (!sd_bus_error_has_name(e, "org.freedesktop.DBus.Error.NameHasNoOwner"))
- log_unit_error(u, "Unexpected error response from GetNameOwner(): %s", e->message);
+ if (!sd_bus_error_has_name(e, "org.freedesktop.DBus.Error.NameHasNoOwner")) {
+ r = sd_bus_error_get_errno(e);
+ log_unit_error_errno(u, r,
+ "Unexpected error response from GetNameOwner(): %s",
+ bus_error_message(e, r));
+ }
new_owner = NULL;
} else {
}
Condition *unit_find_failed_condition(Unit *u) {
- Condition *c, *failed_trigger = NULL;
+ Condition *failed_trigger = NULL;
bool has_succeeded_trigger = false;
if (u->condition_result)
return failed_trigger && !has_succeeded_trigger ? failed_trigger : NULL;
}
-bool unit_has_failed_condition_or_assert(Unit *u) {
- if (dual_timestamp_is_set(&u->condition_timestamp) && !u->condition_result)
- return true;
-
- if (dual_timestamp_is_set(&u->assert_timestamp) && !u->assert_result)
- return true;
-
- return false;
-}
-
static const char* const collect_mode_table[_COLLECT_MODE_MAX] = {
[COLLECT_INACTIVE] = "inactive",
[COLLECT_INACTIVE_OR_FAILED] = "inactive-or-failed",