39dde86c0258f091ec2cfd858075222ff5bde81b
[platform/upstream/coreutils.git] / src / kill.c
1 /* kill -- send a signal to a process
2    Copyright (C) 2002, 2003 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 "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 WRITTEN_BY _("Written by Paul Eggert.")
44 \f
45 #if ! (HAVE_DECL_STRTOIMAX || defined strtoimax)
46 intmax_t strtoimax ();
47 #endif
48
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
66 \f
67 /* The name this program was run with, for error messages.  */
68 char *program_name;
69
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";
75
76 static struct option const long_options[] =
77 {
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}
84 };
85
86 void
87 usage (int status)
88 {
89   if (status != 0)
90     fprintf (stderr, _("Try `%s --help' for more information.\n"),
91              program_name);
92   else
93     {
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\
102 \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);
121     }
122   exit (status);
123 }
124 \f
125 /* Convert OPERAND to a signal number with printable representation SIGNAME.
126    Return the signal number, or -1 if unsuccessful.  */
127
128 static int
129 operand2sig (char const *operand, char *signame)
130 {
131   int signum;
132
133   if (ISDIGIT (*operand))
134     {
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);
141     }
142   else
143     {
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';
151
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;
158
159       free (upcased);
160     }
161
162   if (signum < 0 || sig2str (signum, signame) != 0)
163     {
164       error (0, 0, _("%s: invalid signal"), operand);
165       return -1;
166     }
167
168   return signum;
169 }
170 \f
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.  */
174
175 static void
176 print_table_row (unsigned int num_width, int signum,
177                  unsigned int name_width, char const *signame)
178 {
179   char const *description = strsignal (signum);
180   printf ("%*d %-*s %s\n", num_width, signum, name_width, signame,
181           description ? description : "?");
182 }
183
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.  */
187
188 static int
189 list_signals (bool table, char *const *argv)
190 {
191   int signum;
192   int status = EXIT_SUCCESS;
193   char signame[SIG2STR_MAX];
194
195   if (table)
196     {
197       unsigned int name_width = 0;
198
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++;
203
204       /* Compute the maximum width of a signal name.  */
205       for (signum = 1; signum <= SIGNUM_BOUND; signum++)
206         if (sig2str (signum, signame) == 0)
207           {
208             size_t len = strlen (signame);
209             if (name_width < len)
210               name_width = len;
211           }
212
213       if (argv)
214         for (; *argv; argv++)
215           {
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);
221           }
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);
226     }
227   else
228     {
229       if (argv)
230         for (; *argv; argv++)
231           {
232             signum = operand2sig (*argv, signame);
233             if (signum < 0)
234               status = EXIT_FAILURE;
235             else
236               {
237                 if (ISDIGIT (**argv))
238                   puts (signame);
239                 else
240                   printf ("%d\n", signum);
241               }
242           }
243       else
244         for (signum = 1; signum <= SIGNUM_BOUND; signum++)
245           if (sig2str (signum, signame) == 0)
246             puts (signame);
247     }
248
249   return status;
250 }
251 \f
252 /* Send signal SIGNUM to all the processes or process groups specified
253    by ARGV.  Return a suitable exit status.  */
254
255 static int
256 send_signals (int signum, char *const *argv)
257 {
258   int status = EXIT_SUCCESS;
259   char const *arg = *argv;
260
261   do
262     {
263       char *endp;
264       intmax_t n = (errno = 0, strtoimax (arg, &endp, 10));
265       pid_t pid = n;
266
267       if (errno == ERANGE || pid != n || arg == endp || *endp)
268         {
269           error (0, 0, _("%s: invalid process id"), arg);
270           status = EXIT_FAILURE;
271         }
272       else if (kill (pid, signum) != 0)
273         {
274           error (0, errno, "%s", arg);
275           status = EXIT_FAILURE;
276         }
277     }
278   while ((arg = *++argv));
279
280   return status;
281 }
282 \f
283 int
284 main (int argc, char **argv)
285 {
286   int optc;
287   bool list = false;
288   bool table = false;
289   int signum = -1;
290   char signame[SIG2STR_MAX];
291
292   initialize_main (&argc, &argv);
293   program_name = argv[0];
294   setlocale (LC_ALL, "");
295   bindtextdomain (PACKAGE, LOCALEDIR);
296   textdomain (PACKAGE);
297
298   atexit (close_stdout);
299
300   while ((optc = getopt_long (argc, argv, short_options, long_options, NULL))
301          != -1)
302     switch (optc)
303       {
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)
307           {
308             /* This option is actually a process-id.  */
309             optind--;
310             goto no_more_options;
311           }
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)
322           {
323             error (0, 0, _("invalid option -- %c"), optc);
324             usage (EXIT_FAILURE);
325           }
326         optarg--;
327         /* Fall through.  */
328       case 'n': /* -n is not documented, but is for Bash compatibility.  */
329       case 's':
330         if (0 <= signum)
331           {
332             error (0, 0, _("%s: multiple signals specified"), optarg);
333             usage (EXIT_FAILURE);
334           }
335         signum = operand2sig (optarg, signame);
336         if (signum < 0)
337           usage (EXIT_FAILURE);
338         break;
339
340       case 't':
341         table = true;
342         /* Fall through.  */
343       case 'l':
344         if (list)
345           {
346             error (0, 0, _("multiple -l or -t options specified"));
347             usage (EXIT_FAILURE);
348           }
349         list = true;
350         break;
351
352       case_GETOPT_HELP_CHAR;
353       case_GETOPT_VERSION_CHAR (PROGRAM_NAME, WRITTEN_BY);
354       default:
355         usage (EXIT_FAILURE);
356       }
357  no_more_options:;
358
359   if (signum < 0)
360     signum = SIGTERM;
361   else if (list)
362     {
363       error (0, 0, _("cannot combine signal with -l or -t"));
364       usage (EXIT_FAILURE);
365     }
366
367   if ( ! list && argc <= optind)
368     {
369       error (0, 0, _("no process ID specified"));
370       usage (EXIT_FAILURE);
371     }
372
373   return (list
374           ? list_signals (table, optind < argc ? argv + optind : NULL)
375           : send_signals (signum, argv + optind));
376 }