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