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 : }
|