/*
* anopa - Copyright (C) 2015-2017 Olivier Brunel
*
* aa-kill.c
* Copyright (C) 2015-2018 Olivier Brunel <jjk@jjacky.com>
*
* This file is part of anopa.
*
* anopa is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* anopa is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* anopa. If not, see http://www.gnu.org/licenses/
*/
#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/bytestr.h>
#include <skalibs/types.h>
#include <anopa/common.h>
#include <anopa/output.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
static void _kill (pid_t pid, int sig)
{
char buf[UINT_FMT];
unsigned int u;
u = pid;
buf[uint_fmt (buf, u)] = 0;
aa_bs (AA_OUT, "kill(");
if (u == (unsigned int) -1)
aa_bs (AA_OUT, "-1");
else
aa_bs (AA_OUT, buf);
aa_bs (AA_OUT, ",");
aa_bs (AA_OUT, sig_name (sig));
aa_bs_flush (AA_OUT, ")\n");
}
#else
#define _kill(pid,sig) kill (pid, sig)
#endif
static int
it_kill (direntry *d, void *data)
{
stralloc *sa = data;
char c;
size_t l;
ssize_t 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 (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...]",
" -D, --double-output Enable double-output mode\n"
" -O, --log-file FILE|FD Write log to FILE|FD\n"
" -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[] = {
{ "double-output", no_argument, NULL, 'D' },
{ "help", no_argument, NULL, 'h' },
{ "kill", no_argument, NULL, 'k' },
{ "log-file", required_argument, NULL, 'O' },
{ "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, "DhkO:stuV", longopts, NULL);
if (c == -1)
break;
switch (c)
{
case 'D':
aa_set_double_output (1);
break;
case 'h':
dieusage (RC_OK);
case 'k':
send.kill = 1;
break;
case 'O':
aa_set_log_file_or_die (optarg);
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 (RC_FATAL_USAGE);
}
}
argc -= optind;
argv += optind;
if (argc > 0 || (!send.hup && !send.term && !send.kill))
dieusage (RC_FATAL_USAGE);
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")))
aa_strerr_diefu1sys (RC_FATAL_MEMORY, "stralloc_catb");
if (aa_scan_dir (&sa, 0, it_kill, &sa) < 0)
aa_strerr_diefu1sys (RC_FATAL_IO, "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 RC_OK;
}