diff --git a/TODO b/TODO index a01f2a9953..0d6ac5fb26 100644 --- a/TODO +++ b/TODO @@ -70,7 +70,7 @@ * only add quotacheck deps to .mount units which mention grpquota/usrquota in the mount flags -* Introduce weaker Conflicts. +* Introduce weaker Conflicts. get rid of ignore_dependency_failure External: diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index 14da607a95..ff1b47f9fb 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -281,7 +281,6 @@ services. - RequiresOverridable= @@ -340,6 +339,23 @@ details see above. + + BindTo= + + Configures requirement + dependencies, very similar in style to + Requires=, however + in addition to this behaviour it also + declares that this unit is stopped + when any of the units listed suddenly + disappears. Units can suddenly, + unexpectedly disappear if a service + terminates on its own choice, a device + is unplugged or a mount point + unmounted with involvement of + systemd. + + Conflicts= @@ -440,28 +456,6 @@ state. - - StopRetroactively= - - Takes a boolean - argument. If and - a unit this unit requires stops - without this being requested by the - user, this unit will be stopped as - well. (e.g. if a service exits or - crashes on its own behalf, units this - flag is set for that require it will - be stopped.) Note that normally if a - unit stops without a user request, - units depending on it will not be - terminated. Only if the user requested - shutdown of a unit, all units - depending on that unit will be shut - down as well and at the same - time. Defaults to - . - - StopWhenUnneeded= @@ -630,7 +624,7 @@ side matching. If multiple conditions are specified the unit will be executed iff at least one of them - apply (i.e. a logical OR is + applies (i.e. a logical OR is applied). diff --git a/src/dbus-unit.h b/src/dbus-unit.h index 4a4d23e173..d897ef8ca7 100644 --- a/src/dbus-unit.h +++ b/src/dbus-unit.h @@ -70,9 +70,11 @@ " \n" \ " \n" \ " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -92,7 +94,6 @@ " \n" \ " \n" \ " \n" \ - " \n" \ " \n" \ " \n" \ " \n" \ @@ -112,9 +113,11 @@ { "org.freedesktop.systemd1.Unit", "Requisite", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_REQUISITE] }, \ { "org.freedesktop.systemd1.Unit", "RequisiteOverridable", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_REQUISITE_OVERRIDABLE] }, \ { "org.freedesktop.systemd1.Unit", "Wants", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_WANTS] }, \ + { "org.freedesktop.systemd1.Unit", "BindTo", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_BIND_TO] }, \ { "org.freedesktop.systemd1.Unit", "RequiredBy", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_REQUIRED_BY] }, \ { "org.freedesktop.systemd1.Unit", "RequiredByOverridable",bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_REQUIRED_BY_OVERRIDABLE] }, \ { "org.freedesktop.systemd1.Unit", "WantedBy", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_WANTED_BY] }, \ + { "org.freedesktop.systemd1.Unit", "BoundBy", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_BOUND_BY] }, \ { "org.freedesktop.systemd1.Unit", "Conflicts", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_CONFLICTS] }, \ { "org.freedesktop.systemd1.Unit", "ConflictedBy", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_CONFLICTED_BY] }, \ { "org.freedesktop.systemd1.Unit", "Before", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_BEFORE] }, \ @@ -134,7 +137,6 @@ { "org.freedesktop.systemd1.Unit", "CanReload", bus_unit_append_can_reload, "b", u }, \ { "org.freedesktop.systemd1.Unit", "CanIsolate", bus_unit_append_can_isolate, "b", u }, \ { "org.freedesktop.systemd1.Unit", "Job", bus_unit_append_job, "(uo)", u }, \ - { "org.freedesktop.systemd1.Unit", "StopRetroactively", bus_property_append_bool, "b", &u->meta.stop_retroactively }, \ { "org.freedesktop.systemd1.Unit", "StopWhenUnneeded", bus_property_append_bool, "b", &u->meta.stop_when_unneeded }, \ { "org.freedesktop.systemd1.Unit", "RefuseManualStart", bus_property_append_bool, "b", &u->meta.refuse_manual_start }, \ { "org.freedesktop.systemd1.Unit", "RefuseManualStop", bus_property_append_bool, "b", &u->meta.refuse_manual_stop }, \ diff --git a/src/load-fragment.c b/src/load-fragment.c index bc34451064..828b8d2a98 100644 --- a/src/load-fragment.c +++ b/src/load-fragment.c @@ -1765,11 +1765,11 @@ static int load_from_path(Unit *u, const char *path) { { "Requisite", config_parse_deps, UINT_TO_PTR(UNIT_REQUISITE), "Unit" }, { "RequisiteOverridable", config_parse_deps, UINT_TO_PTR(UNIT_REQUISITE_OVERRIDABLE), "Unit" }, { "Wants", config_parse_deps, UINT_TO_PTR(UNIT_WANTS), "Unit" }, + { "BindTo", config_parse_deps, UINT_TO_PTR(UNIT_BIND_TO), "Unit" }, { "Conflicts", config_parse_deps, UINT_TO_PTR(UNIT_CONFLICTS), "Unit" }, { "Before", config_parse_deps, UINT_TO_PTR(UNIT_BEFORE), "Unit" }, { "After", config_parse_deps, UINT_TO_PTR(UNIT_AFTER), "Unit" }, { "OnFailure", config_parse_deps, UINT_TO_PTR(UNIT_ON_FAILURE), "Unit" }, - { "StopRetroactively", config_parse_bool, &u->meta.stop_retroactively, "Unit" }, { "StopWhenUnneeded", config_parse_bool, &u->meta.stop_when_unneeded, "Unit" }, { "RefuseManualStart", config_parse_bool, &u->meta.refuse_manual_start, "Unit" }, { "RefuseManualStop", config_parse_bool, &u->meta.refuse_manual_stop, "Unit" }, diff --git a/src/manager.c b/src/manager.c index 667be2fdcf..796d3cbebe 100644 --- a/src/manager.c +++ b/src/manager.c @@ -1446,6 +1446,10 @@ static int transaction_add_job_and_dependencies( if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, false, e, NULL)) < 0 && r != -EBADR) goto fail; + SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_BIND_TO], i) + if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, false, e, NULL)) < 0 && r != -EBADR) + goto fail; + SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRES_OVERRIDABLE], i) if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, !override, override, false, e, NULL)) < 0 && r != -EBADR) { log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, bus_error(e, r)); @@ -1487,6 +1491,10 @@ static int transaction_add_job_and_dependencies( SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRED_BY], i) if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, false, e, NULL)) < 0 && r != -EBADR) goto fail; + + SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_BOUND_BY], i) + if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, false, e, NULL)) < 0 && r != -EBADR) + goto fail; } /* JOB_VERIFY_STARTED, JOB_RELOAD require no dependency handling */ diff --git a/src/mount.c b/src/mount.c index 0b67fbed5d..d62ce8f408 100644 --- a/src/mount.c +++ b/src/mount.c @@ -70,9 +70,6 @@ static void mount_init(Unit *u) { * already trying to comply its last one. */ m->exec_context.same_pgrp = true; - /* Make sure we unmount when the devices we require go away */ - m->meta.stop_retroactively = true; - m->timer_watch.type = WATCH_INVALID; m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID; diff --git a/src/unit.c b/src/unit.c index f080e7bef3..fb5583bfb2 100644 --- a/src/unit.c +++ b/src/unit.c @@ -652,13 +652,11 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { if (u->meta.load_state == UNIT_LOADED) { fprintf(f, - "%s\tStopRetroactively: %s\n" "%s\tStopWhenUnneeded: %s\n" "%s\tRefuseManualStart: %s\n" "%s\tRefuseManualStop: %s\n" "%s\tDefaultDependencies: %s\n" "%s\tIgnoreDependencyFailure: %s\n", - prefix, yes_no(u->meta.stop_retroactively), prefix, yes_no(u->meta.stop_when_unneeded), prefix, yes_no(u->meta.refuse_manual_start), prefix, yes_no(u->meta.refuse_manual_stop), @@ -768,6 +766,10 @@ static int unit_add_default_dependencies(Unit *u) { if ((r = unit_add_default_target_dependency(u, target)) < 0) return r; + SET_FOREACH(target, u->meta.dependencies[UNIT_BOUND_BY], i) + if ((r = unit_add_default_target_dependency(u, target)) < 0) + return r; + return 0; } @@ -966,6 +968,10 @@ static void unit_check_unneeded(Unit *u) { if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) return; + SET_FOREACH(other, u->meta.dependencies[UNIT_BOUND_BY], i) + if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) + return; + log_info("Service %s is not needed anymore. Stopping.", u->meta.id); /* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */ @@ -980,27 +986,36 @@ static void retroactively_start_dependencies(Unit *u) { assert(UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u))); SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRES], i) - if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) + if (!set_get(u->meta.dependencies[UNIT_AFTER], other) && + !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) + manager_add_job(u->meta.manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL); + + SET_FOREACH(other, u->meta.dependencies[UNIT_BIND_TO], i) + if (!set_get(u->meta.dependencies[UNIT_AFTER], other) && + !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) manager_add_job(u->meta.manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL); SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRES_OVERRIDABLE], i) - if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) + if (!set_get(u->meta.dependencies[UNIT_AFTER], other) && + !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) manager_add_job(u->meta.manager, JOB_START, other, JOB_FAIL, false, NULL, NULL); SET_FOREACH(other, u->meta.dependencies[UNIT_REQUISITE], i) - if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) + if (!set_get(u->meta.dependencies[UNIT_AFTER], other) && + !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) manager_add_job(u->meta.manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL); SET_FOREACH(other, u->meta.dependencies[UNIT_WANTS], i) - if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) + if (!set_get(u->meta.dependencies[UNIT_AFTER], other) && + !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) manager_add_job(u->meta.manager, JOB_START, other, JOB_FAIL, false, NULL, NULL); SET_FOREACH(other, u->meta.dependencies[UNIT_CONFLICTS], i) - if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) + if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) manager_add_job(u->meta.manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL); SET_FOREACH(other, u->meta.dependencies[UNIT_CONFLICTED_BY], i) - if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) + if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) manager_add_job(u->meta.manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL); } @@ -1011,10 +1026,9 @@ static void retroactively_stop_dependencies(Unit *u) { assert(u); assert(UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u))); - /* Pull down units which need us recursively if enabled */ - SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY], i) - if (other->meta.stop_retroactively && - !UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) + /* Pull down units which are bound to us recursively if enabled */ + SET_FOREACH(other, u->meta.dependencies[UNIT_BOUND_BY], i) + if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) manager_add_job(u->meta.manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL); /* Garbage collect services that might not be needed anymore, if enabled */ @@ -1033,6 +1047,9 @@ static void retroactively_stop_dependencies(Unit *u) { SET_FOREACH(other, u->meta.dependencies[UNIT_REQUISITE_OVERRIDABLE], i) if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) unit_check_unneeded(other); + SET_FOREACH(other, u->meta.dependencies[UNIT_BIND_TO], i) + if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) + unit_check_unneeded(other); } void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) { @@ -1397,9 +1414,11 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_referen [UNIT_WANTS] = UNIT_WANTED_BY, [UNIT_REQUISITE] = UNIT_REQUIRED_BY, [UNIT_REQUISITE_OVERRIDABLE] = UNIT_REQUIRED_BY_OVERRIDABLE, + [UNIT_BIND_TO] = UNIT_BOUND_BY, [UNIT_REQUIRED_BY] = _UNIT_DEPENDENCY_INVALID, [UNIT_REQUIRED_BY_OVERRIDABLE] = _UNIT_DEPENDENCY_INVALID, [UNIT_WANTED_BY] = _UNIT_DEPENDENCY_INVALID, + [UNIT_BOUND_BY] = UNIT_BIND_TO, [UNIT_CONFLICTS] = UNIT_CONFLICTED_BY, [UNIT_CONFLICTED_BY] = UNIT_CONFLICTS, [UNIT_BEFORE] = UNIT_AFTER, @@ -1426,7 +1445,8 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_referen (d == UNIT_REQUIRES || d == UNIT_REQUIRES_OVERRIDABLE || d == UNIT_REQUISITE || - d == UNIT_REQUISITE_OVERRIDABLE)) { + d == UNIT_REQUISITE_OVERRIDABLE || + d == UNIT_BIND_TO)) { return -EINVAL; } @@ -2129,7 +2149,7 @@ int unit_add_node_link(Unit *u, const char *what, bool wants) { if (r < 0) return r; - if ((r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_REQUIRES, device, true)) < 0) + if ((r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_BIND_TO, device, true)) < 0) return r; if (wants) @@ -2313,9 +2333,11 @@ static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = { [UNIT_REQUISITE_OVERRIDABLE] = "RequisiteOverridable", [UNIT_REQUIRED_BY] = "RequiredBy", [UNIT_REQUIRED_BY_OVERRIDABLE] = "RequiredByOverridable", + [UNIT_BIND_TO] = "BindTo", [UNIT_WANTED_BY] = "WantedBy", [UNIT_CONFLICTS] = "Conflicts", [UNIT_CONFLICTED_BY] = "ConflictedBy", + [UNIT_BOUND_BY] = "BoundBy", [UNIT_BEFORE] = "Before", [UNIT_AFTER] = "After", [UNIT_REFERENCES] = "References", diff --git a/src/unit.h b/src/unit.h index 8b6b58e53b..ff11511898 100644 --- a/src/unit.h +++ b/src/unit.h @@ -102,11 +102,13 @@ enum UnitDependency { UNIT_REQUISITE, UNIT_REQUISITE_OVERRIDABLE, UNIT_WANTS, + UNIT_BIND_TO, /* Inverse of the above */ UNIT_REQUIRED_BY, /* inverse of 'requires' and 'requisite' is 'required_by' */ UNIT_REQUIRED_BY_OVERRIDABLE, /* inverse of 'requires_overridable' and 'requisite_overridable' is 'soft_required_by' */ UNIT_WANTED_BY, /* inverse of 'wants' */ + UNIT_BOUND_BY, /* inverse of 'bind_to' */ /* Negative dependencies */ UNIT_CONFLICTS, /* inverse of 'conflicts' is 'conflicted_by' */ @@ -191,9 +193,6 @@ struct Meta { /* Error code when we didn't manage to load the unit (negative) */ int load_error; - /* If some required dep goes down, pull down ourselves, too */ - bool stop_retroactively; - /* Garbage collect us we nobody wants or requires us anymore */ bool stop_when_unneeded; diff --git a/units/fsck@.service.in b/units/fsck@.service.in index 54caa3c965..38815414fa 100644 --- a/units/fsck@.service.in +++ b/units/fsck@.service.in @@ -8,7 +8,7 @@ [Unit] Description=File System Check on %f DefaultDependencies=no -Requires=%i.device +BindTo=%i.device After=systemd-readahead-collect.service systemd-readahead-replay.service %i.device Before=local-fs.target shutdown.target diff --git a/units/getty@.service.m4 b/units/getty@.service.m4 index 98c6a88213..1edcad9f0e 100644 --- a/units/getty@.service.m4 +++ b/units/getty@.service.m4 @@ -14,7 +14,7 @@ m4_ifdef(`TARGET_ARCH', `m4_define(`GETTY', `/sbin/agetty -8 38400')')m4_dnl m4_dnl [Unit] Description=Getty on %I -Requires=dev-%i.device +BindTo=dev-%i.device After=dev-%i.device m4_ifdef(`TARGET_FEDORA', After=rc-local.service diff --git a/units/serial-getty@.service.m4 b/units/serial-getty@.service.m4 index 9a70db0f21..da9bd1946b 100644 --- a/units/serial-getty@.service.m4 +++ b/units/serial-getty@.service.m4 @@ -7,7 +7,7 @@ [Unit] Description=Serial Getty on %I -Requires=dev-%i.device +BindTo=dev-%i.device After=dev-%i.device m4_ifdef(`TARGET_FEDORA', After=rc-local.service