summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2011-08-21 20:05:51 +0200
committerLennart Poettering <lennart@poettering.net>2011-08-21 20:07:46 +0200
commitad293f5a94d8124ece7d1cb860952a87b1c8d98f (patch)
tree31abfee26f58e4e73a4d2286127967929371f31c
parent94959f0fa0c19ae1db0e63d9a5dfc94c660825ba (diff)
cgroup: honour sticky bit when trimming cgroup trees
-rw-r--r--src/cgroup-util.c33
-rw-r--r--src/cgroup-util.h2
-rw-r--r--src/logind-user.c2
-rw-r--r--src/manager.c2
-rw-r--r--src/tmpfiles.c2
-rw-r--r--src/util.c60
-rw-r--r--src/util.h4
7 files changed, 82 insertions, 23 deletions
diff --git a/src/cgroup-util.c b/src/cgroup-util.c
index fd0ac98e28..ec48ea63b4 100644
--- a/src/cgroup-util.c
+++ b/src/cgroup-util.c
@@ -153,17 +153,38 @@ int cg_read_subgroup(DIR *d, char **fn) {
return 0;
}
-int cg_rmdir(const char *controller, const char *path) {
+int cg_rmdir(const char *controller, const char *path, bool honour_sticky) {
char *p;
int r;
- if ((r = cg_get_path(controller, path, NULL, &p)) < 0)
+ r = cg_get_path(controller, path, NULL, &p);
+ if (r < 0)
return r;
+ if (honour_sticky) {
+ char *tasks;
+
+ /* If the sticky bit is set don't remove the directory */
+
+ tasks = strappend(p, "/tasks");
+ if (!tasks) {
+ free(p);
+ return -ENOMEM;
+ }
+
+ r = file_is_sticky(tasks);
+ free(tasks);
+
+ if (r > 0) {
+ free(p);
+ return 0;
+ }
+ }
+
r = rmdir(p);
free(p);
- return r < 0 ? -errno : 0;
+ return (r < 0 && errno != ENOENT) ? -errno : 0;
}
int cg_kill(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, Set *s) {
@@ -302,7 +323,7 @@ int cg_kill_recursive(const char *controller, const char *path, int sig, bool si
ret = r;
if (rem)
- if ((r = cg_rmdir(controller, path)) < 0) {
+ if ((r = cg_rmdir(controller, path, true)) < 0) {
if (ret >= 0 &&
r != -ENOENT &&
r != -EBUSY)
@@ -466,7 +487,7 @@ int cg_migrate_recursive(const char *controller, const char *from, const char *t
ret = r;
if (rem)
- if ((r = cg_rmdir(controller, from)) < 0) {
+ if ((r = cg_rmdir(controller, from, true)) < 0) {
if (ret >= 0 &&
r != -ENOENT &&
r != -EBUSY)
@@ -543,7 +564,7 @@ int cg_trim(const char *controller, const char *path, bool delete_root) {
if ((r = cg_get_path(controller, path, NULL, &fs)) < 0)
return r;
- r = rm_rf(fs, true, delete_root);
+ r = rm_rf(fs, true, delete_root, true);
free(fs);
return r == -ENOENT ? 0 : r;
diff --git a/src/cgroup-util.h b/src/cgroup-util.h
index d142af34bc..f09373bd06 100644
--- a/src/cgroup-util.h
+++ b/src/cgroup-util.h
@@ -52,7 +52,7 @@ int cg_get_by_pid(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);
+int cg_rmdir(const char *controller, const char *path, bool honour_sticky);
int cg_delete(const char *controller, const char *path);
int cg_create(const char *controller, const char *path);
diff --git a/src/logind-user.c b/src/logind-user.c
index 613a5c35ff..56c7de4400 100644
--- a/src/logind-user.c
+++ b/src/logind-user.c
@@ -409,7 +409,7 @@ static int user_remove_runtime_path(User *u) {
if (!u->runtime_path)
return 0;
- r = rm_rf(u->runtime_path, false, true);
+ r = rm_rf(u->runtime_path, false, true, false);
if (r < 0)
log_error("Failed to remove runtime directory %s: %s", u->runtime_path, strerror(-r));
diff --git a/src/manager.c b/src/manager.c
index a189479b36..163f69c22f 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -3073,7 +3073,7 @@ void manager_undo_generators(Manager *m) {
return;
strv_remove(m->lookup_paths.unit_path, m->generator_unit_path);
- rm_rf(m->generator_unit_path, false, true);
+ rm_rf(m->generator_unit_path, false, true, false);
free(m->generator_unit_path);
m->generator_unit_path = NULL;
diff --git a/src/tmpfiles.c b/src/tmpfiles.c
index 421a9154c5..a6b8f859aa 100644
--- a/src/tmpfiles.c
+++ b/src/tmpfiles.c
@@ -586,7 +586,7 @@ static int remove_item(Item *i, const char *instance) {
case TRUNCATE_DIRECTORY:
case RECURSIVE_REMOVE_PATH:
- if ((r = rm_rf(instance, false, i->type == RECURSIVE_REMOVE_PATH)) < 0 &&
+ if ((r = rm_rf(instance, false, i->type == RECURSIVE_REMOVE_PATH, false)) < 0 &&
r != -ENOENT) {
log_error("rm_rf(%s): %s", instance, strerror(-r));
return r;
diff --git a/src/util.c b/src/util.c
index 017b995897..ecfe450dca 100644
--- a/src/util.c
+++ b/src/util.c
@@ -3354,7 +3354,7 @@ int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
return 0;
}
-static int rm_rf_children(int fd, bool only_dirs) {
+static int rm_rf_children(int fd, bool only_dirs, bool honour_sticky) {
DIR *d;
int ret = 0;
@@ -3371,7 +3371,7 @@ static int rm_rf_children(int fd, bool only_dirs) {
for (;;) {
struct dirent buf, *de;
- bool is_dir;
+ bool is_dir, keep_around = false;
int r;
if ((r = readdir_r(d, &buf, &de)) != 0) {
@@ -3395,9 +3395,26 @@ static int rm_rf_children(int fd, bool only_dirs) {
continue;
}
+ if (honour_sticky)
+ keep_around = st.st_uid == 0 && (st.st_mode & S_ISVTX);
+
is_dir = S_ISDIR(st.st_mode);
- } else
+
+ } else {
+ if (honour_sticky) {
+ struct stat st;
+
+ if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
+ if (ret == 0 && errno != ENOENT)
+ ret = -errno;
+ continue;
+ }
+
+ keep_around = st.st_uid == 0 && (st.st_mode & S_ISVTX);
+ }
+
is_dir = de->d_type == DT_DIR;
+ }
if (is_dir) {
int subdir_fd;
@@ -3408,16 +3425,18 @@ static int rm_rf_children(int fd, bool only_dirs) {
continue;
}
- if ((r = rm_rf_children(subdir_fd, only_dirs)) < 0) {
+ if ((r = rm_rf_children(subdir_fd, only_dirs, honour_sticky)) < 0) {
if (ret == 0)
ret = r;
}
- if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) {
- if (ret == 0 && errno != ENOENT)
- ret = -errno;
- }
- } else if (!only_dirs) {
+ if (!keep_around)
+ if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) {
+ if (ret == 0 && errno != ENOENT)
+ ret = -errno;
+ }
+
+ } else if (!only_dirs && !keep_around) {
if (unlinkat(fd, de->d_name, 0) < 0) {
if (ret == 0 && errno != ENOENT)
@@ -3431,7 +3450,7 @@ static int rm_rf_children(int fd, bool only_dirs) {
return ret;
}
-int rm_rf(const char *path, bool only_dirs, bool delete_root) {
+int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky) {
int fd;
int r;
@@ -3449,13 +3468,18 @@ int rm_rf(const char *path, bool only_dirs, bool delete_root) {
return 0;
}
- r = rm_rf_children(fd, only_dirs);
+ r = rm_rf_children(fd, only_dirs, honour_sticky);
+
+ if (delete_root) {
+
+ if (honour_sticky && file_is_sticky(path) > 0)
+ return r;
- if (delete_root)
if (rmdir(path) < 0) {
if (r == 0)
r = -errno;
}
+ }
return r;
}
@@ -5674,6 +5698,18 @@ int block_get_whole_disk(dev_t d, dev_t *ret) {
return -ENOENT;
}
+int file_is_sticky(const char *p) {
+ struct stat st;
+
+ assert(p);
+
+ if (lstat(p, &st) < 0)
+ return -errno;
+
+ return
+ st.st_uid == 0 &&
+ (st.st_mode & S_ISVTX);
+}
static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_NONE] = "none",
diff --git a/src/util.h b/src/util.h
index e23f309d3d..b81edc8b2b 100644
--- a/src/util.h
+++ b/src/util.h
@@ -362,7 +362,7 @@ int get_ctty(pid_t, dev_t *_devnr, char **r);
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
-int rm_rf(const char *path, bool only_dirs, bool delete_root);
+int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky);
int pipe_eof(int fd);
@@ -467,6 +467,8 @@ 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);
+
#define NULSTR_FOREACH(i, l) \
for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)