Welcome to little lamb

Code » anopa » commit 611a698

Add aa-kill

author Olivier Brunel
2015-02-21 13:37:08 UTC
committer Olivier Brunel
2015-04-04 12:47:34 UTC
parent db77fec56ca790edde383a72e5638a9269cab3ce

Add aa-kill

doc/aa-kill.pod +59 -0
package/modes +1 -0
package/targets.mak +4 -2
src/utils/aa-kill.c +197 -0
src/utils/deps-exe/aa-kill +2 -0

diff --git a/doc/aa-kill.pod b/doc/aa-kill.pod
new file mode 100644
index 0000000..1caeed4
--- /dev/null
+++ b/doc/aa-kill.pod
@@ -0,0 +1,59 @@
+=head1 NAME
+
+aa-kill - Send signals to (almost) all processes
+
+=head1 SYNOPSIS
+
+B<aa-kill> [B<-u>] [B<-t>] [B<-k>] [B<-s>]
+
+=head1 OPTIONS
+
+=over
+
+=item B<-h, --help>
+
+Show help screen and exit.
+
+=item B<-k, --kill>
+
+Send SIGKILL
+
+=item B<-s, --skip>
+
+Skip processes whose argv[0][0] is '@' This can be useful to ignore some
+long-running processes that needs to be dealt with e.g. back in the initramfs,
+only after umounting the root filesystem.
+
+=item B<-t, --term>
+
+Send SIGTERM then SIGCONT
+
+=item B<-u, --hup>
+
+Send SIGHUP
+
+=item B<-V, --version>
+
+Show version information and exit.
+
+=back
+
+=head1 DESCRIPTION
+
+B<aa-kill>(1) can be used to send signals to (almost) all running processes. It
+is for example used during stage 3, after B<aa-stop>(1) and before
+B<aa-pivot>(1) to kill any & all procesess that may have not been stopped
+otherwise.
+
+By default it sends nothing, so at least one of B<--hup>, B<--term> or B<--kill>
+must be specified. You can combine them to send all specified signals. They will
+always be sent in that order (SIGHUP, SIGTERM/SIGCONT, SIGKILL).
+
+If B<--skip> was not used, signals are sent using B<kill>(3) with a pid of -1.
+If B<--skip> was used, B<aa-kill>(1) will then scan through I</proc> to list all
+running processes, and check their argv[0][0] (i.e. I</proc/PID/cmdline>) to
+skip any that starts with an '@' Also skipped will be process without cmdline
+(i.e. kernel threads), PID 1, and B<aa-kill>(1) itself.
+
+Note that B<aa-kill>(1) will ignore the signals it sends when B<--skip> isn't
+used, though that won't do much against SIGKILL.
diff --git a/package/modes b/package/modes
index 31e810b..fe462f7 100644
--- a/package/modes
+++ b/package/modes
@@ -2,3 +2,4 @@ aa-start                0755
 aa-stop                 0755
 aa-enable               0755
 aa-echo                 0755
+aa-kill                 0755
diff --git a/package/targets.mak b/package/targets.mak
index a078cfb..32daaf6 100644
--- a/package/targets.mak
+++ b/package/targets.mak
@@ -2,14 +2,16 @@ BIN_TARGETS := \
 aa-start \
 aa-stop \
 aa-enable \
-aa-echo
+aa-echo \
+aa-kill
 
 DOC_TARGETS := \
 anopa.1 \
 aa-start.1 \
 aa-stop.1 \
 aa-enable.1 \
-aa-echo.1
+aa-echo.1 \
+aa-kill.1 \
 
 ifdef DO_ALLSTATIC
 LIBANOPA := libanopa.a
