/* 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