summaryrefslogtreecommitdiff
path: root/src/shared
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2013-06-27 04:14:27 +0200
committerLennart Poettering <lennart@poettering.net>2013-06-27 04:17:34 +0200
commit4ad490007b70e6ac18d3cb04fa2ed92eba1451fa (patch)
tree20c7aab57b1f2722be1a057a28a6e7c16788c976 /src/shared
parentabb26902e424c4142b68ead35676028b12249b77 (diff)
core: general cgroup rework
Replace the very generic cgroup hookup with a much simpler one. With this change only the high-level cgroup settings remain, the ability to set arbitrary cgroup attributes is removed, so is support for adding units to arbitrary cgroup controllers or setting arbitrary paths for them (especially paths that are different for the various controllers). This also introduces a new -.slice root slice, that is the parent of system.slice and friends. This enables easy admin configuration of root-level cgrouo properties. This replaces DeviceDeny= by DevicePolicy=, and implicitly adds in /dev/null, /dev/zero and friends if DeviceAllow= is used (unless this is turned off by DevicePolicy=).
Diffstat (limited to 'src/shared')
-rw-r--r--src/shared/cgroup-label.c11
-rw-r--r--src/shared/cgroup-show.c1
-rw-r--r--src/shared/cgroup-util.c269
-rw-r--r--src/shared/cgroup-util.h24
-rw-r--r--src/shared/fileio.c1
-rw-r--r--src/shared/mkdir.c74
-rw-r--r--src/shared/mkdir.h8
7 files changed, 244 insertions, 144 deletions
diff --git a/src/shared/cgroup-label.c b/src/shared/cgroup-label.c
index 5b5163c250..574a7be3ee 100644
--- a/src/shared/cgroup-label.c
+++ b/src/shared/cgroup-label.c
@@ -36,15 +36,18 @@
#include "util.h"
#include "mkdir.h"
-int cg_create(const char *controller, const char *path, const char *suffix) {
+/* This is split out since it needs label calls, either directly or
+ * indirectly. */
+
+int cg_create(const char *controller, const char *path) {
_cleanup_free_ char *fs = NULL;
int r;
- r = cg_get_path_and_check(controller, path, suffix, &fs);
+ r = cg_get_path_and_check(controller, path, NULL, &fs);
if (r < 0)
return r;
- r = mkdir_parents_label(fs, 0755);
+ r = mkdir_parents_prefix("/sys/fs/cgroup", fs, 0755);
if (r < 0)
return r;
@@ -64,7 +67,7 @@ int cg_create_and_attach(const char *controller, const char *path, pid_t pid) {
assert(pid >= 0);
- r = cg_create(controller, path, NULL);
+ r = cg_create(controller, path);
if (r < 0)
return r;
diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c
index 83cc0731b8..e971f36190 100644
--- a/src/shared/cgroup-show.c
+++ b/src/shared/cgroup-show.c
@@ -241,7 +241,6 @@ static int show_extra_pids(const char *controller, const char *path, const char
unsigned i, j;
int r;
- assert(controller);
assert(path);
if (n_pids <= 0)
diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c
index 9cbc64a541..5816b7d4d6 100644
--- a/src/shared/cgroup-util.c
+++ b/src/shared/cgroup-util.c
@@ -132,7 +132,7 @@ int cg_read_subgroup(DIR *d, char **fn) {
return 0;
}
-int cg_rmdir(const char *controller, const char *path, bool honour_sticky) {
+int cg_rmdir(const char *controller, const char *path) {
_cleanup_free_ char *p = NULL;
int r;
@@ -140,34 +140,6 @@ int cg_rmdir(const char *controller, const char *path, bool honour_sticky) {
if (r < 0)
return r;
- if (honour_sticky) {
- char *fn;
-
- /* If the sticky bit is set on cgroup.procs, don't
- * remove the directory */
-
- fn = strappend(p, "/cgroup.procs");
- if (!fn)
- return -ENOMEM;
-
- r = file_is_priv_sticky(fn);
- free(fn);
-
- if (r > 0)
- return 0;
-
- /* Compatibility ... */
- fn = strappend(p, "/tasks");
- if (!fn)
- return -ENOMEM;
-
- r = file_is_priv_sticky(fn);
- free(fn);
-
- if (r > 0)
- return 0;
- }
-
r = rmdir(p);
if (r < 0 && errno != ENOENT)
return -errno;
@@ -298,7 +270,7 @@ int cg_kill_recursive(const char *controller, const char *path, int sig, bool si
ret = r;
if (rem) {
- r = cg_rmdir(controller, path, true);
+ r = cg_rmdir(controller, path);
if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
return r;
}
@@ -407,7 +379,14 @@ int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char
return ret;
}
-int cg_migrate_recursive(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self, bool rem) {
+int cg_migrate_recursive(
+ const char *cfrom,
+ const char *pfrom,
+ const char *cto,
+ const char *pto,
+ bool ignore_self,
+ bool rem) {
+
_cleanup_closedir_ DIR *d = NULL;
int r, ret = 0;
char *fn;
@@ -448,7 +427,7 @@ int cg_migrate_recursive(const char *cfrom, const char *pfrom, const char *cto,
ret = r;
if (rem) {
- r = cg_rmdir(cfrom, pfrom, true);
+ r = cg_rmdir(cfrom, pfrom);
if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
return r;
}
@@ -558,8 +537,9 @@ int cg_get_path_and_check(const char *controller, const char *path, const char *
}
static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
- char *p;
- bool is_sticky;
+ assert(path);
+ assert(sb);
+ assert(ftwbuf);
if (typeflag != FTW_DP)
return 0;
@@ -567,31 +547,6 @@ static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct
if (ftwbuf->level < 1)
return 0;
- p = strappend(path, "/cgroup.procs");
- if (!p) {
- errno = ENOMEM;
- return 1;
- }
-
- is_sticky = file_is_priv_sticky(p) > 0;
- free(p);
-
- if (is_sticky)
- return 0;
-
- /* Compatibility */
- p = strappend(path, "/tasks");
- if (!p) {
- errno = ENOMEM;
- return 1;
- }
-
- is_sticky = file_is_priv_sticky(p) > 0;
- free(p);
-
- if (is_sticky)
- return 0;
-
rmdir(path);
return 0;
}
@@ -611,28 +566,8 @@ int cg_trim(const char *controller, const char *path, bool delete_root) {
r = errno ? -errno : -EIO;
if (delete_root) {
- bool is_sticky;
- char *p;
-
- p = strappend(fs, "/cgroup.procs");
- if (!p)
- return -ENOMEM;
-
- is_sticky = file_is_priv_sticky(p) > 0;
- free(p);
-
- if (!is_sticky) {
- p = strappend(fs, "/tasks");
- if (!p)
- return -ENOMEM;
-
- is_sticky = file_is_priv_sticky(p) > 0;
- free(p);
- }
-
- if (!is_sticky)
- if (rmdir(fs) < 0 && errno != ENOENT && r == 0)
- return -errno;
+ if (rmdir(fs) < 0 && errno != ENOENT)
+ return -errno;
}
return r;
@@ -699,15 +634,14 @@ int cg_set_task_access(
const char *path,
mode_t mode,
uid_t uid,
- gid_t gid,
- int sticky) {
+ gid_t gid) {
_cleanup_free_ char *fs = NULL, *procs = NULL;
int r;
assert(path);
- if (mode == (mode_t) -1 && uid == (uid_t) -1 && gid == (gid_t) -1 && sticky < 0)
+ if (mode == (mode_t) -1 && uid == (uid_t) -1 && gid == (gid_t) -1)
return 0;
if (mode != (mode_t) -1)
@@ -717,28 +651,6 @@ int cg_set_task_access(
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)
- 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);
if (r < 0)
return r;
@@ -1688,3 +1600,148 @@ int cg_slice_to_path(const char *unit, char **ret) {
return 0;
}
+
+int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value) {
+ _cleanup_free_ char *p = NULL;
+ int r;
+
+ r = cg_get_path(controller, path, attribute, &p);
+ if (r < 0)
+ return r;
+
+ return write_string_file(p, value);
+}
+
+static const char mask_names[] =
+ "cpu\0"
+ "cpuacct\0"
+ "blkio\0"
+ "memory\0"
+ "devices\0";
+
+int cg_create_with_mask(CGroupControllerMask mask, const char *path) {
+ CGroupControllerMask bit = 1;
+ const char *n;
+ int r;
+
+ /* This one will create a cgroup in our private tree, but also
+ * duplicate it in the trees specified in mask, and remove it
+ * in all others */
+
+ /* First create the cgroup in our own hierarchy. */
+ r = cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
+ if (r < 0)
+ return r;
+
+ /* Then, do the same in the other hierarchies */
+ NULSTR_FOREACH(n, mask_names) {
+ if (bit & mask)
+ cg_create(n, path);
+ else
+ cg_trim(n, path, true);
+
+ bit <<= 1;
+ }
+
+ return r;
+}
+
+int cg_attach_with_mask(CGroupControllerMask mask, const char *path, pid_t pid) {
+ CGroupControllerMask bit = 1;
+ const char *n;
+ int r;
+
+ r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, path, pid);
+
+ NULSTR_FOREACH(n, mask_names) {
+ if (bit & mask)
+ cg_attach(n, path, pid);
+ else {
+ char prefix[strlen(path) + 1], *slash;
+
+ /* OK, this one is a bit harder... Now we need
+ * to add to the closest parent cgroup we
+ * can find */
+ strcpy(prefix, path);
+ while ((slash = strrchr(prefix, '/'))) {
+ int q;
+ *slash = 0;
+
+ q = cg_attach(n, prefix, pid);
+ if (q >= 0)
+ break;
+ }
+ }
+
+ bit <<= 1;
+ }
+
+ return r;
+}
+
+int cg_migrate_with_mask(CGroupControllerMask mask, const char *from, const char *to) {
+ CGroupControllerMask bit = 1;
+ const char *n;
+ int r;
+
+ if (path_equal(from, to))
+ return 0;
+
+ r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, false, true);
+
+ NULSTR_FOREACH(n, mask_names) {
+ if (bit & mask)
+ cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, to, n, to, false, false);
+ else {
+ char prefix[strlen(to) + 1], *slash;
+
+ strcpy(prefix, to);
+ while ((slash = strrchr(prefix, '/'))) {
+ int q;
+
+ *slash = 0;
+
+ q = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, to, n, prefix, false, false);
+ if (q >= 0)
+ break;
+ }
+ }
+
+ bit <<= 1;
+ }
+
+ return r;
+}
+
+int cg_trim_with_mask(CGroupControllerMask mask, const char *path, bool delete_root) {
+ CGroupControllerMask bit = 1;
+ const char *n;
+ int r;
+
+ r = cg_trim(SYSTEMD_CGROUP_CONTROLLER, path, delete_root);
+ if (r < 0)
+ return r;
+
+ NULSTR_FOREACH(n, mask_names) {
+ if (bit & mask)
+ cg_trim(n, path, delete_root);
+
+ bit <<= 1;
+ }
+
+ return r;
+}
+
+CGroupControllerMask cg_mask_supported(void) {
+ CGroupControllerMask bit = 1, mask = 0;
+ const char *n;
+
+ NULSTR_FOREACH(n, mask_names) {
+ if (check_hierarchy(n) >= 0)
+ mask |= bit;
+
+ bit <<= 1;
+ }
+
+ return mask;
+}
diff --git a/src/shared/cgroup-util.h b/src/shared/cgroup-util.h
index 2d00bb3fff..9883d941c2 100644
--- a/src/shared/cgroup-util.h
+++ b/src/shared/cgroup-util.h
@@ -28,6 +28,15 @@
#include "set.h"
#include "def.h"
+/* 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
+} CGroupControllerMask;
+
/*
* General rules:
*
@@ -67,15 +76,17 @@ 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, bool honour_sticky);
+int cg_rmdir(const char *controller, const char *path);
int cg_delete(const char *controller, const char *path);
-int cg_create(const char *controller, const char *path, const char *suffix);
+int cg_create(const char *controller, const char *path);
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_attribute(const char *controller, const char *path, const char *attribute, const char *value);
+
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 sticky);
+int cg_set_task_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid);
int cg_install_release_agent(const char *controller, const char *agent);
@@ -113,3 +124,10 @@ char *cg_unescape(const char *p) _pure_;
bool cg_controller_is_valid(const char *p, bool allow_named);
int cg_slice_to_path(const char *unit, char **ret);
+
+int cg_create_with_mask(CGroupControllerMask mask, const char *path);
+int cg_attach_with_mask(CGroupControllerMask mask, const char *path, pid_t pid);
+int cg_migrate_with_mask(CGroupControllerMask mask, const char *from, const char *to);
+int cg_trim_with_mask(CGroupControllerMask mask, const char *path, bool delete_root);
+
+CGroupControllerMask cg_mask_supported(void);
diff --git a/src/shared/fileio.c b/src/shared/fileio.c
index ad068bf30d..dc13c9ee63 100644
--- a/src/shared/fileio.c
+++ b/src/shared/fileio.c
@@ -24,7 +24,6 @@
#include "util.h"
#include "strv.h"
-
int write_string_to_file(FILE *f, const char *line) {
errno = 0;
fputs(line, f);
diff --git a/src/shared/mkdir.c b/src/shared/mkdir.c
index 0e51b64f69..e21a0f3989 100644
--- a/src/shared/mkdir.c
+++ b/src/shared/mkdir.c
@@ -26,15 +26,16 @@
#include <stdlib.h>
#include <stdio.h>
-#include "mkdir.h"
#include "label.h"
#include "util.h"
+#include "path-util.h"
+#include "mkdir.h"
int mkdir_label(const char *path, mode_t mode) {
return label_mkdir(path, mode, true);
}
-static int makedir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid, bool apply) {
+static int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, bool apply) {
struct stat st;
if (label_mkdir(path, mode, apply) >= 0)
@@ -56,36 +57,50 @@ static int makedir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid, boo
}
int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid) {
- return makedir_safe(path, mode, uid, gid, false);
+ return mkdir_safe_internal(path, mode, uid, gid, false);
}
int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid) {
- return makedir_safe(path, mode, uid, gid, true);
+ return mkdir_safe_internal(path, mode, uid, gid, true);
}
-static int makedir_parents(const char *path, mode_t mode, bool apply) {
+static int is_dir(const char* path) {
struct stat st;
+
+ if (stat(path, &st) < 0)
+ return -errno;
+
+ return S_ISDIR(st.st_mode);
+}
+
+static int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, bool apply) {
const char *p, *e;
+ int r;
assert(path);
+ if (prefix && !path_startswith(path, prefix))
+ return -ENOTDIR;
+
/* return immediately if directory exists */
e = strrchr(path, '/');
if (!e)
return -EINVAL;
+
+ if (e == path)
+ return 0;
+
p = strndupa(path, e - path);
- if (stat(p, &st) >= 0) {
- if ((st.st_mode & S_IFMT) == S_IFDIR)
- return 0;
- else
- return -ENOTDIR;
- }
+ r = is_dir(p);
+ if (r > 0)
+ return 0;
+ if (r == 0)
+ return -ENOTDIR;
/* create every parent directory in the path, except the last component */
p = path + strspn(path, "/");
for (;;) {
- int r;
- char *t;
+ char t[strlen(path) + 1];
e = p + strcspn(p, "/");
p = e + strspn(e, "/");
@@ -95,39 +110,36 @@ static int makedir_parents(const char *path, mode_t mode, bool apply) {
if (*p == 0)
return 0;
- t = strndup(path, e - path);
- if (!t)
- return -ENOMEM;
+ memcpy(t, path, e - path);
+ t[e-path] = 0;
- r = label_mkdir(t, mode, apply);
- free(t);
+ if (prefix && path_startswith(prefix, t))
+ continue;
+ r = label_mkdir(t, mode, apply);
if (r < 0 && errno != EEXIST)
return -errno;
}
}
int mkdir_parents(const char *path, mode_t mode) {
- return makedir_parents(path, mode, false);
+ return mkdir_parents_internal(NULL, path, mode, false);
}
int mkdir_parents_label(const char *path, mode_t mode) {
- return makedir_parents(path, mode, true);
+ return mkdir_parents_internal(NULL, path, mode, true);
}
-static int is_dir(const char* path) {
- struct stat st;
- if (stat(path, &st) < 0)
- return -errno;
- return S_ISDIR(st.st_mode);
+int mkdir_parents_prefix(const char *prefix, const char *path, mode_t mode) {
+ return mkdir_parents_internal(prefix, path, mode, true);
}
-static int makedir_p(const char *path, mode_t mode, bool apply) {
+static int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, bool apply) {
int r;
/* Like mkdir -p */
- r = makedir_parents(path, mode, apply);
+ r = mkdir_parents_internal(prefix, path, mode, apply);
if (r < 0)
return r;
@@ -139,9 +151,13 @@ static int makedir_p(const char *path, mode_t mode, bool apply) {
}
int mkdir_p(const char *path, mode_t mode) {
- return makedir_p(path, mode, false);
+ return mkdir_p_internal(NULL, path, mode, false);
}
int mkdir_p_label(const char *path, mode_t mode) {
- return makedir_p(path, mode, true);
+ return mkdir_p_internal(NULL, path, mode, true);
+}
+
+int mkdir_p_prefix(const char *prefix, const char *path, mode_t mode) {
+ return mkdir_p_internal(prefix, path, mode, false);
}
diff --git a/src/shared/mkdir.h b/src/shared/mkdir.h
index ce1c35e9ba..3d39b2910f 100644
--- a/src/shared/mkdir.h
+++ b/src/shared/mkdir.h
@@ -22,11 +22,19 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <sys/types.h>
+
int mkdir_label(const char *path, mode_t mode);
+
int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid);
int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid);
+
int mkdir_parents(const char *path, mode_t mode);
int mkdir_parents_label(const char *path, mode_t mode);
+int mkdir_parents_prefix(const char *prefix, const char *path, mode_t mode);
+
int mkdir_p(const char *path, mode_t mode);
int mkdir_p_label(const char *path, mode_t mode);
+int mkdir_p_prefix(const char *prefix, const char *path, mode_t mode);
+
#endif