/* kill -- send a signal to a process                                           This is the kill utility
   Copyright (C) 2002-2018 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 3 of the License, 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, see <https://www.gnu.org/licenses/>.  */   The GNUv3 license
                                                                                
/* Written by Paul Eggert.  */                                                  
                                                                                
#include <config.h>                                                             Provides system specific information
#include <stdio.h>                                                              Provides standard I/O capability
#include <getopt.h>                                                             ...!includes auto-comment...
#include <sys/types.h>                                                          Provides system data types
#include <signal.h>                                                             ...!includes auto-comment...
                                                                                
#include "system.h"                                                             ...!includes auto-comment...
#include "error.h"                                                              ...!includes auto-comment...
#include "sig2str.h"                                                            ...!includes auto-comment...
#include "operand2sig.h"                                                        ...!includes auto-comment...
#include "quote.h"                                                              ...!includes auto-comment...
                                                                                
/* The official name of this program (e.g., no 'g' prefix).  */                 
#define PROGRAM_NAME "kill"                                                     Line 32
                                                                                
#define AUTHORS proper_name ("Paul Eggert")                                     Line 34
                                                                                
#if ! (HAVE_DECL_STRSIGNAL || defined strsignal)                                Line 36
# if ! (HAVE_DECL_SYS_SIGLIST || defined sys_siglist)                           Line 37
#  if HAVE_DECL__SYS_SIGLIST || defined _sys_siglist                            Line 38
#   define sys_siglist _sys_siglist                                             Line 39
#  elif HAVE_DECL___SYS_SIGLIST || defined __sys_siglist                        Line 40
#   define sys_siglist __sys_siglist                                            Line 41
#  endif                                                                        Line 42
# endif                                                                         Line 43
# if HAVE_DECL_SYS_SIGLIST || defined sys_siglist                               Line 44
#  define strsignal(signum) (0 <= (signum) && (signum) <= SIGNUM_BOUND \        Line 45
                             ? sys_siglist[signum] \                            Line 46
                             : 0)                                               Line 47
# endif                                                                         Line 48
# ifndef strsignal                                                              Line 49
#  define strsignal(signum) 0                                                   Line 50
# endif                                                                         Line 51
#endif                                                                          Line 52
                                                                                
static char const short_options[] =                                             Line 54
  "0::1::2::3::4::5::6::7::8::9::"                                              Line 55
  "A::B::C::D::E::F::G::H::I::J::K::M::"                                        Line 56
  "N::O::P::Q::R::S::T::U::V::W::X::Y::Z::"                                     Line 57
  "Lln:s:t";                                                                    Line 58
                                                                                
static struct option const long_options[] =                                     Line 60
{                                                                               
  {"list", no_argument, NULL, 'l'},                                             Line 62
  {"signal", required_argument, NULL, 's'},                                     Line 63
  {"table", no_argument, NULL, 't'},                                            Line 64
  {GETOPT_HELP_OPTION_DECL},                                                    Line 65
  {GETOPT_VERSION_OPTION_DECL},                                                 Line 66
  {NULL, 0, NULL, 0}                                                            Line 67
};                                                                              Block 1
                                                                                
