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