timeout: add support for "timeout -k KILL_SECS"
function old new delta timeout_main 307 373 +66 timeout_wait - 42 +42 .rodata 104201 104203 +2 packed_usage 34097 34096 -1 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 2/1 up/down: 110/-1) Total: 109 bytes Signed-off-by: Matthew Slowe <foo@mafoo.org.uk> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
		
				
					committed by
					
						
						Denys Vlasenko
					
				
			
			
				
	
			
			
			
						parent
						
							c1eac153e8
						
					
				
				
					commit
					7d49fedc86
				
			@@ -39,13 +39,29 @@
 | 
			
		||||
//kbuild:lib-$(CONFIG_TIMEOUT) += timeout.o
 | 
			
		||||
 | 
			
		||||
//usage:#define timeout_trivial_usage
 | 
			
		||||
//usage:       "[-s SIG] SECS PROG ARGS"
 | 
			
		||||
//usage:       "[-s SIG] [-k KILL_SECS] SECS PROG ARGS"
 | 
			
		||||
//usage:#define timeout_full_usage "\n\n"
 | 
			
		||||
//usage:       "Run PROG. Send SIG to it if it is not gone in SECS seconds.\n"
 | 
			
		||||
//usage:       "Default SIG: TERM."
 | 
			
		||||
//usage:       "If it still exists in KILL_SECS seconds, send KILL.\n"
 | 
			
		||||
 | 
			
		||||
#include "libbb.h"
 | 
			
		||||
 | 
			
		||||
static NOINLINE int timeout_wait(int timeout, pid_t pid)
 | 
			
		||||
{
 | 
			
		||||
	/* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */
 | 
			
		||||
	while (1) {
 | 
			
		||||
		sleep1();
 | 
			
		||||
		if (--timeout <= 0)
 | 
			
		||||
			break;
 | 
			
		||||
		if (kill(pid, 0)) {
 | 
			
		||||
			/* process is gone */
 | 
			
		||||
			return EXIT_SUCCESS;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return EXIT_FAILURE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 | 
			
		||||
int timeout_main(int argc UNUSED_PARAM, char **argv)
 | 
			
		||||
{
 | 
			
		||||
@@ -53,23 +69,29 @@ int timeout_main(int argc UNUSED_PARAM, char **argv)
 | 
			
		||||
	int status;
 | 
			
		||||
	int parent = 0;
 | 
			
		||||
	int timeout;
 | 
			
		||||
	int kill_timeout;
 | 
			
		||||
	pid_t pid;
 | 
			
		||||
#if !BB_MMU
 | 
			
		||||
	char *sv1, *sv2;
 | 
			
		||||
#endif
 | 
			
		||||
	const char *opt_s = "TERM";
 | 
			
		||||
	char *opt_k = NULL;
 | 
			
		||||
 | 
			
		||||
	/* -p option is not documented, it is needed to support NOMMU. */
 | 
			
		||||
 | 
			
		||||
	/* -t SECONDS; -p PARENT_PID */
 | 
			
		||||
	/* '+': stop at first non-option */
 | 
			
		||||
	getopt32(argv, "+s:" USE_FOR_NOMMU("p:+"), &opt_s, &parent);
 | 
			
		||||
	getopt32(argv, "+s:k:" USE_FOR_NOMMU("p:+"), &opt_s, &opt_k, &parent);
 | 
			
		||||
	/*argv += optind; - no, wait for bb_daemonize_or_rexec! */
 | 
			
		||||
 | 
			
		||||
	signo = get_signum(opt_s);
 | 
			
		||||
	if (signo < 0)
 | 
			
		||||
		bb_error_msg_and_die("unknown signal '%s'", opt_s);
 | 
			
		||||
 | 
			
		||||
	kill_timeout = 0;
 | 
			
		||||
	if (opt_k)
 | 
			
		||||
		kill_timeout = parse_duration_str(opt_k);
 | 
			
		||||
 | 
			
		||||
	if (!argv[optind])
 | 
			
		||||
		bb_show_usage();
 | 
			
		||||
	timeout = parse_duration_str(argv[optind++]);
 | 
			
		||||
@@ -103,17 +125,16 @@ int timeout_main(int argc UNUSED_PARAM, char **argv)
 | 
			
		||||
		bb_daemonize_or_rexec(0, argv);
 | 
			
		||||
		/* Here we are grandchild. Sleep, then kill grandparent */
 | 
			
		||||
 grandchild:
 | 
			
		||||
		/* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */
 | 
			
		||||
		while (1) {
 | 
			
		||||
			sleep1();
 | 
			
		||||
			if (--timeout <= 0)
 | 
			
		||||
				break;
 | 
			
		||||
			if (kill(parent, 0)) {
 | 
			
		||||
				/* process is gone */
 | 
			
		||||
		if (timeout_wait(timeout, parent) == EXIT_SUCCESS)
 | 
			
		||||
			return EXIT_SUCCESS;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		kill(parent, signo);
 | 
			
		||||
 | 
			
		||||
		if (kill_timeout > 0) {
 | 
			
		||||
			if (timeout_wait(kill_timeout, parent) == EXIT_SUCCESS)
 | 
			
		||||
				return EXIT_SUCCESS;
 | 
			
		||||
			kill(parent, SIGKILL);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return EXIT_SUCCESS;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user