Improve the check for departures from C89, and fix the departures
[platform/upstream/coreutils.git] / src / kill.c
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 2, or (at your option)
7    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, write to the Free Software Foundation,
16    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
17
18 /* Written by Paul Eggert.  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <getopt.h>
23 #include <sys/types.h>
24 #include <signal.h>
25
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
35
36 #include "system.h"
37 #include "error.h"
38 #include "sig2str.h"
39
40 /* The official name of this program (e.g., no `g' prefix).  */
41 #define PROGRAM_NAME "kill"
42
43 #define AUTHORS "Paul Eggert"
44 \f
45 #if ! (HAVE_DECL_STRSIGNAL || defined strsignal)
46 # if ! (HAVE_DECL_SYS_SIGLIST || defined sys_siglist)
47 #  if HAVE_DECL__SYS_SIGLIST || defined _sys_siglist
48 #   define sys_siglist _sys_siglist
49 #  elif HAVE_DECL___SYS_SIGLIST || defined __sys_siglist
50 #   define sys_siglist __sys_siglist
51 #  endif
52 # endif
53 # if HAVE_DECL_SYS_SIGLIST || defined sys_siglist
54 #  define strsignal(signum) (0 <= (signum) && (signum) <= SIGNUM_BOUND \
55                              ? sys_siglist[signum] \
56                              : 0)
57 # endif
58 # ifndef strsignal
59 #  define strsignal(signum) 0
60 # endif
61 #endif
62 \f
63 /* The name this program was run with, for error messages.  */
64 char *program_name;
65
66 static char const short_options[] =
67   "0::1::2::3::4::5::6::7::8::9::"
68   "A::B::C::D::E::F::G::H::I::J::K::L::M::"
69   "N::O::P::Q::R::S::T::U::V::W::X::Y::Z::"
70   "ln:s:t";
71
72 static struct option const long_options[] =
73 {
74   {"list", no_argument, NULL, 'l'},
75   {"signal", required_argument, NULL, 's'},
76   {"table", no_argument, NULL, 't'},
77   {GETOPT_HELP_OPTION_DECL},
78   {GETOPT_VERSION_OPTION_DECL},
79   {NULL, 0, NULL, 0}
80 };
81
82 void
83 usage (int status)
84 {
85   if (status != EXIT_SUCCESS)
86     fprintf (stderr, _("Try `%s --help' for more information.\n"),
87              program_name);
88   else
89     {
90       printf (_("\
91 Usage: %s [-s SIGNAL | -SIGNAL] PID...\n\
92   or:  %s -l [SIGNAL]...\n\
93   or:  %s -t [SIGNAL]...\n\
94 "),
95               program_name, program_name, program_name);
96       fputs (_("\
97 Send signals to processes, or list signals.\n\
98 \n\
99 "), stdout);
100       fputs (_("\
101 Mandatory arguments to long options are mandatory for short options too.\n\
102 "), stdout);
103       fputs (_("\
104   -s, --signal=SIGNAL, -SIGNAL\n\
105                    specify the name or number of the signal to be sent\n\
106   -l, --list       list signal names, or convert signal names to/from numbers\n\
107   -t, --table      print a table of signal information\n\
108 "), stdout);
109       fputs (HELP_OPTION_DESCRIPTION, stdout);
110       fputs (VERSION_OPTION_DESCRIPTION, stdout);
111       fputs (_("\n\
112 SIGNAL may be a signal name like `HUP', or a signal number like `1',\n\
113 or an exit status of a process terminated by a signal.\n\
114 PID is an integer; if negative it identifies a process group.\n\
115 "), stdout);
116       printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME);
117       printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
118     }
119   exit (status);
120 }
121 \f
122 /* Convert OPERAND to a signal number with printable representation SIGNAME.
123    Return the signal number, or -1 if unsuccessful.  */
124
125 static int
126 operand2sig (char const *operand, char *signame)
127 {
128   int signum;
129
130   if (ISDIGIT (*operand))
131     {
132       char *endp;
133       long int l = (errno = 0, strtol (operand, &endp, 10));
134       int i = l;
135       signum = (operand == endp || *endp || errno || i != l ? -1
136                 : WIFSIGNALED (i) ? WTERMSIG (i)
137                 : i);
138     }
139   else
140     {
141       /* Convert signal to upper case in the C locale, not in the
142          current locale.  Don't assume ASCII; it might be EBCDIC.  */
143       char *upcased = xstrdup (operand);
144       char *p;
145       for (p = upcased; *p; p++)
146         if (strchr ("abcdefghijklmnopqrstuvwxyz", *p))
147           *p += 'A' - 'a';
148
149       /* Look for the signal name, possibly prefixed by "SIG",
150          and possibly lowercased.  */
151       if (! (str2sig (upcased, &signum) == 0
152              || (upcased[0] == 'S' && upcased[1] == 'I' && upcased[2] == 'G'
153                  && str2sig (upcased + 3, &signum) == 0)))
154         signum = -1;
155
156       free (upcased);
157     }
158
159   if (signum < 0 || sig2str (signum, signame) != 0)
160     {
161       error (0, 0, _("%s: invalid signal"), operand);
162       return -1;
163     }
164
165   return signum;
166 }
167 \f
168 /* Print a row of `kill -t' output.  NUM_WIDTH is the maximum signal
169    number width, and SIGNUM is the signal number to print.  The
170    maximum name width is NAME_WIDTH, and SIGNAME is the name to print.  */
171
172 static void
173 print_table_row (unsigned int num_width, int signum,
174                  unsigned int name_width, char const *signame)
175 {
176   char const *description = strsignal (signum);
177   printf ("%*d %-*s %s\n", num_width, signum, name_width, signame,
178           description ? description : "?");
179 }
180
181 /* Print a list of signal names.  If TABLE, print a table.
182    Print the names specified by ARGV if nonzero; otherwise,
183    print all known names.  Return a suitable exit status.  */
184
185 static int
186 list_signals (bool table, char *const *argv)
187 {
188   int signum;
189   int status = EXIT_SUCCESS;
190   char signame[SIG2STR_MAX];
191
192   if (table)
193     {
194       unsigned int name_width = 0;
195
196       /* Compute the maximum width of a signal number.  */
197       unsigned int num_width = 1;
198       for (signum = 1; signum <= SIGNUM_BOUND / 10; signum *= 10)
199         num_width++;
200
201       /* Compute the maximum width of a signal name.  */
202       for (signum = 1; signum <= SIGNUM_BOUND; signum++)
203         if (sig2str (signum, signame) == 0)
204           {
205             size_t len = strlen (signame);
206             if (name_width < len)
207               name_width = len;
208           }
209
210       if (argv)
211         for (; *argv; argv++)
212           {
213             signum = operand2sig (*argv, signame);
214             if (signum < 0)
215               status = EXIT_FAILURE;
216             else
217               print_table_row (num_width, signum, name_width, signame);
218           }
219       else
220         for (signum = 1; signum <= SIGNUM_BOUND; signum++)
221           if (sig2str (signum, signame) == 0)
222             print_table_row (num_width, signum, name_width, signame);
223     }
224   else
225     {
226       if (argv)
227         for (; *argv; argv++)
228           {
229             signum = operand2sig (*argv, signame);
230             if (signum < 0)
231               status = EXIT_FAILURE;
232             else
233               {
234                 if (ISDIGIT (**argv))
235                   puts (signame);
236                 else
237                   printf ("%d\n", signum);
238               }
239           }
240       else
241         for (signum = 1; signum <= SIGNUM_BOUND; signum++)
242           if (sig2str (signum, signame) == 0)
243             puts (signame);
244     }
245
246   return status;
247 }
248 \f
249 /* Send signal SIGNUM to all the processes or process groups specified
250    by ARGV.  Return a suitable exit status.  */
251
252 static int
253 send_signals (int signum, char *const *argv)
254 {
255   int status = EXIT_SUCCESS;
256   char const *arg = *argv;
257
258   do
259     {
260       char *endp;
261       intmax_t n = (errno = 0, strtoimax (arg, &endp, 10));
262       pid_t pid = n;
263
264       if (errno == ERANGE || pid != n || arg == endp || *endp)
265         {
266           error (0, 0, _("%s: invalid process id"), arg);
267           status = EXIT_FAILURE;
268         }
269       else if (kill (pid, signum) != 0)
270         {
271           error (0, errno, "%s", arg);
272           status = EXIT_FAILURE;
273         }
274     }
275   while ((arg = *++argv));
276
277   return status;
278 }
279 \f
280 int
281 main (int argc, char **argv)
282 {
283   int optc;
284   bool list = false;
285   bool table = false;
286   int signum = -1;
287   char signame[SIG2STR_MAX];
288
289   initialize_main (&argc, &argv);
290   program_name = argv[0];
291   setlocale (LC_ALL, "");
292   bindtextdomain (PACKAGE, LOCALEDIR);
293   textdomain (PACKAGE);
294
295   atexit (close_stdout);
296
297   while ((optc = getopt_long (argc, argv, short_options, long_options, NULL))
298          != -1)
299     switch (optc)
300       {
301       case '0': case '1': case '2': case '3': case '4':
302       case '5': case '6': case '7': case '8': case '9':
303         if (optind != 2)
304           {
305             /* This option is actually a process-id.  */
306             optind--;
307             goto no_more_options;
308           }
309         /* Fall through.  */
310       case 'A': case 'B': case 'C': case 'D': case 'E':
311       case 'F': case 'G': case 'H': case 'I': case 'J':
312       case 'K': case 'L': case 'M': case 'N': case 'O':
313       case 'P': case 'Q': case 'R': case 'S': case 'T':
314       case 'U': case 'V': case 'W': case 'X': case 'Y':
315       case 'Z':
316         if (! optarg)
317           optarg = argv[optind - 1] + strlen (argv[optind - 1]);
318         if (optarg != argv[optind - 1] + 2)
319           {
320             error (0, 0, _("invalid option -- %c"), optc);
321             usage (EXIT_FAILURE);
322           }
323         optarg--;
324         /* Fall through.  */
325       case 'n': /* -n is not documented, but is for Bash compatibility.  */
326       case 's':
327         if (0 <= signum)
328           {
329             error (0, 0, _("%s: multiple signals specified"), optarg);
330             usage (EXIT_FAILURE);
331           }
332         signum = operand2sig (optarg, signame);
333         if (signum < 0)
334           usage (EXIT_FAILURE);
335         break;
336
337       case 't':
338         table = true;
339         /* Fall through.  */
340       case 'l':
341         if (list)
342           {
343             error (0, 0, _("multiple -l or -t options specified"));
344             usage (EXIT_FAILURE);
345           }
346         list = true;
347         break;
348
349       case_GETOPT_HELP_CHAR;
350       case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
351       default:
352         usage (EXIT_FAILURE);
353       }
354  no_more_options:;
355
356   if (signum < 0)
357     signum = SIGTERM;
358   else if (list)
359     {
360       error (0, 0, _("cannot combine signal with -l or -t"));
361       usage (EXIT_FAILURE);
362     }
363
364   if ( ! list && argc <= optind)
365     {
366       error (0, 0, _("no process ID specified"));
367       usage (EXIT_FAILURE);
368     }
369
370   return (list
371           ? list_signals (table, optind < argc ? argv + optind : NULL)
372           : send_signals (signum, argv + optind));
373 }