#include <errno.h>
#include <fcntl.h>
+#include <signal.h>
#include <stdlib.h>
#include <sys/types.h>
return fd;
}
+static int pakfire_cgroup_access(struct pakfire_cgroup* cgroup, const char* path,
+ int mode, int flags) {
+ return faccessat(cgroup->fd, path, mode, flags);
+}
+
+static FILE* pakfire_cgroup_open_file(struct pakfire_cgroup* cgroup,
+ const char* path, const char* mode) {
+ FILE* f = NULL;
+
+ // Open cgroup.procs
+ int fd = openat(cgroup->fd, "cgroup.procs", O_CLOEXEC);
+ if (fd < 0) {
+ ERROR(cgroup->pakfire, "%s: Could not open %s: %m\n",
+ pakfire_cgroup_name(cgroup), path);
+ goto ERROR;
+ }
+
+ // Convert into file handle
+ f = fdopen(fd, mode);
+ if (!f)
+ goto ERROR;
+
+ERROR:
+ if (fd)
+ close(fd);
+
+ return f;
+}
+
static ssize_t pakfire_cgroup_read(struct pakfire_cgroup* cgroup, const char* path,
char* buffer, size_t length) {
ssize_t bytes_read = -1;
return NULL;
}
+static int pakfire_cgroup_procs_callback(struct pakfire_cgroup* cgroup,
+ int (*callback)(struct pakfire_cgroup* cgroup, pid_t pid, void* data), void* data) {
+ int r = 0;
+
+ // Check if we have a callback
+ if (!callback) {
+ errno = EINVAL;
+ return 1;
+ }
+
+ // Open cgroup.procs
+ FILE* f = pakfire_cgroup_open_file(cgroup, "cgroup.procs", "r");
+ if (!f)
+ return 1;
+
+ char* line = NULL;
+ size_t l = 0;
+
+ // Walk through all PIDs
+ while (1) {
+ ssize_t bytes_read = getline(&line, &l, f);
+ if (bytes_read < 0)
+ break;
+
+ // Parse PID
+ pid_t pid = strtol(line, NULL, 10);
+
+ // Call callback function
+ r = callback(cgroup, pid, data);
+ if (r)
+ break;
+ }
+
+ // Cleanup
+ fclose(f);
+
+ return r;
+}
+
+static int send_sigkill(struct pakfire_cgroup* cgroup, const pid_t pid, void* data) {
+ DEBUG(cgroup->pakfire, "Sending signal SIGKILL to PID %d\n", pid);
+
+ int r = kill(pid, SIGKILL);
+ if (r < 0 && errno != ESRCH) {
+ ERROR(cgroup->pakfire, "Could not send signal SIGKILL to PID %d: %m\n", pid);
+ return r;
+ }
+
+ return r;
+}
+
/*
Immediately kills all processes in this cgroup
*/
int pakfire_cgroup_killall(struct pakfire_cgroup* cgroup) {
- int r = pakfire_cgroup_write(cgroup, "cgroup.kill", "1");
- if (r)
- ERROR(cgroup->pakfire, "Could not kill processes: %m\n");
+ DEBUG(cgroup->pakfire, "%s: Killing all processes\n", pakfire_cgroup_name(cgroup));
- return r;
+ // Do we have support for cgroup.kill?
+ int r = pakfire_cgroup_access(cgroup, "cgroup.kill", F_OK, 0);
+
+ // Fall back to the legacy version
+ if (r && errno == ENOENT) {
+ return pakfire_cgroup_procs_callback(cgroup, send_sigkill, NULL);
+ }
+
+ return pakfire_cgroup_write(cgroup, "cgroup.kill", "1");
}
/*