cgroups: rework base cgroup parsing

parent c72e7cb5
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#include "memory_utils.h" #include "memory_utils.h"
#include "mount_utils.h" #include "mount_utils.h"
#include "storage/storage.h" #include "storage/storage.h"
#include "string_utils.h"
#include "syscall_wrappers.h" #include "syscall_wrappers.h"
#include "utils.h" #include "utils.h"
...@@ -695,24 +696,33 @@ static struct hierarchy *add_hierarchy(struct cgroup_ops *ops, ...@@ -695,24 +696,33 @@ static struct hierarchy *add_hierarchy(struct cgroup_ops *ops,
char **clist, char *mountpoint, char **clist, char *mountpoint,
char *container_base_path, int type) char *container_base_path, int type)
{ {
struct hierarchy *new; __do_free struct hierarchy *new = NULL;
int newentry; int newentry;
if (abspath(container_base_path))
return syserrno(NULL, "Container base path must be relative to controller mount");
new = zalloc(sizeof(*new)); new = zalloc(sizeof(*new));
if (!new) if (!new)
return ret_set_errno(NULL, ENOMEM); return ret_set_errno(NULL, ENOMEM);
new->controllers = clist; new->version = type;
new->mountpoint = mountpoint; new->controllers = clist;
new->container_base_path = container_base_path; new->mountpoint = mountpoint;
new->version = type; new->container_base_path = container_base_path;
new->cgfd_con = -EBADF; new->cgfd_con = -EBADF;
new->cgfd_limit = -EBADF; new->cgfd_limit = -EBADF;
new->cgfd_mon = -EBADF; new->cgfd_mon = -EBADF;
TRACE("Adding cgroup hierarchy with mountpoint %s and base cgroup %s %s",
mountpoint, container_base_path,
clist ? "with controllers " : "without any controllers");
for (char *const *it = clist; it && *it; it++)
TRACE("%s", *it);
newentry = append_null_to_list((void ***)&ops->hierarchies); newentry = append_null_to_list((void ***)&ops->hierarchies);
(ops->hierarchies)[newentry] = new; (ops->hierarchies)[newentry] = new;
return new; return move_ptr(new);
} }
/* Get a copy of the mountpoint from @line, which is a line from /* Get a copy of the mountpoint from @line, which is a line from
...@@ -790,38 +800,71 @@ static bool controller_in_clist(char *cgline, char *c) ...@@ -790,38 +800,71 @@ static bool controller_in_clist(char *cgline, char *c)
return false; return false;
} }
static inline char *trim(char *s)
{
size_t len;
len = strlen(s);
while ((len > 1) && (s[len - 1] == '\n'))
s[--len] = '\0';
return s;
}
/* @basecginfo is a copy of /proc/$$/cgroup. Return the current cgroup for /* @basecginfo is a copy of /proc/$$/cgroup. Return the current cgroup for
* @controller. * @controller.
*/ */
static char *cg_hybrid_get_current_cgroup(char *basecginfo, char *controller, static char *cg_hybrid_get_current_cgroup(bool relative, char *basecginfo,
int type) char *controller, int type)
{ {
char *p = basecginfo; char *base_cgroup = basecginfo;
for (;;) { for (;;) {
bool is_cgv2_base_cgroup = false; bool is_cgv2_base_cgroup = false;
/* cgroup v2 entry in "/proc/<pid>/cgroup": "0::/some/path" */ /* cgroup v2 entry in "/proc/<pid>/cgroup": "0::/some/path" */
if ((type == CGROUP2_SUPER_MAGIC) && (*p == '0')) if ((type == CGROUP2_SUPER_MAGIC) && (*base_cgroup == '0'))
is_cgv2_base_cgroup = true; is_cgv2_base_cgroup = true;
p = strchr(p, ':'); base_cgroup = strchr(base_cgroup, ':');
if (!p) if (!base_cgroup)
return NULL; return NULL;
p++; base_cgroup++;
if (is_cgv2_base_cgroup || (controller && controller_in_clist(base_cgroup, controller))) {
__do_free char *copy = NULL;
if (is_cgv2_base_cgroup || (controller && controller_in_clist(p, controller))) { base_cgroup = strchr(base_cgroup, ':');
p = strchr(p, ':'); if (!base_cgroup)
if (!p)
return NULL; return NULL;
p++; base_cgroup++;
return copy_to_eol(p);
copy = copy_to_eol(base_cgroup);
if (!copy)
return NULL;
trim(copy);
if (!relative) {
base_cgroup = prune_init_scope(copy);
if (!base_cgroup)
return NULL;
} else {
base_cgroup = copy;
}
if (abspath(base_cgroup))
base_cgroup = deabs(base_cgroup);
if (is_empty_string(base_cgroup))
base_cgroup = ".";
return strdup(base_cgroup);
} }
p = strchr(p, '\n'); base_cgroup = strchr(base_cgroup, '\n');
if (!p) if (!base_cgroup)
return NULL; return NULL;
p++; base_cgroup++;
} }
} }
...@@ -879,17 +922,6 @@ static int get_existing_subsystems(char ***klist, char ***nlist) ...@@ -879,17 +922,6 @@ static int get_existing_subsystems(char ***klist, char ***nlist)
return 0; return 0;
} }
static char *trim(char *s)
{
size_t len;
len = strlen(s);
while ((len > 1) && (s[len - 1] == '\n'))
s[--len] = '\0';
return s;
}
static void lxc_cgfsng_print_hierarchies(struct cgroup_ops *ops) static void lxc_cgfsng_print_hierarchies(struct cgroup_ops *ops)
{ {
int i; int i;
...@@ -3384,16 +3416,14 @@ static int cg_hybrid_init(struct cgroup_ops *ops, bool relative, bool unprivileg ...@@ -3384,16 +3416,14 @@ static int cg_hybrid_init(struct cgroup_ops *ops, bool relative, bool unprivileg
} }
if (type == CGROUP_SUPER_MAGIC) if (type == CGROUP_SUPER_MAGIC)
base_cgroup = cg_hybrid_get_current_cgroup(basecginfo, controller_list[0], CGROUP_SUPER_MAGIC); base_cgroup = cg_hybrid_get_current_cgroup(relative, basecginfo, controller_list[0], CGROUP_SUPER_MAGIC);
else else
base_cgroup = cg_hybrid_get_current_cgroup(basecginfo, NULL, CGROUP2_SUPER_MAGIC); base_cgroup = cg_hybrid_get_current_cgroup(relative, basecginfo, NULL, CGROUP2_SUPER_MAGIC);
if (!base_cgroup) { if (!base_cgroup) {
WARN("Failed to find current cgroup"); WARN("Failed to find current cgroup");
continue; continue;
} }
trim(base_cgroup);
prune_init_scope(base_cgroup);
if (type == CGROUP2_SUPER_MAGIC) if (type == CGROUP2_SUPER_MAGIC)
writeable = test_writeable_v2(mountpoint, base_cgroup); writeable = test_writeable_v2(mountpoint, base_cgroup);
else else
...@@ -3450,8 +3480,7 @@ static int cg_hybrid_init(struct cgroup_ops *ops, bool relative, bool unprivileg ...@@ -3450,8 +3480,7 @@ static int cg_hybrid_init(struct cgroup_ops *ops, bool relative, bool unprivileg
/* Get current cgroup from /proc/self/cgroup for the cgroupfs v2 hierarchy. */ /* Get current cgroup from /proc/self/cgroup for the cgroupfs v2 hierarchy. */
static char *cg_unified_get_current_cgroup(bool relative) static char *cg_unified_get_current_cgroup(bool relative)
{ {
__do_free char *basecginfo = NULL; __do_free char *basecginfo = NULL, *copy = NULL;
char *copy;
char *base_cgroup; char *base_cgroup;
if (!relative && (geteuid() == 0)) if (!relative && (geteuid() == 0))
...@@ -3469,8 +3498,23 @@ static char *cg_unified_get_current_cgroup(bool relative) ...@@ -3469,8 +3498,23 @@ static char *cg_unified_get_current_cgroup(bool relative)
copy = copy_to_eol(base_cgroup); copy = copy_to_eol(base_cgroup);
if (!copy) if (!copy)
return NULL; return NULL;
trim(copy);
if (!relative) {
base_cgroup = prune_init_scope(copy);
if (!base_cgroup)
return NULL;
} else {
base_cgroup = copy;
}
if (abspath(base_cgroup))
base_cgroup = deabs(base_cgroup);
if (is_empty_string(base_cgroup))
base_cgroup = ".";
return trim(copy); return strdup(base_cgroup);
} }
static int cg_unified_init(struct cgroup_ops *ops, bool relative, static int cg_unified_init(struct cgroup_ops *ops, bool relative,
...@@ -3483,8 +3527,6 @@ static int cg_unified_init(struct cgroup_ops *ops, bool relative, ...@@ -3483,8 +3527,6 @@ static int cg_unified_init(struct cgroup_ops *ops, bool relative,
base_cgroup = cg_unified_get_current_cgroup(relative); base_cgroup = cg_unified_get_current_cgroup(relative);
if (!base_cgroup) if (!base_cgroup)
return ret_errno(EINVAL); return ret_errno(EINVAL);
if (!relative)
prune_init_scope(base_cgroup);
/* /*
* We assume that the cgroup we're currently in has been delegated to * We assume that the cgroup we're currently in has been delegated to
......
...@@ -98,21 +98,13 @@ void cgroup_exit(struct cgroup_ops *ops) ...@@ -98,21 +98,13 @@ void cgroup_exit(struct cgroup_ops *ops)
} }
#define INIT_SCOPE "/init.scope" #define INIT_SCOPE "/init.scope"
void prune_init_scope(char *cg) char *prune_init_scope(char *cg)
{ {
char *point; if (is_empty_string(cg))
return NULL;
if (!cg) if (strnequal(cg, INIT_SCOPE, STRLITERALLEN(INIT_SCOPE)))
return; return cg + STRLITERALLEN(INIT_SCOPE);
point = cg + strlen(cg) - strlen(INIT_SCOPE);
if (point < cg)
return;
if (strequal(point, INIT_SCOPE)) { return cg;
if (point == cg)
*(point + 1) = '\0';
else
*point = '\0';
}
} }
...@@ -204,7 +204,7 @@ __hidden extern struct cgroup_ops *cgroup_init(struct lxc_conf *conf); ...@@ -204,7 +204,7 @@ __hidden extern struct cgroup_ops *cgroup_init(struct lxc_conf *conf);
__hidden extern void cgroup_exit(struct cgroup_ops *ops); __hidden extern void cgroup_exit(struct cgroup_ops *ops);
define_cleanup_function(struct cgroup_ops *, cgroup_exit); define_cleanup_function(struct cgroup_ops *, cgroup_exit);
__hidden extern void prune_init_scope(char *cg); __hidden extern char *prune_init_scope(char *cg);
__hidden extern int cgroup_attach(const struct lxc_conf *conf, const char *name, __hidden extern int cgroup_attach(const struct lxc_conf *conf, const char *name,
const char *lxcpath, pid_t pid); const char *lxcpath, pid_t pid);
......
...@@ -150,6 +150,11 @@ static inline bool abspath(const char *str) ...@@ -150,6 +150,11 @@ static inline bool abspath(const char *str)
return *str == '/'; return *str == '/';
} }
static inline char *deabs(char *str)
{
return str + strspn(str, "/");
}
#define strnprintf(buf, buf_size, ...) \ #define strnprintf(buf, buf_size, ...) \
({ \ ({ \
int __ret_strnprintf; \ int __ret_strnprintf; \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment