chiark / gitweb /
Prep v226: Apply missing fixes and changes to src/basic
authorSven Eden <yamakuzure@gmx.net>
Mon, 9 Jan 2017 04:53:00 +0000 (05:53 +0100)
committerSven Eden <yamakuzure@gmx.net>
Tue, 14 Mar 2017 09:22:32 +0000 (10:22 +0100)
18 files changed:
Makefile-man.am
src/basic/cgroup-util.c
src/basic/cgroup-util.h
src/basic/conf-files.h
src/basic/macro.h
src/basic/missing.h
src/basic/ring.h
src/basic/selinux-util.c
src/basic/special.h
src/basic/terminal-util.c
src/basic/terminal-util.h
src/basic/time-util.c
src/basic/time-util.h
src/basic/unit-name.c
src/basic/unit-name.h
src/basic/util.c
src/basic/util.h
src/basic/virt.c

index 35eec77..845f96a 100644 (file)
@@ -363,15 +363,6 @@ man/sd_session_is_remote.html: man/sd_session_is_active.html
 
 endif
 
-if HAVE_PYTHON
-MANPAGES += \
-       man/systemd.index.7
-MANPAGES_ALIAS += \
-       #
-
-
-endif
-
 # Really, do not edit this file.
 
 EXTRA_DIST += \
index b9fd9a6..ec42e25 100644 (file)
@@ -29,7 +29,6 @@
 #include <sys/types.h>
 #include <ftw.h>
 
-#include "cgroup-util.h"
 #include "set.h"
 #include "macro.h"
 #include "util.h"
@@ -41,6 +40,7 @@
 #include "special.h"
 #include "mkdir.h"
 #include "login-util.h"
+#include "cgroup-util.h"
 
 int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {
         _cleanup_free_ char *fs = NULL;
@@ -187,7 +187,7 @@ int cg_kill(const char *controller, const char *path, int sig, bool sigcont, boo
                         if (ignore_self && pid == my_pid)
                                 continue;
 
-                        if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
+                        if (set_get(s, PID_TO_PTR(pid)) == PID_TO_PTR(pid))
                                 continue;
 
                         /* If we haven't killed this process yet, kill
@@ -197,7 +197,7 @@ int cg_kill(const char *controller, const char *path, int sig, bool sigcont, boo
                                         ret = -errno;
                         } else {
                                 if (sigcont && sig != SIGKILL)
-                                        kill(pid, SIGCONT);
+                                        (void) kill(pid, SIGCONT);
 
                                 if (ret == 0)
                                         ret = 1;
@@ -205,7 +205,7 @@ int cg_kill(const char *controller, const char *path, int sig, bool sigcont, boo
 
                         done = false;
 
-                        r = set_put(s, LONG_TO_PTR(pid));
+                        r = set_put(s, PID_TO_PTR(pid));
                         if (r < 0) {
                                 if (ret >= 0)
                                         return r;
@@ -233,7 +233,7 @@ int cg_kill(const char *controller, const char *path, int sig, bool sigcont, boo
 int cg_kill_recursive(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, bool rem, Set *s) {
         _cleanup_set_free_ Set *allocated_set = NULL;
         _cleanup_closedir_ DIR *d = NULL;
-        int r, ret = 0;
+        int r, ret;
         char *fn;
 
         assert(path);
@@ -264,7 +264,7 @@ int cg_kill_recursive(const char *controller, const char *path, int sig, bool si
                         return -ENOMEM;
 
                 r = cg_kill_recursive(controller, p, sig, sigcont, ignore_self, rem, s);
-                if (ret >= 0 && r != 0)
+                if (r != 0 && ret >= 0)
                         ret = r;
         }
 
@@ -318,7 +318,7 @@ int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char
                         if (ignore_self && pid == my_pid)
                                 continue;
 
-                        if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
+                        if (set_get(s, PID_TO_PTR(pid)) == PID_TO_PTR(pid))
                                 continue;
 
                         /* Ignore kernel threads. Since they can only
@@ -338,7 +338,7 @@ int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char
 
                         done = false;
 
-                        r = set_put(s, LONG_TO_PTR(pid));
+                        r = set_put(s, PID_TO_PTR(pid));
                         if (r < 0) {
                                 if (ret >= 0)
                                         return r;
@@ -390,13 +390,9 @@ int cg_migrate_recursive(
 
                 p = strjoin(pfrom, "/", fn, NULL);
                 free(fn);
-                if (!p) {
-                        if (ret >= 0)
+                if (!p)
                                 return -ENOMEM;
 
-                        return ret;
-                }
-
                 r = cg_migrate_recursive(cfrom, p, cto, pto, ignore_self, rem);
                 if (r != 0 && ret >= 0)
                         ret = r;
@@ -436,114 +432,174 @@ int cg_migrate_recursive_fallback(
                 /* This didn't work? Then let's try all prefixes of the destination */
 
                 PATH_FOREACH_PREFIX(prefix, pto) {
-                        r = cg_migrate_recursive(cfrom, pfrom, cto, prefix, ignore_self, rem);
-                        if (r >= 0)
-                                break;
+                        int q;
+
+                        q = cg_migrate_recursive(cfrom, pfrom, cto, prefix, ignore_self, rem);
+                        if (q >= 0)
+                                return q;
                 }
         }
 
-        return 0;
+        return r;
 }
 
