1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 * COPYING NOTES 3 * 4 * timeout.c -- a timeout handler for shell commands 5 * 6 * Copyright (C) 2005-6, Roberto A. Foglietta <me@roberto.foglietta.name> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; version 2 of the License. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. 20 */ 21/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 22 * REVISION NOTES: 23 * released 17-11-2005 by Roberto A. Foglietta 24 * talarm 04-12-2005 by Roberto A. Foglietta 25 * modified 05-12-2005 by Roberto A. Foglietta 26 * sizerdct 06-12-2005 by Roberto A. Foglietta 27 * splitszf 12-05-2006 by Roberto A. Foglietta 28 * rewrite 14-11-2008 vda 29 */ 30 31#include "libbb.h" 32 33int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 34int timeout_main(int argc UNUSED_PARAM, char **argv) 35{ 36 int signo; 37 int status; 38 int parent = 0; 39 int timeout = 10; 40 pid_t pid; 41#if !BB_MMU 42 char *sv1, *sv2; 43#endif 44 const char *opt_s = "TERM"; 45 46 /* -p option is not documented, it is needed to support NOMMU. */ 47 48 /* -t SECONDS; -p PARENT_PID */ 49 opt_complementary = "t+" USE_FOR_NOMMU(":p+"); 50 /* '+': stop at first non-option */ 51 getopt32(argv, "+s:t:" USE_FOR_NOMMU("p:"), &opt_s, &timeout, &parent); 52 /*argv += optind; - no, wait for bb_daemonize_or_rexec! */ 53 signo = get_signum(opt_s); 54 if (signo < 0) 55 bb_error_msg_and_die("unknown signal '%s'", opt_s); 56 57 /* We want to create a grandchild which will watch 58 * and kill the grandparent. Other methods: 59 * making parent watch child disrupts parent<->child link 60 * (example: "tcpsvd 0.0.0.0 1234 timeout service_prog" - 61 * it's better if service_prog is a child of tcpsvd!), 62 * making child watch parent results in programs having 63 * unexpected children. */ 64 65 if (parent) /* we were re-execed, already grandchild */ 66 goto grandchild; 67 if (!argv[optind]) /* no PROG? */ 68 bb_show_usage(); 69 70#if !BB_MMU 71 sv1 = argv[optind]; 72 sv2 = argv[optind + 1]; 73#endif 74 pid = xvfork(); 75 if (pid == 0) { 76 /* Child: spawn grandchild and exit */ 77 parent = getppid(); 78#if !BB_MMU 79 argv[optind] = xasprintf("-p%u", parent); 80 argv[optind + 1] = NULL; 81#endif 82 /* NB: exits with nonzero on error: */ 83 bb_daemonize_or_rexec(0, argv); 84 /* Here we are grandchild. Sleep, then kill grandparent */ 85 grandchild: 86 /* Just sleep(NUGE_NUM); kill(parent) may kill wrong process! */ 87 while (1) { 88 sleep(1); 89 if (--timeout <= 0) 90 break; 91 if (kill(parent, 0)) { 92 /* process is gone */ 93 return EXIT_SUCCESS; 94 } 95 } 96 kill(parent, signo); 97 return EXIT_SUCCESS; 98 } 99 100 /* Parent */ 101 wait(&status); /* wait for child to die */ 102 /* Did intermediate [v]fork or exec fail? */ 103 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 104 return EXIT_FAILURE; 105 /* Ok, exec a program as requested */ 106 argv += optind; 107#if !BB_MMU 108 argv[0] = sv1; 109 argv[1] = sv2; 110#endif 111 BB_EXECVP_or_die(argv); 112} 113