[systemd-commits] 4 commits - Makefile.am TODO src/core src/shared src/systemctl

Lennart Poettering lennart at kemper.freedesktop.org
Fri Jan 18 16:02:44 PST 2013


 Makefile.am               |    3 -
 TODO                      |    7 +++
 src/core/dbus-unit.c      |  103 ++++++++++++++++++++++++++++++++++------------
 src/core/mount.c          |    4 +
 src/core/service.c        |    4 +
 src/core/socket.c         |    4 +
 src/core/swap.c           |    4 +
 src/core/unit.c           |   68 ++++++++++++++++++++++++++----
 src/core/unit.h           |    6 ++
 src/shared/cgroup-util.c  |   64 ++++++++++++++++++++++------
 src/shared/cgroup-util.h  |    2 
 src/shared/dbus-common.c  |   61 +++++++++++++++++++++++++++
 src/shared/dbus-common.h  |    1 
 src/shared/util.c         |   37 +++++++++++-----
 src/shared/util.h         |    1 
 src/systemctl/systemctl.c |   14 ++++--
 16 files changed, 313 insertions(+), 70 deletions(-)

New commits:
commit 71645acac27da55d510f2e4d61cc61b4e5b93035
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Jan 19 01:01:41 2013 +0100

    unit: optionally allow making cgroup attribute changes persistent

diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index d2f8ebf..d1de46a 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -896,10 +896,32 @@ oom:
         return DBUS_HANDLER_RESULT_NEED_MEMORY;
 }
 
