/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "unit-dependency-atom.h" static const UnitDependencyAtom atom_map[_UNIT_DEPENDENCY_MAX] = { /* A table that maps high-level dependency types to low-level dependency "atoms". The latter actually * describe specific facets of dependency behaviour. The former combine them into one user-facing * concept. Atoms are a bit mask, though a bunch of dependency types have only a single bit set. * * Typically when the user configures a dependency they go via dependency type, but when we act on * them we go by atom. * * NB: when you add a new dependency type here, make sure to also add one to the (best-effort) * reverse table in unit_dependency_from_unique_atom() further down. */ [UNIT_REQUIRES] = UNIT_ATOM_PULL_IN_START | UNIT_ATOM_RETROACTIVE_START_REPLACE | UNIT_ATOM_ADD_STOP_WHEN_UNNEEDED_QUEUE | UNIT_ATOM_ADD_DEFAULT_TARGET_DEPENDENCY_QUEUE, [UNIT_REQUISITE] = UNIT_ATOM_PULL_IN_VERIFY | UNIT_ATOM_ADD_STOP_WHEN_UNNEEDED_QUEUE | UNIT_ATOM_ADD_DEFAULT_TARGET_DEPENDENCY_QUEUE, [UNIT_WANTS] = UNIT_ATOM_PULL_IN_START_IGNORED | UNIT_ATOM_RETROACTIVE_START_FAIL | UNIT_ATOM_ADD_STOP_WHEN_UNNEEDED_QUEUE | UNIT_ATOM_ADD_DEFAULT_TARGET_DEPENDENCY_QUEUE, [UNIT_BINDS_TO] = UNIT_ATOM_PULL_IN_START | UNIT_ATOM_RETROACTIVE_START_REPLACE | UNIT_ATOM_CANNOT_BE_ACTIVE_WITHOUT | UNIT_ATOM_ADD_STOP_WHEN_UNNEEDED_QUEUE | UNIT_ATOM_ADD_DEFAULT_TARGET_DEPENDENCY_QUEUE, [UNIT_PART_OF] = UNIT_ATOM_ADD_DEFAULT_TARGET_DEPENDENCY_QUEUE, [UNIT_UPHOLDS] = UNIT_ATOM_PULL_IN_START_IGNORED | UNIT_ATOM_RETROACTIVE_START_REPLACE | UNIT_ATOM_ADD_START_WHEN_UPHELD_QUEUE | UNIT_ATOM_ADD_STOP_WHEN_UNNEEDED_QUEUE | UNIT_ATOM_ADD_DEFAULT_TARGET_DEPENDENCY_QUEUE, [UNIT_REQUIRED_BY] = UNIT_ATOM_PROPAGATE_STOP | UNIT_ATOM_PROPAGATE_RESTART | UNIT_ATOM_PROPAGATE_START_FAILURE | UNIT_ATOM_PINS_STOP_WHEN_UNNEEDED | UNIT_ATOM_DEFAULT_TARGET_DEPENDENCIES, [UNIT_REQUISITE_OF] = UNIT_ATOM_PROPAGATE_STOP | UNIT_ATOM_PROPAGATE_RESTART | UNIT_ATOM_PROPAGATE_START_FAILURE | UNIT_ATOM_PROPAGATE_INACTIVE_START_AS_FAILURE | UNIT_ATOM_PINS_STOP_WHEN_UNNEEDED | UNIT_ATOM_DEFAULT_TARGET_DEPENDENCIES, [UNIT_WANTED_BY] = UNIT_ATOM_DEFAULT_TARGET_DEPENDENCIES | UNIT_ATOM_PINS_STOP_WHEN_UNNEEDED, [UNIT_BOUND_BY] = UNIT_ATOM_RETROACTIVE_STOP_ON_STOP | UNIT_ATOM_PROPAGATE_STOP | UNIT_ATOM_PROPAGATE_RESTART | UNIT_ATOM_PROPAGATE_START_FAILURE | UNIT_ATOM_PINS_STOP_WHEN_UNNEEDED | UNIT_ATOM_ADD_CANNOT_BE_ACTIVE_WITHOUT_QUEUE | UNIT_ATOM_DEFAULT_TARGET_DEPENDENCIES, [UNIT_UPHELD_BY] = UNIT_ATOM_START_STEADILY | UNIT_ATOM_DEFAULT_TARGET_DEPENDENCIES | UNIT_ATOM_PINS_STOP_WHEN_UNNEEDED, [UNIT_CONSISTS_OF] = UNIT_ATOM_PROPAGATE_STOP | UNIT_ATOM_PROPAGATE_RESTART, [UNIT_CONFLICTS] = UNIT_ATOM_PULL_IN_STOP | UNIT_ATOM_RETROACTIVE_STOP_ON_START, [UNIT_CONFLICTED_BY] = UNIT_ATOM_PULL_IN_STOP_IGNORED | UNIT_ATOM_RETROACTIVE_STOP_ON_START | UNIT_ATOM_PROPAGATE_STOP_FAILURE, [UNIT_PROPAGATES_STOP_TO] = UNIT_ATOM_RETROACTIVE_STOP_ON_STOP | UNIT_ATOM_PROPAGATE_STOP, /* These are simple dependency types: they consist of a single atom only */ [UNIT_ON_FAILURE] = UNIT_ATOM_ON_FAILURE, [UNIT_ON_SUCCESS] = UNIT_ATOM_ON_SUCCESS, [UNIT_ON_FAILURE_OF] = UNIT_ATOM_ON_FAILURE_OF, [UNIT_ON_SUCCESS_OF] = UNIT_ATOM_ON_SUCCESS_OF, [UNIT_BEFORE] = UNIT_ATOM_BEFORE, [UNIT_AFTER] = UNIT_ATOM_AFTER, [UNIT_TRIGGERS] = UNIT_ATOM_TRIGGERS, [UNIT_TRIGGERED_BY] = UNIT_ATOM_TRIGGERED_BY, [UNIT_PROPAGATES_RELOAD_TO] = UNIT_ATOM_PROPAGATES_RELOAD_TO, [UNIT_JOINS_NAMESPACE_OF] = UNIT_ATOM_JOINS_NAMESPACE_OF, [UNIT_REFERENCES] = UNIT_ATOM_REFERENCES, [UNIT_REFERENCED_BY] = UNIT_ATOM_REFERENCED_BY, [UNIT_IN_SLICE] = UNIT_ATOM_IN_SLICE, [UNIT_SLICE_OF] = UNIT_ATOM_SLICE_OF, /* These are dependency types without effect on our state engine. We maintain them only to make * things discoverable/debuggable as they are the inverse dependencies to some of the above. As they * have no effect of their own, they all map to no atoms at all, i.e. the value 0. */ [UNIT_RELOAD_PROPAGATED_FROM] = 0, [UNIT_STOP_PROPAGATED_FROM] = 0, }; UnitDependencyAtom unit_dependency_to_atom(UnitDependency d) { if (d < 0) return _UNIT_DEPENDENCY_ATOM_INVALID; assert(d < _UNIT_DEPENDENCY_MAX); return atom_map[d]; } UnitDependency unit_dependency_from_unique_atom(UnitDependencyAtom atom) { /* This is a "best-effort" function that maps the specified 'atom' mask to a dependency type that is * is equal to or has a superset of bits set if that's uniquely possible. The idea is that this * function is used when iterating through deps that have a specific atom: if there's exactly one * dependency type of the specific atom we don't need iterate through all deps a unit has, but can * pinpoint things directly. * * This function will return _UNIT_DEPENDENCY_INVALID in case the specified value is not known or not * uniquely defined, i.e. there are multiple dependencies with the atom or the combination set. */ switch ((int64_t) atom) { /* Note that we can't list UNIT_REQUIRES here since it's a true subset of UNIT_BINDS_TO, and * hence its atom bits not uniquely mappable. */ case UNIT_ATOM_PULL_IN_VERIFY | UNIT_ATOM_ADD_STOP_WHEN_UNNEEDED_QUEUE | UNIT_ATOM_ADD_DEFAULT_TARGET_DEPENDENCY_QUEUE: case UNIT_ATOM_PULL_IN_VERIFY: /* a single dep type uses this atom */ return UNIT_REQUISITE; case UNIT_ATOM_PULL_IN_START_IGNORED | UNIT_ATOM_RETROACTIVE_START_FAIL | UNIT_ATOM_ADD_STOP_WHEN_UNNEEDED_QUEUE | UNIT_ATOM_ADD_DEFAULT_TARGET_DEPENDENCY_QUEUE: case UNIT_ATOM_RETROACTIVE_START_FAIL: return UNIT_WANTS; case UNIT_ATOM_PULL_IN_START | UNIT_ATOM_RETROACTIVE_START_REPLACE | UNIT_ATOM_CANNOT_BE_ACTIVE_WITHOUT | UNIT_ATOM_ADD_STOP_WHEN_UNNEEDED_QUEUE | UNIT_ATOM_ADD_DEFAULT_TARGET_DEPENDENCY_QUEUE: case UNIT_ATOM_CANNOT_BE_ACTIVE_WITHOUT: return UNIT_BINDS_TO; case UNIT_ATOM_PULL_IN_START_IGNORED | UNIT_ATOM_RETROACTIVE_START_REPLACE | UNIT_ATOM_ADD_START_WHEN_UPHELD_QUEUE | UNIT_ATOM_ADD_STOP_WHEN_UNNEEDED_QUEUE | UNIT_ATOM_ADD_DEFAULT_TARGET_DEPENDENCY_QUEUE: case UNIT_ATOM_ADD_START_WHEN_UPHELD_QUEUE: return UNIT_UPHOLDS; case UNIT_ATOM_PROPAGATE_STOP | UNIT_ATOM_PROPAGATE_RESTART | UNIT_ATOM_PROPAGATE_START_FAILURE | UNIT_ATOM_PROPAGATE_INACTIVE_START_AS_FAILURE | UNIT_ATOM_PINS_STOP_WHEN_UNNEEDED | UNIT_ATOM_DEFAULT_TARGET_DEPENDENCIES: case UNIT_ATOM_PROPAGATE_INACTIVE_START_AS_FAILURE: return UNIT_REQUISITE_OF; case UNIT_ATOM_RETROACTIVE_STOP_ON_STOP | UNIT_ATOM_PROPAGATE_STOP | UNIT_ATOM_PROPAGATE_RESTART | UNIT_ATOM_PROPAGATE_START_FAILURE | UNIT_ATOM_PINS_STOP_WHEN_UNNEEDED | UNIT_ATOM_ADD_CANNOT_BE_ACTIVE_WITHOUT_QUEUE | UNIT_ATOM_DEFAULT_TARGET_DEPENDENCIES: case UNIT_ATOM_ADD_CANNOT_BE_ACTIVE_WITHOUT_QUEUE: return UNIT_BOUND_BY; case UNIT_ATOM_START_STEADILY | UNIT_ATOM_DEFAULT_TARGET_DEPENDENCIES | UNIT_ATOM_PINS_STOP_WHEN_UNNEEDED: case UNIT_ATOM_START_STEADILY: return UNIT_UPHELD_BY; case UNIT_ATOM_PULL_IN_STOP | UNIT_ATOM_RETROACTIVE_STOP_ON_START: case UNIT_ATOM_PULL_IN_STOP: return UNIT_CONFLICTS; case UNIT_ATOM_PULL_IN_STOP_IGNORED | UNIT_ATOM_RETROACTIVE_STOP_ON_START | UNIT_ATOM_PROPAGATE_STOP_FAILURE: case UNIT_ATOM_PULL_IN_STOP_IGNORED: case UNIT_ATOM_PROPAGATE_STOP_FAILURE: return UNIT_CONFLICTED_BY; /* And now, the simple ones */ case UNIT_ATOM_ON_FAILURE: return UNIT_ON_FAILURE; case UNIT_ATOM_ON_SUCCESS: return UNIT_ON_SUCCESS; case UNIT_ATOM_ON_SUCCESS_OF: return UNIT_ON_SUCCESS_OF; case UNIT_ATOM_ON_FAILURE_OF: return UNIT_ON_FAILURE_OF; case UNIT_ATOM_BEFORE: return UNIT_BEFORE; case UNIT_ATOM_AFTER: return UNIT_AFTER; case UNIT_ATOM_TRIGGERS: return UNIT_TRIGGERS; case UNIT_ATOM_TRIGGERED_BY: return UNIT_TRIGGERED_BY; case UNIT_ATOM_PROPAGATES_RELOAD_TO: return UNIT_PROPAGATES_RELOAD_TO; case UNIT_ATOM_JOINS_NAMESPACE_OF: return UNIT_JOINS_NAMESPACE_OF; case UNIT_ATOM_REFERENCES: return UNIT_REFERENCES; case UNIT_ATOM_REFERENCED_BY: return UNIT_REFERENCED_BY; case UNIT_ATOM_IN_SLICE: return UNIT_IN_SLICE; case UNIT_ATOM_SLICE_OF: return UNIT_SLICE_OF; default: return _UNIT_DEPENDENCY_INVALID; } }