LCOV - code coverage report
Current view: top level - src - kill.c (source / functions) Hit Total Coverage
Test: coreutils.info Lines: 125 133 94.0 %
Date: 2018-01-30 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /* kill -- send a signal to a process
       2             :    Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
       3             : 
       4             :    This program is free software: you can redistribute it and/or modify
       5             :    it under the terms of the GNU General Public License as published by
       6             :    the Free Software Foundation, either version 3 of the License, or
       7             :    (at your option) any later version.
       8             : 
       9             :    This program is distributed in the hope that it will be useful,
      10             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :    GNU General Public License for more details.
      13             : 
      14             :    You should have received a copy of the GNU General Public License
      15             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
      16             : 
      17             : /* Written by Paul Eggert.  */
      18             : 
      19             : #include <config.h>
      20             : #include <stdio.h>
      21             : #include <getopt.h>
      22             : #include <sys/types.h>
      23             : #include <signal.h>
      24             : 
      25             : #if HAVE_SYS_WAIT_H
      26             : # include <sys/wait.h>
      27             : #endif
      28             : #ifndef WIFSIGNALED
      29             : # define WIFSIGNALED(s) (((s) & 0xFFFF) - 1 < (unsigned int) 0xFF)
      30             : #endif
      31             : #ifndef WTERMSIG
      32             : # define WTERMSIG(s) ((s) & 0x7F)
      33             : #endif
      34             : 
      35             : #include "system.h"
      36             : #include "error.h"
      37             : #include "sig2str.h"
      38             : 
      39             : /* The official name of this program (e.g., no `g' prefix).  */
      40             : #define PROGRAM_NAME "kill"
      41             : 
      42             : #define AUTHORS "Paul Eggert"
      43             : 
      44             : #if ! (HAVE_DECL_STRSIGNAL || defined strsignal)
      45             : # if ! (HAVE_DECL_SYS_SIGLIST || defined sys_siglist)
      46             : #  if HAVE_DECL__SYS_SIGLIST || defined _sys_siglist
      47             : #   define sys_siglist _sys_siglist
      48             : #  elif HAVE_DECL___SYS_SIGLIST || defined __sys_siglist
      49             : #   define sys_siglist __sys_siglist
      50             : #  endif
      51             : # endif
      52             : # if HAVE_DECL_SYS_SIGLIST || defined sys_siglist
      53             : #  define strsignal(signum) (0 <= (signum) && (signum) <= SIGNUM_BOUND \
      54             :                              ? sys_siglist[signum] \
      55             :                              : 0)
      56             : # endif
      57             : # ifndef strsignal
      58             : #  define strsignal(signum) 0
      59             : # endif
      60             : #endif
      61             : 
      62             : /* The name this program was run with, for error messages.  */
      63             : char *program_name;
      64             : 
      65             : static char const short_options[] =
      66             :   "0::1::2::3::4::5::6::7::8::9::"
      67             :   "A::B::C::D::E::F::G::H::I::J::K::L::M::"
      68             :   "N::O::P::Q::R::S::T::U::V::W::X::Y::Z::"
      69             :   "ln:s:t";
      70             : 
      71             : static struct option const long_options[] =
      72             : {
      73             :   {"list", no_argument, NULL, 'l'},
      74             :   {"signal", required_argument, NULL, 's'},
      75             :   {"table", no_argument, NULL, 't'},
      76             :   {GETOPT_HELP_OPTION_DECL},
      77             :   {GETOPT_VERSION_OPTION_DECL},
      78             :   {NULL, 0, NULL, 0}
      79             : };
      80             : 
      81             : void
      82          19 : usage (int status)
      83             : {
      84          19 :   if (status != EXIT_SUCCESS)
      85          18 :     fprintf (stderr, _("Try `%s --help' for more information.\n"),
      86             :              program_name);
      87             :   else
      88             :     {
      89           1 :       printf (_("\
      90             : Usage: %s [-s SIGNAL | -SIGNAL] PID...\n\
      91             :   or:  %s -l [SIGNAL]...\n\
      92             :   or:  %s -t [SIGNAL]...\n\
      93             : "),
      94             :               program_name, program_name, program_name);
      95           1 :       fputs (_("\
      96             : Send signals to processes, or list signals.\n\
      97             : \n\
      98             : "), stdout);
      99           1 :       fputs (_("\
     100             : Mandatory arguments to long options are mandatory for short options too.\n\
     101             : "), stdout);
     102           1 :       fputs (_("\
     103             :   -s, --signal=SIGNAL, -SIGNAL\n\
     104             :                    specify the name or number of the signal to be sent\n\
     105             :   -l, --list       list signal names, or convert signal names to/from numbers\n\
     106             :   -t, --table      print a table of signal information\n\
     107             : "), stdout);
     108           1 :       fputs (HELP_OPTION_DESCRIPTION, stdout);
     109           1 :       fputs (VERSION_OPTION_DESCRIPTION, stdout);
     110           1 :       fputs (_("\n\
     111             : SIGNAL may be a signal name like `HUP', or a signal number like `1',\n\
     112             : or an exit status of a process terminated by a signal.\n\
     113             : PID is an integer; if negative it identifies a process group.\n\
     114             : "), stdout);
     115           1 :       printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME);
     116           1 :       emit_bug_reporting_address ();
     117             :     }
     118          19 :   exit (status);
     119             : }
     120             : 
     121             : /* Convert OPERAND to a signal number with printable representation SIGNAME.
     122             :    Return the signal number, or -1 if unsuccessful.  */
     123             : 
     124             : static int
     125          28 : operand2sig (char const *operand, char *signame)
     126             : {
     127             :   int signum;
     128             : 
     129          28 :   if (ISDIGIT (*operand))
     130             :     {
     131             :       char *endp;
     132          13 :       long int l = (errno = 0, strtol (operand, &endp, 10));
     133          13 :       int i = l;
     134          39 :       signum = (operand == endp || *endp || errno || i != l ? -1
     135          40 :                 : WIFSIGNALED (i) ? WTERMSIG (i)
     136          17 :                 : i);
     137             :     }
     138             :   else
     139             :     {
     140             :       /* Convert signal to upper case in the C locale, not in the
     141             :          current locale.  Don't assume ASCII; it might be EBCDIC.  */
     142          15 :       char *upcased = xstrdup (operand);
     143             :       char *p;
     144          32 :       for (p = upcased; *p; p++)
     145          17 :         if (strchr ("abcdefghijklmnopqrstuvwxyz", *p))
     146           7 :           *p += 'A' - 'a';
     147             : 
     148             :       /* Look for the signal name, possibly prefixed by "SIG",
     149             :          and possibly lowercased.  */
     150          29 :       if (! (str2sig (upcased, &signum) == 0
     151          16 :              || (upcased[0] == 'S' && upcased[1] == 'I' && upcased[2] == 'G'
     152           0 :                  && str2sig (upcased + 3, &signum) == 0)))
     153          14 :         signum = -1;
     154             : 
     155          15 :       free (upcased);
     156             :     }
     157             : 
     158          28 :   if (signum < 0 || sig2str (signum, signame) != 0)
     159             :     {
     160          17 :       error (0, 0, _("%s: invalid signal"), operand);
     161          17 :       return -1;
     162             :     }
     163             : 
     164          11 :   return signum;
     165             : }
     166             : 
     167             : /* Print a row of `kill -t' output.  NUM_WIDTH is the maximum signal
     168             :    number width, and SIGNUM is the signal number to print.  The
     169             :    maximum name width is NAME_WIDTH, and SIGNAME is the name to print.  */
     170             : 
     171             : static void
     172          63 : print_table_row (unsigned int num_width, int signum,
     173             :                  unsigned int name_width, char const *signame)
     174             : {
     175          63 :   char const *description = strsignal (signum);
     176          63 :   printf ("%*d %-*s %s\n", num_width, signum, name_width, signame,
     177             :           description ? description : "?");
     178          63 : }
     179             : 
     180             : /* Print a list of signal names.  If TABLE, print a table.
     181             :    Print the names specified by ARGV if nonzero; otherwise,
     182             :    print all known names.  Return a suitable exit status.  */
     183             : 
     184             : static int
     185          16 : list_signals (bool table, char *const *argv)
     186             : {
     187             :   int signum;
     188          16 :   int status = EXIT_SUCCESS;
     189             :   char signame[SIG2STR_MAX];
     190             : 
     191          16 :   if (table)
     192             :     {
     193           4 :       unsigned int name_width = 0;
     194             : 
     195             :       /* Compute the maximum width of a signal number.  */
     196           4 :       unsigned int num_width = 1;
     197           8 :       for (signum = 1; signum <= SIGNUM_BOUND / 10; signum *= 10)
     198           4 :         num_width++;
     199             : 
     200             :       /* Compute the maximum width of a signal name.  */
     201         260 :       for (signum = 1; signum <= SIGNUM_BOUND; signum++)
     202         256 :         if (sig2str (signum, signame) == 0)
     203             :           {
     204         248 :             size_t len = strlen (signame);
     205         248 :             if (name_width < len)
     206          20 :               name_width = len;
     207             :           }
     208             : 
     209           4 :       if (argv)
     210           7 :         for (; *argv; argv++)
     211             :           {
     212           4 :             signum = operand2sig (*argv, signame);
     213           4 :             if (signum < 0)
     214           3 :               status = EXIT_FAILURE;
     215             :             else
     216           1 :               print_table_row (num_width, signum, name_width, signame);
     217             :           }
     218             :       else
     219          65 :         for (signum = 1; signum <= SIGNUM_BOUND; signum++)
     220          64 :           if (sig2str (signum, signame) == 0)
     221          62 :             print_table_row (num_width, signum, name_width, signame);
     222             :     }
     223             :   else
     224             :     {
     225          12 :       if (argv)
     226          21 :         for (; *argv; argv++)
     227             :           {
     228          12 :             signum = operand2sig (*argv, signame);
     229          12 :             if (signum < 0)
     230           9 :               status = EXIT_FAILURE;
     231             :             else
     232             :               {
     233           3 :                 if (ISDIGIT (**argv))
     234           2 :                   puts (signame);
     235             :                 else
     236           1 :                   printf ("%d\n", signum);
     237             :               }
     238             :           }
     239             :       else
     240         195 :         for (signum = 1; signum <= SIGNUM_BOUND; signum++)
     241         192 :           if (sig2str (signum, signame) == 0)
     242         186 :             puts (signame);
     243             :     }
     244             : 
     245          16 :   return status;
     246             : }
     247             : 
     248             : /* Send signal SIGNUM to all the processes or process groups specified
     249             :    by ARGV.  Return a suitable exit status.  */
     250             : 
     251             : static int
     252           9 : send_signals (int signum, char *const *argv)
     253             : {
     254           9 :   int status = EXIT_SUCCESS;
     255           9 :   char const *arg = *argv;
     256             : 
     257             :   do
     258             :     {
     259             :       char *endp;
     260          16 :       intmax_t n = (errno = 0, strtoimax (arg, &endp, 10));
     261          16 :       pid_t pid = n;
     262             : 
     263          16 :       if (errno == ERANGE || pid != n || arg == endp || *endp)
     264             :         {
     265          16 :           error (0, 0, _("%s: invalid process id"), arg);
     266          16 :           status = EXIT_FAILURE;
     267             :         }
     268           0 :       else if (kill (pid, signum) != 0)
     269             :         {
     270           0 :           error (0, errno, "%s", arg);
     271           0 :           status = EXIT_FAILURE;
     272             :         }
     273             :     }
     274          16 :   while ((arg = *++argv));
     275             : 
     276           9 :   return status;
     277             : }
     278             : 
     279             : int
     280          45 : main (int argc, char **argv)
     281             : {
     282             :   int optc;
     283          45 :   bool list = false;
     284          45 :   bool table = false;
     285          45 :   int signum = -1;
     286             :   char signame[SIG2STR_MAX];
     287             : 
     288             :   initialize_main (&argc, &argv);
     289          45 :   program_name = argv[0];
     290          45 :   setlocale (LC_ALL, "");
     291             :   bindtextdomain (PACKAGE, LOCALEDIR);
     292             :   textdomain (PACKAGE);
     293             : 
     294          45 :   atexit (close_stdout);
     295             : 
     296         115 :   while ((optc = getopt_long (argc, argv, short_options, long_options, NULL))
     297             :          != -1)
     298          41 :     switch (optc)
     299             :       {
     300           5 :       case '0': case '1': case '2': case '3': case '4':
     301             :       case '5': case '6': case '7': case '8': case '9':
     302           5 :         if (optind != 2)
     303             :           {
     304             :             /* This option is actually a process-id.  */
     305           0 :             optind--;
     306           0 :             goto no_more_options;
     307             :           }
     308             :         /* Fall through.  */
     309             :       case 'A': case 'B': case 'C': case 'D': case 'E':
     310             :       case 'F': case 'G': case 'H': case 'I': case 'J':
     311             :       case 'K': case 'L': case 'M': case 'N': case 'O':
     312             :       case 'P': case 'Q': case 'R': case 'S': case 'T':
     313             :       case 'U': case 'V': case 'W': case 'X': case 'Y':
     314             :       case 'Z':
     315           8 :         if (! optarg)
     316           6 :           optarg = argv[optind - 1] + strlen (argv[optind - 1]);
     317           8 :         if (optarg != argv[optind - 1] + 2)
     318             :           {
     319           0 :             error (0, 0, _("invalid option -- %c"), optc);
     320           0 :             usage (EXIT_FAILURE);
     321             :           }
     322           8 :         optarg--;
     323             :         /* Fall through.  */
     324          13 :       case 'n': /* -n is not documented, but is for Bash compatibility.  */
     325             :       case 's':
     326          13 :         if (0 <= signum)
     327             :           {
     328           1 :             error (0, 0, _("%s: multiple signals specified"), optarg);
     329           1 :             usage (EXIT_FAILURE);
     330             :           }
     331          12 :         signum = operand2sig (optarg, signame);
     332          12 :         if (signum < 0)
     333           5 :           usage (EXIT_FAILURE);
     334           7 :         break;
     335             : 
     336           4 :       case 't':
     337           4 :         table = true;
     338             :         /* Fall through.  */
     339          19 :       case 'l':
     340          19 :         if (list)
     341             :           {
     342           1 :             error (0, 0, _("multiple -l or -t options specified"));
     343           1 :             usage (EXIT_FAILURE);
     344             :           }
     345          18 :         list = true;
     346          18 :         break;
     347             : 
     348           1 :       case_GETOPT_HELP_CHAR;
     349           1 :       case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
     350           7 :       default:
     351           7 :         usage (EXIT_FAILURE);
     352             :       }
     353          29 :  no_more_options:;
     354             : 
     355          29 :   if (signum < 0)
     356          23 :     signum = SIGTERM;
     357           6 :   else if (list)
     358             :     {
     359           1 :       error (0, 0, _("cannot combine signal with -l or -t"));
     360           1 :       usage (EXIT_FAILURE);
     361             :     }
     362             : 
     363          28 :   if ( ! list && argc <= optind)
     364             :     {
     365           3 :       error (0, 0, _("no process ID specified"));
     366           3 :       usage (EXIT_FAILURE);
     367             :     }
     368             : 
     369             :   return (list
     370          16 :           ? list_signals (table, optind < argc ? argv + optind : NULL)
     371          41 :           : send_signals (signum, argv + optind));
     372             : }

Generated by: LCOV version 1.10