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/[email protected]
WantedBy=services@%i.target
> srv disable [email protected]
rm '/home/alxchk/.config/systemd/user/[email protected]/[email protected]'
alxchk > srv enable [email protected]
ln -s '/home/alxchk/.config/systemd/user/[email protected]'
'/home/alxchk/.config/systemd/user/[email protected]/[email protected]'
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
[email protected]
http://lists.freedesktop.org/mailman/listinfo/systemd-devel