diff --git a/src/utils/aa-kill.c b/src/utils/aa-kill.c
new file mode 100644
index 0000000..25b0757
--- /dev/null
+++ b/src/utils/aa-kill.c
@@ -0,0 +1,197 @@
+
+#define _BSD_SOURCE
+
+#include <getopt.h>
+#include <unistd.h>
+#include <signal.h>
+#include <skalibs/sig.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/uint.h>
+#include <anopa/common.h>
+#include <anopa/scan_dir.h>
+
+static struct {
+    unsigned int term : 1;
+    unsigned int kill : 1;
+    unsigned int hup : 1;
+
+    unsigned int skip_at : 1;
+} send = { 0, };
+static char ownpid[UINT_FMT];
+
+#if 0
+#include <skalibs/buffer.h>
+static void _kill (pid_t pid, int sig)
+{
+    char buf[UINT_FMT];
+    unsigned int u;
+
+    u = pid;
+    buf[uint_fmt (buf, u)] = 0;
+    buffer_putsnoflush (buffer_1small, "kill(");
+    if (u == (unsigned int) -1)
+        buffer_putsnoflush (buffer_1small, "-1");
+    else
+        buffer_putsnoflush (buffer_1small, buf);
+    buffer_putsnoflush (buffer_1small, ",");
+    buffer_putsnoflush (buffer_1small, sig_name (sig));
+    buffer_putsflush (buffer_1small, ")\n");
+}
+#else
+#define _kill(pid,sig)  kill (pid, sig)
+#endif
+
+static int
+it_kill (direntry *d, void *data)
+{
+    stralloc *sa = data;
+    char c;
+    int l;
+    int r;
+
+    /* ignore files, not-number dirs, PID 1 and ourself */
+    if (d->d_type != DT_DIR || *d->d_name < '1' || *d->d_name > '9'
+            || str_equal (d->d_name, "1") || str_equal (d->d_name, ownpid))
+        return 0;
+
+    l = sa->len;
+    sa->s[l - 1] = '/';
+    if (stralloc_cats (sa, d->d_name)
+            && stralloc_catb (sa, "/cmdline", sizeof ("/cmdline")))
+        r = openreadnclose (sa->s, &c, 1);
+    else
+        r = -1;
+    sa->len = l;
+    sa->s[l - 1] = '\0';
+
+    /* skip empty cmdline (kernel threads) and anything starting with '@' */
+    if (r == 1 && c != '@')
+    {
+        unsigned int u;
+        pid_t pid;
+
+        if (!uint_scan (d->d_name, &u))
+            goto done;
+        pid = (pid_t) u;
+        if (pid != u)
+            goto done;
+        if (send.hup)
+            _kill (pid, SIGHUP);
+        if (send.term)
+        {
+            _kill (pid, SIGTERM);
+            _kill (pid, SIGCONT);
+        }
+        if (send.kill)
+            _kill (pid, SIGKILL);
+    }
+
+done:
+    return 0;
+}
+
+static void
+dieusage (int rc)
+{
+    aa_die_usage (rc, "[OPTION...]",
+            " -u, --hup                     Send SIGHUP\n"
+            " -t, --term                    Send SIGTERM then SIGCONT\n"
+            " -k, --kill                    Send SIGKILL\n"
+            " -s, --skip-at                 Skip processes whose cmdline starts with '@'\n"
+            " -h, --help                    Show this help screen and exit\n"
+            " -V, --version                 Show version information and exit\n"
+            );
+}
+
+int
+main (int argc, char * const argv[])
+{
+    PROG = "aa-kill";
+
+    for (;;)
+    {
+        struct option longopts[] = {
+            { "help",               no_argument,        NULL,   'h' },
+            { "kill",               no_argument,        NULL,   'k' },
+            { "skip-at",            no_argument,        NULL,   's' },
+            { "term",               no_argument,        NULL,   't' },
+            { "hup",                no_argument,        NULL,   'u' },
+            { "version",            no_argument,        NULL,   'V' },
+            { NULL, 0, 0, 0 }
+        };
+        int c;
+
+        c = getopt_long (argc, argv, "hkstuV", longopts, NULL);
+        if (c == -1)
+            break;
+        switch (c)
+        {
+            case 'h':
+                dieusage (0);
+
+            case 'k':
+                send.kill = 1;
+                break;
+
+            case 's':
+                send.skip_at = 1;
+                break;
+
+            case 't':
+                send.term = 1;
+                break;
+
+            case 'u':
+                send.hup = 1;
+                break;
+
+            case 'V':
+                aa_die_version ();
+
+            default:
+                dieusage (1);
+        }
+    }
+    argc -= optind;
+    argv += optind;
+
+    if (argc > 0 || (!send.hup && !send.term && !send.kill))
+        dieusage (1);
+
+    if (send.skip_at)
+    {
+        stralloc sa = STRALLOC_ZERO;
+        unsigned int u;
+
+        u = (unsigned int) getpid ();
+        ownpid[uint_fmt (ownpid, u)] = '\0';
+
+        if (!stralloc_catb (&sa, "/proc", sizeof ("/proc")))
+            strerr_diefu1sys (1, "stralloc_catb");
+        if (aa_scan_dir (&sa, 0, it_kill, &sa) < 0)
+            strerr_diefu1sys (1, "scan /proc");
+        stralloc_free (&sa);
+    }
+    else
+    {
+        if (send.hup)
+        {
+            sig_ignore (SIGHUP);
+            _kill (-1, SIGHUP);
+        }
+
+        if (send.term)
+        {
+            sig_ignore (SIGTERM);
+            _kill (-1, SIGTERM);
+            _kill (-1, SIGCONT);
+        }
+
+        if (send.kill)
+            _kill (-1, SIGKILL);
+    }
+
+    return 0;
+}
diff --git a/src/utils/deps-exe/aa-kill b/src/utils/deps-exe/aa-kill
new file mode 100644
index 0000000..30987b4
--- /dev/null
+++ b/src/utils/deps-exe/aa-kill
@@ -0,0 +1,2 @@
+${LIBANOPA}
+-lskarnet