]> git.ipfire.org Git - pakfire.git/commitdiff
cgroup: Implement function to kill all processes left
authorMichael Tremer <michael.tremer@ipfire.org>
Sat, 27 Mar 2021 17:34:46 +0000 (17:34 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sat, 27 Mar 2021 17:34:46 +0000 (17:34 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/cgroup.c
src/libpakfire/include/pakfire/cgroup.h
tests/libpakfire/cgroup.c

index 2dfe2cbd000231c4bec8625f88c60c07ea75bd0a..8e2c713e181bae21162cedad52cd332a715d25e3 100644 (file)
@@ -21,6 +21,7 @@
 #include <errno.h>
 #include <linux/limits.h>
 #include <linux/magic.h>
+#include <signal.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
@@ -325,7 +326,7 @@ int pakfire_cgroup_detach(Pakfire pakfire, const char* group, pid_t pid) {
 }
 
 static ssize_t pakfire_cgroup_procs_callback(Pakfire pakfire, const char* group,
-               int (*func)(Pakfire pakfire, pid_t pid)) {
+               int (*func)(Pakfire pakfire, pid_t pid, void* data), void* data) {
        FILE* f = pakfire_cgroup_fopen(pakfire, group, "cgroup.procs", "r");
        if (!f)
                return -1;
@@ -343,7 +344,18 @@ static ssize_t pakfire_cgroup_procs_callback(Pakfire pakfire, const char* group,
                // Increment process counter
                num_processes++;
 
-               DEBUG(pakfire, "Read line %s\n", line);
+               // Process callback
+               if (func) {
+                       // Parse PID
+                       pid_t pid = strtol(line, NULL, 10);
+
+                       // Call callback function
+                       int r = func(pakfire, pid, data);
+                       if (r) {
+                               fclose(f);
+                               return -r;
+                       }
+               }
        }
 
        fclose(f);
@@ -353,5 +365,46 @@ static ssize_t pakfire_cgroup_procs_callback(Pakfire pakfire, const char* group,
 }
 
 ssize_t pakfire_cgroup_num_processes(Pakfire pakfire, const char* group) {
-       return pakfire_cgroup_procs_callback(pakfire, group, NULL);
+       return pakfire_cgroup_procs_callback(pakfire, group, NULL, NULL);
+}
+
+static int send_signal(Pakfire pakfire, pid_t pid, void* data) {
+       int* signum = (int*)data;
+
+       DEBUG(pakfire, "Sending signal %d to PID %d\n", *signum, pid);
+
+       int r = kill(pid, *signum);
+       if (r < 0 && errno != ESRCH) {
+               ERROR(pakfire, "Could not send signal %d to PID %d: %s\n",
+                       *signum, pid, strerror(errno));
+               return r;
+       }
+
+       return 0;
+}
+
+int pakfire_cgroup_killall(Pakfire pakfire, const char* group) {
+       DEBUG(pakfire, "Killing all processes in cgroup %s\n", group);
+       int signum = SIGTERM;
+
+       int count = 0;
+       while (1) {
+               // Kill all processes
+               size_t num_procs = pakfire_cgroup_procs_callback(pakfire, group,
+                       send_signal, &signum);
+
+               // If no processes are left, we are done
+               if (!num_procs)
+                       return 0;
+
+               DEBUG(pakfire, "  %zu process(es) left\n", num_procs);
+
+               // Use SIGKILL after 5 attempts with SIGTERM
+               if (count++ > 5 && signum == SIGTERM)
+                       signum = SIGKILL;
+
+               usleep(100000);
+       }
+
+       return 1;
 }
index e9766a676f53345f9794bc4c6c6c32f31f7bbdf9..f474faad8a069bfa9d46b454c3254b1a3f2cd915 100644 (file)
@@ -35,6 +35,8 @@ int pakfire_cgroup_detach(Pakfire pakfire, const char* group, pid_t pid);
 
 ssize_t pakfire_cgroup_num_processes(Pakfire pakfire, const char* group);
 
+int pakfire_cgroup_killall(Pakfire pakfire, const char* group);
+
 #endif
 
 #endif /* PAKFIRE_CGROUP_H */
index f6cdb7b1bcc6f26d835f8e5d4c64f3e4916f27cf..8bd32c1250ca1486e7a462c37ef4044c57a381ab 100644 (file)
@@ -18,6 +18,7 @@
 #                                                                             #
 #############################################################################*/
 
+#include <signal.h>
 #include <sys/types.h>
 #include <unistd.h>
 
@@ -43,7 +44,7 @@ static int test_attach(const struct test* t) {
        // Fetch the PID of the test process
        pid_t pid = getpid();
 
-       printf("This process's PID: %d\n", pid);
+       LOG("This process's PID: %d\n", pid);
 
        ASSERT_SUCCESS(
                pakfire_cgroup_create(t->pakfire, "pakfire/test")
@@ -76,9 +77,65 @@ static int test_attach(const struct test* t) {
        return EXIT_SUCCESS;
 }
 
+static void handle_signal(int signum) {
+       pid_t pid = getpid();
+
+       LOG("Process %d received signal %d\n", pid, signum);
+}
+
+static int child_process() {
+       LOG("Child process started with PID %d\n", getpid());
+
+       signal(SIGTERM, handle_signal);
+
+       // Do nothing
+       while (1) {
+               sleep(1);
+
+               LOG("Child process is still alive\n");
+       }
+
+       return 0;
+}
+
+static pid_t fork_child_process() {
+       pid_t pid = fork();
+       ASSERT(pid >= 0);
+
+       // Jump into child function
+       if (pid == 0)
+               return child_process();
+
+       return pid;
+}
+
+static int test_killall(const struct test* t) {
+       ASSERT_SUCCESS(
+               pakfire_cgroup_create(t->pakfire, "pakfire/test")
+       );
+
+       // Launch a background we can kill :)
+       pid_t pid = fork_child_process();
+
+       // Attach child to cgroup
+       ASSERT_SUCCESS(
+               pakfire_cgroup_attach(t->pakfire, "pakfire/test", pid)
+       );
+
+       // Kill everything
+       ASSERT_SUCCESS(
+               pakfire_cgroup_killall(t->pakfire, "pakfire/test")
+       );
+
+       ASSERT_SUCCESS(
+               pakfire_cgroup_destroy(t->pakfire, "pakfire/test")
+       );
+}
+
 int main(int argc, char** argv) {
        testsuite_add_test(test_create_and_destroy);
        testsuite_add_test(test_attach);
+       testsuite_add_test(test_killall);
 
        return testsuite_run();
 }