+static int next_and_parse_mode(DBusMessageIter *iter, bool *runtime) {
+        const char *mode;
+
+        assert(iter);
+        assert(runtime);
+
+        dbus_message_iter_next(iter);
+        if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+                return -EINVAL;
+
+        dbus_message_iter_get_basic(iter, &mode);
+        if (streq(mode, "runtime"))
+                *runtime = true;
+        else if (streq(mode, "persistent"))
+                *runtime = false;
+        else
+                return -EINVAL;
+
+        return 0;
+}
+
 int bus_unit_cgroup_set(Unit *u, DBusMessageIter *iter) {
         int r;
         _cleanup_strv_free_ char **a = NULL;
         char **name;
+        bool runtime;
 
         assert(u);
         assert(iter);
@@ -911,8 +933,12 @@ int bus_unit_cgroup_set(Unit *u, DBusMessageIter *iter) {
         if (r < 0)
                 return r;
 
+        r = next_and_parse_mode(iter, &runtime);
+        if (r < 0)
+                return r;
+
         STRV_FOREACH(name, a) {
-                _cleanup_free_ char *controller = NULL, *old_path = NULL, *new_path = NULL;
+                _cleanup_free_ char *controller = NULL, *old_path = NULL, *new_path = NULL, *contents = NULL;
                 CGroupBonding *b;
 
                 r = cg_split_spec(*name, &controller, &new_path);
@@ -938,6 +964,15 @@ int bus_unit_cgroup_set(Unit *u, DBusMessageIter *iter) {
                         if (old_path)
                                 cg_trim(controller, old_path, true);
                 }
+
+                contents = strjoin("[", UNIT_VTABLE(u)->exec_section, "]\n"
+                                   "ControlGroup=", *name, "\n", NULL);
+                if (!contents)
+                        return -ENOMEM;
+
+                r = unit_write_drop_in(u, runtime, *name, contents);
+                if (r < 0)
+                        return r;
         }
 
         return 0;
@@ -947,6 +982,7 @@ int bus_unit_cgroup_unset(Unit *u, DBusMessageIter *iter) {
         _cleanup_strv_free_ char **a = NULL;
         char **name;
         int r;
+        bool runtime;
 
         assert(u);
         assert(iter);
@@ -958,6 +994,10 @@ int bus_unit_cgroup_unset(Unit *u, DBusMessageIter *iter) {
         if (r < 0)
                 return r;
 
+        r = next_and_parse_mode(iter, &runtime);
+        if (r < 0)
+                return r;
+
         STRV_FOREACH(name, a) {
                 _cleanup_free_ char *controller = NULL, *path = NULL, *target = NULL;
                 CGroupBonding *b;
@@ -966,6 +1006,11 @@ int bus_unit_cgroup_unset(Unit *u, DBusMessageIter *iter) {
                 if (r < 0)
                         return r;
 
+                if (!controller || streq(controller, SYSTEMD_CGROUP_CONTROLLER))
+                        return -EINVAL;
+
+                unit_remove_drop_in(u, runtime, *name);
+
                 b = cgroup_bonding_find_list(u->cgroup_bondings, controller);
                 if (!b)
                         continue;
@@ -1004,16 +1049,12 @@ int bus_unit_cgroup_attribute_get(Unit *u, DBusMessageIter *iter, char ***_resul
 
         STRV_FOREACH(name, l) {
                 _cleanup_free_ char *controller = NULL;
-                const char *dot;
                 CGroupAttribute *a;
                 CGroupBonding *b;
 
-                dot = strchr(*name, '.');
-                if (dot) {
-                        controller = strndup(*name, dot - *name);
-                        if (!controller)
-                                return -ENOMEM;
-                }
+                r = cg_controller_from_attr(*name, &controller);
+                if (r < 0)
+                        return r;
 
                 /* First attempt, read the value from the kernel */
                 b = cgroup_bonding_find_list(u->cgroup_bondings, controller);
@@ -1055,8 +1096,10 @@ int bus_unit_cgroup_attribute_get(Unit *u, DBusMessageIter *iter, char ***_resul
 }
 
 int bus_unit_cgroup_attribute_set(Unit *u, DBusMessageIter *iter) {
-        DBusMessageIter sub, sub2;
+        _cleanup_strv_free_ char **l = NULL;
         int r;
+        bool runtime = false;
+        char **name, **value;
 
         assert(u);
         assert(iter);
@@ -1064,27 +1107,19 @@ int bus_unit_cgroup_attribute_set(Unit *u, DBusMessageIter *iter) {
         if (!unit_get_exec_context(u))
                 return -EINVAL;
 
-        if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
-            dbus_message_iter_get_element_type(iter) != DBUS_TYPE_STRUCT)
-            return -EINVAL;
+        r = bus_parse_strv_pairs_iter(iter, &l);
+        if (r < 0)
+                return r;
 
-        dbus_message_iter_recurse(iter, &sub);
+        r = next_and_parse_mode(iter, &runtime);
+        if (r < 0)
+                return r;
 
-        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
-                const char *name, *value;
+        STRV_FOREACH_PAIR(name, value, l) {
+                _cleanup_free_ char *contents = NULL;
                 CGroupAttribute *a;
 
-                assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT);
-
-                dbus_message_iter_recurse(&sub, &sub2);
-
-                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
-                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) < 0)
-                        return -EINVAL;
-
-                dbus_message_iter_next(&sub);
-
-                r = unit_add_cgroup_attribute(u, NULL, name, value, NULL, &a);
+                r = unit_add_cgroup_attribute(u, NULL, *name, *value, NULL, &a);
                 if (r < 0)
                         return r;
 
@@ -1107,6 +1142,15 @@ int bus_unit_cgroup_attribute_set(Unit *u, DBusMessageIter *iter) {
                         /* Make it count */
                         cgroup_attribute_apply(a, u->cgroup_bondings);
                 }
+
+                contents = strjoin("[", UNIT_VTABLE(u)->exec_section, "]\n"
+                                   "ControlGroupAttribute=", *name, " ", *value, "\n", NULL);
+                if (!contents)
+                        return -ENOMEM;
+
+                r = unit_write_drop_in(u, runtime, *name, contents);
+                if (r < 0)
+                        return r;
         }
 
         return 0;
@@ -1115,6 +1159,7 @@ int bus_unit_cgroup_attribute_set(Unit *u, DBusMessageIter *iter) {
 int bus_unit_cgroup_attribute_unset(Unit *u, DBusMessageIter *iter) {
         _cleanup_strv_free_ char **l = NULL;
         char **name;
+        bool runtime;
         int r;
 
         assert(u);
@@ -1127,12 +1172,18 @@ int bus_unit_cgroup_attribute_unset(Unit *u, DBusMessageIter *iter) {
         if (r < 0)
                 return r;
 
+        r = next_and_parse_mode(iter, &runtime);
+        if (r < 0)
+                return r;
+
         STRV_FOREACH(name, l) {
                 CGroupAttribute *a;
 
                 a = cgroup_attribute_find_list(u->cgroup_attributes, NULL, *name);
                 if (a)
                         cgroup_attribute_free(a);
+
+                unit_remove_drop_in(u, runtime, *name);
         }
 
         return 0;
diff --git a/src/core/mount.c b/src/core/mount.c
index 18ce73b..03eff9d 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -1888,13 +1888,15 @@ DEFINE_STRING_TABLE_LOOKUP(mount_result, MountResult);
 
 const UnitVTable mount_vtable = {
         .object_size = sizeof(Mount),
-        .exec_context_offset = offsetof(Mount, exec_context),
 
         .sections =
                 "Unit\0"
                 "Mount\0"
                 "Install\0",
 
+        .exec_context_offset = offsetof(Mount, exec_context),
+        .exec_section = "Mount",
+
         .no_alias = true,
         .no_instances = true,
 
diff --git a/src/core/service.c b/src/core/service.c
index bc41617..ee5a1a4 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -3832,13 +3832,15 @@ DEFINE_STRING_TABLE_LOOKUP(start_limit_action, StartLimitAction);
 
 const UnitVTable service_vtable = {
         .object_size = sizeof(Service),
-        .exec_context_offset = offsetof(Service, exec_context),
 
         .sections =
                 "Unit\0"
                 "Service\0"
                 "Install\0",
 
+        .exec_context_offset = offsetof(Service, exec_context),
+        .exec_section = "Service",
+
         .init = service_init,
         .done = service_done,
         .load = service_load,
diff --git a/src/core/socket.c b/src/core/socket.c
index f2d8548..f74d88e 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -2388,13 +2388,15 @@ DEFINE_STRING_TABLE_LOOKUP(socket_result, SocketResult);
 
 const UnitVTable socket_vtable = {
         .object_size = sizeof(Socket),
-        .exec_context_offset = offsetof(Socket, exec_context),
 
         .sections =
                 "Unit\0"
                 "Socket\0"
                 "Install\0",
 
+        .exec_context_offset = offsetof(Socket, exec_context),
+        .exec_section = "Socket",
+
         .init = socket_init,
         .done = socket_done,
         .load = socket_load,
diff --git a/src/core/swap.c b/src/core/swap.c
index c8e25d0..a2f1187 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -1382,13 +1382,15 @@ DEFINE_STRING_TABLE_LOOKUP(swap_result, SwapResult);
 
 const UnitVTable swap_vtable = {
         .object_size = sizeof(Swap),
-        .exec_context_offset = offsetof(Swap, exec_context),
 
         .sections =
                 "Unit\0"
                 "Swap\0"
                 "Install\0",
 
+        .exec_context_offset = offsetof(Swap, exec_context),
+        .exec_section = "Swap",
+
         .no_alias = true,
         .no_instances = true,
 
diff --git a/src/core/unit.c b/src/core/unit.c
index 6cf0236..98237c8 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -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,
@@ -2758,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",
diff --git a/src/core/unit.h b/src/core/unit.h
index 23cd9ef..297b35d 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -271,6 +271,9 @@ struct UnitVTable {
          * ExecContext is found, if the unit type has that */
         size_t exec_context_offset;
 
+        /* The name of the section with the exec settings of ExecContext */
+        const char *exec_section;
+
         /* Config file sections this unit type understands, separated
          * by NUL chars */
         const char *sections;
@@ -551,6 +554,9 @@ int unit_exec_context_defaults(Unit *u, ExecContext *c);
 
 ExecContext *unit_get_exec_context(Unit *u);
 
+int unit_write_drop_in(Unit *u, bool runtime, const char *name, const char *data);
+int unit_remove_drop_in(Unit *u, bool runtime, const char *name);
+
 const char *unit_active_state_to_string(UnitActiveState i);
 UnitActiveState unit_active_state_from_string(const char *s);
 
diff --git a/src/shared/dbus-common.c b/src/shared/dbus-common.c
index e9a78c2..50891a8 100644
--- a/src/shared/dbus-common.c
+++ b/src/shared/dbus-common.c
@@ -927,6 +927,67 @@ int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l) {
         return 0;
 }
 
+int bus_parse_strv_pairs_iter(DBusMessageIter *iter, char ***_l) {
+        DBusMessageIter sub, sub2;
+        unsigned n = 0, i = 0;
+        char **l;
+
+        assert(iter);
+        assert(_l);
+
+        if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
+            dbus_message_iter_get_element_type(iter) != DBUS_TYPE_STRUCT)
+            return -EINVAL;
+
+        dbus_message_iter_recurse(iter, &sub);
+
+        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+                n++;
+                dbus_message_iter_next(&sub);
+        }
+
+        l = new(char*, n*2+1);
+        if (!l)
+                return -ENOMEM;
+
+        dbus_message_iter_recurse(iter, &sub);
+
+        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+                const char *a, *b;
+
+                assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT);
+
+                dbus_message_iter_recurse(&sub, &sub2);
+
+                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &a, true) < 0 ||
+                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &b, false) < 0)
+                        return -EINVAL;
+
+                l[i] = strdup(a);
+                if (!l[i]) {
+                        strv_free(l);
+                        return -ENOMEM;
+                }
+
+                l[++i] = strdup(b);
+                if (!l[i]) {
+                        strv_free(l);
+                        return -ENOMEM;
+                }
+
+                i++;
+                dbus_message_iter_next(&sub);
+        }
+
+        assert(i == n*2);
+        l[i] = NULL;
+
+        if (_l)
+                *_l = l;
+
+        return 0;
+}
+
 int bus_append_strv_iter(DBusMessageIter *iter, char **l) {
         DBusMessageIter sub;
 
diff --git a/src/shared/dbus-common.h b/src/shared/dbus-common.h
index bcbf18f..e141c9e 100644
--- a/src/shared/dbus-common.h
+++ b/src/shared/dbus-common.h
@@ -197,6 +197,7 @@ unsigned bus_events_to_flags(uint32_t events);
 
 int bus_parse_strv(DBusMessage *m, char ***_l);
 int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l);
+int bus_parse_strv_pairs_iter(DBusMessageIter *iter, char ***_l);
 
 int bus_append_strv_iter(DBusMessageIter *iter, char **l);
 
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index fb4ae24..408a4f0 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -2177,6 +2177,7 @@ static int set_cgroup(DBusConnection *bus, char **args) {
         DBusMessageIter iter;
         int r;
         _cleanup_free_ char *n = NULL;
+        const char *runtime;
 
         assert(bus);
         assert(args);
@@ -2208,6 +2209,10 @@ static int set_cgroup(DBusConnection *bus, char **args) {
         if (r < 0)
                 return log_oom();
 
+        runtime = arg_runtime ? "runtime" : "persistent";
+        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &runtime))
+                return log_oom();
+
         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
         if (!reply) {
                 log_error("Failed to issue method call: %s", bus_error_message(&error));
@@ -2224,6 +2229,7 @@ static int set_cgroup_attr(DBusConnection *bus, char **args) {
         DBusMessageIter iter, sub, sub2;
         char **x, **y;
         _cleanup_free_ char *n = NULL;
+        const char *runtime;
 
         assert(bus);
         assert(args);
@@ -2260,8 +2266,10 @@ static int set_cgroup_attr(DBusConnection *bus, char **args) {
                         return log_oom();
         }
 
-        if (!dbus_message_iter_close_container(&iter, &sub))
-                return -ENOMEM;
+        runtime = arg_runtime ? "runtime" : "persistent";
+        if (!dbus_message_iter_close_container(&iter, &sub) ||
+            !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &runtime))
+                return log_oom();
 
         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
         if (!reply) {
@@ -3163,7 +3171,7 @@ static int print_property(const char *name, DBusMessageIter *iter) {
                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 &&
                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) {
 
-                                        printf("ControlGroupAttribute={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
+                                        printf("ControlGroupAttributes={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
                                                controller,
                                                attr,
                                                value);

commit e884315e3d28df0d5f4e7d4590730e9760b8f447
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Jan 19 00:59:19 2013 +0100

    cgroup: additional validity checks for cgroup attribute names

diff --git a/src/core/unit.c b/src/core/unit.c
index 83359e1..6cf0236 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -2156,26 +2156,27 @@ int unit_add_cgroup_attribute(
 
         _cleanup_free_ char *c = NULL;
         CGroupAttribute *a;
+        int r;
 
         assert(u);
         assert(name);
         assert(value);
 
         if (!controller) {
-                const char *dot;
-
-                dot = strchr(name, '.');
-                if (!dot)
+                r = cg_controller_from_attr(name, &c);
+                if (r < 0)
                         return -EINVAL;
 
-                c = strndup(name, dot - name);
-                if (!c)
-                        return -ENOMEM;
-
                 controller = c;
+        } else {
+                if (!filename_is_safe(name))
+                        return -EINVAL;
+
+                if (!filename_is_safe(controller))
+                        return -EINVAL;
         }
 
-        if (streq(controller, SYSTEMD_CGROUP_CONTROLLER))
+        if (!controller || streq(controller, SYSTEMD_CGROUP_CONTROLLER))
                 return -EINVAL;
 
         a = cgroup_attribute_find_list(u->cgroup_attributes, controller, name);
diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c
index f0d0d48..acace52 100644
--- a/src/shared/cgroup-util.c
+++ b/src/shared/cgroup-util.c
@@ -990,6 +990,8 @@ int cg_split_spec(const char *spec, char **controller, char **path) {
         assert(spec);
 
         if (*spec == '/') {
+                if (!path_is_safe(spec))
+                        return -EINVAL;
 
                 if (path) {
                         t = strdup(spec);
@@ -1007,7 +1009,7 @@ int cg_split_spec(const char *spec, char **controller, char **path) {
 
         e = strchr(spec, ':');
         if (!e) {
-                if (strchr(spec, '/') || spec[0] == 0)
+                if (!filename_is_safe(spec))
                         return -EINVAL;
 
                 if (controller) {
@@ -1024,29 +1026,34 @@ int cg_split_spec(const char *spec, char **controller, char **path) {
                 return 0;
         }
 
-        if (e[1] != '/' || e == spec || memchr(spec, '/', e-spec))
+        t = strndup(spec, e-spec);
+        if (!t)
+                return -ENOMEM;
+        if (!filename_is_safe(t)) {
+                free(t);
                 return -EINVAL;
-
-        if (controller) {
-                t = strndup(spec, e-spec);
-                if (!t)
-                        return -ENOMEM;
-
         }
 
-        if (path) {
-                u = strdup(e+1);
-                if (!u) {
-                        free(t);
-                        return -ENOMEM;
-                }
+        u = strdup(e+1);
+        if (!u) {
+                free(t);
+                return -ENOMEM;
+        }
+        if (!path_is_safe(u)) {
+                free(t);
+                free(u);
+                return -EINVAL;
         }
 
         if (controller)
                 *controller = t;
+        else
+                free(t);
 
         if (path)
                 *path = u;
+        else
+                free(u);
 
         return 0;
 }
@@ -1290,3 +1297,32 @@ int cg_pid_get_unit(pid_t pid, char **unit) {
 int cg_pid_get_user_unit(pid_t pid, char **unit) {
         return cg_pid_get("/user/", pid, unit);
 }
+
+int cg_controller_from_attr(const char *attr, char **controller) {
+        const char *dot;
+        char *c;
+
+        assert(attr);
+        assert(controller);
+
+        if (!filename_is_safe(attr))
+                return -EINVAL;
+
+        dot = strchr(attr, '.');
+        if (!dot) {
+                *controller = NULL;
+                return 0;
+        }
+
+        c = strndup(attr, dot - attr);
+        if (!c)
+                return -ENOMEM;
+
+        if (!filename_is_safe(c)) {
+                free(c);
+                return -EINVAL;
+        }
+
+        *controller = c;
+        return 1;
+}
diff --git a/src/shared/cgroup-util.h b/src/shared/cgroup-util.h
index 920cf63..06c6bfb 100644
--- a/src/shared/cgroup-util.h
+++ b/src/shared/cgroup-util.h
@@ -76,3 +76,5 @@ int cg_pid_get_user_unit(pid_t pid, char **unit);
 int cgroup_to_unit(char *cgroup, char **unit);
 
 char **cg_shorten_controllers(char **controllers);
+
+int cg_controller_from_attr(const char *attr, char **controller);
diff --git a/src/shared/util.c b/src/shared/util.c
index 37e383f..1aaebf0 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -561,9 +561,9 @@ int fchmod_umask(int fd, mode_t m) {
 }
 
 int write_one_line_file_atomic(const char *fn, const char *line) {
-        FILE *f;
+        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_free_ char *p = NULL;
         int r;
-        char *p;
 
         assert(fn);
         assert(line);
@@ -585,12 +585,9 @@ int write_one_line_file_atomic(const char *fn, const char *line) {
 
         fflush(f);
 
-        if (ferror(f)) {
-                if (errno != 0)
-                        r = -errno;
-                else
-                        r = -EIO;
-        } else {
+        if (ferror(f))
+                r = errno ? -errno : -EIO;
+        else {
                 if (rename(p, fn) < 0)
                         r = -errno;
                 else
@@ -601,9 +598,6 @@ finish:
         if (r < 0)
                 unlink(p);
 
-        fclose(f);
-        free(p);
-
         return r;
 }
 
@@ -5613,6 +5607,27 @@ bool string_is_safe(const char *p) {
         return true;
 }
 
+bool path_is_safe(const char *p) {
+
+        if (isempty(p))
+                return false;
+
+        if (streq(p, "..") || startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../"))
+                return false;
+
+        if (strlen(p) > PATH_MAX)
+                return false;
+
+        /* The following two checks are not really dangerous, but hey, they still are confusing */
+        if (streq(p, ".") || startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./"))
+                return false;
+
+        if (strstr(p, "//"))
+                return false;
+
+        return true;
+}
+
 /* hey glibc, APIs with callbacks without a user pointer are so useless */
 void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
                  int (*compar) (const void *, const void *, void *), void *arg) {
diff --git a/src/shared/util.h b/src/shared/util.h
index cdaff45..d260385 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -543,6 +543,7 @@ _malloc_ static inline void *memdup_multiply(const void *p, size_t a, size_t b)
 }
 
 bool filename_is_safe(const char *p);
+bool path_is_safe(const char *p);
 bool string_is_safe(const char *p);
 
 void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,

commit adf36dd0aec564a00a7445e328c3e27f44938629
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Jan 19 00:11:45 2013 +0100

    update TODO

diff --git a/TODO b/TODO
index a74ffc3..626ea3d 100644
--- a/TODO
+++ b/TODO
@@ -20,6 +20,13 @@ Fedora 19:
 
 Features:
 
+* link runlevel targets on install only if sysv compat is enabled
+
+* logind: when executing sleep/shutdown job, keep track of its id, and
+  as long as the job is running refuse any further operation.
+
+* maybe not install getty at tty1.service symlink in /etc but in /usr?
+
 * re-enable "make check" for gtk-doc (broken for unknown reason)
 
 * logind: make PrepareForSuspend(false) an official api for notification of resumes

commit 0fa57908e1b159867299261bc46c7a03629709e4
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Jan 19 00:11:36 2013 +0100

    build-sys: prune the list of directories we create on install

diff --git a/Makefile.am b/Makefile.am
index 25d9995..c57ea0d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3967,10 +3967,7 @@ systemd-install-data-hook:
 		$(DESTDIR)$(systemunitdir)/runlevel4.target.wants \
 		$(DESTDIR)$(systemunitdir)/runlevel5.target.wants \
 		$(DESTDIR)$(systemunitdir)/multi-user.target.wants \
-		$(DESTDIR)$(systemunitdir)/graphical.target.wants \
 		$(DESTDIR)$(pkgsysconfdir)/system \
-		$(DESTDIR)$(pkgsysconfdir)/system/sysinit.target.wants \
-		$(DESTDIR)$(pkgsysconfdir)/system/local-fs.target.wants \
 		$(DESTDIR)$(pkgsysconfdir)/system/multi-user.target.wants \
 		$(DESTDIR)$(pkgsysconfdir)/system/getty.target.wants \
 		$(DESTDIR)$(pkgsysconfdir)/user \



More information about the systemd-commits mailing list