void                                                                            Line 70
usage (int status)                                                              Line 71
{                                                                               
  if (status != EXIT_SUCCESS)                                                   Line 73
    emit_try_help ();                                                           ...!common auto-comment...
  else                                                                          Line 75
    {                                                                           
      printf (_("\                                                              Line 77
Usage: %s [-s SIGNAL | -SIGNAL] PID...\n\                                       Line 78
  or:  %s -l [SIGNAL]...\n\                                                     Line 79
  or:  %s -t [SIGNAL]...\n\                                                     Line 80
"),                                                                             Line 81
              program_name, program_name, program_name);                        Line 82
      fputs (_("\                                                               Line 83
Send signals to processes, or list signals.\n\                                  Line 84
"), stdout);                                                                    Line 85
                                                                                
      emit_mandatory_arg_note ();                                               ...!common auto-comment...
                                                                                
      fputs (_("\                                                               Line 89
  -s, --signal=SIGNAL, -SIGNAL\n\                                               Line 90
                   specify the name or number of the signal to be sent\n\       Line 91
  -l, --list       list signal names, or convert signal names to/from numbers\n\Line 92
  -t, --table      print a table of signal information\n\                       Line 93
"), stdout);                                                                    Line 94
      fputs (HELP_OPTION_DESCRIPTION, stdout);                                  Line 95
      fputs (VERSION_OPTION_DESCRIPTION, stdout);                               Line 96
      fputs (_("\n\                                                             Line 97
SIGNAL may be a signal name like 'HUP', or a signal number like '1',\n\         Line 98
or the exit status of a process terminated by a signal.\n\                      Line 99
PID is an integer; if negative it identifies a process group.\n\                Line 100
"), stdout);                                                                    Line 101
      printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME);                             Line 102
      emit_ancillary_info (PROGRAM_NAME);                                       Line 103
    }                                                                           
  exit (status);                                                                Line 105
}                                                                               Block 2
                                                                                
/* 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.  */      
                                                                                
static void                                                                     Line 112
print_table_row (int num_width, int signum,                                     Line 113
                 int name_width, char const *signame)                           Line 114
{                                                                               
  char const *description = strsignal (signum);                                 Line 116
  printf ("%*d %-*s %s\n", num_width, signum, name_width, signame,              Line 117
          description ? description : "?");                                     Line 118
}                                                                               Block 3
                                                                                
/* 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                                                                      Line 125
list_signals (bool table, char *const *argv)                                    Line 126
{                                                                               
  int signum;                                                                   Line 128
  int status = EXIT_SUCCESS;                                                    Line 129
  char signame[SIG2STR_MAX];                                                    Line 130
                                                                                
  if (table)                                                                    Line 132
    {                                                                           
      unsigned int name_width = 0;                                              Line 134
                                                                                
      /* Compute the maximum width of a signal number.  */                      
      unsigned int num_width = 1;                                               Line 137
      for (signum = 1; signum <= SIGNUM_BOUND / 10; signum *= 10)               Line 138
        num_width++;                                                            Line 139
                                                                                
      /* Compute the maximum width of a signal name.  */                        
      for (signum = 1; signum <= SIGNUM_BOUND; signum++)                        Line 142
        if (sig2str (signum, signame) == 0)                                     Line 143
          {                                                                     
            size_t len = strlen (signame);                                      Line 145
            if (name_width < len)                                               Line 146
              name_width = len;                                                 Line 147
          }                                                                     
                                                                                
      if (argv)                                                                 Line 150
        for (; *argv; argv++)                                                   Line 151
          {                                                                     
            signum = operand2sig (*argv, signame);                              Line 153
            if (signum < 0)                                                     Line 154
              status = EXIT_FAILURE;                                            Line 155
            else                                                                Line 156
              print_table_row (num_width, signum, name_width, signame);         Line 157
          }                                                                     
      else                                                                      Line 159
        for (signum = 1; signum <= SIGNUM_BOUND; signum++)                      Line 160
          if (sig2str (signum, signame) == 0)                                   Line 161
            print_table_row (num_width, signum, name_width, signame);           Line 162
    }                                                                           
  else                                                                          Line 164
    {                                                                           
      if (argv)                                                                 Line 166
        for (; *argv; argv++)                                                   Line 167
          {                                                                     
            signum = operand2sig (*argv, signame);                              Line 169
            if (signum < 0)                                                     Line 170
              status = EXIT_FAILURE;                                            Line 171
            else                                                                Line 172
              {                                                                 
                if (ISDIGIT (**argv))                                           Line 174
                  puts (signame);                                               Line 175
                else                                                            Line 176
                  printf ("%d\n", signum);                                      Line 177
              }                                                                 
          }                                                                     
      else                                                                      Line 180
        for (signum = 1; signum <= SIGNUM_BOUND; signum++)                      Line 181
          if (sig2str (signum, signame) == 0)                                   Line 182
            puts (signame);                                                     Line 183
    }                                                                           
                                                                                
  return status;                                                                Line 186
}                                                                               Block 4
                                                                                
/* Send signal SIGNUM to all the processes or process groups specified          
   by ARGV.  Return a suitable exit status.  */                                 
                                                                                
static int                                                                      Line 192
send_signals (int signum, char *const *argv)                                    Line 193
{                                                                               
  int status = EXIT_SUCCESS;                                                    Line 195
  char const *arg = *argv;                                                      Line 196
                                                                                
  do                                                                            
    {                                                                           
      char *endp;                                                               Line 200
      intmax_t n = (errno = 0, strtoimax (arg, &endp, 10));                     Line 201
      pid_t pid = n;                                                            Line 202
                                                                                
      if (errno == ERANGE || pid != n || arg == endp || *endp)                  Line 204
        {                                                                       
          error (0, 0, _("%s: invalid process id"), quote (arg));               Line 206
          status = EXIT_FAILURE;                                                Line 207
        }                                                                       
      else if (kill (pid, signum) != 0)                                         Line 209
        {                                                                       
          error (0, errno, "%s", quote (arg));                                  Line 211
          status = EXIT_FAILURE;                                                Line 212
        }                                                                       
    }                                                                           
  while ((arg = *++argv));                                                      Line 215
                                                                                
  return status;                                                                Line 217
}                                                                               Block 5
                                                                                
int                                                                             
main (int argc, char **argv)                                                    Line 221
{                                                                               
  int optc;                                                                     Line 223
  bool list = false;                                                            Line 224
  bool table = false;                                                           Line 225
  int signum = -1;                                                              Line 226
  char signame[SIG2STR_MAX];                                                    Line 227
                                                                                
  initialize_main (&argc, &argv);                                               VMS-specific entry point handling wildcard expansion
  set_program_name (argv[0]);                                                   Retains program name and discards path
  setlocale (LC_ALL, "");                                                       Sets up internationalization (i18n)
  bindtextdomain (PACKAGE, LOCALEDIR);                                          Assigns i18n directorySets text domain for _() [gettext()] function
  textdomain (PACKAGE);                                                         Sets text domain for _() [gettext()] function
                                                                                
  atexit (close_stdout);                                                        Close stdout on exit (see gnulib)
                                                                                
  while ((optc = getopt_long (argc, argv, short_options, long_options, NULL))   Line 237
         != -1)                                                                 Line 238
    switch (optc)                                                               Line 239
      {                                                                         
      case '0': case '1': case '2': case '3': case '4':                         Line 241
      case '5': case '6': case '7': case '8': case '9':                         Line 242
        if (optind != 2)                                                        Line 243
          {                                                                     
            /* This option is actually a process-id.  */                        
            optind--;                                                           Line 246
            goto no_more_options;                                               Line 247
          }                                                                     
        FALLTHROUGH;                                                            Line 249
      case 'A': case 'B': case 'C': case 'D': case 'E':                         Line 250
      case 'F': case 'G': case 'H': case 'I': case 'J':                         Line 251
      case 'K': /*case 'L':*/ case 'M': case 'N': case 'O':                     Line 252
      case 'P': case 'Q': case 'R': case 'S': case 'T':                         Line 253
      case 'U': case 'V': case 'W': case 'X': case 'Y':                         Line 254
      case 'Z':                                                                 Line 255
        if (! optarg)                                                           Line 256
          optarg = argv[optind - 1] + strlen (argv[optind - 1]);                Line 257
        if (optarg != argv[optind - 1] + 2)                                     Line 258
          {                                                                     
            error (0, 0, _("invalid option -- %c"), optc);                      Line 260
            usage (EXIT_FAILURE);                                               Line 261
          }                                                                     
        optarg--;                                                               Line 263
        FALLTHROUGH;                                                            Line 264
      case 'n': /* -n is not documented, but is for Bash compatibility.  */     Line 265
      case 's':                                                                 Line 266
        if (0 <= signum)                                                        Line 267
          {                                                                     
            error (0, 0, _("%s: multiple signals specified"), quote (optarg));  Line 269
            usage (EXIT_FAILURE);                                               Line 270
          }                                                                     
        signum = operand2sig (optarg, signame);                                 Line 272
        if (signum < 0)                                                         Line 273
          usage (EXIT_FAILURE);                                                 Line 274
        break;                                                                  Line 275
                                                                                
      case 'L': /* -L is not documented, but is for procps compatibility.  */   Line 277
      case 't':                                                                 Line 278
        table = true;                                                           Line 279
        FALLTHROUGH;                                                            Line 280
      case 'l':                                                                 Line 281
        if (list)                                                               Line 282
          {                                                                     
            error (0, 0, _("multiple -l or -t options specified"));             Line 284
            usage (EXIT_FAILURE);                                               Line 285
          }                                                                     
        list = true;                                                            Line 287
        break;                                                                  Line 288
                                                                                
      case_GETOPT_HELP_CHAR;                                                    Line 290
      case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);                         Line 291
      default:                                                                  Line 292
        usage (EXIT_FAILURE);                                                   Line 293
      }                                                                         
 no_more_options:                                                               Line 295
                                                                                
  if (signum < 0)                                                               Line 297
    signum = SIGTERM;                                                           Line 298
  else if (list)                                                                Line 299
    {                                                                           
      error (0, 0, _("cannot combine signal with -l or -t"));                   Line 301
      usage (EXIT_FAILURE);                                                     Line 302
    }                                                                           
                                                                                
  if ( ! list && argc <= optind)                                                Line 305
    {                                                                           
      error (0, 0, _("no process ID specified"));                               Line 307
      usage (EXIT_FAILURE);                                                     Line 308
    }                                                                           
                                                                                
  return (list                                                                  Line 311
          ? list_signals (table, optind < argc ? argv + optind : NULL)          Line 312
          : send_signals (signum, argv + optind));                              Line 313
}                                                                               Block 6