[systemd-commits] 4 commits - TODO man/systemd.exec.xml man/tmpfiles.d.xml src/cgroup-util.c src/cgroup-util.h src/cgroup.c src/cgroup.h src/conf-parser.c src/conf-parser.h src/dbus-execute.c src/execute.c src/execute.h src/journal src/load-fragment-gperf.gperf.m4 src/login src/manager.c src/tmpfiles.c src/util.c src/util.h

Lennart Poettering lennart at kemper.freedesktop.org
Wed Jan 18 07:40:17 PST 2012


 TODO                             |    5 +-
 man/systemd.exec.xml             |   15 ++++++++
 man/tmpfiles.d.xml               |   14 ++++++-
 src/cgroup-util.c                |   47 ++++++++++++++++++++++----
 src/cgroup-util.h                |    2 -
 src/cgroup.c                     |   19 +++-------
 src/cgroup.h                     |    8 ++--
 src/conf-parser.c                |   30 ++++++++++++++++
 src/conf-parser.h                |    1 
 src/dbus-execute.c               |    1 
 src/execute.c                    |   17 ++++++++-
 src/execute.h                    |    1 
 src/journal/journal-send.c       |    5 ++
 src/load-fragment-gperf.gperf.m4 |    3 +
 src/login/logind-session.c       |    2 -
 src/manager.c                    |    7 ++-
 src/tmpfiles.c                   |   70 ++++++++++++++++++++++++++++++++++-----
 src/util.c                       |   27 +++++++++------
 src/util.h                       |    2 -
 19 files changed, 221 insertions(+), 55 deletions(-)

New commits:
commit 31ed59c51126fce7d958c188772a397e2a1ed010
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Jan 18 16:39:04 2012 +0100

    tmpfiles: support writing short strings to files, in order to support /sys manipulations at boot time, a la sysctl

diff --git a/TODO b/TODO
index 0c3cc9d..f3eb8c5 100644
--- a/TODO
+++ b/TODO
@@ -21,6 +21,8 @@ Bugfixes:
 
 Features:
 
+* rework namespace support, don't use pivot_root, and mount things after creating the namespace, not before
+
 * systemctl journal command
 
 * journalctl: --cursor support, priority filtering
@@ -82,7 +84,6 @@ Features:
 * service restart retry configuration
 
 * tmpfiles: apply "x" on "D" too (see patch from William Douglas)
-* tmpfiles: support generation of char/block devices, symlinks and one-line files (think sysfs)
 
 * don't set $HOME in services unless requested
 
diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml
index 080da66..25a7c9b 100644
--- a/man/tmpfiles.d.xml
+++ b/man/tmpfiles.d.xml
@@ -98,12 +98,17 @@ L    /tmp/foobar -    -    -    -   /dev/null</programlisting>
                         <variablelist>
                                 <varlistentry>
                                         <term><varname>f</varname></term>
-                                        <listitem><para>Create a file if it doesn't exist yet</para></listitem>
+                                        <listitem><para>Create a file if it doesn't exist yet (optionally writing a short string into it, if the argument parameter is passed)</para></listitem>
                                 </varlistentry>
 
                                 <varlistentry>
                                         <term><varname>F</varname></term>
-                                        <listitem><para>Create or truncate a file</para></listitem>
+                                        <listitem><para>Create or truncate a file (optionally writing a short string into it, if the argument parameter is passed)</para></listitem>
+                                </varlistentry>
+
+                                <varlistentry>
+                                        <term><varname>w</varname></term>
+                                        <listitem><para>Write the argument parameter to a file, if it exists.</para></listitem>
                                 </varlistentry>
 
                                 <varlistentry>
@@ -260,7 +265,10 @@ L    /tmp/foobar -    -    -    -   /dev/null</programlisting>
                         path of the symlink. For c, b determines the
                         major/minor of the device node, with major and
                         minor formatted as integers, separated by :,
-                        e.g. "1:3". Ignored for all other lines.</para>
+                        e.g. "1:3". For f, F, w may be used to specify
+                        a short string that is written to the file,
+                        suffixed by a newline. Ignored for all other
+                        lines.</para>
                 </refsect2>
 
         </refsect1>
