chiark / gitweb /
unit: optionally allow making cgroup attribute changes persistent
[elogind.git] / src / core / unit.c
index 45453dce64a6464899721ad5f7c133fcac4e418f..98237c81472d5b2095db445cad4732b41978e8a5 100644 (file)
@@ -45,6 +45,7 @@
 #include "cgroup-util.h"
 #include "missing.h"
 #include "cgroup-attr.h"
+#include "mkdir.h"
 
 const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = {
         [UNIT_SERVICE] = &service_vtable,
@@ -1022,9 +1023,9 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) {
               t == JOB_STOP  ? SD_MESSAGE_UNIT_STOPPING :
                                SD_MESSAGE_UNIT_RELOADING;
 
-        log_struct(LOG_INFO,
+        log_struct_unit(LOG_INFO,
+                   u->id,
                    MESSAGE_ID(mid),
-                   "UNIT=%s", u->id,
                    "MESSAGE=%s", buf,
                    NULL);
 }
@@ -1438,9 +1439,9 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
                         check_unneeded_dependencies(u);
 
                 if (ns != os && ns == UNIT_FAILED) {
-                        log_struct(LOG_NOTICE,
+                        log_struct_unit(LOG_NOTICE,
+                                   u->id,
                                    "MESSAGE=Unit %s entered failed state", u->id,
-                                   "UNIT=%s", u->id,
                                    NULL);
                         unit_trigger_on_failure(u);
                 }
@@ -1781,6 +1782,7 @@ static const char *resolve_template(Unit *u, const char *name, const char*path,
 
         assert(u);
         assert(name || path);
+        assert(p);
 
         if (!name)
                 name = path_get_file_name(path);
@@ -1795,7 +1797,8 @@ static const char *resolve_template(Unit *u, const char *name, const char*path,
         else {
                 char *i;
 
-                if (!(i = unit_name_to_prefix(u->id)))
+                i = unit_name_to_prefix(u->id);
+                if (!i)
                         return NULL;
 
                 s = unit_name_replace_instance(name, i);
@@ -1812,22 +1815,20 @@ static const char *resolve_template(Unit *u, const char *name, const char*path,
 int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) {
         Unit *other;
         int r;
-        char *s;
+        _cleanup_free_ char *s = NULL;
 
         assert(u);
         assert(name || path);
 
-        if (!(name = resolve_template(u, name, path, &s)))
+        name = resolve_template(u, name, path, &s);
+        if (!name)
                 return -ENOMEM;
 
-        if ((r = manager_load_unit(u->manager, name, path, NULL, &other)) < 0)
-                goto finish;
-
-        r = unit_add_dependency(u, d, other, add_reference);
+        r = manager_load_unit(u->manager, name, path, NULL, &other);
+        if (r < 0)
+                return r;
 
-finish:
-        free(s);
-        return r;
+        return unit_add_dependency(u, d, other, add_reference);
 }
 
 int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference) {
@@ -1941,8 +1942,9 @@ int unit_add_cgroup(Unit *u, CGroupBonding *b) {
         assert(b->path);
 
         if (!b->controller) {
-                if (!(b->controller = strdup(SYSTEMD_CGROUP_CONTROLLER)))
-                        return -ENOMEM;
+                b->controller = strdup(SYSTEMD_CGROUP_CONTROLLER);
+                if (!b->controller)
+                        return log_oom();
 
                 b->ours = true;
         }
@@ -1956,7 +1958,8 @@ int unit_add_cgroup(Unit *u, CGroupBonding *b) {
                 l = hashmap_get(u->manager->cgroup_bondings, b->path);
                 LIST_PREPEND(CGroupBonding, by_path, l, b);
 
-                if ((r = hashmap_replace(u->manager->cgroup_bondings, b->path, l)) < 0) {
+                r = hashmap_replace(u->manager->cgroup_bondings, b->path, l);
+                if (r < 0) {
                         LIST_REMOVE(CGroupBonding, by_path, l, b);
                         return r;
                 }
@@ -1969,26 +1972,21 @@ int unit_add_cgroup(Unit *u, CGroupBonding *b) {
 }
 
 char *unit_default_cgroup_path(Unit *u) {
-        char *p;
-
         assert(u);
 
         if (u->instance) {
-                char *t;
+                _cleanup_free_ char *t = NULL;
 
                 t = unit_name_template(u->id);
                 if (!t)
                         return NULL;
 
-                p = strjoin(u->manager->cgroup_hierarchy, "/", t, "/", u->instance, NULL);
-                free(t);
+                return strjoin(u->manager->cgroup_hierarchy, "/", t, "/", u->instance, NULL);
         } else
-                p = strjoin(u->manager->cgroup_hierarchy, "/", u->id, NULL);
-
-        return p;
+                return strjoin(u->manager->cgroup_hierarchy, "/", u->id, NULL);
 }
 
-int unit_add_cgroup_from_text(Unit *u, const char *name) {
+int unit_add_cgroup_from_text(Unit *u, const char *name, bool overwrite, CGroupBonding **ret) {
         char *controller = NULL, *path = NULL;
         CGroupBonding *b = NULL;
         bool ours = false;
@@ -1997,7 +1995,8 @@ int unit_add_cgroup_from_text(Unit *u, const char *name) {
         assert(u);
         assert(name);
 
-        if ((r = cg_split_spec(name, &controller, &path)) < 0)
+        r = cg_split_spec(name, &controller, &path);
+        if (r < 0)
                 return r;
 
         if (!path) {
@@ -2013,16 +2012,42 @@ int unit_add_cgroup_from_text(Unit *u, const char *name) {
         if (!path || !controller) {
                 free(path);
                 free(controller);
-
-                return -ENOMEM;
+                return log_oom();
         }
 
-        if (cgroup_bonding_find_list(u->cgroup_bondings, controller)) {
+        b = cgroup_bonding_find_list(u->cgroup_bondings, controller);
+        if (b) {
+                if (streq(path, b->path)) {
+                        free(path);
+                        free(controller);
+
+                        if (ret)
+                                *ret = b;
+                        return 0;
+                }
+
+                if (overwrite && !b->essential) {
+                        free(controller);
+
+                        free(b->path);
+                        b->path = path;
+
+                        b->ours = ours;
+                        b->realized = false;
+
+                        if (ret)
+                                *ret = b;
+
+                        return 1;
+                }
+
                 r = -EEXIST;
+                b = NULL;
                 goto fail;
         }
 
-        if (!(b = new0(CGroupBonding, 1))) {
+        b = new0(CGroupBonding, 1);
+        if (!b) {
                 r = -ENOMEM;
                 goto fail;
         }
@@ -2032,10 +2057,14 @@ int unit_add_cgroup_from_text(Unit *u, const char *name) {
         b->ours = ours;
         b->essential = streq(controller, SYSTEMD_CGROUP_CONTROLLER);
 
-        if ((r = unit_add_cgroup(u, b)) < 0)
+        r = unit_add_cgroup(u, b);
+        if (r < 0)
                 goto fail;
 
-        return 0;
+        if (ret)
+                *ret = b;
+
+        return 1;
 
 fail:
         free(path);
@@ -2057,10 +2086,12 @@ static int unit_add_one_default_cgroup(Unit *u, const char *controller) {
         if (cgroup_bonding_find_list(u->cgroup_bondings, controller))
                 return 0;
 
-        if (!(b = new0(CGroupBonding, 1)))
+        b = new0(CGroupBonding, 1);
+        if (!b)
                 return -ENOMEM;
 
-        if (!(b->controller = strdup(controller)))
+        b->controller = strdup(controller);
+        if (!b->controller)
                 goto fail;
 
         b->path = unit_default_cgroup_path(u);
@@ -2070,7 +2101,8 @@ static int unit_add_one_default_cgroup(Unit *u, const char *controller) {
         b->ours = true;
         b->essential = streq(controller, SYSTEMD_CGROUP_CONTROLLER);
 
-        if ((r = unit_add_cgroup(u, b)) < 0)
+        r = unit_add_cgroup(u, b);
+        if (r < 0)
                 goto fail;
 
         return 0;
@@ -2096,7 +2128,8 @@ int unit_add_default_cgroups(Unit *u) {
         if (!u->manager->cgroup_hierarchy)
                 return 0;
 
-        if ((r = unit_add_one_default_cgroup(u, NULL)) < 0)
+        r = unit_add_one_default_cgroup(u, NULL);
+        if (r < 0)
                 return r;
 
         STRV_FOREACH(c, u->manager->default_controllers)
@@ -2111,42 +2144,69 @@ int unit_add_default_cgroups(Unit *u) {
 CGroupBonding* unit_get_default_cgroup(Unit *u) {
         assert(u);
 
-        return cgroup_bonding_find_list(u->cgroup_bondings, SYSTEMD_CGROUP_CONTROLLER);
+        return cgroup_bonding_find_list(u->cgroup_bondings, NULL);
 }
 
-int unit_add_cgroup_attribute(Unit *u, const char *controller, const char *name, const char *value, CGroupAttributeMapCallback map_callback) {
-        int r;
-        char *c = NULL;
+int unit_add_cgroup_attribute(
+                Unit *u,
+                const char *controller,
+                const char *name,
+                const char *value,
+                CGroupAttributeMapCallback map_callback,
+                CGroupAttribute **ret) {
+
+        _cleanup_free_ char *c = NULL;
         CGroupAttribute *a;
+        int r;
 
         assert(u);
         assert(name);
         assert(value);
 
         if (!controller) {
-                const char *dot;
+                r = cg_controller_from_attr(name, &c);
+                if (r < 0)
+                        return -EINVAL;
 
-                dot = strchr(name, '.');
-                if (!dot)
+                controller = c;
+        } else {
+                if (!filename_is_safe(name))
                         return -EINVAL;
 
-                c = strndup(name, dot - name);
-                if (!c)
+                if (!filename_is_safe(controller))
+                        return -EINVAL;
+        }
+
+        if (!controller || streq(controller, SYSTEMD_CGROUP_CONTROLLER))
+                return -EINVAL;
+
+        a = cgroup_attribute_find_list(u->cgroup_attributes, controller, name);
+        if (a) {
+                char *v;
+
+                if (streq(value, a->value)) {
+                        if (ret)
+                                *ret = a;
+
+                        return 0;
+                }
+
+                v = strdup(value);
+                if (!v)
                         return -ENOMEM;
 
-                controller = c;
-        }
+                free(a->value);
+                a->value = v;
 
-        if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
-                r = -EINVAL;
-                goto finish;
+                if (ret)
+                        *ret = a;
+
+                return 1;
         }
 
         a = new0(CGroupAttribute, 1);
-        if (!a) {
-                r = -ENOMEM;
-                goto finish;
-        }
+        if (!a)
+                return -ENOMEM;
 
         if (c) {
                 a->controller = c;
@@ -2167,14 +2227,14 @@ int unit_add_cgroup_attribute(Unit *u, const char *controller, const char *name,
         }
 
         a->map_callback = map_callback;
+        a->unit = u;
 
         LIST_PREPEND(CGroupAttribute, by_unit, u->cgroup_attributes, a);
 
-        r = 0;
+        if (ret)
+                *ret = a;
 
-finish:
-        free(c);
-        return r;
+        return 1;
 }
 
 int unit_load_related_unit(Unit *u, const char *type, Unit **_found) {
@@ -2699,6 +2759,54 @@ ExecContext *unit_get_exec_context(Unit *u) {
         return (ExecContext*) ((uint8_t*) u + offset);
 }
 
+int unit_write_drop_in(Unit *u, bool runtime, const char *name, const char *data) {
+        _cleanup_free_ char *p = NULL, *q = NULL;
+        assert(u);
+
+        if (u->manager->running_as != SYSTEMD_SYSTEM)
+                return -ENOTSUP;
+
+        if (!filename_is_safe(name))
+                return -EINVAL;
+
+        p = strjoin(runtime ? "/run/systemd/system/" : "/etc/systemd/systemd/", u->id, ".d", NULL);
+        if (!p)
+                return -ENOMEM;
+
+        q = strjoin(p, "/50-", name, ".conf", NULL);
+        if (!q)
+                return -ENOMEM;
+
+        mkdir_p(p, 0755);
+        return write_one_line_file_atomic(q, data);
+}
+
+int unit_remove_drop_in(Unit *u, bool runtime, const char *name) {
+        _cleanup_free_ char *p = NULL, *q = NULL;
+
+        assert(u);
+
+        if (u->manager->running_as != SYSTEMD_SYSTEM)
+                return -ENOTSUP;
+
+        if (!filename_is_safe(name))
+                return -EINVAL;
+
+        p = strjoin(runtime ? "/run/systemd/system/" : "/etc/systemd/systemd/", u->id, ".d", NULL);
+        if (!p)
+                return -ENOMEM;
+
+        q = strjoin(p, "/50-", name, ".conf", NULL);
+        if (!q)
+                return -ENOMEM;
+
+        if (unlink(q) < 0)
+                return -errno;
+
+        rmdir(p);
+        return 0;
+}
+
 static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = {
         [UNIT_ACTIVE] = "active",
         [UNIT_RELOADING] = "reloading",