#include "cgroup.h"
#include "cgroup_utils.h"
#include "commands.h"
+#include "conf.h"
#include "log.h"
-#include "storage.h"
+#include "storage/storage.h"
#include "utils.h"
lxc_log_define(lxc_cgfsng, lxc);
c2 = c1;
else if (c1 < c2)
c1 = c2;
- else if (!c1 && c2) // The reverse case is obvs. not needed.
+ else if (!c1 && c2) /* The reverse case is obvs. not needed. */
c1 = c2;
/* If the above logic is correct, c1 should always hold a valid string
bool bret = false, flipped_bit = false;
lastslash = strrchr(path, '/');
- if (!lastslash) { // bug... this shouldn't be possible
+ if (!lastslash) { /* bug... this shouldn't be possible */
ERROR("Invalid path: %s.", path);
return bret;
}
int ret;
lastslash = strrchr(path, '/');
- if (!lastslash) { // bug... this shouldn't be possible
+ if (!lastslash) { /* bug... this shouldn't be possible */
ERROR("cgfsng:copy_parent_file: bad path %s", path);
return false;
}
printf("Cgroup information:\n");
printf(" container name: %s\n", d->name ? d->name : "(null)");
printf(" lxc.cgroup.use: %s\n", cgroup_use ? cgroup_use : "(null)");
- printf(" lxc.cgroup.pattern: %s\n", d->cgroup_pattern ? d->cgroup_pattern : "(null)");
- printf(" cgroup: %s\n", d->container_cgroup ? d->container_cgroup : "(null)");
+ printf(" lxc.cgroup.pattern: %s\n",
+ d->cgroup_pattern ? d->cgroup_pattern : "(null)");
+ printf(" cgroup: %s\n",
+ d->container_cgroup ? d->container_cgroup : "(null)");
}
static void lxc_cgfsng_print_hierarchies()
const char *tmp;
errno = 0;
tmp = lxc_global_config_value("lxc.cgroup.use");
-
if (!cgroup_use && errno != 0) { /* lxc.cgroup.use can be NULL */
CGFSNG_DEBUG("Failed to retrieve list of cgroups to use\n");
return false;
return parse_hierarchies();
}
-static void *cgfsng_init(const char *name)
+static void *cgfsng_init(struct lxc_handler *handler)
{
- struct cgfsng_handler_data *d;
const char *cgroup_pattern;
+ struct cgfsng_handler_data *d;
d = must_alloc(sizeof(*d));
memset(d, 0, sizeof(*d));
- d->name = must_copy_string(name);
+ /* copy container name */
+ d->name = must_copy_string(handler->name);
+ /* copy system-wide cgroup information */
cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
- if (!cgroup_pattern) { // lxc.cgroup.pattern is only NULL on error
+ if (!cgroup_pattern) {
+ /* lxc.cgroup.pattern is only NULL on error. */
ERROR("Error getting cgroup pattern");
goto out_free;
}
static bool create_path_for_hierarchy(struct hierarchy *h, char *cgname)
{
h->fullcgpath = must_make_path(h->mountpoint, h->base_cgroup, cgname, NULL);
- if (dir_exists(h->fullcgpath)) { // it must not already exist
+ if (dir_exists(h->fullcgpath)) { /* it must not already exist */
ERROR("Path \"%s\" already existed.", h->fullcgpath);
return false;
}
*/
static inline bool cgfsng_create(void *hdata)
{
- struct cgfsng_handler_data *d = hdata;
- char *tmp, *cgname, *offset;
int i;
- int idx = 0;
size_t len;
+ char *cgname, *offset, *tmp;
+ int idx = 0;
+ struct cgfsng_handler_data *d = hdata;
if (!d)
return false;
+
if (d->container_cgroup) {
WARN("cgfsng_create called a second time");
return false;
ERROR("Failed expanding cgroup name pattern");
return false;
}
- len = strlen(tmp) + 5; // leave room for -NNN\0
+ len = strlen(tmp) + 5; /* leave room for -NNN\0 */
cgname = must_alloc(len);
strcpy(cgname, tmp);
free(tmp);
for (i = 0; hierarchies[i]; i++) {
if (!create_path_for_hierarchy(hierarchies[i], cgname)) {
int j;
- SYSERROR("Failed to create %s: %s", hierarchies[i]->fullcgpath, strerror(errno));
+ ERROR("Failed to create \"%s\"", hierarchies[i]->fullcgpath);
free(hierarchies[i]->fullcgpath);
hierarchies[i]->fullcgpath = NULL;
for (j = 0; j < i; j++)
return true;
}
-struct chown_data {
- struct cgfsng_handler_data *d;
- uid_t origuid; // target uid in parent namespace
-};
-
/*
* chgrp the container cgroups to container group. We leave
* the container owner as cgroup owner. So we must make the
const char *inpath,
const char *filename)
{
- /*
- * XXX Remove this case after 2.0 release. It's for dealing with
- * containers spawned under the old buggy cgfsng which wasn't around
- * for long.
- */
- if (strncmp(inpath, "/sys/fs/cgroup/", 15) == 0)
- return must_make_path(inpath, filename, NULL);
return must_make_path(h->mountpoint, inpath, filename, NULL);
}
struct hierarchy *h = hierarchies[i];
path = lxc_cmd_get_cgroup_path(name, lxcpath, h->controllers[0]);
- if (!path) // not running
+ if (!path) /* not running */
continue;
fullpath = build_full_cgpath_from_monitorpath(h, path, "cgroup.procs");
*p = '\0';
path = lxc_cmd_get_cgroup_path(name, lxcpath, subsystem);
- if (!path) // not running
+ if (!path) /* not running */
return -1;
h = get_hierarchy(subsystem);
*p = '\0';
path = lxc_cmd_get_cgroup_path(name, lxcpath, subsystem);
- if (!path) // not running
+ if (!path) /* not running */
return -1;
h = get_hierarchy(subsystem);
return ret;
}
+/*
+ * take devices cgroup line
+ * /dev/foo rwx
+ * and convert it to a valid
+ * type major:minor mode
+ * line. Return <0 on error. Dest is a preallocated buffer
+ * long enough to hold the output.
+ */
+static int convert_devpath(const char *invalue, char *dest)
+{
+ int n_parts;
+ char *p, *path, type;
+ struct stat sb;
+ unsigned long minor, major;
+ int ret = -EINVAL;
+ char *mode = NULL;
+
+ path = must_copy_string(invalue);
+
+ /*
+ * read path followed by mode; ignore any trailing text.
+ * A ' # comment' would be legal. Technically other text
+ * is not legal, we could check for that if we cared to
+ */
+ for (n_parts = 1, p = path; *p && n_parts < 3; p++) {
+ if (*p != ' ')
+ continue;
+ *p = '\0';
+ if (n_parts != 1)
+ break;
+ p++;
+ n_parts++;
+ while (*p == ' ')
+ p++;
+ mode = p;
+ if (*p == '\0')
+ goto out;
+ }
+
+ if (n_parts == 1)
+ goto out;
+
+ ret = stat(path, &sb);
+ if (ret < 0)
+ goto out;
+
+ mode_t m = sb.st_mode & S_IFMT;
+ switch (m) {
+ case S_IFBLK:
+ type = 'b';
+ break;
+ case S_IFCHR:
+ type = 'c';
+ break;
+ default:
+ ERROR("Unsupported device type %i for %s", m, path);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ major = MAJOR(sb.st_rdev);
+ minor = MINOR(sb.st_rdev);
+ ret = snprintf(dest, 50, "%c %lu:%lu %s", type, major, minor, mode);
+ if (ret < 0 || ret >= 50) {
+ ERROR("Error on configuration value \"%c %lu:%lu %s\" (max 50 "
+ "chars)", type, major, minor, mode);
+ ret = -ENAMETOOLONG;
+ goto out;
+ }
+ ret = 0;
+
+out:
+ free(path);
+ return ret;
+}
+
/*
* Called from setup_limits - here we have the container's cgroup_data because
* we created the cgroups
static int lxc_cgroup_set_data(const char *filename, const char *value, struct cgfsng_handler_data *d)
{
char *fullpath, *p;
+ /* "b|c <2^64-1>:<2^64-1> r|w|m" = 47 chars max */
+ char converted_value[50];
struct hierarchy *h;
int ret = 0;
char *controller = NULL;
if ((p = strchr(controller, '.')) != NULL)
*p = '\0';
+ if (strcmp("devices.allow", filename) == 0 && value[0] == '/') {
+ ret = convert_devpath(value, converted_value);
+ if (ret < 0)
+ return ret;
+ value = converted_value;
+
+ }
+
h = get_hierarchy(controller);
if (!h) {
ERROR("Failed to setup limits for the \"%s\" controller. "