Hi list! First patch removes StopWhenUnneeded= when service starts, if service will be stopped after start, because WantedBy=,RequiredBy,.. is empty.
Second one allows templated enable, like: > grep WantedBy ~/.config/systemd/user/mpop@.timer WantedBy=services@%i.target > srv disable mpop@iit.timer rm '/home/alxchk/.config/systemd/user/services@iit.target.wants/mpop@iit.timer' alxchk > srv enable mpop@iit.timer ln -s '/home/alxchk/.config/systemd/user/mpop@.timer' '/home/alxchk/.config/systemd/user/services@iit.target.wants/mpop@iit.timer'
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index c7bf043..06c5d25 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -1096,7 +1096,7 @@ const BusProperty bus_unit_properties[] = { { "CanReload", bus_unit_append_can_reload, "b", 0 }, { "CanIsolate", bus_unit_append_can_isolate, "b", 0 }, { "Job", bus_unit_append_job, "(uo)", 0 }, - { "StopWhenUnneeded", bus_property_append_bool, "b", offsetof(Unit, stop_when_unneeded) }, + { "StopWhenUnneeded", bus_property_append_bool, "b", offsetof(Unit, stop_when_unneeded_runtime) }, { "RefuseManualStart", bus_property_append_bool, "b", offsetof(Unit, refuse_manual_start) }, { "RefuseManualStop", bus_property_append_bool, "b", offsetof(Unit, refuse_manual_stop) }, { "AllowIsolate", bus_property_append_bool, "b", offsetof(Unit, allow_isolate) }, diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 7fba0cf..4f3e52a 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -114,7 +114,7 @@ Unit.ReloadPropagatedFrom, config_parse_unit_deps, UNIT_RELOAD Unit.PropagateReloadFrom, config_parse_unit_deps, UNIT_RELOAD_PROPAGATED_FROM, 0 Unit.PartOf, config_parse_unit_deps, UNIT_PART_OF, 0 Unit.RequiresMountsFor, config_parse_unit_requires_mounts_for, 0, offsetof(Unit, requires_mounts_for) -Unit.StopWhenUnneeded, config_parse_bool, 0, offsetof(Unit, stop_when_unneeded) +Unit.StopWhenUnneeded, config_parse_bool, 0, offsetof(Unit, stop_when_unneeded_unit) Unit.RefuseManualStart, config_parse_bool, 0, offsetof(Unit, refuse_manual_start) Unit.RefuseManualStop, config_parse_bool, 0, offsetof(Unit, refuse_manual_stop) Unit.AllowIsolate, config_parse_bool, 0, offsetof(Unit, allow_isolate) diff --git a/src/core/unit.c b/src/core/unit.c index 1194c52..b4dfa68 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -731,7 +731,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { "%s\tOnFailureIsolate: %s\n" "%s\tIgnoreOnIsolate: %s\n" "%s\tIgnoreOnSnapshot: %s\n", - prefix, yes_no(u->stop_when_unneeded), + prefix, yes_no(u->stop_when_unneeded_unit), prefix, yes_no(u->refuse_manual_start), prefix, yes_no(u->refuse_manual_stop), prefix, yes_no(u->default_dependencies), @@ -1063,6 +1063,14 @@ int unit_start(Unit *u) { return -EALREADY; } + u->stop_when_unneeded_runtime = u->stop_when_unneeded_unit; + + if (unit_unneeded(u)) { + log_debug("Started unneded unit %s with StopWhenUnneeded=yes." + "Disabling unneeded property.", u->id); + u->stop_when_unneeded_runtime = false; + } + /* Forward to the main object, if we aren't it. */ if ((following = unit_following(u))) { log_debug("Redirecting start request from %s to %s.", u->id, following->id); @@ -1178,36 +1186,44 @@ bool unit_can_reload(Unit *u) { return UNIT_VTABLE(u)->can_reload(u); } -static void unit_check_unneeded(Unit *u) { +bool unit_unneeded(Unit *u) { Iterator i; Unit *other; assert(u); + if (!u->stop_when_unneeded_runtime) + return false; + + SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i) + if (unit_pending_active(other)) + return false; + + SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i) + if (unit_pending_active(other)) + return false; + + SET_FOREACH(other, u->dependencies[UNIT_WANTED_BY], i) + if (unit_pending_active(other)) + return false; + + SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i) + if (unit_pending_active(other)) + return false; + + return true; +} + +static void unit_check_unneeded(Unit *u) { + /* If this service shall be shut down when unneeded then do * so. */ - if (!u->stop_when_unneeded) - return; - if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u))) return; - SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i) - if (unit_pending_active(other)) - return; - - SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i) - if (unit_pending_active(other)) - return; - - SET_FOREACH(other, u->dependencies[UNIT_WANTED_BY], i) - if (unit_pending_active(other)) - return; - - SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i) - if (unit_pending_active(other)) - return; + if (! unit_unneeded(u)) + return; log_info("Service %s is not needed anymore. Stopping.", u->id); diff --git a/src/core/unit.h b/src/core/unit.h index d1ecae7..4ba5628 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -198,7 +198,8 @@ struct Unit { UnitFileState unit_file_state; /* Garbage collect us we nobody wants or requires us anymore */ - bool stop_when_unneeded; + bool stop_when_unneeded_unit; + bool stop_when_unneeded_runtime; /* Create default dependencies */ bool default_dependencies; @@ -479,6 +480,7 @@ bool unit_can_isolate(Unit *u); int unit_start(Unit *u); int unit_stop(Unit *u); int unit_reload(Unit *u); +bool unit_unneeded(Unit *u); int unit_kill(Unit *u, KillWho w, int signo, DBusError *error); diff --git a/src/shared/log.c b/src/shared/log.c index 8d3458e..3aa1a13 100644 --- a/src/shared/log.c +++ b/src/shared/log.c @@ -1,4 +1,4 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +//*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ /*** This file is part of systemd.
diff --git a/src/shared/install.c b/src/shared/install.c index a9d75f3..49100a4 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -36,6 +36,7 @@ #include "install.h" #include "conf-parser.h" #include "conf-files.h" +#include "specifier.h" typedef struct { char *name; @@ -51,6 +52,33 @@ typedef struct { Hashmap *have_installed; } InstallContext; +static char *name_printf(char * prefix, char * instance, char* format) { + + /* + * This will use the passed string as format string and + * replace the following specifiers, if any: + * + * %p: the unit prefix + * %i: the instance + * + * Pass empty_prefix and empty_instance, if not specified, + * to get better error. + */ + + char empty_prefix[] = "%p"; + char empty_instance[] = "%i"; + + const Specifier table[] = { + { 'p', specifier_string, prefix ? : empty_prefix}, + { 'i', specifier_string, instance ? : empty_instance}, + { 0, NULL, NULL } + }; + + assert(format); + + return specifier_printf(format, table, NULL); +} + static int lookup_paths_init_from_scope(LookupPaths *paths, UnitFileScope scope) { assert(paths); assert(scope >= 0); @@ -1271,13 +1299,21 @@ static int install_info_symlink_wants( STRV_FOREACH(s, i->wanted_by) { char *path; + char *instance = NULL; + char *prefix = NULL; + char *dst = NULL; - if (!unit_name_is_valid(*s, true)) { + unit_name_to_instance(i->name, &instance); + prefix = unit_name_to_prefix(i->name); + + dst = name_printf(prefix, instance, *s); + + if (!unit_name_is_valid(dst, true)) { r = -EINVAL; continue; } - if (asprintf(&path, "%s/%s.wants/%s", config_path, *s, i->name) < 0) + if (asprintf(&path, "%s/%s.wants/%s", config_path, dst, i->name) < 0) return -ENOMEM; q = create_symlink(i->path, path, force, changes, n_changes);
_______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel