From: Michael Tremer Date: Tue, 9 Aug 2022 14:46:04 +0000 (+0000) Subject: cgroup: Implement legacy way to kill processes X-Git-Tag: 0.9.28~545 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=034ba70ea197ad6a80627edec7798d09bde5260f;p=pakfire.git cgroup: Implement legacy way to kill processes Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/cgroup.c b/src/libpakfire/cgroup.c index 873d13dae..2d7d8a3d5 100644 --- a/src/libpakfire/cgroup.c +++ b/src/libpakfire/cgroup.c @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -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"); } /*