diff --git a/src/tmpfiles.c b/src/tmpfiles.c
index 2096019..f3c38a8 100644
--- a/src/tmpfiles.c
+++ b/src/tmpfiles.c
@@ -54,6 +54,7 @@ typedef enum ItemType {
         /* These ones take file names */
         CREATE_FILE = 'f',
         TRUNCATE_FILE = 'F',
+        WRITE_FILE = 'w',
         CREATE_DIRECTORY = 'd',
         TRUNCATE_DIRECTORY = 'D',
         CREATE_FIFO = 'p',
@@ -574,19 +575,48 @@ static int create_item(Item *i) {
                 return 0;
 
         case CREATE_FILE:
-        case TRUNCATE_FILE: {
-                int fd;
+        case TRUNCATE_FILE:
+        case WRITE_FILE: {
+                int fd, flags;
+
+                flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND :
+                        i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0;
 
                 u = umask(0);
-                fd = open(i->path, O_CREAT|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW|
-                          (i->type == TRUNCATE_FILE ? O_TRUNC : 0), i->mode);
+                fd = open(i->path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode);
                 umask(u);
 
                 if (fd < 0) {
+                        if (i->type == WRITE_FILE && errno == ENOENT)
+                                break;
+
                         log_error("Failed to create file %s: %m", i->path);
                         return -errno;
                 }
 
+                if (i->argument) {
+                        ssize_t n;
+                        size_t l;
+                        struct iovec iovec[2];
+                        static const char new_line = '\n';
+
+                        l = strlen(i->argument);
+
+                        zero(iovec);
+                        iovec[0].iov_base = i->argument;
+                        iovec[0].iov_len = l;
+
+                        iovec[1].iov_base = (void*) &new_line;
+                        iovec[1].iov_len = 1;
+
+                        n = writev(fd, iovec, 2);
+                        if (n < 0 || (size_t) n != l+1) {
+                                log_error("Failed to write file %s: %s", i->path, n < 0 ? strerror(-n) : "Short");
+                                close_nointr_nofail(fd);
+                                return n < 0 ? n : -EIO;
+                        }
+                }
+
                 close_nointr_nofail(fd);
 
                 if (stat(i->path, &st) < 0) {
@@ -752,6 +782,7 @@ static int remove_item_instance(Item *i, const char *instance) {
         case IGNORE_PATH:
         case RELABEL_PATH:
         case RECURSIVE_RELABEL_PATH:
+        case WRITE_FILE:
                 break;
 
         case REMOVE_PATH:
@@ -793,6 +824,7 @@ static int remove_item(Item *i) {
         case IGNORE_PATH:
         case RELABEL_PATH:
         case RECURSIVE_RELABEL_PATH:
+        case WRITE_FILE:
                 break;
 
         case REMOVE_PATH:
@@ -857,7 +889,10 @@ static bool item_equal(Item *a, Item *b) {
             (a->age_set && a->age != b->age))
             return false;
 
-        if (a->type == CREATE_SYMLINK &&
+        if ((a->type == CREATE_FILE ||
+             a->type == TRUNCATE_FILE ||
+             a->type == WRITE_FILE ||
+             a->type == CREATE_SYMLINK) &&
             !streq(a->argument, b->argument))
                 return false;
 
@@ -874,7 +909,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
         char *mode = NULL, *user = NULL, *group = NULL, *age = NULL;
         char type;
         Hashmap *h;
-        int r;
+        int r, n = -1;
 
         assert(fname);
         assert(line >= 1);
@@ -893,19 +928,30 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
                    "%ms "
                    "%ms "
                    "%ms "
-                   "%ms",
+                   "%n",
                    &type,
                    &i->path,
                    &mode,
                    &user,
                    &group,
                    &age,
-                   &i->argument) < 2) {
+                   &n) < 2) {
                 log_error("[%s:%u] Syntax error.", fname, line);
                 r = -EIO;
                 goto finish;
         }
 
+        if (n >= 0)  {
+                n += strspn(buffer+n, WHITESPACE);
+                if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
+                        i->argument = unquote(buffer+n, "\"");
+                        if (!i->argument) {
+                                log_error("Out of memory");
+                                return -ENOMEM;
+                        }
+                }
+        }
+
         switch(type) {
 
         case CREATE_FILE:
@@ -928,6 +974,14 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
                 }
                 break;
 
+        case WRITE_FILE:
+                if (!i->argument) {
+                        log_error("[%s:%u] Write file requires argument.", fname, line);
+                        r = -EBADMSG;
+                        goto finish;
+                }
+                break;
+
         case CREATE_CHAR_DEVICE:
         case CREATE_BLOCK_DEVICE: {
                 unsigned major, minor;
diff --git a/src/util.c b/src/util.c
index 8004beb..fbc37c4 100644
--- a/src/util.c
+++ b/src/util.c
@@ -4118,7 +4118,8 @@ char *unquote(const char *s, const char* quotes) {
         size_t l;
         assert(s);
 
-        if ((l = strlen(s)) < 2)
+        l = strlen(s);
+        if (l < 2)
                 return strdup(s);
 
         if (strchr(quotes, s[0]) && s[l-1] == s[0])

commit 88f06645623467f9c8db88afca64557d62e38c61
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Jan 18 15:41:21 2012 +0100

    manager: don't place units in the 'cpu' group when run as user instance, for now

diff --git a/src/manager.c b/src/manager.c
index bab1662..19e5441 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -247,8 +247,11 @@ int manager_new(ManagerRunningAs running_as, Manager **_m) {
         if (!(m->environment = strv_copy(environ)))
                 goto fail;
 
-        if (!(m->default_controllers = strv_new("cpu", NULL)))
-                goto fail;
+        if (running_as == MANAGER_SYSTEM) {
+                m->default_controllers = strv_new("cpu", NULL);
+                if (!m->default_controllers)
+                        goto fail;
+        }
 
         if (!(m->units = hashmap_new(string_hash_func, string_compare_func)))
                 goto fail;

commit 9058851be7821edac08c1fa7ecafe5cba9ab9022
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Jan 18 15:40:58 2012 +0100

    journal: when sending journal data via file, place it in /dev/shm, to allow early boot operation, even if it sucks

diff --git a/src/journal/journal-send.c b/src/journal/journal-send.c
index 03bd170..00029fe 100644
--- a/src/journal/journal-send.c
+++ b/src/journal/journal-send.c
@@ -140,13 +140,16 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
         int i, j = 0;
         struct msghdr mh;
         struct sockaddr_un sa;
-        char path[] = "/tmp/journal.XXXXXX";
         ssize_t k;
         union {
                 struct cmsghdr cmsghdr;
                 uint8_t buf[CMSG_SPACE(sizeof(int))];
         } control;
         struct cmsghdr *cmsg;
+        /* We use /dev/shm instead of /tmp here, since we want this to
+         * be a tmpfs, and one that is available from early boot on
+         * and where unprivileged users can create files. */
+        char path[] = "/dev/shm/journal.XXXXXX";
 
         if (!iov || n <= 0)
                 return -EINVAL;

commit 8d53b4534a5923721b5f1e9dd7e8f4a903d02d51
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Jan 18 15:40:21 2012 +0100

    exec: introduce ControlGroupPersistant= to make cgroups persistant

diff --git a/TODO b/TODO
index e2a19ad..0c3cc9d 100644
--- a/TODO
+++ b/TODO
@@ -84,8 +84,6 @@ Features:
 * tmpfiles: apply "x" on "D" too (see patch from William Douglas)
 * tmpfiles: support generation of char/block devices, symlinks and one-line files (think sysfs)
 
-* Introduce ControlGroupPersistant=yes to set +t on the tasks file when creating the cgroup
-
 * don't set $HOME in services unless requested
 
 * hide PAM/TCPWrap options in fragment parser when compile time disabled
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index c1ab6b9..97bdbba 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -777,6 +777,21 @@
                         </varlistentry>
 
                         <varlistentry>
+                                <term><varname>ControlGroupPersistant=</varname></term>
+                                <listitem><para>Takes a boolean
+                                argument. If true, the control groups
+                                created for this unit will be marked
+                                to be persistant, i.e. systemd will
+                                not remove them when stopping the
+                                unit. The default is false, meaning
+                                that the control groups will be
+                                removed when the unit is stopped. For
+                                details about the semantics of this
+                                logic see <ulink
+                                url="http://www.freedesktop.org/wiki/Software/systemd/PaxControlGroups">PaxControlGroups</ulink>.</para></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
                                 <term><varname>ControlGroupAttribute=</varname></term>
 
                                 <listitem><para>Set a specific control
diff --git a/src/cgroup-util.c b/src/cgroup-util.c
index f74280f..904d300 100644
--- a/src/cgroup-util.c
+++ b/src/cgroup-util.c
@@ -173,7 +173,7 @@ int cg_rmdir(const char *controller, const char *path, bool honour_sticky) {
                         return -ENOMEM;
                 }
 
-                r = file_is_sticky(tasks);
+                r = file_is_priv_sticky(tasks);
                 free(tasks);
 
                 if (r > 0) {
@@ -571,7 +571,7 @@ static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct
                 return 1;
         }
 
-        is_sticky = file_is_sticky(p) > 0;
+        is_sticky = file_is_priv_sticky(p) > 0;
         free(p);
 
         if (is_sticky)
@@ -606,7 +606,7 @@ int cg_trim(const char *controller, const char *path, bool delete_root) {
                         return -ENOMEM;
                 }
 
-                is_sticky = file_is_sticky(p) > 0;
+                is_sticky = file_is_priv_sticky(p) > 0;
                 free(p);
 
                 if (!is_sticky)
@@ -712,7 +712,11 @@ int cg_set_group_access(const char *controller, const char *path, mode_t mode, u
         assert(controller);
         assert(path);
 
-        if ((r = cg_get_path(controller, path, NULL, &fs)) < 0)
+        if (mode != (mode_t) -1)
+                mode &= 0777;
+
+        r = cg_get_path(controller, path, NULL, &fs);
+        if (r < 0)
                 return r;
 
         r = chmod_and_chown(fs, mode, uid, gid);
@@ -721,16 +725,47 @@ int cg_set_group_access(const char *controller, const char *path, mode_t mode, u
         return r;
 }
 
-int cg_set_task_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid) {
+int cg_set_task_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid, int sticky) {
         char *fs;
         int r;
 
         assert(controller);
         assert(path);
 
-        if ((r = cg_get_path(controller, path, "tasks", &fs)) < 0)
+        if (mode == (mode_t) -1 && uid == (uid_t) -1 && gid == (gid_t) -1 && sticky < 0)
+                return 0;
+
+        if (mode != (mode_t) -1)
+                mode &= 0666;
+
+        r = cg_get_path(controller, path, "tasks", &fs);
+        if (r < 0)
                 return r;
 
+        if (sticky >= 0 && mode != (mode_t) -1)
+                /* Both mode and sticky param are passed */
+                mode |= (sticky ? S_ISVTX : 0);
+        else if ((sticky >= 0 && mode == (mode_t) -1) ||
+                 (mode != (mode_t) -1 && sticky < 0)) {
+                struct stat st;
+
+                /* Only one param is passed, hence read the current
+                 * mode from the file itself */
+
+                r = lstat(fs, &st);
+                if (r < 0) {
+                        free(fs);
+                        return -errno;
+                }
+
+                if (mode == (mode_t) -1)
+                        /* No mode set, we just shall set the sticky bit */
+                        mode = (st.st_mode & ~S_ISVTX) | (sticky ? S_ISVTX : 0);
+                else
+                        /* Only mode set, leave sticky bit untouched */
+                        mode = (st.st_mode & ~0777) | mode;
+        }
+
         r = chmod_and_chown(fs, mode, uid, gid);
         free(fs);
 
diff --git a/src/cgroup-util.h b/src/cgroup-util.h
index f09373b..37e4255 100644
--- a/src/cgroup-util.h
+++ b/src/cgroup-util.h
@@ -60,7 +60,7 @@ int cg_attach(const char *controller, const char *path, pid_t pid);
 int cg_create_and_attach(const char *controller, const char *path, pid_t pid);
 
 int cg_set_group_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid);
-int cg_set_task_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid);
+int cg_set_task_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid, int sticky);
 
 int cg_install_release_agent(const char *controller, const char *agent);
 
diff --git a/src/cgroup.c b/src/cgroup.c
index e141b41..9aff02e 100644
--- a/src/cgroup.c
+++ b/src/cgroup.c
@@ -60,7 +60,7 @@ int cgroup_bonding_realize_list(CGroupBonding *first) {
         return 0;
 }
 
-void cgroup_bonding_free(CGroupBonding *b, bool remove_or_trim) {
+void cgroup_bonding_free(CGroupBonding *b, bool trim) {
         assert(b);
 
         if (b->unit) {
@@ -79,13 +79,8 @@ void cgroup_bonding_free(CGroupBonding *b, bool remove_or_trim) {
                 }
         }
 
-        if (b->realized && b->ours && remove_or_trim) {
-
-                if (cgroup_bonding_is_empty(b) > 0)
-                        cg_delete(b->controller, b->path);
-                else
-                        cg_trim(b->controller, b->path, false);
-        }
+        if (b->realized && b->ours && trim)
+                cg_trim(b->controller, b->path, false);
 
         free(b->controller);
         free(b->path);
@@ -159,21 +154,21 @@ int cgroup_bonding_set_group_access_list(CGroupBonding *first, mode_t mode, uid_
         return 0;
 }
 
-int cgroup_bonding_set_task_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid) {
+int cgroup_bonding_set_task_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid, int sticky) {
         assert(b);
 
         if (!b->realized)
                 return -EINVAL;
 
-        return cg_set_task_access(b->controller, b->path, mode, uid, gid);
+        return cg_set_task_access(b->controller, b->path, mode, uid, gid, sticky);
 }
 
-int cgroup_bonding_set_task_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid) {
+int cgroup_bonding_set_task_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid, int sticky) {
         CGroupBonding *b;
         int r;
 
         LIST_FOREACH(by_unit, b, first) {
-                r = cgroup_bonding_set_task_access(b, mode, uid, gid);
+                r = cgroup_bonding_set_task_access(b, mode, uid, gid, sticky);
                 if (r < 0)
                         return r;
         }
diff --git a/src/cgroup.h b/src/cgroup.h
index f33d844..db4feb9 100644
--- a/src/cgroup.h
+++ b/src/cgroup.h
@@ -53,8 +53,8 @@ struct CGroupBonding {
 int cgroup_bonding_realize(CGroupBonding *b);
 int cgroup_bonding_realize_list(CGroupBonding *first);
 
-void cgroup_bonding_free(CGroupBonding *b, bool remove_or_trim);
-void cgroup_bonding_free_list(CGroupBonding *first, bool remove_or_trim);
+void cgroup_bonding_free(CGroupBonding *b, bool trim);
+void cgroup_bonding_free_list(CGroupBonding *first, bool trim);
 
 int cgroup_bonding_install(CGroupBonding *b, pid_t pid);
 int cgroup_bonding_install_list(CGroupBonding *first, pid_t pid);
@@ -62,8 +62,8 @@ int cgroup_bonding_install_list(CGroupBonding *first, pid_t pid);
 int cgroup_bonding_set_group_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid);
 int cgroup_bonding_set_group_access_list(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid);
 
-int cgroup_bonding_set_task_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid);
-int cgroup_bonding_set_task_access_list(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid);
+int cgroup_bonding_set_task_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid, int sticky);
+int cgroup_bonding_set_task_access_list(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid, int sticky);
 
 int cgroup_bonding_kill(CGroupBonding *b, int sig, bool sigcont, Set *s);
 int cgroup_bonding_kill_list(CGroupBonding *first, int sig, bool sigcont, Set *s);
diff --git a/src/conf-parser.c b/src/conf-parser.c
index 3ccd1c0..ac8d9f5 100644
--- a/src/conf-parser.c
+++ b/src/conf-parser.c
@@ -509,6 +509,36 @@ int config_parse_bool(
         return 0;
 }
 
+int config_parse_tristate(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        int k;
+        int *b = data;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        /* Tristates are like booleans, but can also take the 'default' value, i.e. "-1" */
+
+        k = parse_boolean(rvalue);
+        if (k < 0) {
+                log_error("[%s:%u] Failed to parse boolean value, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        *b = !!k;
+        return 0;
+}
+
 int config_parse_string(
                 const char *filename,
                 unsigned line,
diff --git a/src/conf-parser.h b/src/conf-parser.h
index e970ee2..35edcb6 100644
--- a/src/conf-parser.h
+++ b/src/conf-parser.h
@@ -95,6 +95,7 @@ int config_parse_long(const char *filename, unsigned line, const char *section,
 int config_parse_uint64(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_size(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_bool(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_tristate(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_string(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_path(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_strv(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/dbus-execute.c b/src/dbus-execute.c
index caeaf77..e02d61c 100644
--- a/src/dbus-execute.c
+++ b/src/dbus-execute.c
@@ -416,5 +416,6 @@ const BusProperty bus_exec_context_properties[] = {
         { "KillSignal",               bus_property_append_int,               "i", offsetof(ExecContext, kill_signal)                  },
         { "UtmpIdentifier",           bus_property_append_string,            "s", offsetof(ExecContext, utmp_id),                true },
         { "ControlGroupModify",       bus_property_append_bool,              "b", offsetof(ExecContext, control_group_modify)         },
+        { "ControlGroupModify",       bus_property_append_bool,              "b", offsetof(ExecContext, control_group_persistant)     },
         { NULL, }
 };
diff --git a/src/execute.c b/src/execute.c
index cacc8a7..650c6c1 100644
--- a/src/execute.c
+++ b/src/execute.c
@@ -993,7 +993,7 @@ int exec_spawn(ExecCommand *command,
                 char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL;
                 unsigned n_env = 0;
                 int saved_stdout = -1, saved_stdin = -1;
-                bool keep_stdout = false, keep_stdin = false;
+                bool keep_stdout = false, keep_stdin = false, set_access = false;
 
                 /* child */
 
@@ -1218,11 +1218,21 @@ int exec_spawn(ExecCommand *command,
                         if (cgroup_bondings && context->control_group_modify) {
                                 err = cgroup_bonding_set_group_access_list(cgroup_bondings, 0755, uid, gid);
                                 if (err >= 0)
-                                        err = cgroup_bonding_set_task_access_list(cgroup_bondings, 0644, uid, gid);
+                                        err = cgroup_bonding_set_task_access_list(cgroup_bondings, 0644, uid, gid, context->control_group_persistant);
                                 if (err < 0) {
                                         r = EXIT_CGROUP;
                                         goto fail_child;
                                 }
+
+                                set_access = true;
+                        }
+                }
+
+                if (cgroup_bondings && !set_access && context->control_group_persistant >= 0)  {
+                        err = cgroup_bonding_set_task_access_list(cgroup_bondings, (mode_t) -1, (uid_t) -1, (uid_t) -1, context->control_group_persistant);
+                        if (err < 0) {
+                                r = EXIT_CGROUP;
+                                goto fail_child;
                         }
                 }
 
@@ -1488,6 +1498,7 @@ void exec_context_init(ExecContext *c) {
         c->mount_flags = MS_SHARED;
         c->kill_signal = SIGTERM;
         c->send_sigkill = true;
+        c->control_group_persistant = -1;
 }
 
 void exec_context_done(ExecContext *c) {
@@ -1673,6 +1684,7 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
                 "%sNonBlocking: %s\n"
                 "%sPrivateTmp: %s\n"
                 "%sControlGroupModify: %s\n"
+                "%sControlGroupPersistant: %s\n"
                 "%sPrivateNetwork: %s\n",
                 prefix, c->umask,
                 prefix, c->working_directory ? c->working_directory : "/",
@@ -1680,6 +1692,7 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
                 prefix, yes_no(c->non_blocking),
                 prefix, yes_no(c->private_tmp),
                 prefix, yes_no(c->control_group_modify),
+                prefix, yes_no(c->control_group_persistant),
                 prefix, yes_no(c->private_network));
 
         STRV_FOREACH(e, c->environment)
diff --git a/src/execute.h b/src/execute.h
index 187e8d2..ff33fa9 100644
--- a/src/execute.h
+++ b/src/execute.h
@@ -163,6 +163,7 @@ struct ExecContext {
         bool private_network;
 
         bool control_group_modify;
+        int control_group_persistant;
 
         /* This is not exposed to the user but available
          * internally. We need it to make sure that whenever we spawn
diff --git a/src/load-fragment-gperf.gperf.m4 b/src/load-fragment-gperf.gperf.m4
index c3f2957..8adedc5 100644
--- a/src/load-fragment-gperf.gperf.m4
+++ b/src/load-fragment-gperf.gperf.m4
@@ -86,7 +86,8 @@ $1.KillMode,                     config_parse_kill_mode,             0,
 $1.KillSignal,                   config_parse_kill_signal,           0,                             offsetof($1, exec_context.kill_signal)
 $1.SendSIGKILL,                  config_parse_bool,                  0,                             offsetof($1, exec_context.send_sigkill)
 $1.UtmpIdentifier,               config_parse_unit_string_printf,    0,                             offsetof($1, exec_context.utmp_id)
-$1.ControlGroupModify,           config_parse_bool,                  0,                             offsetof($1, exec_context.control_group_modify)'
+$1.ControlGroupModify,           config_parse_bool,                  0,                             offsetof($1, exec_context.control_group_modify)
+$1.ControlGroupPersistant,       config_parse_tristate,              0,                             offsetof($1, exec_context.control_group_persistant)'
 )m4_dnl
 Unit.Names,                      config_parse_unit_names,            0,                             0
 Unit.Description,                config_parse_unit_string_printf,    0,                             offsetof(Unit, description)
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index bb802e5..5ea7e26 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -434,7 +434,7 @@ static int session_create_one_group(Session *s, const char *controller, const ch
         if (r < 0)
                 return r;
 
-        r = cg_set_task_access(controller, path, 0644, s->user->uid, s->user->gid);
+        r = cg_set_task_access(controller, path, 0644, s->user->uid, s->user->gid, -1);
         if (r >= 0)
                 r = cg_set_group_access(controller, path, 0755, s->user->uid, s->user->gid);
 
diff --git a/src/util.c b/src/util.c
index b6e490d..8004beb 100644
--- a/src/util.c
+++ b/src/util.c
@@ -3483,7 +3483,9 @@ static int rm_rf_children(int fd, bool only_dirs, bool honour_sticky) {
                         }
 
                         if (honour_sticky)
-                                keep_around = st.st_uid == 0 && (st.st_mode & S_ISVTX);
+                                keep_around =
+                                        (st.st_uid == 0 || st.st_uid == getuid()) &&
+                                        (st.st_mode & S_ISVTX);
 
                         is_dir = S_ISDIR(st.st_mode);
 
@@ -3497,7 +3499,9 @@ static int rm_rf_children(int fd, bool only_dirs, bool honour_sticky) {
                                         continue;
                                 }
 
-                                keep_around = st.st_uid == 0 && (st.st_mode & S_ISVTX);
+                                keep_around =
+                                        (st.st_uid == 0 || st.st_uid == getuid()) &&
+                                        (st.st_mode & S_ISVTX);
                         }
 
                         is_dir = de->d_type == DT_DIR;
@@ -3559,7 +3563,7 @@ int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky
 
         if (delete_root) {
 
-                if (honour_sticky && file_is_sticky(path) > 0)
+                if (honour_sticky && file_is_priv_sticky(path) > 0)
                         return r;
 
                 if (rmdir(path) < 0 && errno != ENOENT) {
@@ -3578,11 +3582,13 @@ int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
          * first change the access mode and only then hand out
          * ownership to avoid a window where access is too open. */
 
-        if (chmod(path, mode) < 0)
-                return -errno;
+        if (mode != (mode_t) -1)
+                if (chmod(path, mode) < 0)
+                        return -errno;
 
-        if (chown(path, uid, gid) < 0)
-                return -errno;
+        if (uid != (uid_t) -1 || gid != (gid_t) -1)
+                if (chown(path, uid, gid) < 0)
+                        return -errno;
 
         return 0;
 }
@@ -5810,7 +5816,7 @@ int block_get_whole_disk(dev_t d, dev_t *ret) {
         return -ENOENT;
 }
 
-int file_is_sticky(const char *p) {
+int file_is_priv_sticky(const char *p) {
         struct stat st;
 
         assert(p);
@@ -5819,7 +5825,7 @@ int file_is_sticky(const char *p) {
                 return -errno;
 
         return
-                st.st_uid == 0 &&
+                (st.st_uid == 0 || st.st_uid == getuid()) &&
                 (st.st_mode & S_ISVTX);
 }
 
diff --git a/src/util.h b/src/util.h
index 590dc17..6acfcc8 100644
--- a/src/util.h
+++ b/src/util.h
@@ -478,7 +478,7 @@ bool in_charset(const char *s, const char* charset);
 
 int block_get_whole_disk(dev_t d, dev_t *ret);
 
-int file_is_sticky(const char *p);
+int file_is_priv_sticky(const char *p);
 
 int strdup_or_null(const char *a, char **b);
 



More information about the systemd-commits mailing list