Avoid spurious failure on x86 solaris2.9 when using c89.
[coreutils.git] / src / kill.c
blob9798455b96cec14afd97dad73c7dfb8a181c4d20
1 /* kill -- send a signal to a process
2 Copyright (C) 2002, 2003, 2004 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 2, or (at your option)
7 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, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 /* Written by Paul Eggert. */
20 #include <config.h>
21 #include <stdio.h>
22 #include <getopt.h>
23 #include <sys/types.h>
24 #include <signal.h>
26 #if HAVE_SYS_WAIT_H
27 # include <sys/wait.h>
28 #endif
29 #ifndef WIFSIGNALED
30 # define WIFSIGNALED(s) (((s) & 0xFFFF) - 1 < (unsigned int) 0xFF)
31 #endif
32 #ifndef WTERMSIG
33 # define WTERMSIG(s) ((s) & 0x7F)
34 #endif
36 #include "system.h"
37 #include "error.h"
38 #include "sig2str.h"
40 /* The official name of this program (e.g., no `g' prefix). */
41 #define PROGRAM_NAME "kill"
43 #define AUTHORS "Paul Eggert"
45 #if ! (HAVE_DECL_STRTOIMAX || defined strtoimax)
46 intmax_t strtoimax ();
47 #endif
49 #if ! (HAVE_DECL_STRSIGNAL || defined strsignal)
50 # if ! (HAVE_DECL_SYS_SIGLIST || defined sys_siglist)
51 # if HAVE_DECL__SYS_SIGLIST || defined _sys_siglist
52 # define sys_siglist _sys_siglist
53 # elif HAVE_DECL___SYS_SIGLIST || defined __sys_siglist
54 # define sys_siglist __sys_siglist
55 # endif
56 # endif
57 # if HAVE_DECL_SYS_SIGLIST || defined sys_siglist
58 # define strsignal(signum) (0 <= (signum) && (signum) <= SIGNUM_BOUND \
59 ? sys_siglist[signum] \
60 : 0)
61 # endif
62 # ifndef strsignal
63 # define strsignal(signum) 0
64 # endif
65 #endif
67 /* The name this program was run with, for error messages. */
68 char *program_name;
70 static char const short_options[] =
71 "0::1::2::3::4::5::6::7::8::9::"
72 "A::B::C::D::E::F::G::H::I::J::K::L::M::"
73 "N::O::P::Q::R::S::T::U::V::W::X::Y::Z::"
74 "ln:s:t";
76 static struct option const long_options[] =
78 {"list", no_argument, NULL, 'l'},
79 {"signal", required_argument, NULL, 's'},
80 {"table", no_argument, NULL, 't'},
81 {GETOPT_HELP_OPTION_DECL},
82 {GETOPT_VERSION_OPTION_DECL},
83 {NULL, 0, NULL, 0}
86 void
87 usage (int status)
89 if (status != EXIT_SUCCESS)
90 fprintf (stderr, _("Try `%s --help' for more information.\n"),
91 program_name);
92 else
94 printf (_("\
95 Usage: %s [-s SIGNAL | -SIGNAL] PID...\n\
96 or: %s -l [SIGNAL]...\n\
97 or: %s -t [SIGNAL]...\n\
98 "),
99 program_name, program_name, program_name);
100 fputs (_("\
101 Send signals to processes, or list signals.\n\
103 "), stdout);
104 fputs (_("\
105 Mandatory arguments to long options are mandatory for short options too.\n\
106 "), stdout);
107 fputs (_("\
108 -s, --signal=SIGNAL, -SIGNAL\n\
109 specify the name or number of the signal to be sent\n\
110 -l, --list list signal names, or convert signal names to/from numbers\n\
111 -t, --table print a table of signal information\n\
112 "), stdout);
113 fputs (HELP_OPTION_DESCRIPTION, stdout);
114 fputs (VERSION_OPTION_DESCRIPTION, stdout);
115 fputs (_("\n\
116 SIGNAL may be a signal name like `HUP', or a signal number like `1',\n\
117 or an exit status of a process terminated by a signal.\n\
118 PID is an integer; if negative it identifies a process group.\n\
119 "), stdout);
120 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
122 exit (status);
125 /* Convert OPERAND to a signal number with printable representation SIGNAME.
126 Return the signal number, or -1 if unsuccessful. */
128 static int
129 operand2sig (char const *operand, char *signame)
131 int signum;
133 if (ISDIGIT (*operand))
135 char *endp;
136 long int l = (errno = 0, strtol (operand, &endp, 10));
137 int i = l;
138 signum = (operand == endp || *endp || errno || i != l ? -1
139 : WIFSIGNALED (i) ? WTERMSIG (i)
140 : i);
142 else
144 /* Convert signal to upper case in the C locale, not in the
145 current locale. Don't assume ASCII; it might be EBCDIC. */
146 char *upcased = xstrdup (operand);
147 char *p;
148 for (p = upcased; *p; p++)
149 if (strchr ("abcdefghijklmnopqrstuvwxyz", *p))
150 *p += 'A' - 'a';
152 /* Look for the signal name, possibly prefixed by "SIG",
153 and possibly lowercased. */
154 if (! (str2sig (upcased, &signum) == 0
155 || (upcased[0] == 'S' && upcased[1] == 'I' && upcased[2] == 'G'
156 && str2sig (upcased + 3, &signum) == 0)))
157 signum = -1;
159 free (upcased);
162 if (signum < 0 || sig2str (signum, signame) != 0)
164 error (0, 0, _("%s: invalid signal"), operand);
165 return -1;
168 return signum;
171 /* Print a row of `kill -t' output. NUM_WIDTH is the maximum signal
172 number width, and SIGNUM is the signal number to print. The
173 maximum name width is NAME_WIDTH, and SIGNAME is the name to print. */
175 static void
176 print_table_row (unsigned int num_width, int signum,
177 unsigned int name_width, char const *signame)
179 char const *description = strsignal (signum);
180 printf ("%*d %-*s %s\n", num_width, signum, name_width, signame,
181 description ? description : "?");
184 /* Print a list of signal names. If TABLE, print a table.
185 Print the names specified by ARGV if nonzero; otherwise,
186 print all known names. Return a suitable exit status. */
188 static int
189 list_signals (bool table, char *const *argv)
191 int signum;
192 int status = EXIT_SUCCESS;
193 char signame[SIG2STR_MAX];
195 if (table)
197 unsigned int name_width = 0;
199 /* Compute the maximum width of a signal number. */
200 unsigned int num_width = 1;
201 for (signum = 1; signum <= SIGNUM_BOUND / 10; signum *= 10)
202 num_width++;
204 /* Compute the maximum width of a signal name. */
205 for (signum = 1; signum <= SIGNUM_BOUND; signum++)
206 if (sig2str (signum, signame) == 0)
208 size_t len = strlen (signame);
209 if (name_width < len)
210 name_width = len;
213 if (argv)
214 for (; *argv; argv++)
216 signum = operand2sig (*argv, signame);
217 if (signum < 0)
218 status = EXIT_FAILURE;
219 else
220 print_table_row (num_width, signum, name_width, signame);
222 else
223 for (signum = 1; signum <= SIGNUM_BOUND; signum++)
224 if (sig2str (signum, signame) == 0)
225 print_table_row (num_width, signum, name_width, signame);
227 else
229 if (argv)
230 for (; *argv; argv++)
232 signum = operand2sig (*argv, signame);
233 if (signum < 0)
234 status = EXIT_FAILURE;
235 else
237 if (ISDIGIT (**argv))
238 puts (signame);
239 else
240 printf ("%d\n", signum);
243 else
244 for (signum = 1; signum <= SIGNUM_BOUND; signum++)
245 if (sig2str (signum, signame) == 0)
246 puts (signame);
249 return status;
252 /* Send signal SIGNUM to all the processes or process groups specified
253 by ARGV. Return a suitable exit status. */
255 static int
256 send_signals (int signum, char *const *argv)
258 int status = EXIT_SUCCESS;
259 char const *arg = *argv;
263 char *endp;
264 intmax_t n = (errno = 0, strtoimax (arg, &endp, 10));
265 pid_t pid = n;
267 if (errno == ERANGE || pid != n || arg == endp || *endp)
269 error (0, 0, _("%s: invalid process id"), arg);
270 status = EXIT_FAILURE;
272 else if (kill (pid, signum) != 0)
274 error (0, errno, "%s", arg);
275 status = EXIT_FAILURE;
278 while ((arg = *++argv));
280 return status;
284 main (int argc, char **argv)
286 int optc;
287 bool list = false;
288 bool table = false;
289 int signum = -1;
290 char signame[SIG2STR_MAX];
292 initialize_main (&argc, &argv);
293 program_name = argv[0];
294 setlocale (LC_ALL, "");
295 bindtextdomain (PACKAGE, LOCALEDIR);
296 textdomain (PACKAGE);
298 atexit (close_stdout);
300 while ((optc = getopt_long (argc, argv, short_options, long_options, NULL))
301 != -1)
302 switch (optc)
304 case '0': case '1': case '2': case '3': case '4':
305 case '5': case '6': case '7': case '8': case '9':
306 if (optind != 2)
308 /* This option is actually a process-id. */
309 optind--;
310 goto no_more_options;
312 /* Fall through. */
313 case 'A': case 'B': case 'C': case 'D': case 'E':
314 case 'F': case 'G': case 'H': case 'I': case 'J':
315 case 'K': case 'L': case 'M': case 'N': case 'O':
316 case 'P': case 'Q': case 'R': case 'S': case 'T':
317 case 'U': case 'V': case 'W': case 'X': case 'Y':
318 case 'Z':
319 if (! optarg)
320 optarg = argv[optind - 1] + strlen (argv[optind - 1]);
321 if (optarg != argv[optind - 1] + 2)
323 error (0, 0, _("invalid option -- %c"), optc);
324 usage (EXIT_FAILURE);
326 optarg--;
327 /* Fall through. */
328 case 'n': /* -n is not documented, but is for Bash compatibility. */
329 case 's':
330 if (0 <= signum)
332 error (0, 0, _("%s: multiple signals specified"), optarg);
333 usage (EXIT_FAILURE);
335 signum = operand2sig (optarg, signame);
336 if (signum < 0)
337 usage (EXIT_FAILURE);
338 break;
340 case 't':
341 table = true;
342 /* Fall through. */
343 case 'l':
344 if (list)
346 error (0, 0, _("multiple -l or -t options specified"));
347 usage (EXIT_FAILURE);
349 list = true;
350 break;
352 case_GETOPT_HELP_CHAR;
353 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
354 default:
355 usage (EXIT_FAILURE);
357 no_more_options:;
359 if (signum < 0)
360 signum = SIGTERM;
361 else if (list)
363 error (0, 0, _("cannot combine signal with -l or -t"));
364 usage (EXIT_FAILURE);
367 if ( ! list && argc <= optind)
369 error (0, 0, _("no process ID specified"));
370 usage (EXIT_FAILURE);
373 return (list
374 ? list_signals (table, optind < argc ? argv + optind : NULL)
375 : send_signals (signum, argv + optind));