-static const char *normalize_controller(const char *controller) {
+static const char *controller_to_dirname(const char *controller) {
+        const char *e;
 
         assert(controller);
 
-        if (startswith(controller, "name="))
-                return controller + 5;
-        else
+        /* Converts a controller name to the directory name below
+         * /sys/fs/cgroup/ we want to mount it to. Effectively, this
+         * just cuts off the name= prefixed used for named
+         * hierarchies, if it is specified. */
+
+        e = startswith(controller, "name=");
+        if (e)
+                return e;
+
                 return controller;
 }
 
-static int join_path(const char *controller, const char *path, const char *suffix, char **fs) {
+static int join_path_legacy(const char *controller, const char *path, const char *suffix, char **fs) {
+        const char *dn;
         char *t = NULL;
 
-        if (!isempty(controller)) {
-                if (!isempty(path) && !isempty(suffix))
-                        t = strjoin("/sys/fs/cgroup/", controller, "/", path, "/", suffix, NULL);
-                else if (!isempty(path))
-                        t = strjoin("/sys/fs/cgroup/", controller, "/", path, NULL);
-                else if (!isempty(suffix))
-                        t = strjoin("/sys/fs/cgroup/", controller, "/", suffix, NULL);
-                else
-                        t = strappend("/sys/fs/cgroup/", controller);
-        } else {
-                if (!isempty(path) && !isempty(suffix))
-                        t = strjoin(path, "/", suffix, NULL);
-                else if (!isempty(path))
-                        t = strdup(path);
+        assert(fs);
+        assert(controller);
+
+        dn = controller_to_dirname(controller);
+
+        if (isempty(path) && isempty(suffix))
+                t = strappend("/sys/fs/cgroup/", dn);
+        else if (isempty(path))
+                t = strjoin("/sys/fs/cgroup/", dn, "/", suffix, NULL);
+        else if (isempty(suffix))
+                t = strjoin("/sys/fs/cgroup/", dn, "/", path, NULL);
                 else
-                        return -EINVAL;
+                t = strjoin("/sys/fs/cgroup/", dn, "/", path, "/", suffix, NULL);
+        if (!t)
+                return -ENOMEM;
+
+        *fs = t;
+        return 0;
         }
 
+static int join_path_unified(const char *path, const char *suffix, char **fs) {
+        char *t;
+
+        assert(fs);
+
+        if (isempty(path) && isempty(suffix))
+                t = strdup("/sys/fs/cgroup");
+        else if (isempty(path))
+                t = strappend("/sys/fs/cgroup/", suffix);
+        else if (isempty(suffix))
+                t = strappend("/sys/fs/cgroup/", path);
+        else
+                t = strjoin("/sys/fs/cgroup/", path, "/", suffix, NULL);
         if (!t)
                 return -ENOMEM;
 
-        *fs = path_kill_slashes(t);
+        *fs = t;
         return 0;
 }
 
 int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) {
-        const char *p;
-        static thread_local bool good = false;
+        int unified, r;
 
         assert(fs);
 
-        if (controller && !cg_controller_is_valid(controller))
+        if (!controller) {
+                char *t;
+
+                /* If no controller is specified, we return the path
+                 * *below* the controllers, without any prefix. */
+
+                if (!path && !suffix)
                 return -EINVAL;
 
-        if (_unlikely_(!good)) {
-                int r;
+                if (!suffix)
+                        t = strdup(path);
+                else if (!path)
+                        t = strdup(suffix);
+                else
+                        t = strjoin(path, "/", suffix, NULL);
+                if (!t)
+                        return -ENOMEM;
 
-                r = path_is_mount_point("/sys/fs/cgroup", 0);
+                *fs = path_kill_slashes(t);
+                return 0;
+        }
+
+        if (!cg_controller_is_valid(controller))
+                return -EINVAL;
+
+        unified = cg_unified();
+        if (unified < 0)
+                return unified;
+
+        if (unified > 0)
+                r = join_path_unified(path, suffix, fs);
+        else
+                r = join_path_legacy(controller, path, suffix, fs);
                 if (r < 0)
                         return r;
-                if (r == 0)
-                        return -ENOENT;
 
-                /* Cache this to save a few stat()s */
-                good = true;
+        path_kill_slashes(*fs);
+        return 0;
         }
 
-        p = controller ? normalize_controller(controller) : NULL;
+static int controller_is_accessible(const char *controller) {
+        int unified;
 
-        return join_path(p, path, suffix, fs);
-}
+        assert(controller);
 
-static int check_hierarchy(const char *p) {
-        const char *cc;
+        /* Checks whether a specific controller is accessible,
+         * i.e. its hierarchy mounted. In the unified hierarchy all
+         * controllers are considered accessible, except for the named
+         * hierarchies */
 
-        assert(p);
+        if (!cg_controller_is_valid(controller))
+                return -EINVAL;
+
+        unified = cg_unified();
+        if (unified < 0)
+                return unified;
+        if (unified > 0) {
+                /* We don't support named hierarchies if we are using
+                 * the unified hierarchy. */
 
-        if (!filename_is_valid(p))
+                if (streq(controller, ELOGIND_CGROUP_CONTROLLER))
                 return 0;
 
-        /* Check if this controller actually really exists */
-        cc = strjoina("/sys/fs/cgroup/", p);
+                if (startswith(controller, "name="))
+                        return -EOPNOTSUPP;
+
+        } else {
+                const char *cc, *dn;
+
+                dn = controller_to_dirname(controller);
+                cc = strjoina("/sys/fs/cgroup/", dn);
+
         if (laccess(cc, F_OK) < 0)
                 return -errno;
+        }
 
         return 0;
 }
 
 int cg_get_path_and_check(const char *controller, const char *path, const char *suffix, char **fs) {
-        const char *p;
         int r;
 
+        assert(controller);
         assert(fs);
 
-        if (!cg_controller_is_valid(controller))
-                return -EINVAL;
-
-        /* Normalize the controller syntax */
-        p = normalize_controller(controller);
-
-        /* Check if this controller actually really exists */
-        r = check_hierarchy(p);
+        /* Check if the specified controller is actually accessible */
+        r = controller_is_accessible(controller);
         if (r < 0)
                 return r;
 
-        return join_path(p, path, suffix, fs);
+        return cg_get_path(controller, path, suffix, fs);
 }
 
 static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
@@ -557,7 +613,7 @@ static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct
         if (ftwbuf->level < 1)
                 return 0;
 
-        rmdir(path);
+        (void) rmdir(path);
         return 0;
 }
 
@@ -572,8 +628,14 @@ int cg_trim(const char *controller, const char *path, bool delete_root) {
                 return r;
 
         errno = 0;
-        if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) != 0)
-                r = errno ? -errno : -EIO;
+        if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) != 0) {
+                if (errno == ENOENT)
+                        r = 0;
+                else if (errno != 0)
+                        r = -errno;
+                else
+                        r = -EIO;
+        }
 
         if (delete_root) {
                 if (rmdir(fs) < 0 && errno != ENOENT)
@@ -583,23 +645,6 @@ int cg_trim(const char *controller, const char *path, bool delete_root) {
         return r;
 }
 
-/// UNNEDED by elogind
-#if 0
-int cg_delete(const char *controller, const char *path) {
-        _cleanup_free_ char *parent = NULL;
-        int r;
-
-        assert(path);
-
-        r = path_get_parent(path, &parent);
-        if (r < 0)
-                return r;
-
-        r = cg_migrate_recursive(controller, path, controller, parent, false, true);
-        return r == -ENOENT ? 0 : r;
-}
-#endif // 0
-
 int cg_create(const char *controller, const char *path) {
         _cleanup_free_ char *fs = NULL;
         int r;
@@ -678,13 +723,15 @@ int cg_attach_fallback(const char *controller, const char *path, pid_t pid) {
                  * the destination */
 
                 PATH_FOREACH_PREFIX(prefix, path) {
-                        r = cg_attach(controller, prefix, pid);
-                        if (r >= 0)
-                                break;
+                        int q;
+
+                        q = cg_attach(controller, prefix, pid);
+                        if (q >= 0)
+                                return q;
                 }
         }
 
-        return 0;
+        return r;
 }
 
 /// UNNEEDED by elogind
@@ -699,7 +746,8 @@ int cg_set_group_access(
         _cleanup_free_ char *fs = NULL;
         int r;
 
-        assert(path);
+        if (mode == MODE_INVALID && uid == UID_INVALID && gid == GID_INVALID)
+                return 0;
 
         if (mode != MODE_INVALID)
                 mode &= 0777;
@@ -719,7 +767,7 @@ int cg_set_task_access(
                 gid_t gid) {
 
         _cleanup_free_ char *fs = NULL, *procs = NULL;
-        int r;
+        int r, unified;
 
         assert(path);
 
@@ -737,13 +785,18 @@ int cg_set_task_access(
         if (r < 0)
                 return r;
 
+        unified = cg_unified();
+        if (unified < 0)
+                return unified;
+        if (unified)
+                return 0;
+
         /* Compatibility, Always keep values for "tasks" in sync with
          * "cgroup.procs" */
-        r = cg_get_path(controller, path, "tasks", &procs);
-        if (r < 0)
-                return r;
+        if (cg_get_path(controller, path, "tasks", &procs) >= 0)
+                (void) chmod_and_chown(procs, mode, uid, gid);
 
-        return chmod_and_chown(procs, mode, uid, gid);
+        return 0;
 }
 #endif // 0
 
@@ -751,35 +804,49 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
         _cleanup_fclose_ FILE *f = NULL;
         char line[LINE_MAX];
         const char *fs;
-        size_t cs;
+        size_t cs = 0;
+        int unified;
 
         assert(path);
         assert(pid >= 0);
 
+        unified = cg_unified();
+        if (unified < 0)
+                return unified;
+        if (unified == 0) {
         if (controller) {
                 if (!cg_controller_is_valid(controller))
                         return -EINVAL;
-
-                controller = normalize_controller(controller);
         } else
                 controller = ELOGIND_CGROUP_CONTROLLER;
 
-        fs = procfs_file_alloca(pid, "cgroup");
+                cs = strlen(controller);
+        }
 
+        fs = procfs_file_alloca(pid, "cgroup");
         f = fopen(fs, "re");
         if (!f)
                 return errno == ENOENT ? -ESRCH : -errno;
 
-        cs = strlen(controller);
-
         FOREACH_LINE(line, f, return -errno) {
-                char *l, *p, *e;
+                char *e, *p;
+
+                truncate_nl(line);
+
+                if (unified) {
+                        e = startswith(line, "0:");
+                        if (!e)
+                                continue;
+
+                        e = strchr(e, ':');
+                        if (!e)
+                                continue;
+                } else {
+                        char *l;
                 size_t k;
                 const char *word, *state;
                 bool found = false;
 
-                truncate_nl(line);
-
                 l = strchr(line, ':');
                 if (!l)
                         continue;
@@ -790,24 +857,16 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
                         continue;
 
                 *e = 0;
-
                 FOREACH_WORD_SEPARATOR(word, k, l, ",", state) {
-
                         if (k == cs && memcmp(word, controller, cs) == 0) {
                                 found = true;
                                 break;
                         }
-
-                        if (k == 5 + cs &&
-                            memcmp(word, "name=", 5) == 0 &&
-                            memcmp(word+5, controller, cs) == 0) {
-                                found = true;
-                                break;
-                        }
                 }
 
                 if (!found)
                         continue;
+                }
 
                 p = strdup(e + 1);
                 if (!p)
@@ -817,18 +876,24 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
                 return 0;
         }
 
-        return -ENOENT;
+        return -ENODATA;
 }
 
 /// UNNEEDED by elogind
 #if 0
 int cg_install_release_agent(const char *controller, const char *agent) {
         _cleanup_free_ char *fs = NULL, *contents = NULL;
-        char *sc;
-        int r;
+        const char *sc;
+        int r, unified;
 
         assert(agent);
 
+        unified = cg_unified();
+        if (unified < 0)
+                return unified;
+        if (unified) /* doesn't apply to unified hierarchy */
+                return -EOPNOTSUPP;
+
         r = cg_get_path(controller, NULL, "release_agent", &fs);
         if (r < 0)
                 return r;
@@ -838,7 +903,7 @@ int cg_install_release_agent(const char *controller, const char *agent) {
                 return r;
 
         sc = strstrip(contents);
-        if (sc[0] == 0) {
+        if (isempty(sc)) {
                 r = write_string_file_no_create(fs, agent);
                 if (r < 0)
                         return r;
@@ -872,7 +937,13 @@ int cg_install_release_agent(const char *controller, const char *agent) {
 
 int cg_uninstall_release_agent(const char *controller) {
         _cleanup_free_ char *fs = NULL;
-        int r;
+        int r, unified;
+
+        unified = cg_unified();
+        if (unified < 0)
+                return unified;
+        if (unified) /* Doesn't apply to unified hierarchy */
+                return -EOPNOTSUPP;
 
         r = cg_get_path(controller, NULL, "notify_on_release", &fs);
         if (r < 0)
@@ -896,49 +967,69 @@ int cg_uninstall_release_agent(const char *controller) {
 }
 #endif // 0
 
-int cg_is_empty(const char *controller, const char *path, bool ignore_self) {
+int cg_is_empty(const char *controller, const char *path) {
         _cleanup_fclose_ FILE *f = NULL;
-        pid_t pid = 0, self_pid;
-        bool found = false;
+        pid_t pid;
         int r;
 
         assert(path);
 
         r = cg_enumerate_processes(controller, path, &f);
+        if (r == -ENOENT)
+                return 1;
         if (r < 0)
-                return r == -ENOENT ? 1 : r;
+                return r;
+
+        r = cg_read_pid(f, &pid);
+        if (r < 0)
+                return r;
 
-        self_pid = getpid();
+        return r == 0;
+}
 
-        while ((r = cg_read_pid(f, &pid)) > 0) {
+int cg_is_empty_recursive(const char *controller, const char *path) {
+        int unified, r;
 
-                if (ignore_self && pid == self_pid)
-                        continue;
+        assert(path);
 
-                found = true;
-                break;
-        }
+        /* The root cgroup is always populated */
+        if (controller && (isempty(path) || path_equal(path, "/")))
+                return false;
+
+        unified = cg_unified();
+        if (unified < 0)
+                return unified;
+
+        if (unified > 0) {
+                _cleanup_free_ char *populated = NULL, *t = NULL;
+
+                /* On the unified hierarchy we can check empty state
+                 * via the "cgroup.populated" attribute. */
 
+                r = cg_get_path(controller, path, "cgroup.populated", &populated);
         if (r < 0)
                 return r;
 
-        return !found;
-}
+                r = read_one_line_file(populated, &t);
+                if (r == -ENOENT)
+                        return 1;
+                if (r < 0)
+                        return r;
 
-int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self) {
+                return streq(t, "0");
+        } else {
         _cleanup_closedir_ DIR *d = NULL;
         char *fn;
-        int r;
 
-        assert(path);
-
-        r = cg_is_empty(controller, path, ignore_self);
+                r = cg_is_empty(controller, path);
         if (r <= 0)
                 return r;
 
         r = cg_enumerate_subgroups(controller, path, &d);
+                if (r == -ENOENT)
+                        return 1;
         if (r < 0)
-                return r == -ENOENT ? 1 : r;
+                        return r;
 
         while ((r = cg_read_subgroup(d, &fn)) > 0) {
                 _cleanup_free_ char *p = NULL;
@@ -948,21 +1039,20 @@ int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_
                 if (!p)
                         return -ENOMEM;
 
-                r = cg_is_empty_recursive(controller, p, ignore_self);
+                        r = cg_is_empty_recursive(controller, p);
                 if (r <= 0)
                         return r;
         }
-
         if (r < 0)
                 return r;
 
-        return 1;
+                return true;
+        }
 }
 
 int cg_split_spec(const char *spec, char **controller, char **path) {
-        const char *e;
         char *t = NULL, *u = NULL;
-        _cleanup_free_ char *v = NULL;
+        const char *e;
 
         assert(spec);
 
@@ -990,7 +1080,7 @@ int cg_split_spec(const char *spec, char **controller, char **path) {
                         return -EINVAL;
 
                 if (controller) {
-                        t = strdup(normalize_controller(spec));
+                        t = strdup(spec);
                         if (!t)
                                 return -ENOMEM;
 
@@ -1003,10 +1093,7 @@ int cg_split_spec(const char *spec, char **controller, char **path) {
                 return 0;
         }
 
-        v = strndup(spec, e-spec);
-        if (!v)
-                return -ENOMEM;
-        t = strdup(normalize_controller(v));
+        t = strndup(spec, e-spec);
         if (!t)
                 return -ENOMEM;
         if (!cg_controller_is_valid(t)) {
@@ -1014,13 +1101,9 @@ int cg_split_spec(const char *spec, char **controller, char **path) {
                 return -EINVAL;
         }
 
-        if (streq(e+1, "")) {
-                u = strdup("/");
-                if (!u) {
-                        free(t);
-                        return -ENOMEM;
-                }
-        } else {
+        if (isempty(e+1))
+                u = NULL;
+        else {
                 u = strdup(e+1);
                 if (!u) {
                         free(t);
@@ -1087,7 +1170,11 @@ int cg_get_root_path(char **path) {
         if (r < 0)
                 return r;
 
-        e = endswith(p, "/" SPECIAL_SYSTEM_SLICE);
+        e = endswith(p, "/" SPECIAL_INIT_SCOPE);
+        if (!e)
+                e = endswith(p, "/" SPECIAL_SYSTEM_SLICE); /* legacy */
+        if (!e)
+                e = endswith(p, "/system"); /* even more legacy */
         if (e)
                 *e = 0;
 
@@ -1115,7 +1202,7 @@ int cg_shift_path(const char *cgroup, const char *root, const char **shifted) {
         }
 
         p = path_startswith(cgroup, root);
-        if (p)
+        if (p && p > cgroup)
                 *shifted = p - 1;
         else
                 *shifted = cgroup;
@@ -1379,17 +1466,15 @@ int cg_pid_get_user_unit(pid_t pid, char **unit) {
 }
 
 int cg_path_get_machine_name(const char *path, char **machine) {
-        _cleanup_free_ char *u = NULL, *sl = NULL;
+        _cleanup_free_ char *u = NULL;
+        const char *sl;
         int r;
 
         r = cg_path_get_unit(path, &u);
         if (r < 0)
                 return r;
 
-        sl = strjoin("/run/systemd/machines/unit:", u, NULL);
-        if (!sl)
-                return -ENOMEM;
-
+        sl = strjoina("/run/systemd/machines/unit:", u);
         return readlink_malloc(sl, machine);
 }
 
@@ -1582,30 +1667,37 @@ char *cg_escape(const char *p) {
             p[0] == '.' ||
             streq(p, "notify_on_release") ||
             streq(p, "release_agent") ||
-            streq(p, "tasks"))
+            streq(p, "tasks") ||
+            startswith(p, "cgroup."))
                 need_prefix = true;
         else {
                 const char *dot;
 
                 dot = strrchr(p, '.');
                 if (dot) {
+                        CGroupController c;
+                        size_t l = dot - p;
 
-                        if (dot - p == 6 && memcmp(p, "cgroup", 6) == 0)
-                                need_prefix = true;
-                        else {
-                                char *n;
+                        for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
+                                const char *n;
 
-                                n = strndupa(p, dot - p);
+                                n = cgroup_controller_to_string(c);
+
+                                if (l != strlen(n))
+                                        continue;
+
+                                if (memcmp(p, n, l) != 0)
+                                        continue;
 
-                                if (check_hierarchy(n) >= 0)
                                         need_prefix = true;
+                                break;
                         }
                 }
         }
 
         if (need_prefix)
                 return strappend("_", p);
-        else
+
                 return strdup(p);
 }
 
@@ -1742,19 +1834,11 @@ int cg_get_attribute(const char *controller, const char *path, const char *attri
 }
 #endif // 0
 
-static const char mask_names[] =
-        "cpu\0"
-        "cpuacct\0"
-        "blkio\0"
-        "memory\0"
-        "devices\0";
-
 /// UNNEEDED by elogind
 #if 0
-int cg_create_everywhere(CGroupControllerMask supported, CGroupControllerMask mask, const char *path) {
-        CGroupControllerMask bit = 1;
-        const char *n;
-        int r;
+int cg_create_everywhere(CGroupMask supported, CGroupMask mask, const char *path) {
+        CGroupController c;
+        int r, unified;
 
         /* This one will create a cgroup in our private tree, but also
          * duplicate it in the trees specified in mask, and remove it
@@ -1765,44 +1849,58 @@ int cg_create_everywhere(CGroupControllerMask supported, CGroupControllerMask ma
         if (r < 0)
                 return r;
 
-        /* Then, do the same in the other hierarchies */
-        NULSTR_FOREACH(n, mask_names) {
+        /* If we are in the unified hierarchy, we are done now */
+        unified = cg_unified();
+        if (unified < 0)
+                return unified;
+        if (unified > 0)
+                return 0;
+
+        /* Otherwise, do the same in the other hierarchies */
+        for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
+                CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
+                const char *n;
+
+                n = cgroup_controller_to_string(c);
+
                 if (mask & bit)
-                        cg_create(n, path);
+                        (void) cg_create(n, path);
                 else if (supported & bit)
-                        cg_trim(n, path, true);
-
-                bit <<= 1;
+                        (void) cg_trim(n, path, true);
         }
 
         return 0;
 }
 #endif // 0
 
-int cg_attach_everywhere(CGroupControllerMask supported, const char *path, pid_t pid, cg_migrate_callback_t path_callback, void *userdata) {
-        CGroupControllerMask bit = 1;
-        const char *n;
-        int r;
+int cg_attach_everywhere(CGroupMask supported, const char *path, pid_t pid, cg_migrate_callback_t path_callback, void *userdata) {
+        CGroupController c;
+        int r, unified;
 
         r = cg_attach(ELOGIND_CGROUP_CONTROLLER, path, pid);
         if (r < 0)
                 return r;
 
-        NULSTR_FOREACH(n, mask_names) {
+        unified = cg_unified();
+        if (unified < 0)
+                return unified;
+        if (unified > 0)
+                return 0;
 
-                if (supported & bit) {
+        for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
+                CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
                         const char *p = NULL;
 
+                if (!(supported & bit))
+                        continue;
+
                         if (path_callback)
                                 p = path_callback(bit, userdata);
 
                         if (!p)
                                 p = path;
 
-                        cg_attach_fallback(n, p, pid);
-                }
-
-                bit <<= 1;
+                (void) cg_attach_fallback(cgroup_controller_to_string(c), p, pid);
         }
 
         return 0;
@@ -1810,27 +1908,26 @@ int cg_attach_everywhere(CGroupControllerMask supported, const char *path, pid_t
 
 /// UNNEEDED by elogind
 #if 0
-int cg_attach_many_everywhere(CGroupControllerMask supported, const char *path, Set* pids, cg_migrate_callback_t path_callback, void *userdata) {
+int cg_attach_many_everywhere(CGroupMask supported, const char *path, Set* pids, cg_migrate_callback_t path_callback, void *userdata) {
         Iterator i;
         void *pidp;
         int r = 0;
 
         SET_FOREACH(pidp, pids, i) {
-                pid_t pid = PTR_TO_LONG(pidp);
+                pid_t pid = PTR_TO_PID(pidp);
                 int q;
 
                 q = cg_attach_everywhere(supported, path, pid, path_callback, userdata);
-                if (q < 0)
+                if (q < 0 && r >= 0)
                         r = q;
         }
 
         return r;
 }
 
-int cg_migrate_everywhere(CGroupControllerMask supported, const char *from, const char *to, cg_migrate_callback_t to_callback, void *userdata) {
-        CGroupControllerMask bit = 1;
-        const char *n;
-        int r;
+int cg_migrate_everywhere(CGroupMask supported, const char *from, const char *to, cg_migrate_callback_t to_callback, void *userdata) {
+        CGroupController c;
+        int r = 0, unified;
 
         if (!path_equal(from, to))  {
                 r = cg_migrate_recursive(ELOGIND_CGROUP_CONTROLLER, from, ELOGIND_CGROUP_CONTROLLER, to, false, true);
@@ -1838,56 +1935,127 @@ int cg_migrate_everywhere(CGroupControllerMask supported, const char *from, cons
                         return r;
         }
 
-        NULSTR_FOREACH(n, mask_names) {
-                if (supported & bit) {
+        unified = cg_unified();
+        if (unified < 0)
+                return unified;
+        if (unified > 0)
+                return r;
+
+        for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
+                CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
                         const char *p = NULL;
 
+                if (!(supported & bit))
+                        continue;
+
                         if (to_callback)
                                 p = to_callback(bit, userdata);
 
                         if (!p)
                                 p = to;
 
-                        cg_migrate_recursive_fallback(ELOGIND_CGROUP_CONTROLLER, to, n, p, false, false);
-                }
-
-                bit <<= 1;
+                (void) cg_migrate_recursive_fallback(ELOGIND_CGROUP_CONTROLLER, to, cgroup_controller_to_string(c), p, false, false);
         }
 
         return 0;
 }
 
-int cg_trim_everywhere(CGroupControllerMask supported, const char *path, bool delete_root) {
-        CGroupControllerMask bit = 1;
-        const char *n;
-        int r;
+int cg_trim_everywhere(CGroupMask supported, const char *path, bool delete_root) {
+        CGroupController c;
+        int r, unified;
 
         r = cg_trim(ELOGIND_CGROUP_CONTROLLER, path, delete_root);
         if (r < 0)
                 return r;
 
-        NULSTR_FOREACH(n, mask_names) {
-                if (supported & bit)
-                        cg_trim(n, path, delete_root);
+        unified = cg_unified();
+        if (unified < 0)
+                return unified;
+        if (unified > 0)
+                return r;
+
+        for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
+                CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
+
+                if (!(supported & bit))
+                        continue;
 
-                bit <<= 1;
+                (void) cg_trim(cgroup_controller_to_string(c), path, delete_root);
         }
 
         return 0;
 }
 
-CGroupControllerMask cg_mask_supported(void) {
-        CGroupControllerMask bit = 1, mask = 0;
-        const char *n;
+int cg_mask_supported(CGroupMask *ret) {
+        CGroupMask mask = 0;
+        int r, unified;
+
+        /* Determines the mask of supported cgroup controllers. Only
+         * includes controllers we can make sense of and that are
+         * actually accessible. */
+
+        unified = cg_unified();
+        if (unified < 0)
+                return unified;
+        if (unified > 0) {
+                _cleanup_free_ char *root = NULL, *controllers = NULL, *path = NULL;
+                const char *c;
+
+                /* In the unified hierarchy we can read the supported
+                 * and accessible controllers from a the top-level
+                 * cgroup attribute */
+
+                r = cg_get_root_path(&root);
+                if (r < 0)
+                        return r;
+
+                r = cg_get_path(ELOGIND_CGROUP_CONTROLLER, root, "cgroup.controllers", &path);
+                if (r < 0)
+                        return r;
+
+                r = read_one_line_file(path, &controllers);
+                if (r < 0)
+                        return r;
+
+                c = controllers;
+                for (;;) {
+                        _cleanup_free_ char *n = NULL;
+                        CGroupController v;
 
-        NULSTR_FOREACH(n, mask_names) {
-                if (check_hierarchy(n) >= 0)
-                        mask |= bit;
+                        r = extract_first_word(&c, &n, NULL, 0);
+                        if (r < 0)
+                                return r;
+                        if (r == 0)
+                                break;
 
-                bit <<= 1;
+                        v = cgroup_controller_from_string(n);
+                        if (v < 0)
+                                continue;
+
+                        mask |= CGROUP_CONTROLLER_TO_MASK(v);
         }
 
-        return mask;
+                /* Currently, we only support the memory controller in
+                 * the unified hierarchy, mask everything else off. */
+                mask &= CGROUP_MASK_MEMORY;
+
+        } else {
+                CGroupController c;
+
+                /* In the legacy hierarchy, we check whether which
+                 * hierarchies are mounted. */
+
+                for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
+                        const char *n;
+
+                        n = cgroup_controller_to_string(c);
+                        if (controller_is_accessible(n) >= 0)
+                                mask |= CGROUP_CONTROLLER_TO_MASK(c);
+                }
+        }
+
+        *ret = mask;
+        return 0;
 }
 
 int cg_kernel_controllers(Set *controllers) {
@@ -1897,6 +2065,11 @@ int cg_kernel_controllers(Set *controllers) {
 
         assert(controllers);
 
+        /* Determines the full list of kernel-known controllers. Might
+         * include controllers we don't actually support, arbitrary
+         * named hierarchies and controllers that aren't currently
+         * accessible (because not mounted). */
+
         f = fopen("/proc/cgroups", "re");
         if (!f) {
                 if (errno == ENOENT)
@@ -1917,7 +2090,7 @@ int cg_kernel_controllers(Set *controllers) {
                         if (feof(f))
                                 break;
 
-                        if (ferror(f) && errno)
+                        if (ferror(f) && errno != 0)
                                 return -errno;
 
                         return -EBADMSG;
@@ -1928,7 +2101,7 @@ int cg_kernel_controllers(Set *controllers) {
                         continue;
                 }
 
-                if (!filename_is_valid(controller)) {
+                if (!cg_controller_is_valid(controller)) {
                         free(controller);
                         return -EBADMSG;
                 }
@@ -1941,3 +2114,122 @@ int cg_kernel_controllers(Set *controllers) {
         return 0;
 }
 #endif // 0
+
+static thread_local int unified_cache = -1;
+
+int cg_unified(void) {
+        struct statfs fs;
+
+        /* Checks if we support the unified hierarchy. Returns an
+         * error when the cgroup hierarchies aren't mounted yet or we
+         * have any other trouble determining if the unified hierarchy
+         * is supported. */
+
+        if (unified_cache >= 0)
+                return unified_cache;
+
+        if (statfs("/sys/fs/cgroup/", &fs) < 0)
+                return -errno;
+
+        if (F_TYPE_EQUAL(fs.f_type, CGROUP_SUPER_MAGIC))
+                unified_cache = true;
+        else if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC))
+                unified_cache = false;
+        else
+                return -ENOEXEC;
+
+        return unified_cache;
+}
+
+void cg_unified_flush(void) {
+        unified_cache = -1;
+}
+
+int cg_enable_everywhere(CGroupMask supported, CGroupMask mask, const char *p) {
+        _cleanup_free_ char *fs = NULL;
+        CGroupController c;
+        int r, unified;
+
+        assert(p);
+
+        if (supported == 0)
+                return 0;
+
+        unified = cg_unified();
+        if (unified < 0)
+                return unified;
+        if (!unified) /* on the legacy hiearchy there's no joining of controllers defined */
+                return 0;
+
+        r = cg_get_path(ELOGIND_CGROUP_CONTROLLER, p, "cgroup.subtree_control", &fs);
+        if (r < 0)
+                return r;
+
+        for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
+                CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
+                const char *n;
+
+                if (!(supported & bit))
+                        continue;
+
+                n = cgroup_controller_to_string(c);
+                {
+                        char s[1 + strlen(n) + 1];
+
+                        s[0] = mask & bit ? '+' : '-';
+                        strcpy(s + 1, n);
+
+                        r = write_string_file(fs, s, 0);
+                        if (r < 0)
+                                log_debug_errno(r, "Failed to enable controller %s for %s (%s): %m", n, p, fs);
+                }
+        }
+
+        return 0;
+}
+
+bool cg_is_unified_wanted(void) {
+        static thread_local int wanted = -1;
+        int r, unified;
+
+        /* If the hierarchy is already mounted, then follow whatever
+         * was chosen for it. */
+        unified = cg_unified();
+        if (unified >= 0)
+                return unified;
+
+        /* Otherwise, let's see what the kernel command line has to
+         * say. Since checking that is expensive, let's cache the
+         * result. */
+        if (wanted >= 0)
+                return wanted;
+
+        r = get_proc_cmdline_key("systemd.unified_cgroup_hierarchy", NULL);
+        if (r > 0)
+                return (wanted = true);
+        else {
+                _cleanup_free_ char *value = NULL;
+
+                r = get_proc_cmdline_key("systemd.unified_cgroup_hierarchy=", &value);
+                if (r < 0)
+                        return false;
+                if (r == 0)
+                        return (wanted = false);
+
+                return (wanted = parse_boolean(value) > 0);
+        }
+}
+
+bool cg_is_legacy_wanted(void) {
+        return !cg_is_unified_wanted();
+}
+
+static const char *cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = {
+        [CGROUP_CONTROLLER_CPU] = "cpu",
+        [CGROUP_CONTROLLER_CPUACCT] = "cpuacct",
+        [CGROUP_CONTROLLER_BLKIO] = "blkio",
+        [CGROUP_CONTROLLER_MEMORY] = "memory",
+        [CGROUP_CONTROLLER_DEVICE] = "devices",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(cgroup_controller, CGroupController);
index 9d0cc85..7b0ec64 100644 (file)
 #include "set.h"
 #include "def.h"
 
+/* An enum of well known cgroup controllers */
+typedef enum CGroupController {
+        CGROUP_CONTROLLER_CPU,
+        CGROUP_CONTROLLER_CPUACCT,
+        CGROUP_CONTROLLER_BLKIO,
+        CGROUP_CONTROLLER_MEMORY,
+        CGROUP_CONTROLLER_DEVICE,
+        _CGROUP_CONTROLLER_MAX,
+        _CGROUP_CONTROLLER_INVALID = -1,
+} CGroupController;
+
+#define CGROUP_CONTROLLER_TO_MASK(c) (1 << (c))
+
 /* A bit mask of well known cgroup controllers */
-typedef enum CGroupControllerMask {
-        CGROUP_CPU = 1,
-        CGROUP_CPUACCT = 2,
-        CGROUP_BLKIO = 4,
-        CGROUP_MEMORY = 8,
-        CGROUP_DEVICE = 16,
-        _CGROUP_CONTROLLER_MASK_ALL = 31
-} CGroupControllerMask;
+typedef enum CGroupMask {
+        CGROUP_MASK_CPU = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPU),
+        CGROUP_MASK_CPUACCT = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUACCT),
+        CGROUP_MASK_BLKIO = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BLKIO),
+        CGROUP_MASK_MEMORY = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_MEMORY),
+        CGROUP_MASK_DEVICE = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_DEVICE),
+        _CGROUP_MASK_ALL = CGROUP_CONTROLLER_TO_MASK(_CGROUP_CONTROLLER_MAX) - 1
+} CGroupMask;
 
 /*
  * General rules:
@@ -77,7 +90,6 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **path);
 int cg_trim(const char *controller, const char *path, bool delete_root);
 
 int cg_rmdir(const char *controller, const char *path);
-// UNNEEDED int cg_delete(const char *controller, const char *path);
 
 int cg_create(const char *controller, const char *path);
 int cg_attach(const char *controller, const char *path, pid_t pid);
@@ -93,8 +105,8 @@ int cg_attach_fallback(const char *controller, const char *path, pid_t pid);
 // UNNEEDED int cg_install_release_agent(const char *controller, const char *agent);
 // UNNEEDED int cg_uninstall_release_agent(const char *controller);
 
-int cg_is_empty(const char *controller, const char *path, bool ignore_self);
-int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self);
+int cg_is_empty(const char *controller, const char *path);
+int cg_is_empty_recursive(const char *controller, const char *path);
 
 int cg_get_root_path(char **path);
 
@@ -126,14 +138,24 @@ bool cg_controller_is_valid(const char *p);
 
 // UNNEEDED int cg_slice_to_path(const char *unit, char **ret);
 
-typedef const char* (*cg_migrate_callback_t)(CGroupControllerMask mask, void *userdata);
+typedef const char* (*cg_migrate_callback_t)(CGroupMask mask, void *userdata);
 
-// UNNEEDED int cg_create_everywhere(CGroupControllerMask supported, CGroupControllerMask mask, const char *path);
-int cg_attach_everywhere(CGroupControllerMask supported, const char *path, pid_t pid, cg_migrate_callback_t callback, void *userdata);
-// UNNEEDED int cg_attach_many_everywhere(CGroupControllerMask supported, const char *path, Set* pids, cg_migrate_callback_t callback, void *userdata);
-// UNNEEDED int cg_migrate_everywhere(CGroupControllerMask supported, const char *from, const char *to, cg_migrate_callback_t callback, void *userdata);
-// UNNEEDED int cg_trim_everywhere(CGroupControllerMask supported, const char *path, bool delete_root);
+// UNNEEDED int cg_create_everywhere(CGroupMask supported, CGroupMask mask, const char *path);
+int cg_attach_everywhere(CGroupMask supported, const char *path, pid_t pid, cg_migrate_callback_t callback, void *userdata);
+// UNNEEDED int cg_attach_many_everywhere(CGroupMask supported, const char *path, Set* pids, cg_migrate_callback_t callback, void *userdata);
+// UNNEEDED int cg_migrate_everywhere(CGroupMask supported, const char *from, const char *to, cg_migrate_callback_t callback, void *userdata);
+// UNNEEDED int cg_trim_everywhere(CGroupMask supported, const char *path, bool delete_root);
+int cg_enable_everywhere(CGroupMask supported, CGroupMask mask, const char *p);
 
-// UNNEEDED CGroupControllerMask cg_mask_supported(void);
+// UNNEEDED int cg_mask_supported(CGroupMask *ret);
 
 // UNNEEDED int cg_kernel_controllers(Set *controllers);
+
+int cg_unified(void);
+void cg_unified_flush(void);
+
+bool cg_is_unified_wanted(void);
+bool cg_is_legacy_wanted(void);
+
+const char* cgroup_controller_to_string(CGroupController c) _const_;
+CGroupController cgroup_controller_from_string(const char *s) _pure_;
index 3169a90..d8aebc5 100644 (file)
@@ -22,7 +22,6 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-
-int conf_files_list(char ***strv, const char *suffix, const char *root, const char *dir, ...);
-int conf_files_list_strv(char ***strv, const char *suffix, const char *root, const char* const* dirs);
-int conf_files_list_nulstr(char ***strv, const char *suffix, const char *root, const char *dirs);
+int conf_files_list(char ***ret, const char *suffix, const char *root, const char *dir, ...);
+int conf_files_list_strv(char ***ret, const char *suffix, const char *root, const char* const* dirs);
+int conf_files_list_nulstr(char ***ret, const char *suffix, const char *root, const char *dirs);
index 627d768..cbc3ca9 100644 (file)
@@ -298,6 +298,9 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
 #define PTR_TO_GID(p) ((gid_t) (((uintptr_t) (p))-1))
 #define GID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1))
 
+#define PTR_TO_PID(p) ((pid_t) ((uintptr_t) p))
+#define PID_TO_PTR(p) ((void*) ((uintptr_t) p))
+
 #define memzero(x,l) (memset((x), 0, (l)))
 #define zero(x) (memzero(&(x), sizeof(x)))
 
index 37e1133..37c3f67 100644 (file)
@@ -480,6 +480,14 @@ struct btrfs_ioctl_quota_ctl_args {
 #define BTRFS_SUPER_MAGIC 0x9123683E
 #endif
 
+#ifndef CGROUP_SUPER_MAGIC
+#define CGROUP_SUPER_MAGIC 0x27e0eb
+#endif
+
+#ifndef TMPFS_MAGIC
+#define TMPFS_MAGIC 0x01021994
+#endif
+
 #ifndef MS_MOVE
 #define MS_MOVE 8192
 #endif
index fc857e7..dcd0a3e 100644 (file)
@@ -50,7 +50,6 @@ int ring_push(Ring *r, const void *u8, size_t size);
 void ring_pull(Ring *r, size_t size);
 
 /* return size of occupied buffer in bytes */
-static inline size_t ring_get_size(Ring *r)
-{
+static inline size_t ring_get_size(Ring *r) {
         return r->used;
 }
index 03ebab3..cea80b6 100644 (file)
@@ -207,11 +207,11 @@ int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
         if (!mac_selinux_use())
                 return -EOPNOTSUPP;
 
-        r = getcon(&mycon);
+        r = getcon_raw(&mycon);
         if (r < 0)
                 return -errno;
 
-        r = getfilecon(exe, &fcon);
+        r = getfilecon_raw(exe, &fcon);
         if (r < 0)
                 return -errno;
 
@@ -233,7 +233,7 @@ int mac_selinux_get_our_label(char **label) {
         if (!mac_selinux_use())
                 return -EOPNOTSUPP;
 
-        r = getcon(label);
+        r = getcon_raw(label);
         if (r < 0)
                 return -errno;
 #endif
@@ -257,7 +257,7 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *
         if (!mac_selinux_use())
                 return -EOPNOTSUPP;
 
-        r = getcon(&mycon);
+        r = getcon_raw(&mycon);
         if (r < 0)
                 return -errno;
 
@@ -268,7 +268,7 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *
         if (!exec_label) {
                 /* If there is no context set for next exec let's use context
                    of target executable */
-                r = getfilecon(exe, &fcon);
+                r = getfilecon_raw(exe, &fcon);
                 if (r < 0)
                         return -errno;
         }
index e51310e..f30458f 100644 (file)
 #define SPECIAL_USER_SLICE "user.slice"
 #define SPECIAL_MACHINE_SLICE "machine.slice"
 #define SPECIAL_ROOT_SLICE "-.slice"
+
+/* The scope unit systemd itself lives in. */
+#define SPECIAL_INIT_SCOPE "init.scope"
index 73e5c2e..51abc78 100644 (file)
@@ -1092,3 +1092,22 @@ int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
 
         return 0;
 }
+
+int ptsname_namespace(int pty, char **ret) {
+        int no = -1, r;
+
+        /* Like ptsname(), but doesn't assume that the path is
+         * accessible in the local namespace. */
+
+        r = ioctl(pty, TIOCGPTN, &no);
+        if (r < 0)
+                return -errno;
+
+        if (no < 0)
+                return -EIO;
+
+        if (asprintf(ret, "/dev/pts/%i", no) < 0)
+                return -ENOMEM;
+
+        return 0;
+}
index 5964ae5..fc61e3a 100644 (file)
@@ -107,3 +107,5 @@ int get_ctty(pid_t, dev_t *_devnr, char **r);
 
 int getttyname_malloc(int fd, char **r);
 // UNNEEDED int getttyname_harder(int fd, char **r);
+
+int ptsname_namespace(int pty, char **ret);
index 6c8973c..15185a2 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "util.h"
 #include "time-util.h"
+#include "path-util.h"
 #include "strv.h"
 
 usec_t now(clockid_t clock_id) {
@@ -36,6 +37,14 @@ usec_t now(clockid_t clock_id) {
         return timespec_load(&ts);
 }
 
+nsec_t now_nsec(clockid_t clock_id) {
+        struct timespec ts;
+
+        assert_se(clock_gettime(clock_id, &ts) == 0);
+
+        return timespec_load_nsec(&ts);
+}
+
 dual_timestamp* dual_timestamp_get(dual_timestamp *ts) {
         assert(ts);
 
@@ -132,6 +141,18 @@ usec_t timespec_load(const struct timespec *ts) {
                 (usec_t) ts->tv_nsec / NSEC_PER_USEC;
 }
 
+nsec_t timespec_load_nsec(const struct timespec *ts) {
+        assert(ts);
+
+        if (ts->tv_sec == (time_t) -1 &&
+            ts->tv_nsec == (long) -1)
+                return NSEC_INFINITY;
+
+        return
+                (nsec_t) ts->tv_sec * NSEC_PER_SEC +
+                (nsec_t) ts->tv_nsec;
+}
+
 struct timespec *timespec_store(struct timespec *ts, usec_t u)  {
         assert(ts);
 
@@ -985,7 +1006,10 @@ bool timezone_is_valid(const char *name) {
         const char *p, *t;
         struct stat st;
 
-        if (!name || *name == 0 || *name == '/')
+        if (isempty(name))
+                return false;
+
+        if (name[0] == '/')
                 return false;
 
         for (p = name; *p; p++) {
@@ -1036,3 +1060,30 @@ clockid_t clock_boottime_or_monotonic(void) {
 
         return clock;
 }
+
+int get_timezone(char **tz) {
+        _cleanup_free_ char *t = NULL;
+        const char *e;
+        char *z;
+        int r;
+
+        r = readlink_malloc("/etc/localtime", &t);
+        if (r < 0)
+                return r; /* returns EINVAL if not a symlink */
+
+        e = path_startswith(t, "/usr/share/zoneinfo/");
+        if (!e)
+                e = path_startswith(t, "../usr/share/zoneinfo/");
+        if (!e)
+                return -EINVAL;
+
+        if (!timezone_is_valid(e))
+                return -EINVAL;
+
+        z = strdup(e);
+        if (!z)
+                return -ENOMEM;
+
+        *tz = z;
+        return 0;
+}
index 84ba371..9cd6949 100644 (file)
@@ -87,6 +87,8 @@ struct timespec *timespec_store(struct timespec *ts, usec_t u);
 usec_t timeval_load(const struct timeval *tv) _pure_;
 struct timeval *timeval_store(struct timeval *tv, usec_t u);
 
+nsec_t timespec_load_nsec(const struct timespec *ts) _pure_;
+
 char *format_timestamp(char *buf, size_t l, usec_t t);
 // UNNEEDED char *format_timestamp_utc(char *buf, size_t l, usec_t t);
 char *format_timestamp_us(char *buf, size_t l, usec_t t);
@@ -110,3 +112,5 @@ int parse_nsec(const char *t, nsec_t *nsec);
 clockid_t clock_boottime_or_monotonic(void);
 
 #define xstrftime(buf, fmt, tm) assert_se(strftime(buf, ELEMENTSOF(buf), fmt, tm) > 0)
+
+int get_timezone(char **timezone);
index f896526..0f5b716 100644 (file)
@@ -598,6 +598,42 @@ int unit_name_from_dbus_path(const char *path, char **name) {
         return 0;
 }
 
+const char* unit_dbus_interface_from_type(UnitType t) {
+
+        static const char *const table[_UNIT_TYPE_MAX] = {
+                [UNIT_SERVICE] = "org.freedesktop.systemd1.Service",
+                [UNIT_SOCKET] = "org.freedesktop.systemd1.Socket",
+                [UNIT_BUSNAME] = "org.freedesktop.systemd1.BusName",
+                [UNIT_TARGET] = "org.freedesktop.systemd1.Target",
+                [UNIT_SNAPSHOT] = "org.freedesktop.systemd1.Snapshot",
+                [UNIT_DEVICE] = "org.freedesktop.systemd1.Device",
+                [UNIT_MOUNT] = "org.freedesktop.systemd1.Mount",
+                [UNIT_AUTOMOUNT] = "org.freedesktop.systemd1.Automount",
+                [UNIT_SWAP] = "org.freedesktop.systemd1.Swap",
+                [UNIT_TIMER] = "org.freedesktop.systemd1.Timer",
+                [UNIT_PATH] = "org.freedesktop.systemd1.Path",
+                [UNIT_SLICE] = "org.freedesktop.systemd1.Slice",
+                [UNIT_SCOPE] = "org.freedesktop.systemd1.Scope",
+        };
+
+        if (t < 0)
+                return NULL;
+        if (t >= _UNIT_TYPE_MAX)
+                return NULL;
+
+        return table[t];
+}
+
+const char *unit_dbus_interface_from_name(const char *name) {
+        UnitType t;
+
+        t = unit_name_to_type(name);
+        if (t < 0)
+                return NULL;
+
+        return unit_dbus_interface_from_type(t);
+}
+
 static char *do_escape_mangle(const char *f, UnitNameMangle allow_globs, char *t) {
         const char *valid_chars;
 
@@ -802,7 +838,7 @@ static const char* const unit_type_table[_UNIT_TYPE_MAX] = {
         [UNIT_TIMER] = "timer",
         [UNIT_PATH] = "path",
         [UNIT_SLICE] = "slice",
-        [UNIT_SCOPE] = "scope"
+        [UNIT_SCOPE] = "scope",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(unit_type, UnitType);
index 2a954e5..2e04c7d 100644 (file)
@@ -152,6 +152,9 @@ int unit_name_from_path(const char *path, const char *suffix, char **ret);
 char *unit_dbus_path_from_name(const char *name);
 int unit_name_from_dbus_path(const char *path, char **name);
 
+const char* unit_dbus_interface_from_type(UnitType t);
+const char *unit_dbus_interface_from_name(const char *name);
+
 typedef enum UnitNameMangle {
         UNIT_NAME_NOGLOB,
         UNIT_NAME_GLOB,
index 473165f..3df9148 100644 (file)
@@ -403,7 +403,10 @@ int parse_uid(const char *s, uid_t* ret_uid) {
                 return -ERANGE;
 
         if (!uid_is_valid(uid))
-                return -ENXIO;
+                return -ENXIO; /* we return ENXIO instead of EINVAL
+                                * here, to make it easy to distuingish
+                                * invalid numeric uids invalid
+                                * strings. */
 
         if (ret_uid)
                 *ret_uid = uid;
@@ -6198,6 +6201,9 @@ int openpt_in_namespace(pid_t pid, int flags) {
                 if (master < 0)
                         _exit(EXIT_FAILURE);
 
+                if (unlockpt(master) < 0)
+                        _exit(EXIT_FAILURE);
+
                 cmsg = CMSG_FIRSTHDR(&mh);
                 cmsg->cmsg_level = SOL_SOCKET;
                 cmsg->cmsg_type = SCM_RIGHTS;
index 4e5a573..afe5ec6 100644 (file)
@@ -366,6 +366,9 @@ int fd_is_temporary_fs(int fd);
 
 int pipe_eof(int fd);
 
+DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE);
+#define _cleanup_cpu_free_ _cleanup_(CPU_FREEp)
+
 // UNNEEDED cpu_set_t* cpu_set_malloc(unsigned *ncpus);
 
 #define xsprintf(buf, fmt, ...) assert_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf))
@@ -397,8 +400,6 @@ bool nulstr_contains(const char*nulstr, const char *needle);
 
 // UNNEEDED bool plymouth_running(void);
 
-bool machine_name_is_valid(const char *s) _pure_;
-
 char* strshorten(char *s, size_t l);
 
 // UNNEEDED int symlink_idempotent(const char *from, const char *to);
@@ -566,6 +567,7 @@ _pure_ static inline bool string_is_glob(const char *p) {
 // UNNEEDED                 void *arg);
 
 #define _(String) gettext (String)
+#define N_(String) String
 // UNNEEDED void init_gettext(void);
 bool is_locale_utf8(void);
 
index 764de95..1f9843b 100644 (file)
@@ -156,7 +156,8 @@ static int detect_vm_dmi(const char **_id) {
                 "VMW\0"                   "vmware\0"
                 "innotek GmbH\0"          "oracle\0"
                 "Xen\0"                   "xen\0"
-                "Bochs\0"                 "bochs\0";
+                "Bochs\0"                 "bochs\0"
+                "Parallels\0"             "parallels\0";
         unsigned i;
 
         for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) {
@@ -244,8 +245,9 @@ int detect_vm(const char **id) {
         r = detect_vm_dmi(&_id);
 
         /* kvm with and without Virtualbox */
+        /* Parallels exports KVMKVMKVM leaf */
         if (streq_ptr(_id_cpuid, "kvm")) {
-                if (r > 0 && streq(_id, "oracle"))
+                if (r > 0 && (streq(_id, "oracle") || streq(_id, "parallels")))
                         goto finish;
 
                 _id = _id_cpuid;