return cgroup->path;
}
-static struct pakfire_cgroup* pakfire_cgroup_parent(struct pakfire_cgroup* cgroup) {
- struct pakfire_cgroup* parent = NULL;
+static int pakfire_cgroup_parent(struct pakfire_cgroup* cgroup, struct pakfire_cgroup** parent) {
char path[PATH_MAX];
int r;
// Cannot return parent for root group
- if (pakfire_cgroup_is_root(cgroup))
- return NULL;
+ if (pakfire_cgroup_is_root(cgroup)) {
+ *parent = NULL;
+ return 0;
+ }
// Determine the path of the parent
r = pakfire_path_dirname(path, cgroup->path);
- if (r) {
- ERROR(cgroup->ctx, "Could not determine path for parent cgroup: %m\n");
- return NULL;
+ if (r < 0) {
+ ERROR(cgroup->ctx, "Could not determine path for parent cgroup: %s\n", strerror(-r));
+ return r;
}
- // dirname() returns . if no directory component could be found
- if (strcmp(path, ".") == 0)
- *path = '\0';
-
// Open the cgroup
- r = pakfire_cgroup_open(&parent, cgroup->ctx, path, 0);
- if (r) {
- ERROR(cgroup->ctx, "Could not open parent cgroup: %m\n");
- parent = NULL;
- }
-
- return parent;
+ return pakfire_cgroup_open(parent, cgroup->ctx, path, 0);
}
static int pakfire_cgroup_setup_devices(struct pakfire_cgroup* cgroup) {
static int pakfire_cgroup_write(struct pakfire_cgroup* cgroup,
const char* path, const char* format, ...) {
+ ssize_t bytes_written = 0;
va_list args;
+ int fd = -EBADF;
int r = 0;
// Check if this cgroup has been destroyed already
if (cgroup->fd < 0) {
ERROR(cgroup->ctx, "Trying to write to destroyed cgroup\n");
- errno = EPERM;
- return 1;
+ return -EPERM;
}
// Open the file
- int fd = openat(cgroup->fd, path, O_WRONLY|O_CLOEXEC);
+ fd = openat(cgroup->fd, path, O_WRONLY|O_CLOEXEC);
if (fd < 0) {
DEBUG(cgroup->ctx, "Could not open %s/%s for writing: %m\n",
pakfire_cgroup_name(cgroup), path);
- return -errno;
+ r = -errno;
+ goto ERROR;
}
// Write buffer
va_start(args, format);
- ssize_t bytes_written = vdprintf(fd, format, args);
+ bytes_written = vdprintf(fd, format, args);
va_end(args);
// Check if content was written okay
DEBUG(cgroup->ctx, "Could not write to %s/%s: %m\n",
pakfire_cgroup_name(cgroup), path);
r = -errno;
+ goto ERROR;
}
- // Close fd
- close(fd);
+ERROR:
+ if (fd > 0)
+ close(fd);
return r;
}
Enables a cgroup controller.
*/
static int pakfire_cgroup_enable_controller(struct pakfire_cgroup* cgroup, const char* name) {
+ struct pakfire_cgroup* parent = NULL;
int r;
// Try to enable the controller
r = pakfire_cgroup_write(cgroup, "cgroup.subtree_control", "+%s", name);
- if (r < 0)
- ERROR(cgroup->ctx, "Could not enable controller '%s': %s\n", name, strerror(-r));
+ if (r < 0) {
+ switch (-r) {
+ case ENOENT:
+ // Fetch the parent group
+ r = pakfire_cgroup_parent(cgroup, &parent);
+ if (r < 0)
+ return r;
+
+ // When we have reached root, we cannot continue
+ if (!parent)
+ return -ENOTSUP;
+
+ // Ensure it is enabled there
+ r = pakfire_cgroup_enable_controller(parent, name);
+ if (r < 0)
+ return 0;
+
+ // Once that was successful, try again
+ return pakfire_cgroup_enable_controller(cgroup, name);
+
+ default:
+ ERROR(cgroup->ctx, "Could not enable controller '%s': %s\n",
+ name, strerror(-r));
+ break;
+ }
+ }
return r;
}