author | Olivier Brunel
<jjk@jjacky.com> 2015-02-21 13:37:08 UTC |
committer | Olivier Brunel
<jjk@jjacky.com> 2015-04-04 12:47:34 UTC |
parent | db77fec56ca790edde383a72e5638a9269cab3ce |
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