summaryrefslogtreecommitdiff
path: root/src/shared
diff options
context:
space:
mode:
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