dd: clarify meaning of multiplication factors; put xM in order
[platform/upstream/coreutils.git] / src / timeout.c
1 /* timeout -- run a command with bounded time
2    Copyright (C) 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
18 /* timeout - Start a command, and kill it if the specified timeout expires
19
20    We try to behave like a shell starting a single (foreground) job,
21    and will kill the job if we receive the alarm signal we setup.
22    The exit status of the job is returned, or one of these errors:
23      EXIT_TIMEDOUT      124      job timed out
24      EXIT_CANCELED      125      internal error
25      EXIT_CANNOT_INVOKE 126      error executing job
26      EXIT_ENOENT        127      couldn't find job to exec
27
28    Caveats:
29      If user specifies the KILL (9) signal is to be sent on timeout,
30      the monitor is killed and so exits with 128+9 rather than 124.
31
32      If you start a command in the background, which reads from the tty
33      and so is immediately sent SIGTTIN to stop, then the timeout
34      process will ignore this so it can timeout the command as expected.
35      This can be seen with `timeout 10 dd&` for example.
36      However if one brings this group to the foreground with the `fg`
37      command before the timer expires, the command will remain
38      in the sTop state as the shell doesn't send a SIGCONT
39      because the timeout process (group leader) is already running.
40      To get the command running again one can Ctrl-Z, and do fg again.
41      Note one can Ctrl-C the whole job when in this state.
42      I think this could be fixed but I'm not sure the extra
43      complication is justified for this scenario.
44
45    Written by Pádraig Brady.  */
46
47 #include <config.h>
48 #include <getopt.h>
49 #include <stdio.h>
50 #include <sys/types.h>
51 #include <signal.h>
52
53 #if HAVE_SYS_WAIT_H
54 # include <sys/wait.h>
55 #endif
56 #ifndef WIFSIGNALED
57 # define WIFSIGNALED(s) (((s) & 0xFFFF) - 1 < (unsigned int) 0xFF)
58 #endif
59 #ifndef WTERMSIG
60 # define WTERMSIG(s) ((s) & 0x7F)
61 #endif
62
63 #include "system.h"
64 #include "xstrtol.h"
65 #include "sig2str.h"
66 #include "operand2sig.h"
67 #include "cloexec.h"
68 #include "error.h"
69 #include "long-options.h"
70 #include "quote.h"
71
72 #define PROGRAM_NAME "timeout"
73
74 #define AUTHORS proper_name_utf8 ("Padraig Brady", "P\303\241draig Brady")
75
76 /* Note ETIMEDOUT is 110 on linux but this is non standard */
77 #define EXIT_TIMEDOUT 124
78
79 /* Internal failure.  */
80 #define EXIT_CANCELED 125
81
82 static int timed_out;
83 static int term_signal = SIGTERM;  /* same default as kill command.  */
84 static int monitored_pid;
85 static int sigs_to_ignore[NSIG];   /* so monitor can ignore sigs it resends.  */
86
87 static struct option const long_options[] =
88 {
89   {"signal", required_argument, NULL, 's'},
90   {NULL, 0, NULL, 0}
91 };
92
93 /* send sig to group but not ourselves.
94  * FIXME: Is there a better way to achieve this?  */
95 static int
96 send_sig (int where, int sig)
97 {
98   sigs_to_ignore[sig] = 1;
99   return kill (where, sig);
100 }
101
102 static void
103 cleanup (int sig)
104 {
105   if (sig == SIGALRM)
106     {
107       timed_out = 1;
108       sig = term_signal;
109     }
110   if (monitored_pid)
111     {
112       if (sigs_to_ignore[sig])
113         {
114           sigs_to_ignore[sig] = 0;
115           return;
116         }
117       send_sig (0, sig);
118       if (sig != SIGKILL && sig != SIGCONT)
119         send_sig (0, SIGCONT);
120     }
121   else /* we're the child or the child is not exec'd yet.  */
122     _exit (128 + sig);
123 }
124
125 static void
126 usage (int status)
127 {
128   if (status != EXIT_SUCCESS)
129     fprintf (stderr, _("Try `%s --help' for more information.\n"),
130              program_name);
131   else
132     {
133       printf (_("\
134 Usage: %s [OPTION] NUMBER[SUFFIX] COMMAND [ARG]...\n\
135   or:  %s [OPTION]\n"), program_name, program_name);
136
137       fputs (_("\
138 Start COMMAND, and kill it if still running after NUMBER seconds.\n\
139 SUFFIX may be `s' for seconds (the default), `m' for minutes,\n\
140 `h' for hours or `d' for days.\n\
141 \n\
142 "), stdout);
143
144       fputs (_("\
145 Mandatory arguments to long options are mandatory for short options too.\n\
146 "), stdout);
147       fputs (_("\
148   -s, --signal=SIGNAL\n\
149                    specify the signal to be sent on timeout.\n\
150                    SIGNAL may be a name like `HUP' or a number.\n\
151                    See `kill -l` for a list of signals\n"), stdout);
152
153       fputs (HELP_OPTION_DESCRIPTION, stdout);
154       fputs (VERSION_OPTION_DESCRIPTION, stdout);
155       fputs (_("\n\
156 If the command times out, then we exit with status 124,\n\
157 otherwise the normal exit status of the command is returned.\n\
158 If no signal is specified, the TERM signal is sent. The TERM signal\n\
159 will kill processes which do not catch this signal. For other processes,\n\
160 it may be necessary to use the KILL (9) signal, since this signal cannot\n\
161 be caught.\n"), stdout);
162       emit_bug_reporting_address ();
163     }
164   exit (status);
165 }
166
167 /* Given an integer value *X, and a suffix character, SUFFIX_CHAR,
168    scale *X by the multiplier implied by SUFFIX_CHAR.  SUFFIX_CHAR may
169    be the NUL byte or `s' to denote seconds, `m' for minutes, `h' for
170    hours, or `d' for days.  If SUFFIX_CHAR is invalid, don't modify *X
171    and return false.  If *X would overflow, don't modify *X and return false.
172    Otherwise return true.  */
173
174 static bool
175 apply_time_suffix (unsigned int *x, char suffix_char)
176 {
177   int multiplier = 1;
178
179   switch (suffix_char)
180     {
181     case 0:
182     case 's':
183       return true;
184     case 'd':
185       multiplier *= 24;
186     case 'h':
187       multiplier *= 60;
188     case 'm':
189       multiplier *= 60;
190       break;
191     default:
192       return false;
193     }
194
195   if (*x > UINT_MAX / multiplier)
196       return false;
197
198   *x *= multiplier;
199
200   return true;
201 }
202
203 static void
204 install_signal_handlers (void)
205 {
206   struct sigaction sa;
207   sigemptyset(&sa.sa_mask);  /* Allow concurrent calls to handler */
208   sa.sa_handler = cleanup;
209   sa.sa_flags = SA_RESTART;  /* restart syscalls (like wait() below) */
210
211   sigaction (SIGALRM, &sa, NULL); /* our timeout.  */
212   sigaction (SIGINT, &sa, NULL);  /* Ctrl-C at terminal for example.  */
213   sigaction (SIGQUIT, &sa, NULL); /* Ctrl-\ at terminal for example.  */
214   sigaction (SIGTERM, &sa, NULL); /* if we're killed, stop monitored proc.  */
215   sigaction (SIGHUP, &sa, NULL);  /* terminal closed for example.  */
216 }
217
218 int
219 main (int argc, char **argv)
220 {
221   unsigned long timeout;
222   char signame[SIG2STR_MAX];
223   int c;
224   char *ep;
225
226   initialize_main (&argc, &argv);
227   set_program_name (argv[0]);
228   setlocale (LC_ALL, "");
229   bindtextdomain (PACKAGE, LOCALEDIR);
230   textdomain (PACKAGE);
231
232   initialize_exit_failure (EXIT_CANCELED);
233   atexit (close_stdout);
234
235   parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, VERSION,
236                       usage, AUTHORS, (char const *) NULL);
237
238   while ((c = getopt_long (argc, argv, "+s:", long_options, NULL)) != -1)
239     {
240       switch (c)
241         {
242         case 's':
243           term_signal = operand2sig (optarg, signame);
244           if (term_signal == -1)
245             usage (EXIT_CANCELED);
246           break;
247         default:
248           usage (EXIT_CANCELED);
249           break;
250         }
251     }
252
253   if (argc - optind < 2)
254     usage (EXIT_CANCELED);
255
256   if (xstrtoul (argv[optind], &ep, 10, &timeout, NULL)
257       /* Invalid interval. Note 0 disables timeout  */
258       || (timeout > UINT_MAX)
259       /* Extra chars after the number and an optional s,m,h,d char.  */
260       || (*ep && *(ep + 1))
261       /* Check any suffix char and update timeout based on the suffix.  */
262       || !apply_time_suffix ((unsigned int *) &timeout, *ep))
263     {
264       error (0, 0, _("invalid time interval %s"), quote (argv[optind]));
265       usage (EXIT_CANCELED);
266     }
267   optind++;
268
269   argc -= optind;
270   argv += optind;
271
272   /* Ensure we're in our own group so all subprocesses can be killed.
273      Note we don't just put the child in a separate group as
274      then we would need to worry about foreground and background groups
275      and propagating signals between them.  */
276   setpgid (0, 0);
277
278   /* Setup handlers before fork() so that we
279      handle any signals caused by child, without races.  */
280   install_signal_handlers ();
281   signal (SIGTTIN, SIG_IGN);    /* don't sTop if background child needs tty.  */
282   signal (SIGTTOU, SIG_IGN);    /* don't sTop if background child needs tty.  */
283
284   monitored_pid = fork ();
285   if (monitored_pid == -1)
286     {
287       perror ("fork");
288       return errno;
289     }
290   else if (monitored_pid == 0)
291     {                           /* child */
292       int exit_status;
293
294       /* exec doesn't reset SIG_IGN -> SIG_DFL.  */
295       signal (SIGTTIN, SIG_DFL);
296       signal (SIGTTOU, SIG_DFL);
297
298       execvp (argv[0], argv);   /* FIXME: should we use "sh -c" ... here?  */
299
300       /* exit like sh, env, nohup, ...  */
301       exit_status = (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
302       perror (argv[0]);
303       return exit_status;
304     }
305   else
306     {
307       int status;
308
309       alarm ((unsigned int) timeout);
310
311       /* We're just waiting for a single process here, so wait() suffices.
312          Note the signal() calls above on linux and BSD at least, essentially
313          call the lower level sigaction() with the SA_RESTART flag set, which
314          ensures the following wait call will only return if the child exits,
315          not on this process receiving a signal. Also we're not passing
316          WUNTRACED | WCONTINUED to a waitpid() call and so will not get
317          indication that the child has stopped or continued.  */
318       wait (&status);
319
320       if (WIFEXITED (status))
321         status = WEXITSTATUS (status);
322       else if (WIFSIGNALED (status))
323         status = WTERMSIG (status) + 128;     /* what sh does at least.  */
324
325       if (timed_out)
326         return EXIT_TIMEDOUT;
327       else
328         return status;
329     }
330 }
331
332 /*
333  * Local variables:
334  *  indent-tabs-mode: nil
335  * End:
336  */