/* kill -- send a signal to a process

   Copyright (C) 2006, Aaron Griffin - trimmed for early-userspace
   Original  by Paul Eggert.

   Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.

   This program 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 2, or (at your option)
   any later version.

   This program 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 this program; if not, write to the Free Software Foundation,
   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <getopt.h>
#include <sys/types.h>
#include <signal.h>
#include <inttypes.h>
#include <sys/wait.h>

static char const short_options[] = "0::1::2::3::4::5::6::7::8::9::n:s:";

void
usage (int status)
{
    puts ("Usage: kill [-s SIGNAL | -SIGNAL] PID [PID\n"
          "  NOTE: Only numeric signals may be used with this version of kill");
    exit (status);
}

/* Convert OPERAND to a signal number with printable representation SIGNAME.
   Return the signal number, or -1 if unsuccessful.  */
static int
operand2sig (char const *operand)
{
    int signum = -1;

    if (isdigit (*operand))
    {
        char *endp;
        long int l = (errno = 0, strtol (operand, &endp, 10));
        int i = l;
        signum = (operand == endp || *endp || errno || i != l ? -1
                  : WIFSIGNALED (i) ? WTERMSIG (i)
                  : i);
    }

    if (signum < 0)
    {
        fprintf (stderr, "%s: invalid signal\n", operand);
        return -1;
    }

    return signum;
}

/* Send signal SIGNUM to all the processes or process groups specified
   by ARGV.  Return a suitable exit status.  */
static int
send_signals (int signum, char *const *argv)
{
    int status = EXIT_SUCCESS;
    char const *arg = *argv;

    do
    {
        char *endp;
        intmax_t n = (errno = 0, strtoimax (arg, &endp, 10));
        pid_t pid = n;

        if (errno == ERANGE || pid != n || arg == endp || *endp)
        {
            fprintf(stderr, "%s: invalid process id\n", arg);
            status = EXIT_FAILURE;
        }
        else if (kill (pid, signum) != 0)
        {
            fprintf(stderr, "%s: %s\n", arg, strerror(errno));
            status = EXIT_FAILURE;
        }
    }
    while ((arg = *++argv));

    return status;
}

int
main (int argc, char **argv)
{
    int optc;
    int signum = -1;

    while ((optc = getopt(argc, argv, short_options)) != -1)
        switch (optc)
        {
        case '0': case '1': case '2': case '3': case '4':
        case '5': case '6': case '7': case '8': case '9':
            if (optind != 2)
            {
                /* This option is actually a process-id.  */
                optind--;
                break;
            }
            if (! optarg)
                optarg = argv[optind - 1] + strlen (argv[optind - 1]);
            if (optarg != argv[optind - 1] + 2)
            {
                fprintf (stderr, "invalid option -- %c\n", optc);
                usage (EXIT_FAILURE);
            }
            optarg--;
        case 's':
            if (0 <= signum)
            {
                fprintf (stderr, "%s: multiple signals specified\n", optarg);
                usage (EXIT_FAILURE);
            }
            signum = operand2sig (optarg);
            if (signum < 0)
                usage (EXIT_FAILURE);
            break;
        default:
            usage (EXIT_FAILURE);
        }

    if (signum < 0) signum = SIGTERM;

    if ( argc <= optind)
    {
        fprintf (stderr, "no process ID specified\n");
        usage (EXIT_FAILURE);
    }

    return send_signals (signum, argv + optind);
}
