Ver Fonte

Implement a timeout in run_external_process

Marc Di Luzio há 6 anos atrás
pai
commit
e9ff2cbb10
1 ficheiros alterados com 32 adições e 0 exclusões
  1. 32 0
      daemon/external-helper.c

+ 32 - 0
daemon/external-helper.c

@@ -37,6 +37,7 @@ POSSIBILITY OF SUCH DAMAGE.
 #include <linux/limits.h>
 #include <stdio.h>
 #include <sys/wait.h>
+#include <time.h>
 #include <unistd.h>
 
 /**
@@ -47,6 +48,16 @@ int run_external_process(const char *const *exec_args)
 	pid_t p;
 	int status = 0;
 
+	/* set up our signaling for the child and the timout */
+	sigset_t mask;
+	sigset_t omask;
+	sigemptyset(&mask);
+	sigaddset(&mask, SIGCHLD);
+	if (sigprocmask(SIG_BLOCK, &mask, &omask) < 0) {
+		LOG_ERROR("sigprocmask failed: %s\n", strerror(errno));
+		return -1;
+	}
+
 	if ((p = fork()) < 0) {
 		LOG_ERROR("Failed to fork(): %s\n", strerror(errno));
 		return false;
@@ -65,6 +76,27 @@ int run_external_process(const char *const *exec_args)
 		_exit(EXIT_SUCCESS);
 	}
 
+	/* Set up the timout */
+	struct timespec timeout;
+	timeout.tv_sec = 5; /* Magic timeout value of 5s for now - should be sane for most commands */
+	timeout.tv_nsec = 0;
+
+	/* Wait for the child to finish up with a timout */
+	while (true) {
+		if (sigtimedwait(&mask, NULL, &timeout) < 0) {
+			if (errno == EINTR) {
+				continue;
+			} else if (errno == EAGAIN) {
+				LOG_ERROR("Child process timed out for %s, killing and returning\n", exec_args[0]);
+				kill(p, SIGKILL);
+			} else {
+				LOG_ERROR("sigtimedwait failed: %s\n", strerror(errno));
+				return -1;
+			}
+		}
+		break;
+	}
+
 	if (waitpid(p, &status, 0) < 0) {
 		LOG_ERROR("Failed to waitpid(%d): %s\n", (int)p, strerror(errno));
 		return -1;