0d09c2b582b43fffbcd279ea5de5148f7db09086
[platform/upstream/coreutils.git] / src / kill.c
1 /* kill -- send a signal to a process
2    Copyright (C) 2002-2005, 2008-2012 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 #include "system.h"
26 #include "error.h"
27 #include "sig2str.h"
28 #include "operand2sig.h"
29
30 /* The official name of this program (e.g., no `g' prefix).  */
31 #define PROGRAM_NAME "kill"
32
33 #define AUTHORS proper_name ("Paul Eggert")
34 \f
35 #if ! (HAVE_DECL_STRSIGNAL || defined strsignal)
36 # if ! (HAVE_DECL_SYS_SIGLIST || defined sys_siglist)
37 #  if HAVE_DECL__SYS_SIGLIST || defined _sys_siglist
38 #   define sys_siglist _sys_siglist
39 #  elif HAVE_DECL___SYS_SIGLIST || defined __sys_siglist
40 #   define sys_siglist __sys_siglist
41 #  endif
42 # endif
43 # if HAVE_DECL_SYS_SIGLIST || defined sys_siglist
44 #  define strsignal(signum) (0 <= (signum) && (signum) <= SIGNUM_BOUND \
45                              ? sys_siglist[signum] \
46                              : 0)
47 # endif
48 # ifndef strsignal
49 #  define strsignal(signum) 0
50 # endif
51 #endif
52 \f
53 static char const short_options[] =
54   "0::1::2::3::4::5::6::7::8::9::"
55   "A::B::C::D::E::F::G::H::I::J::K::L::M::"
56   "N::O::P::Q::R::S::T::U::V::W::X::Y::Z::"
57   "ln:s:t";
58
59 static struct option const long_options[] =
60 {
61   {"list", no_argument, NULL, 'l'},
62   {"signal", required_argument, NULL, 's'},
63   {"table", no_argument, NULL, 't'},
64   {GETOPT_HELP_OPTION_DECL},
65   {GETOPT_VERSION_OPTION_DECL},
66   {NULL, 0, NULL, 0}
67 };
68
69 void
70 usage (int status)
71 {
72   if (status != EXIT_SUCCESS)
73     fprintf (stderr, _("Try `%s --help' for more information.\n"),
74              program_name);
75   else
76     {
77       printf (_("\
78 Usage: %s [-s SIGNAL | -SIGNAL] PID...\n\
79   or:  %s -l [SIGNAL]...\n\
80   or:  %s -t [SIGNAL]...\n\
81 "),
82               program_name, program_name, program_name);
83       fputs (_("\
84 Send signals to processes, or list signals.\n\
85 \n\
86 "), stdout);
87       fputs (_("\
88 Mandatory arguments to long options are mandatory for short options too.\n\
89 "), stdout);
90       fputs (_("\
91   -s, --signal=SIGNAL, -SIGNAL\n\
92                    specify the name or number of the signal to be sent\n\
93   -l, --list       list signal names, or convert signal names to/from numbers\n\
94   -t, --table      print a table of signal information\n\
95 "), stdout);
96       fputs (HELP_OPTION_DESCRIPTION, stdout);
97       fputs (VERSION_OPTION_DESCRIPTION, stdout);
98       fputs (_("\n\
99 SIGNAL may be a signal name like `HUP', or a signal number like `1',\n\
100 or the exit status of a process terminated by a signal.\n\
101 PID is an integer; if negative it identifies a process group.\n\
102 "), stdout);
103       printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME);
104       emit_ancillary_info ();
105     }
106   exit (status);
107 }
108 \f
109 /* Print a row of `kill -t' output.  NUM_WIDTH is the maximum signal
110    number width, and SIGNUM is the signal number to print.  The
111    maximum name width is NAME_WIDTH, and SIGNAME is the name to print.  */
112
113 static void
114 print_table_row (unsigned int num_width, int signum,
115                  unsigned int name_width, char const *signame)
116 {
117   char const *description = strsignal (signum);
118   printf ("%*d %-*s %s\n", num_width, signum, name_width, signame,
119           description ? description : "?");
120 }
121
122 /* Print a list of signal names.  If TABLE, print a table.
123    Print the names specified by ARGV if nonzero; otherwise,
124    print all known names.  Return a suitable exit status.  */
125
126 static int
127 list_signals (bool table, char *const *argv)
128 {
129   int signum;
130   int status = EXIT_SUCCESS;
131   char signame[SIG2STR_MAX];
132
133   if (table)
134     {
135       unsigned int name_width = 0;
136
137       /* Compute the maximum width of a signal number.  */
138       unsigned int num_width = 1;
139       for (signum = 1; signum <= SIGNUM_BOUND / 10; signum *= 10)
140         num_width++;
141
142       /* Compute the maximum width of a signal name.  */
143       for (signum = 1; signum <= SIGNUM_BOUND; signum++)
144         if (sig2str (signum, signame) == 0)
145           {
146             size_t len = strlen (signame);
147             if (name_width < len)
148               name_width = len;
149           }
150
151       if (argv)
152         for (; *argv; argv++)
153           {
154             signum = operand2sig (*argv, signame);
155             if (signum < 0)
156               status = EXIT_FAILURE;
157             else
158               print_table_row (num_width, signum, name_width, signame);
159           }
160       else
161         for (signum = 1; signum <= SIGNUM_BOUND; signum++)
162           if (sig2str (signum, signame) == 0)
163             print_table_row (num_width, signum, name_width, signame);
164     }
165   else
166     {
167       if (argv)
168         for (; *argv; argv++)
169           {
170             signum = operand2sig (*argv, signame);
171             if (signum < 0)
172               status = EXIT_FAILURE;
173             else
174               {
175                 if (ISDIGIT (**argv))
176                   puts (signame);
177                 else
178                   printf ("%d\n", signum);
179               }
180           }
181       else
182         for (signum = 1; signum <= SIGNUM_BOUND; signum++)
183           if (sig2str (signum, signame) == 0)
184             puts (signame);
185     }
186
187   return status;
188 }
189 \f
190 /* Send signal SIGNUM to all the processes or process groups specified
191    by ARGV.  Return a suitable exit status.  */
192
193 static int
194 send_signals (int signum, char *const *argv)
195 {
196   int status = EXIT_SUCCESS;
197   char const *arg = *argv;
198
199   do
200     {
201       char *endp;
202       intmax_t n = (errno = 0, strtoimax (arg, &endp, 10));
203       pid_t pid = n;
204
205       if (errno == ERANGE || pid != n || arg == endp || *endp)
206         {
207           error (0, 0, _("%s: invalid process id"), arg);
208           status = EXIT_FAILURE;
209         }
210       else if (kill (pid, signum) != 0)
211         {
212           error (0, errno, "%s", arg);
213           status = EXIT_FAILURE;
214         }
215     }
216   while ((arg = *++argv));
217
218   return status;
219 }
220 \f
221 int
222 main (int argc, char **argv)
223 {
224   int optc;
225   bool list = false;
226   bool table = false;
227   int signum = -1;
228   char signame[SIG2STR_MAX];
229
230   initialize_main (&argc, &argv);
231   set_program_name (argv[0]);
232   setlocale (LC_ALL, "");
233   bindtextdomain (PACKAGE, LOCALEDIR);
234   textdomain (PACKAGE);
235
236   atexit (close_stdout);
237
238   while ((optc = getopt_long (argc, argv, short_options, long_options, NULL))
239          != -1)
240     switch (optc)
241       {
242       case '0': case '1': case '2': case '3': case '4':
243       case '5': case '6': case '7': case '8': case '9':
244         if (optind != 2)
245           {
246             /* This option is actually a process-id.  */
247             optind--;
248             goto no_more_options;
249           }
250         /* Fall through.  */
251       case 'A': case 'B': case 'C': case 'D': case 'E':
252       case 'F': case 'G': case 'H': case 'I': case 'J':
253       case 'K': case 'L': case 'M': case 'N': case 'O':
254       case 'P': case 'Q': case 'R': case 'S': case 'T':
255       case 'U': case 'V': case 'W': case 'X': case 'Y':
256       case 'Z':
257         if (! optarg)
258           optarg = argv[optind - 1] + strlen (argv[optind - 1]);
259         if (optarg != argv[optind - 1] + 2)
260           {
261             error (0, 0, _("invalid option -- %c"), optc);
262             usage (EXIT_FAILURE);
263           }
264         optarg--;
265         /* Fall through.  */
266       case 'n': /* -n is not documented, but is for Bash compatibility.  */
267       case 's':
268         if (0 <= signum)
269           {
270             error (0, 0, _("%s: multiple signals specified"), optarg);
271             usage (EXIT_FAILURE);
272           }
273         signum = operand2sig (optarg, signame);
274         if (signum < 0)
275           usage (EXIT_FAILURE);
276         break;
277
278       case 't':
279         table = true;
280         /* Fall through.  */
281       case 'l':
282         if (list)
283           {
284             error (0, 0, _("multiple -l or -t options specified"));
285             usage (EXIT_FAILURE);
286           }
287         list = true;
288         break;
289
290       case_GETOPT_HELP_CHAR;
291       case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
292       default:
293         usage (EXIT_FAILURE);
294       }
295  no_more_options:
296
297   if (signum < 0)
298     signum = SIGTERM;
299   else if (list)
300     {
301       error (0, 0, _("cannot combine signal with -l or -t"));
302       usage (EXIT_FAILURE);
303     }
304
305   if ( ! list && argc <= optind)
306     {
307       error (0, 0, _("no process ID specified"));
308       usage (EXIT_FAILURE);
309     }
310
311   return (list
312           ? list_signals (table, optind < argc ? argv + optind : NULL)
313           : send_signals (signum, argv + optind));
314 }