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