mirror of
git://git.sv.gnu.org/coreutils.git
synced 2026-04-13 23:36:10 +02:00
instead of hard-coding --help and --version descriptions. Split --help output into smaller pieces. Use fputs, not printf.
769 lines
18 KiB
C
769 lines
18 KiB
C
/* kill -- send a signal to a process
|
||
Copyright (C) 2001 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||
|
||
/* Written by Marcus Brinkmann. */
|
||
|
||
#include <config.h>
|
||
#include <stdio.h>
|
||
#include <getopt.h>
|
||
#include <sys/types.h>
|
||
|
||
#include <signal.h>
|
||
|
||
#include "system.h"
|
||
#include "closeout.h"
|
||
#include "human.h"
|
||
#include "error.h"
|
||
#include "xstrtol.h"
|
||
|
||
/* The official name of this program (e.g., no `g' prefix). */
|
||
#define PROGRAM_NAME "kill"
|
||
|
||
#define AUTHORS "Marcus Brinkmann"
|
||
|
||
|
||
/* An invalid signal number. */
|
||
#define NO_SIG -1
|
||
|
||
/* A structure holding the number and the name of a signal. */
|
||
struct sigspec
|
||
{
|
||
int signum;
|
||
char *signame;
|
||
};
|
||
|
||
/* The list of signals was taken from bash 2.05. The best name for a
|
||
signal comes after any possible alias, so it is read it from back
|
||
to front. This is why the terminating null entry comes first. */
|
||
static struct sigspec sigspecs[] =
|
||
{
|
||
{ NO_SIG, NULL },
|
||
|
||
/* Null is used to test for the existance and ownership of a PID. */
|
||
{ 0, "0" },
|
||
|
||
/* AIX */
|
||
#if defined (SIGLOST) /* resource lost (eg, record-lock lost) */
|
||
{ SIGLOST, "LOST" },
|
||
#endif
|
||
|
||
#if defined (SIGMSG) /* HFT input data pending */
|
||
{ SIGMSG, "MSG" },
|
||
#endif
|
||
|
||
#if defined (SIGDANGER) /* system crash imminent */
|
||
{ SIGDANGER, "DANGER" },
|
||
#endif
|
||
|
||
#if defined (SIGMIGRATE) /* migrate process to another CPU */
|
||
{ SIGMIGRATE, "MIGRATE" },
|
||
#endif
|
||
|
||
#if defined (SIGPRE) /* programming error */
|
||
{ SIGPRE, "PRE" },
|
||
#endif
|
||
|
||
#if defined (SIGVIRT) /* AIX virtual time alarm */
|
||
{ SIGVIRT, "VIRT" },
|
||
#endif
|
||
|
||
#if defined (SIGALRM1) /* m:n condition variables */
|
||
{ SIGALRM1, "ALRM1" },
|
||
#endif
|
||
|
||
#if defined (SIGWAITING) /* m:n scheduling */
|
||
{ SIGWAITING, "WAITING" },
|
||
#endif
|
||
|
||
#if defined (SIGGRANT) /* HFT monitor mode granted */
|
||
{ SIGGRANT, "GRANT" },
|
||
#endif
|
||
|
||
#if defined (SIGKAP) /* keep alive poll from native keyboard */
|
||
{ SIGKAP, "KAP" },
|
||
#endif
|
||
|
||
#if defined (SIGRETRACT) /* HFT monitor mode retracted */
|
||
{ SIGRETRACT, "RETRACT" },
|
||
#endif
|
||
|
||
#if defined (SIGSOUND) /* HFT sound sequence has completed */
|
||
{ SIGSOUND, "SOUND" },
|
||
#endif
|
||
|
||
#if defined (SIGSAK) /* Secure Attention Key */
|
||
{ SIGSAK, "SAK" },
|
||
#endif
|
||
|
||
/* SunOS5 */
|
||
#if defined (SIGLWP) /* special signal used by thread library */
|
||
{ SIGLWP, "LWP" },
|
||
#endif
|
||
|
||
#if defined (SIGFREEZE) /* special signal used by CPR */
|
||
{ SIGFREEZE, "FREEZE" },
|
||
#endif
|
||
|
||
#if defined (SIGTHAW) /* special signal used by CPR */
|
||
{ SIGTHAW, "THAW" },
|
||
#endif
|
||
|
||
#if defined (SIGCANCEL) /* thread cancellation signal used by libthread */
|
||
{ SIGCANCEL, "CANCEL" },
|
||
#endif
|
||
|
||
/* HP-UX */
|
||
#if defined (SIGDIL) /* DIL signal (?) */
|
||
{ SIGDIL, "DIL" },
|
||
#endif
|
||
|
||
/* System V */
|
||
#if defined (SIGCLD) /* Like SIGCHLD. */
|
||
{ SIGCLD, "CLD" },
|
||
#endif
|
||
|
||
#if defined (SIGPWR) /* power state indication */
|
||
{ SIGPWR, "PWR" },
|
||
#endif
|
||
|
||
#if defined (SIGPOLL) /* Pollable event (for streams) */
|
||
{ SIGPOLL, "POLL" },
|
||
#endif
|
||
|
||
/* Unknown */
|
||
#if defined (SIGWINDOW)
|
||
{ SIGWINDOW, "WINDOW" },
|
||
#endif
|
||
|
||
/* Common */
|
||
#if defined (SIGHUP) /* hangup */
|
||
{ SIGHUP, "HUP" },
|
||
#endif
|
||
|
||
#if defined (SIGINT) /* interrupt */
|
||
{ SIGINT, "INT" },
|
||
#endif
|
||
|
||
#if defined (SIGQUIT) /* quit */
|
||
{ SIGQUIT, "QUIT" },
|
||
#endif
|
||
|
||
#if defined (SIGILL) /* illegal instruction (not reset when caught) */
|
||
{ SIGILL, "ILL" },
|
||
#endif
|
||
|
||
#if defined (SIGTRAP) /* trace trap (not reset when caught) */
|
||
{ SIGTRAP, "TRAP" },
|
||
#endif
|
||
|
||
#if defined (SIGIOT) /* IOT instruction */
|
||
{ SIGIOT, "IOT" },
|
||
#endif
|
||
|
||
#if defined (SIGABRT) /* Cause current process to dump core. */
|
||
{ SIGABRT, "ABRT" },
|
||
#endif
|
||
|
||
#if defined (SIGEMT) /* EMT instruction */
|
||
{ SIGEMT, "EMT" },
|
||
#endif
|
||
|
||
#if defined (SIGFPE) /* floating point exception */
|
||
{ SIGFPE, "FPE" },
|
||
#endif
|
||
|
||
#if defined (SIGKILL) /* kill (cannot be caught or ignored) */
|
||
{ SIGKILL, "KILL" },
|
||
#endif
|
||
|
||
#if defined (SIGBUS) /* bus error */
|
||
{ SIGBUS, "BUS" },
|
||
#endif
|
||
|
||
#if defined (SIGSEGV) /* segmentation violation */
|
||
{ SIGSEGV, "SEGV" },
|
||
#endif
|
||
|
||
#if defined (SIGSYS) /* bad argument to system call */
|
||
{ SIGSYS, "SYS" },
|
||
#endif
|
||
|
||
#if defined (SIGPIPE) /* write on a pipe with no one to read it */
|
||
{ SIGPIPE, "PIPE" },
|
||
#endif
|
||
|
||
#if defined (SIGALRM) /* alarm clock */
|
||
{ SIGALRM, "ALRM" },
|
||
#endif
|
||
|
||
#if defined (SIGTERM) /* software termination signal from kill */
|
||
{ SIGTERM, "TERM" },
|
||
#endif
|
||
|
||
#if defined (SIGURG) /* urgent condition on IO channel */
|
||
{ SIGURG, "URG" },
|
||
#endif
|
||
|
||
#if defined (SIGSTOP) /* sendable stop signal not from tty */
|
||
{ SIGSTOP, "STOP" },
|
||
#endif
|
||
|
||
#if defined (SIGTSTP) /* stop signal from tty */
|
||
{ SIGTSTP, "TSTP" },
|
||
#endif
|
||
|
||
#if defined (SIGCONT) /* continue a stopped process */
|
||
{ SIGCONT, "CONT" },
|
||
#endif
|
||
|
||
#if defined (SIGCHLD) /* to parent on child stop or exit */
|
||
{ SIGCHLD, "CHLD" },
|
||
#endif
|
||
|
||
#if defined (SIGTTIN) /* to readers pgrp upon background tty read */
|
||
{ SIGTTIN, "TTIN" },
|
||
#endif
|
||
|
||
#if defined (SIGTTOU) /* like TTIN for output if (tp->t_local<OSTOP) */
|
||
{ SIGTTOU, "TTOU" },
|
||
#endif
|
||
|
||
#if defined (SIGIO) /* input/output possible signal */
|
||
{ SIGIO, "IO" },
|
||
#endif
|
||
|
||
#if defined (SIGXCPU) /* exceeded CPU time limit */
|
||
{ SIGXCPU, "XCPU" },
|
||
#endif
|
||
|
||
#if defined (SIGXFSZ) /* exceeded file size limit */
|
||
{ SIGXFSZ, "XFSZ" },
|
||
#endif
|
||
|
||
#if defined (SIGVTALRM) /* virtual time alarm */
|
||
{ SIGVTALRM, "VTALRM" },
|
||
#endif
|
||
|
||
#if defined (SIGPROF) /* profiling time alarm */
|
||
{ SIGPROF, "PROF" },
|
||
#endif
|
||
|
||
#if defined (SIGWINCH) /* window changed */
|
||
{ SIGWINCH, "WINCH" },
|
||
#endif
|
||
|
||
/* 4.4 BSD */
|
||
#if defined (SIGINFO) && !defined (_SEQUENT_) /* information request */
|
||
{ SIGINFO, "INFO" },
|
||
#endif
|
||
|
||
#if defined (SIGUSR1) /* user defined signal 1 */
|
||
{ SIGUSR1, "USR1" },
|
||
#endif
|
||
|
||
#if defined (SIGUSR2) /* user defined signal 2 */
|
||
{ SIGUSR2, "USR2" },
|
||
#endif
|
||
|
||
#if defined (SIGKILLTHR) /* BeOS: Kill Thread */
|
||
{ SIGKILLTHR, "KILLTHR" }
|
||
#endif
|
||
};
|
||
|
||
/* The last entry of the complete signal list, including real time
|
||
signals. */
|
||
struct sigspec *sigspecs_last;
|
||
|
||
/* The number of sigspecs in the list. */
|
||
int sigspecs_size;
|
||
|
||
/* The number of digits in NSIG (approx.). */
|
||
int nsig_digits;
|
||
|
||
|
||
/* The name this program was run with, for error messages. */
|
||
char *program_name;
|
||
|
||
/* All options which require an argument are known to the
|
||
pre-scan loop in main(). */
|
||
#define OPT_SIGSPEC_LONG "sigspec"
|
||
#define OPT_SIGNUM_LONG "signum"
|
||
|
||
static struct option const long_options[] =
|
||
{
|
||
{"list", no_argument, NULL, 'l'},
|
||
{"long-list", no_argument, NULL, 'L'},
|
||
{OPT_SIGSPEC_LONG, required_argument, NULL, 's'},
|
||
{OPT_SIGNUM_LONG, required_argument, NULL, 'n'},
|
||
{GETOPT_HELP_OPTION_DECL},
|
||
{GETOPT_VERSION_OPTION_DECL},
|
||
{NULL, 0, NULL, 0}
|
||
};
|
||
|
||
void
|
||
usage (int status)
|
||
{
|
||
if (status != 0)
|
||
fprintf (stderr, _("Try `%s --help' for more information.\n"),
|
||
program_name);
|
||
else
|
||
{
|
||
printf (_("\
|
||
Usage: %s [-s SIGSPEC | -n SIGNUM | -SIGSPEC] PID ...\n\
|
||
or: %s -l [SIGSPEC] ...\n\
|
||
"),
|
||
program_name, program_name);
|
||
fputs (_("\
|
||
Send the signal named by SIGSPEC or SIGNUM to processes named by PID.\n\
|
||
\n\
|
||
-s, --" OPT_SIGSPEC_LONG " SIGSPEC name or number of signal to be sent\n\
|
||
-n, --" OPT_SIGNUM_LONG " SIGNUM number of signal to be sent\n\
|
||
\n\
|
||
-l, --list list the signal names\n\
|
||
-L, --long-list list the signal names with their numbers\n\
|
||
\n\
|
||
"), stdout);
|
||
fputs (HELP_OPTION_DESCRIPTION, stdout);
|
||
fputs (VERSION_OPTION_DESCRIPTION, stdout);
|
||
fputs (_("\
|
||
\n\
|
||
kill returns true if at least one signal was successfully sent, or\n\
|
||
false if an error occurs or an invalid option is encountered.\n\
|
||
"), stdout);
|
||
puts (_("\nReport bugs to <bug-sh-utils@gnu.org>."));
|
||
}
|
||
exit (status);
|
||
}
|
||
|
||
|
||
/* The function is called once before option parsing. It calculates
|
||
the maximum number of digits in a signum, adds the realtime signal
|
||
specs to the signal list, and adds all signals of the form -SIGTERM
|
||
and -TERM as possible options. */
|
||
static void
|
||
initialize (void)
|
||
{
|
||
char number[LONGEST_HUMAN_READABLE + 1];
|
||
struct sigspec *newspecs;
|
||
|
||
nsig_digits = strlen (human_readable ((uintmax_t) NSIG, number, 1, 1));
|
||
|
||
sigspecs_size = sizeof (sigspecs) / sizeof (struct sigspec);
|
||
|
||
#if defined (SIGRTMIN) || defined (SIGRTMAX)
|
||
/* POSIX 1003.1b-1993 defines real time signals. The following code
|
||
is so convoluted because it also takes care of incomplete
|
||
implementations. */
|
||
# ifndef SIGRTMIN
|
||
# define SIGRTMIN SIGRTMAX
|
||
# endif
|
||
# ifndef SIGRTMAX
|
||
# define SIGRTMAX SIGRTMIN
|
||
# endif
|
||
|
||
/* Sanity check. */
|
||
if (SIGRTMAX >= SIGRTMIN)
|
||
{
|
||
int rtsigc = SIGRTMAX - SIGRTMIN + 1;
|
||
int i;
|
||
/* Account for "RTMIN+" resp "RTMAX-", the number and '\0'. */
|
||
int maxlength = nsig_digits + 6 + 1;
|
||
|
||
newspecs = xmalloc (sizeof (struct sigspec)
|
||
* (sigspecs_size + rtsigc));
|
||
|
||
/* After this, newspecs will always point to the last element of
|
||
the array. */
|
||
newspecs->signum = NO_SIG;
|
||
newspecs->signame = NULL;
|
||
|
||
(++newspecs)->signum = SIGRTMAX;
|
||
newspecs->signame = "RTMAX";
|
||
if (rtsigc > 1)
|
||
{
|
||
(++newspecs)->signum = SIGRTMIN;
|
||
newspecs->signame = "RTMIN";
|
||
}
|
||
|
||
/* Create new elements for all missing realtime signals. */
|
||
for (i = 0; i < rtsigc - 2; i++)
|
||
{
|
||
(++newspecs)->signum = SIGRTMIN + 1 + i;
|
||
newspecs->signame = xmalloc (maxlength);
|
||
|
||
snprintf (newspecs->signame, maxlength, "%s%d",
|
||
(i < (rtsigc - 2)/2
|
||
? "RTMIN+" : "RTMAX-"),
|
||
(i < (rtsigc - 2)/2
|
||
? i + 1 : (rtsigc - 2) - i));
|
||
}
|
||
|
||
/* Copy the existing elements in the following space. */
|
||
for (i = 1; i < sigspecs_size; i++)
|
||
*(++newspecs) = sigspecs[i];
|
||
|
||
sigspecs_last = newspecs;
|
||
sigspecs_size += rtsigc;
|
||
}
|
||
#else
|
||
sigspecs_last = sigspecs + (sigspecs_size - 1);
|
||
#endif
|
||
}
|
||
|
||
|
||
typedef enum { LIST_NONE, LIST_FLAT, LIST_PRETTY } list_t;
|
||
|
||
/* Print out a table listing all signals specifications with their
|
||
preferred name. */
|
||
static void
|
||
list_signals (list_t type)
|
||
{
|
||
int i = 0;
|
||
int entrylen = 0;
|
||
int unsorted;
|
||
int entries;
|
||
int last_signum = NO_SIG;
|
||
int column = 0;
|
||
struct sigspec *spec = sigspecs_last;
|
||
struct sigspec **specs = xmalloc (sizeof (struct sigspec *)
|
||
* (sigspecs_size - 1));
|
||
|
||
|
||
/* Gather maximum name length and prepare sort array. Note that the
|
||
list is reversed in the array. This is taken into account by the
|
||
output routine below. */
|
||
while (spec->signum != NO_SIG)
|
||
{
|
||
specs[i++] = spec;
|
||
if (spec->signame && strlen (spec->signame) > entrylen)
|
||
entrylen = strlen (spec->signame);
|
||
spec--;
|
||
}
|
||
|
||
/* Sort the array by signal number. This is a simple bubble sort,
|
||
but the point is that the order of entries with the same signum
|
||
is presevered (otherwise the preferred alias is lost). */
|
||
if (sigspecs_size > 2)
|
||
do
|
||
{
|
||
unsorted = 0;
|
||
|
||
for (i = 0; i < sigspecs_size - 2; i++)
|
||
{
|
||
if (specs[i]->signum > specs[i+1]->signum)
|
||
{
|
||
struct sigspec *saved = specs[i];
|
||
specs[i] = specs[i+1];
|
||
specs[i+1] = saved;
|
||
unsorted = 1;
|
||
}
|
||
}
|
||
}
|
||
while (unsorted);
|
||
|
||
/* Account for "NR) NAME ". Calculate for 79 columns, the 80 takes
|
||
into account that the last entry is not followed by a space. */
|
||
entrylen += nsig_digits + 2 + 1;
|
||
entries = 80 / entrylen;
|
||
if (entries < 1)
|
||
entries = 1;
|
||
|
||
for (i = 0; i < sigspecs_size - 1; i++)
|
||
{
|
||
/* Skip duplicated signal numbers, signums without name and the
|
||
special signal number `0'. */
|
||
if (specs[i]->signame && specs[i]->signum
|
||
&& (last_signum == NO_SIG || last_signum != specs[i]->signum))
|
||
{
|
||
switch (type)
|
||
{
|
||
case LIST_PRETTY:
|
||
column++;
|
||
printf ("%*i) %-*s", nsig_digits, specs[i]->signum,
|
||
entrylen - nsig_digits - 2 + (column != entries ? 1 : 0),
|
||
specs[i]->signame);
|
||
if (column == entries - 1)
|
||
{
|
||
column = 0;
|
||
putchar ('\n');
|
||
}
|
||
break;
|
||
case LIST_FLAT:
|
||
column += printf ("%s%s",
|
||
(column == 0 ? ""
|
||
: (column + strlen (specs[i]->signame) > 78
|
||
? "\n" : " ")),
|
||
specs[i]->signame);
|
||
if (column > 79)
|
||
column = strlen (specs[i]->signame);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
last_signum = specs[i]->signum;
|
||
}
|
||
if (i == sigspecs_size - 2)
|
||
putchar ('\n');
|
||
}
|
||
}
|
||
|
||
|
||
/* Turn a string into a signal number, or a number into a signal
|
||
number. If STRING is "2", or "INT", then return the integer 2.
|
||
Return NO_SIG if STRING doesn't contain a valid signal
|
||
descriptor. */
|
||
static int
|
||
decode_signal (char const *sigspec)
|
||
{
|
||
struct sigspec const *spec = sigspecs_last;
|
||
long l;
|
||
|
||
if (xstrtol (sigspec, NULL, 0, &l, "") == LONGINT_OK)
|
||
{
|
||
int sig = l;
|
||
|
||
if (sig != l)
|
||
return NO_SIG;
|
||
|
||
while (spec->signum != NO_SIG && spec->signum != sig)
|
||
spec--;
|
||
return spec->signum;
|
||
}
|
||
|
||
/* A leading `SIG' may be omitted. */
|
||
while (spec->signum != NO_SIG)
|
||
{
|
||
if (spec->signame
|
||
&& (strcasecmp (sigspec, spec->signame) == 0
|
||
|| (strncasecmp (sigspec, "SIG", 3) == 0
|
||
&& strcasecmp (sigspec + 3, spec->signame) == 0)))
|
||
return (spec->signum);
|
||
spec--;
|
||
}
|
||
return NO_SIG;
|
||
}
|
||
|
||
/* Find the preferred name for the signal with the number SIGNUM. */
|
||
static char const *const
|
||
name_signal (int signum)
|
||
{
|
||
struct sigspec const *spec = sigspecs_last;
|
||
|
||
while (spec->signum != NO_SIG && spec->signum != signum)
|
||
spec--;
|
||
return spec->signame;
|
||
}
|
||
|
||
/* Send the signal SIGNUM to process PID, using kill (). If an error
|
||
occurs, it is reported and passed through to the caller. */
|
||
static int
|
||
send_signal (pid_t pid, int signum)
|
||
{
|
||
int err;
|
||
|
||
err = kill (pid, signum);
|
||
if (err)
|
||
{
|
||
uintmax_t nr = (uintmax_t) (pid < 0 ? -pid : pid);
|
||
char number[LONGEST_HUMAN_READABLE + 1];
|
||
|
||
error (0, errno, "(%s%s)", (pid < 0 ? "-" : ""),
|
||
human_readable (nr, number, 1, 1));
|
||
}
|
||
return err;
|
||
}
|
||
|
||
|
||
int
|
||
main (int argc, char **argv)
|
||
{
|
||
int optc;
|
||
int err = 0;
|
||
int success = 0;
|
||
list_t list = LIST_NONE;
|
||
int sig_num = NO_SIG;
|
||
int i;
|
||
char **extra_opt;
|
||
int extra_opt_size = 0;
|
||
|
||
program_name = argv[0];
|
||
setlocale (LC_ALL, "");
|
||
bindtextdomain (PACKAGE, LOCALEDIR);
|
||
textdomain (PACKAGE);
|
||
|
||
atexit (close_stdout);
|
||
|
||
initialize ();
|
||
|
||
extra_opt = xmalloc ((argc - 1) * sizeof (char *));
|
||
for (i = 1; i < argc; i++)
|
||
{
|
||
intmax_t dummy;
|
||
|
||
/* getopt will ignore everything following `--', so we do as
|
||
well. */
|
||
if (!strcmp ("--", argv[i]))
|
||
break;
|
||
|
||
/* Skip this argument if it doesn't look like an option. */
|
||
if (argv[i][0] != '-')
|
||
continue;
|
||
|
||
/* Skip it if it follows an option requiring an argument. */
|
||
if (i > 1 && argv[i-1][0] == '-')
|
||
{
|
||
/* A short option that doesn't look like -nTERM. */
|
||
if ((argv[i-1][1] == 'n' || argv[i-1][1] == 's')
|
||
&& argv[i-1][2] == '\0')
|
||
continue;
|
||
|
||
/* A long option (not `--', which was excluded above). */
|
||
if (argv[i-1][1] == '-'
|
||
&& (!strncmp (OPT_SIGNUM_LONG, &(argv[i-1][2]),
|
||
strlen (&argv[i-1][2]))
|
||
|| !strncmp (OPT_SIGSPEC_LONG, &(argv[i-1][2]),
|
||
strlen (&argv[i-1][2]))))
|
||
continue;
|
||
}
|
||
|
||
/* At this point we know that this argument is not argument to
|
||
another option, and that it starts with `-' but is not `--'. */
|
||
|
||
if (decode_signal (&(argv[i][1])) != NO_SIG
|
||
|| xstrtoimax (argv[i], NULL, 10, &dummy, "") == LONGINT_OK)
|
||
{
|
||
/* It is either a valid signal specifier or potentially a
|
||
valid process group. So remember it and make getopt not
|
||
care about it. */
|
||
extra_opt[extra_opt_size++] = argv[i];
|
||
argv[i][0] = 'X';
|
||
}
|
||
}
|
||
|
||
while ((optc = getopt_long (argc, argv, "s:n:lL", long_options, NULL))
|
||
!= -1)
|
||
switch (optc)
|
||
{
|
||
case 's':
|
||
case 'n':
|
||
if (sig_num != NO_SIG)
|
||
{
|
||
error (0, 0, _("%s: only one signal specififier allowed"), optarg);
|
||
usage (1);
|
||
}
|
||
sig_num = decode_signal (optarg);
|
||
if (sig_num == NO_SIG)
|
||
error (1, 0, _("%s: invalid signal specifier"), optarg);
|
||
break;
|
||
case 'l':
|
||
list = LIST_FLAT;
|
||
break;
|
||
case 'L':
|
||
list = LIST_PRETTY;
|
||
break;
|
||
case_GETOPT_HELP_CHAR;
|
||
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
|
||
default:
|
||
usage (1);
|
||
}
|
||
|
||
argc -= optind;
|
||
argv += optind;
|
||
|
||
for (i = 0; i < extra_opt_size; i++)
|
||
extra_opt[i][0] = '-';
|
||
|
||
if (extra_opt_size > 0 && sig_num == NO_SIG)
|
||
{
|
||
char **arg = argv;
|
||
|
||
/* Find the first extra option collected in the remaining
|
||
argument list and if necessary, replace it with the first
|
||
remaining argument. This is a precaution in case getopt()
|
||
mangles the order of non-option arguments. */
|
||
|
||
while (*arg && *arg != extra_opt[0])
|
||
arg++;
|
||
if (*arg && *arg != argv[0])
|
||
*arg = argv[0];
|
||
|
||
argc--;
|
||
argv++;
|
||
|
||
/* Interpret the first one as a signal specifier. */
|
||
sig_num = decode_signal (&(extra_opt[0][1]));
|
||
if (sig_num == NO_SIG)
|
||
error (1, 0, _("%s: invalid signal specifier"), extra_opt[0]);
|
||
}
|
||
|
||
if (!list && sig_num == NO_SIG)
|
||
sig_num = SIGTERM;
|
||
|
||
if (argc == 0)
|
||
{
|
||
if (list)
|
||
list_signals (list);
|
||
else
|
||
{
|
||
error (0, 0, _("too few arguments"));
|
||
usage (1);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
int j;
|
||
for (j = 0; j < argc; j++)
|
||
if (list)
|
||
{
|
||
int signum = decode_signal (argv[j]);
|
||
if (signum == NO_SIG)
|
||
{
|
||
error (0, 0, _("%s: invalid signal specifier"), argv[j]);
|
||
err = 1;
|
||
}
|
||
else
|
||
{
|
||
char const *const name = name_signal (signum);
|
||
printf ("%s\n", name ? name : "(unknown)");
|
||
success = 1;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
intmax_t nr;
|
||
pid_t pid;
|
||
int inval = 0;
|
||
|
||
if (xstrtoimax (argv[j], NULL, 10, &nr, "") != LONGINT_OK)
|
||
inval = 1;
|
||
pid = (pid_t) nr;
|
||
if (inval || pid != nr)
|
||
{
|
||
error (0, 0, _("%s: invalid process id"), argv[j]);
|
||
err = 1;
|
||
continue;
|
||
}
|
||
if (send_signal (pid, sig_num))
|
||
err = 1;
|
||
else
|
||
success = 1;
|
||
}
|
||
}
|
||
|
||
exit ((success || !err) ? 0 : 1);
|
||
}
|