diff options
author | Jim Meyering <jim@meyering.net> | 2002-04-28 21:32:36 +0000 |
---|---|---|
committer | Jim Meyering <jim@meyering.net> | 2002-04-28 21:32:36 +0000 |
commit | ed05aed044f82b9280493692425b90d8f395ebea (patch) | |
tree | fd028d17bc50e9699e0cab860aa02b4c7df65fbe /src | |
parent | 02be728995239e82b191ce762f82b59412fcca4f (diff) | |
download | coreutils-ed05aed044f82b9280493692425b90d8f395ebea.tar.xz |
Rewrite from scratch. Support everything
required by POSIX 1003.1-2001; when this conflicts with Bash,
stick with POSIX. The conflicts are kill -l output format,
and lower case signal names preceded by `-' (e.g., "kill -hup"
is no longer supported). Remove -L or --long-list option.
Add -t or --table option. Rename --sigspec to --signal;
remove --signum and do not advertise obsolescent option -n.
Use str2sig and str2sig to convert between signal names and
numbers.
Diffstat (limited to 'src')
-rw-r--r-- | src/kill.c | 881 |
1 files changed, 243 insertions, 638 deletions
diff --git a/src/kill.c b/src/kill.c index d0c8ea84f..f53bb3a5b 100644 --- a/src/kill.c +++ b/src/kill.c @@ -1,5 +1,5 @@ /* kill -- send a signal to a process - Copyright (C) 2001 Free Software Foundation, Inc. + Copyright (C) 2002 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 @@ -15,300 +15,68 @@ 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. */ +/* Written by Paul Eggert. */ #include <config.h> #include <stdio.h> #include <getopt.h> #include <sys/types.h> - #include <signal.h> +#if HAVE_SYS_WAIT_H +# include <sys/wait.h> +#endif +#ifndef WIFSIGNALED +# define WIFSIGNALED(s) (((s) & 0xFFFF) - 1 < (unsigned int) 0xFF) +#endif +#ifndef WTERMSIG +# define WTERMSIG(s) ((s) & 0x7F) +#endif + #include "system.h" #include "closeout.h" -#include "human.h" #include "error.h" -#include "xstrtol.h" +#include "sig2str.h" /* The official name of this program (e.g., no `g' prefix). */ #define PROGRAM_NAME "kill" -#define AUTHORS "Marcus Brinkmann" - +#define AUTHORS "Paul Eggert" -/* 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" }, +#if ! (HAVE_DECL_STRTOIMAX || defined strtoimax) +intmax_t strtoimax (); #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" } +#if ! (HAVE_DECL_STRSIGNAL || defined strsignal) +# if ! (HAVE_DECL_SYS_SIGLIST || defined sys_siglist) +# if HAVE_DECL__SYS_SIGLIST || defined _sys_siglist +# define sys_siglist _sys_siglist +# endif +# endif +# if HAVE_DECL_SYS_SIGLIST || defined sys_siglist +# define strsignal(signum) (0 <= (signum) && (signum) <= SIGNUM_BOUND \ + ? sys_siglist[signum] \ + : 0) +# endif +# ifndef strsignal +# define strsignal(signum) 0 +# endif #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 char const short_options[] = + "0::1::2::3::4::5::6::7::8::9::" + "A::B::C::D::E::F::G::H::I::J::K::L::M::" + "N::O::P::Q::R::S::T::U::V::W::X::Y::Z::" + "ln:s:t"; 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'}, + {"signal", required_argument, NULL, 's'}, + {"table", no_argument, NULL, 't'}, {GETOPT_HELP_OPTION_DECL}, {GETOPT_VERSION_OPTION_DECL}, {NULL, 0, NULL, 0} @@ -323,282 +91,207 @@ usage (int status) else { printf (_("\ -Usage: %s [-s SIGSPEC | -n SIGNUM | -SIGSPEC] PID ...\n\ - or: %s -l [SIGSPEC] ...\n\ +Usage: %s [-s SIGNAL | -SIGNAL] PID...\n\ + or: %s -l [SIGNAL]...\n\ + or: %s -t [SIGNAL]...\n\ "), - program_name, program_name); + program_name, 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\ +Send signals to processes, or list signals.\n\ \n\ "), stdout); + fputs (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +"), stdout); + fputs (_("\ + -s, --signal SIGNAL, -SIGNAL Name or number of signal to be sent.\n\ + -l, --list List signal names.\n\ + -t, --table Print a table of signal information.\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\ + fputs (_("\n\ +SIGNAL may be a signal name like `HUP', or a signal number like `1',\n\ +or an exit status of a process terminated by a signal.\n\ +PID is an integer; if negative it identifies a process group.\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; +/* Convert OPERAND to a signal number with printable representation SIGNAME. + Return the signal number, or -1 if unsuccessful. */ - 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 +static int +operand2sig (char const *operand, char *signame) +{ + int signum; - /* Sanity check. */ - if (SIGRTMAX >= SIGRTMIN) + if (ISDIGIT (*operand)) { - 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]; + 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); + } + else + { + /* Convert signal to upper case in the C locale, not in the + current locale. Don't assume ASCII; it might be EBCDIC. */ + char *upcased = xstrdup (operand); + char *p; + for (p = upcased; *p; p++) + if (strchr ("abcdefghijklmnopqrstuvwxyz", *p)) + *p += 'A' - 'a'; + + /* Look for the signal name, possibly prefixed by "SIG", + and possibly lowercased. */ + if (! (str2sig (upcased, &signum) == 0 + || (upcased[0] == 'S' && upcased[1] == 'I' && upcased[2] == 'G' + && str2sig (upcased + 3, &signum) == 0))) + signum = -1; + + free (upcased); + } - sigspecs_last = newspecs; - sigspecs_size += rtsigc; + if (signum < 0 || sig2str (signum, signame) != 0) + { + error (0, 0, _("%s: invalid signal"), operand); + return -1; } -#else - sigspecs_last = sigspecs + (sigspecs_size - 1); -#endif -} + return signum; +} -typedef enum { LIST_NONE, LIST_FLAT, LIST_PRETTY } list_t; +/* Print a row of `kill -t' output. NUM_WIDTH is the maximum signal + number width, and SIGNUM is the signal number to print. The + maximum name width is NAME_WIDTH, and SIGNAME is the name to print. */ -/* Print out a table listing all signals specifications with their - preferred name. */ static void -list_signals (list_t type) +print_table_row (int num_width, int signum, + int name_width, char const *signame) { - 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'); - } + char const *description = strsignal (signum); + printf ("%*d %-*s %s\n", num_width, signum, name_width, signame, + description ? description : "?"); } - -/* 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. */ +/* Print a list of signal names. If TABLE, print a table. + Print the names specified by ARGV if nonzero; otherwise, + print all known names. Return a suitable exit status. */ + static int -decode_signal (char const *sigspec) +list_signals (bool table, char *const *argv) { - struct sigspec const *spec = sigspecs_last; - long l; + int signum; + int status = EXIT_SUCCESS; + char signame[SIG2STR_MAX]; - if (xstrtol (sigspec, NULL, 0, &l, "") == LONGINT_OK) + if (table) { - int sig = l; + int name_width = 0; - if (sig != l) - return NO_SIG; + /* Compute the maximum width of a signal number. */ + int num_width = 1; + for (signum = 1; signum <= SIGNUM_BOUND / 10; signum *= 10) + num_width++; - while (spec->signum != NO_SIG && spec->signum != sig) - spec--; - return spec->signum; - } + /* Compute the maximum width of a signal name. */ + for (signum = 1; signum <= SIGNUM_BOUND; signum++) + if (sig2str (signum, signame) == 0) + { + size_t len = strlen (signame); + if (name_width < len) + name_width = len; + } - /* A leading `SIG' may be omitted. */ - while (spec->signum != NO_SIG) + if (argv) + for (; *argv; argv++) + { + signum = operand2sig (*argv, signame); + if (signum < 0) + status = EXIT_FAILURE; + else + print_table_row (num_width, signum, name_width, signame); + } + else + for (signum = 1; signum <= SIGNUM_BOUND; signum++) + if (sig2str (signum, signame) == 0) + print_table_row (num_width, signum, name_width, signame); + } + else { - if (spec->signame - && (strcasecmp (sigspec, spec->signame) == 0 - || (strncasecmp (sigspec, "SIG", 3) == 0 - && strcasecmp (sigspec + 3, spec->signame) == 0))) - return (spec->signum); - spec--; + if (argv) + for (; *argv; argv++) + { + signum = operand2sig (*argv, signame); + if (signum < 0) + status = EXIT_FAILURE; + else + { + if (ISDIGIT (**argv)) + puts (signame); + else + printf ("%d\n", signum); + } + } + else + for (signum = 1; signum <= SIGNUM_BOUND; signum++) + if (sig2str (signum, signame) == 0) + puts (signame); } - 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; + return status; } + +/* Send signal SIGNUM to all the processes or process groups specified + by ARGV. Return a suitable exit status. */ -/* 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) +send_signals (int signum, char *const *argv) { - int err; + int status = EXIT_SUCCESS; + char const *arg = *argv; - err = kill (pid, signum); - if (err) + if (! arg) { - uintmax_t nr = (uintmax_t) (pid < 0 ? -pid : pid); - char number[LONGEST_HUMAN_READABLE + 1]; + error (0, 0, _("missing operand after `%s'"), argv[-1]); + usage (EXIT_FAILURE); + } - error (0, errno, "(%s%s)", (pid < 0 ? "-" : ""), - human_readable (nr, number, 1, 1)); + do + { + char *endp; + intmax_t n = (errno = 0, strtoimax (arg, &endp, 10)); + pid_t pid = n; + + if (errno == ERANGE || pid != n || arg == endp || *endp) + { + error (0, 0, _("%s: invalid process id"), arg); + status = EXIT_FAILURE; + } + else if (kill (pid, signum) != 0) + { + error (0, errno, "%s", arg); + status = EXIT_FAILURE; + } } - return err; -} + while ((arg = *++argv)); + return status; +} 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; + bool list = false; + bool table = false; + int signum = -1; + char signame[SIG2STR_MAX]; program_name = argv[0]; setlocale (LC_ALL, ""); @@ -607,162 +300,74 @@ main (int argc, char **argv) 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)) + while ((optc = getopt_long (argc, argv, short_options, long_options, NULL)) != -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--; + goto no_more_options; + } + /* Fall through. */ + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': case 'G': case 'H': case 'I': case 'J': + case 'K': case 'L': case 'M': case 'N': case 'O': + case 'P': case 'Q': case 'R': case 'S': case 'T': + case 'U': case 'V': case 'W': case 'X': case 'Y': + case 'Z': + if (! optarg) + optarg = argv[optind - 1] + strlen (argv[optind - 1]); + if (optarg != argv[optind - 1] + 2) + { + error (0, 0, _("invalid option -- %c"), optc); + usage (EXIT_FAILURE); + } + optarg--; + /* Fall through. */ + case 'n': /* -n is not documented, but is for Bash compatibility. */ case 's': - case 'n': - if (sig_num != NO_SIG) + if (0 <= signum) { - error (0, 0, _("%s: only one signal specififier allowed"), optarg); - usage (1); + error (0, 0, _("%s: multiple signals specified"), optarg); + usage (EXIT_FAILURE); } - sig_num = decode_signal (optarg); - if (sig_num == NO_SIG) - error (1, 0, _("%s: invalid signal specifier"), optarg); + signum = operand2sig (optarg, signame); + if (signum < 0) + usage (EXIT_FAILURE); break; + + case 't': + table = true; + /* Fall through. */ case 'l': - list = LIST_FLAT; - break; - case 'L': - list = LIST_PRETTY; + if (list) + { + error (0, 0, _("multiple -l or -t options specified")); + usage (EXIT_FAILURE); + } + list = true; break; + case_GETOPT_HELP_CHAR; case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); default: - usage (1); + usage (EXIT_FAILURE); } + no_more_options:; - 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 + if (signum < 0) + signum = SIGTERM; + else if (list) { - 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; - } + error (0, 0, _("cannot combine signal with -l or -t")); + usage (EXIT_FAILURE); } - exit ((success || !err) ? 0 : 1); + return (list + ? list_signals (table, optind == argc ? NULL : argv + optind) + : send_signals (signum, argv + optind)); } |