]> git.ipfire.org Git - people/stevee/pakfire.git/commitdiff
cgroup: Implement legacy way to kill processes
authorMichael Tremer <michael.tremer@ipfire.org>
Tue, 9 Aug 2022 14:46:04 +0000 (14:46 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Tue, 9 Aug 2022 14:46:04 +0000 (14:46 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/cgroup.c

index 873d13dae26f5eff739f3cba4fbc63caec7eee2a..2d7d8a3d5a421a083039d461c5f34944fef64782 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <signal.h>
 #include <stdlib.h>
 #include <sys/types.h>
 
@@ -229,6 +230,35 @@ ERROR:
        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;
@@ -498,15 +528,72 @@ struct pakfire_cgroup* pakfire_cgroup_unref(struct pakfire_cgroup* cgroup) {
        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");
 }
 
 /*