len = strlen(entry);
prefixed = must_alloc(len + 6);
- memcpy(prefixed, "name=", sizeof("name=") - 1);
- memcpy(prefixed + sizeof("name=") - 1, entry, len);
+
+ memcpy(prefixed, "name=", STRLITERALLEN("name="));
+ memcpy(prefixed + STRLITERALLEN("name="), entry, len);
prefixed[len + 5] = '\0';
return prefixed;
}
/* Given a handler's cgroup data, return the struct hierarchy for the controller
* @c, or NULL if there is none.
*/
-struct hierarchy *get_hierarchy(struct cgroup_ops *ops, const char *c)
+struct hierarchy *get_hierarchy(struct cgroup_ops *ops, const char *controller)
{
int i;
- if (!ops->hierarchies)
+ errno = ENOENT;
+
+ if (!ops->hierarchies) {
+ TRACE("There are no useable cgroup controllers");
return NULL;
+ }
for (i = 0; ops->hierarchies[i]; i++) {
- if (!c) {
+ if (!controller) {
/* This is the empty unified hierarchy. */
if (ops->hierarchies[i]->controllers &&
!ops->hierarchies[i]->controllers[0])
continue;
}
- if (string_in_list(ops->hierarchies[i]->controllers, c))
+ if (string_in_list(ops->hierarchies[i]->controllers, controller))
return ops->hierarchies[i];
}
+ if (controller)
+ WARN("There is no useable %s controller", controller);
+ else
+ WARN("There is no empty unified cgroup hierarchy");
+
return NULL;
}
}
}
- clonechildrenpath =
- must_make_path(cgpath, "cgroup.clone_children", NULL);
+ clonechildrenpath = must_make_path(cgpath, "cgroup.clone_children", NULL);
/* unified hierarchy doesn't have clone_children */
if (!file_exists(clonechildrenpath)) {
free(clonechildrenpath);
return cgroup_rmdir(arg->hierarchies, arg->container_cgroup);
}
-__cgfsng_ops static void cgfsng_destroy(struct cgroup_ops *ops, struct lxc_handler *handler)
+__cgfsng_ops static void cgfsng_payload_destroy(struct cgroup_ops *ops,
+ struct lxc_handler *handler)
{
int ret;
struct generic_userns_exec_data wrap;
}
}
+__cgfsng_ops static void cgfsng_monitor_destroy(struct cgroup_ops *ops,
+ struct lxc_handler *handler)
+{
+ int len;
+ char *pivot_path;
+ struct lxc_conf *conf = handler->conf;
+ char pidstr[INTTYPE_TO_STRLEN(pid_t)];
+
+ if (!ops->hierarchies)
+ return;
+
+ len = snprintf(pidstr, sizeof(pidstr), "%d", handler->monitor_pid);
+ if (len < 0 || (size_t)len >= sizeof(pidstr))
+ return;
+
+ for (int i = 0; ops->hierarchies[i]; i++) {
+ int ret;
+ struct hierarchy *h = ops->hierarchies[i];
+
+ if (!h->monitor_full_path)
+ continue;
+
+ if (conf && conf->cgroup_meta.dir)
+ pivot_path = must_make_path(h->mountpoint,
+ h->container_base_path,
+ conf->cgroup_meta.dir,
+ PIVOT_CGROUP,
+ "cgroup.procs", NULL);
+ else
+ pivot_path = must_make_path(h->mountpoint,
+ h->container_base_path,
+ PIVOT_CGROUP,
+ "cgroup.procs", NULL);
+
+ ret = mkdir_p(pivot_path, 0755);
+ if (ret < 0 && errno != EEXIST)
+ goto next;
+
+ /* Move ourselves into the pivot cgroup to delete our own
+ * cgroup.
+ */
+ ret = lxc_write_to_file(pivot_path, pidstr, len, false, 0666);
+ if (ret != 0)
+ goto next;
+
+ ret = recursive_destroy(h->monitor_full_path);
+ if (ret < 0)
+ WARN("Failed to destroy \"%s\"", h->monitor_full_path);
+
+ next:
+ free(pivot_path);
+ }
+}
+
static bool cg_unified_create_cgroup(struct hierarchy *h, char *cgname)
{
size_t i, parts_len;
if (dir_exists(h->monitor_full_path))
return true;
+ if (!cg_legacy_handle_cpuset_hierarchy(h, cgname)) {
+ ERROR("Failed to handle legacy cpuset controller");
+ return false;
+ }
+
ret = mkdir_p(h->monitor_full_path, 0755);
if (ret < 0) {
ERROR("Failed to create cgroup \"%s\"", h->monitor_full_path);
__cgfsng_ops static inline bool cgfsng_monitor_create(struct cgroup_ops *ops,
struct lxc_handler *handler)
{
- char *monitor_cgroup;
+ char *monitor_cgroup, *offset, *tmp;
+ int idx = 0;
+ size_t len;
bool bret = false;
struct lxc_conf *conf = handler->conf;
return bret;
if (conf->cgroup_meta.dir)
- monitor_cgroup = lxc_string_join("/", (const char *[]){conf->cgroup_meta.dir, ops->monitor_pattern, handler->name, NULL}, false);
+ tmp = lxc_string_join("/",
+ (const char *[]){conf->cgroup_meta.dir,
+ ops->monitor_pattern,
+ handler->name, NULL},
+ false);
else
- monitor_cgroup = must_make_path(ops->monitor_pattern, handler->name, NULL);
- if (!monitor_cgroup)
+ tmp = must_make_path(ops->monitor_pattern, handler->name, NULL);
+ if (!tmp)
return bret;
- for (int i = 0; ops->hierarchies[i]; i++) {
- if (!monitor_create_path_for_hierarchy(ops->hierarchies[i], monitor_cgroup)) {
- ERROR("Failed to create cgroup \"%s\"", ops->hierarchies[i]->monitor_full_path);
- free(ops->hierarchies[i]->container_full_path);
- ops->hierarchies[i]->container_full_path = NULL;
- for (int j = 0; j < i; j++)
- remove_path_for_hierarchy(ops->hierarchies[j], monitor_cgroup, true);
- goto on_error;
+ len = strlen(tmp) + 5; /* leave room for -NNN\0 */
+ monitor_cgroup = must_alloc(len);
+ (void)strlcpy(monitor_cgroup, tmp, len);
+ free(tmp);
+ offset = monitor_cgroup + len - 5;
+
+ do {
+ if (idx) {
+ int ret = snprintf(offset, 5, "-%d", idx);
+ if (ret < 0 || (size_t)ret >= 5)
+ goto on_error;
}
- }
- bret = true;
+ for (int i = 0; ops->hierarchies[i]; i++) {
+ if (!monitor_create_path_for_hierarchy(ops->hierarchies[i], monitor_cgroup)) {
+ ERROR("Failed to create cgroup \"%s\"", ops->hierarchies[i]->monitor_full_path);
+ free(ops->hierarchies[i]->container_full_path);
+ ops->hierarchies[i]->container_full_path = NULL;
+
+ for (int j = 0; j < i; j++)
+ remove_path_for_hierarchy(ops->hierarchies[j], monitor_cgroup, true);
+
+ idx++;
+ break;
+ }
+ }
+ } while (idx > 0 && idx < 1000);
+
+ if (idx < 1000)
+ bret = true;
on_error:
free(monitor_cgroup);
bool monitor)
{
int len;
- char pidstr[25];
+ char pidstr[INTTYPE_TO_STRLEN(pid_t)];
- len = snprintf(pidstr, 25, "%d", pid);
- if (len < 0 || len >= 25)
+ len = snprintf(pidstr, sizeof(pidstr), "%d", pid);
+ if (len < 0 || (size_t)len >= sizeof(pidstr))
return false;
for (int i = 0; ops->hierarchies[i]; i++) {
free(full_path);
- len = strlen(base_path) + sizeof("/lxc-1000") - 1 +
- sizeof("/cgroup-procs") - 1;
+ len = strlen(base_path) + STRLITERALLEN("/lxc-1000") +
+ STRLITERALLEN("/cgroup-procs");
full_path = must_alloc(len + 1);
do {
if (idx)
const char *lxcpath, pid_t pid)
{
int i, len, ret;
- char pidstr[25];
+ char pidstr[INTTYPE_TO_STRLEN(pid_t)];
- len = snprintf(pidstr, 25, "%d", pid);
- if (len < 0 || len >= 25)
+ len = snprintf(pidstr, sizeof(pidstr), "%d", pid);
+ if (len < 0 || (size_t)len >= sizeof(pidstr))
return false;
for (i = 0; ops->hierarchies[i]; i++) {
return false;
}
ops->cgroup_pattern = must_copy_string(cgroup_pattern);
- ops->monitor_pattern = must_copy_string("lxc.monitor");
+ ops->monitor_pattern = MONITOR_CGROUP;
return true;
}
}
cgfsng_ops->data_init = cgfsng_data_init;
- cgfsng_ops->destroy = cgfsng_destroy;
+ cgfsng_ops->payload_destroy = cgfsng_payload_destroy;
+ cgfsng_ops->monitor_destroy = cgfsng_monitor_destroy;
cgfsng_ops->monitor_create = cgfsng_monitor_create;
cgfsng_ops->monitor_enter = cgfsng_monitor_enter;
cgfsng_ops->payload_create = cgfsng_payload_create;