if ((r = unit_name_to_instance(s, &i)) < 0)
goto fail;
- if (i && unit_vtable[t]->no_instances)
+ if (i && unit_vtable[t]->no_instances) {
+ r = -EINVAL;
goto fail;
+ }
/* Ensure that this unit is either instanced or not instanced,
* but not both. */
u->meta.id = s;
u->meta.instance = i;
- LIST_PREPEND(Meta, units_per_type, u->meta.manager->units_per_type[t], &u->meta);
+ LIST_PREPEND(Meta, units_by_type, u->meta.manager->units_by_type[t], &u->meta);
if (UNIT_VTABLE(u)->init)
UNIT_VTABLE(u)->init(u);
bidi_set_free(u, u->meta.dependencies[d]);
if (u->meta.type != _UNIT_TYPE_INVALID)
- LIST_REMOVE(Meta, units_per_type, u->meta.manager->units_per_type[u->meta.type], &u->meta);
+ LIST_REMOVE(Meta, units_by_type, u->meta.manager->units_by_type[u->meta.type], &u->meta);
if (u->meta.in_load_queue)
LIST_REMOVE(Meta, load_queue, u->meta.manager->load_queue, &u->meta);
u->meta.manager->n_in_gc_queue--;
}
- cgroup_bonding_free_list(u->meta.cgroup_bondings);
+ cgroup_bonding_free_list(u->meta.cgroup_bondings, u->meta.manager->n_serializing <= 0);
free(u->meta.description);
free(u->meta.fragment_path);
/* If syslog or kernel logging is requested, make sure our own
* logging daemon is run first. */
- if ((r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_LOGGER_SOCKET, NULL, true)) < 0)
- return r;
-
if (u->meta.manager->running_as == MANAGER_SYSTEM)
- if ((r = unit_add_dependency_by_name(u, UNIT_REQUIRES, SPECIAL_LOGGER_SOCKET, NULL, true)) < 0)
+ if ((r = unit_add_two_dependencies_by_name(u, UNIT_REQUIRES, UNIT_AFTER, SPECIAL_LOGGER_SOCKET, NULL, true)) < 0)
return r;
return 0;
"%s\tRefuseManualStart: %s\n"
"%s\tRefuseManualStop: %s\n"
"%s\tDefaultDependencies: %s\n"
- "%s\rOnFailureIsolate: %s\n",
+ "%s\tOnFailureIsolate: %s\n"
+ "%s\tIgnoreOnIsolate: %s\n"
+ "%s\tIgnoreOnSnapshot: %s\n",
prefix, yes_no(u->meta.stop_when_unneeded),
prefix, yes_no(u->meta.refuse_manual_start),
prefix, yes_no(u->meta.refuse_manual_stop),
prefix, yes_no(u->meta.default_dependencies),
- prefix, yes_no(u->meta.on_failure_isolate));
+ prefix, yes_no(u->meta.on_failure_isolate),
+ prefix, yes_no(u->meta.ignore_on_isolate),
+ prefix, yes_no(u->meta.ignore_on_snapshot));
LIST_FOREACH(by_unit, b, u->meta.cgroup_bondings)
fprintf(f, "%s\tControlGroup: %s:%s\n",
if ((r = unit_add_default_dependencies(u)) < 0)
goto fail;
+ if (u->meta.on_failure_isolate &&
+ set_size(u->meta.dependencies[UNIT_ON_FAILURE]) > 1) {
+
+ log_error("More than one OnFailure= dependencies specified for %s but OnFailureIsolate= enabled. Refusing.",
+ u->meta.id);
+
+ r = -EINVAL;
+ goto fail;
+ }
+
assert((u->meta.load_state != UNIT_MERGED) == !u->meta.merged_into);
unit_add_to_dbus_queue(unit_follow_merge(u));
assert(b->path);
- if (!b->controller)
+ if (!b->controller) {
if (!(b->controller = strdup(SYSTEMD_CGROUP_CONTROLLER)))
return -ENOMEM;
+ b->ours = true;
+ }
+
/* Ensure this hasn't been added yet */
assert(!b->unit);
int unit_add_cgroup_from_text(Unit *u, const char *name) {
char *controller = NULL, *path = NULL;
CGroupBonding *b = NULL;
+ bool ours = false;
int r;
assert(u);
if ((r = cg_split_spec(name, &controller, &path)) < 0)
return r;
- if (!path)
+ if (!path) {
path = default_cgroup_path(u);
+ ours = true;
+ }
- if (!controller)
+ if (!controller) {
controller = strdup(SYSTEMD_CGROUP_CONTROLLER);
+ ours = true;
+ }
if (!path || !controller) {
free(path);
b->controller = controller;
b->path = path;
- b->ours = false;
+ b->ours = ours;
+ b->essential = streq(controller, SYSTEMD_CGROUP_CONTROLLER);
if ((r = unit_add_cgroup(u, b)) < 0)
goto fail;
/* Adds in the default cgroups, if they weren't specified
* otherwise. */
+ if (!u->meta.manager->cgroup_hierarchy)
+ return 0;
+
if ((r = unit_add_one_default_cgroup(u, NULL)) < 0)
return r;
return unit_name_to_path(u->meta.instance);
}
+static char *specifier_cgroup(char specifier, void *data, void *userdata) {
+ Unit *u = userdata;
+ assert(u);
+
+ return default_cgroup_path(u);
+}
+
+static char *specifier_cgroup_root(char specifier, void *data, void *userdata) {
+ Unit *u = userdata;
+ char *p;
+ assert(u);
+
+ if (specifier == 'r')
+ return strdup(u->meta.manager->cgroup_hierarchy);
+
+ if (parent_of_path(u->meta.manager->cgroup_hierarchy, &p) < 0)
+ return strdup("");
+
+ if (streq(p, "/")) {
+ free(p);
+ return strdup("");
+ }
+
+ return p;
+}
+
+static char *specifier_runtime(char specifier, void *data, void *userdata) {
+ Unit *u = userdata;
+ assert(u);
+
+ if (u->meta.manager->running_as == MANAGER_USER) {
+ const char *e;
+
+ e = getenv("XDG_RUNTIME_DIR");
+ if (e)
+ return strdup(e);
+ }
+
+ return strdup("/run");
+}
+
char *unit_name_printf(Unit *u, const char* format) {
/*
char *unit_full_printf(Unit *u, const char *format) {
/* This is similar to unit_name_printf() but also supports
- * unescaping */
+ * unescaping. Also, adds a couple of additional codes:
+ *
+ * %c cgroup path of unit
+ * %r root cgroup path of this systemd instance (e.g. "/user/lennart/shared/systemd-4711")
+ * %R parent of root cgroup path (e.g. "/usr/lennart/shared")
+ * %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR)
+ */
const Specifier table[] = {
{ 'n', specifier_string, u->meta.id },
{ 'i', specifier_string, u->meta.instance },
{ 'I', specifier_instance_unescaped, NULL },
{ 'f', specifier_filename, NULL },
+ { 'c', specifier_cgroup, NULL },
+ { 'r', specifier_cgroup_root, NULL },
+ { 'R', specifier_cgroup_root, NULL },
+ { 't', specifier_runtime, NULL },
{ 0, NULL, NULL }
};
return 0;
for (;;) {
- char line[1024], *l, *v;
+ char line[LINE_MAX], *l, *v;
size_t k;
if (!fgets(line, sizeof(line), f)) {
}
bool unit_need_daemon_reload(Unit *u) {
- struct stat st;
-
assert(u);
- if (!u->meta.fragment_path)
- return false;
+ if (u->meta.fragment_path) {
+ struct stat st;
- zero(st);
- if (stat(u->meta.fragment_path, &st) < 0)
- /* What, cannot access this anymore? */
- return true;
+ zero(st);
+ if (stat(u->meta.fragment_path, &st) < 0)
+ /* What, cannot access this anymore? */
+ return true;
+
+ if (u->meta.fragment_mtime > 0 &&
+ timespec_load(&st.st_mtim) != u->meta.fragment_mtime)
+ return true;
+ }
- return
- u->meta.fragment_mtime &&
- timespec_load(&st.st_mtim) != u->meta.fragment_mtime;
+ if (UNIT_VTABLE(u)->need_daemon_reload)
+ return UNIT_VTABLE(u)->need_daemon_reload(u);
+
+ return false;
}
void unit_reset_failed(Unit *u) {
return UNIT_VTABLE(u)->kill(u, w, m, signo, error);
}
-
int unit_following_set(Unit *u, Set **s) {
assert(u);
assert(s);