From 7ac4cd6176a273a8e7cd146fd189dc2e07d582c8 Mon Sep 17 00:00:00 2001
From: tanyifeng <tanyifeng1@huawei.com>
Date: Wed, 3 Apr 2019 19:54:36 +0800
Subject: [PATCH 075/131] lxc: add timeout for attach

Signed-off-by: wujing <wujing50@huawei.com>
Signed-off-by: LiFeng <lifeng68@huawei.com>
---
 src/lxc/attach.c           | 79 ++++++++++++++++++++++++++++++++++++++
 src/lxc/attach_options.h   |  1 +
 src/lxc/tools/arguments.h  |  4 ++
 src/lxc/tools/lxc_attach.c | 11 ++++++
 src/lxc/tools/lxc_start.c  | 13 +------
 src/lxc/utils.c            | 13 +++++++
 src/lxc/utils.h            |  2 +
 7 files changed, 111 insertions(+), 12 deletions(-)

diff --git a/src/lxc/attach.c b/src/lxc/attach.c
index 618f2f1c..79049c3d 100644
--- a/src/lxc/attach.c
+++ b/src/lxc/attach.c
@@ -69,6 +69,20 @@
 #include <sys/personality.h>
 #endif
 
+typedef enum {
+	ATTACH_INIT,
+	ATTACH_TIMEOUT,
+	ATTACH_MAX,
+} attach_timeout_t;
+
+static volatile attach_timeout_t g_attach_timeout_state = ATTACH_INIT;
+
+struct attach_timeout_conf {
+	unsigned int timeout;
+	unsigned long long start_time;
+	pid_t pid;
+};
+
 lxc_log_define(attach, lxc);
 
 /* Define default options if no options are supplied by the user. */
@@ -1145,6 +1159,59 @@ static inline void lxc_attach_terminal_close_log(struct lxc_terminal *terminal)
 	terminal->log_fd = -EBADF;
 }
 
+/* isulad: attach timeout thread function */
+static void* wait_attach_timeout(void *arg)
+{
+	struct attach_timeout_conf *conf = (struct attach_timeout_conf *)arg;
+
+	if (!conf || conf->timeout < 1)
+		goto out;
+	sleep(conf->timeout);
+	if (lxc_process_alive(conf->pid, conf->start_time)) {
+		g_attach_timeout_state = ATTACH_TIMEOUT;
+		if (kill(conf->pid, SIGKILL) < 0) {
+			ERROR("Failed to send signal %d to pid %d", SIGKILL, conf->pid);
+		}
+	}
+
+out:
+	free(conf);
+	return ((void *)0);
+}
+
+/* isulad: create attach timeout thread */
+static int create_attach_timeout_thread(unsigned int attach_timeout, pid_t pid)
+{
+	int ret = 0;
+	pthread_t ptid;
+	pthread_attr_t attr;
+	struct attach_timeout_conf *timeout_conf = NULL;
+
+	timeout_conf = malloc(sizeof(struct attach_timeout_conf));
+	if (!timeout_conf) {
+		ERROR("Failed to malloc attach timeout conf");
+		ret = -1;
+		goto out;
+	}
+
+	memset(timeout_conf, 0, sizeof(struct attach_timeout_conf));
+	timeout_conf->timeout = attach_timeout;
+	timeout_conf->pid = pid;
+	timeout_conf->start_time = lxc_get_process_startat(pid);
+
+	pthread_attr_init(&attr);
+	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+	ret = pthread_create(&ptid, &attr, wait_attach_timeout, timeout_conf);
+	if (ret != 0) {
+		ERROR("Create attach wait timeout thread failed");
+		free(timeout_conf);
+		goto out;
+	}
+
+out:
+	return ret;
+}
+
 int lxc_attach(const char *name, const char *lxcpath,
 	       lxc_attach_exec_t exec_function, void *exec_payload,
 	       lxc_attach_options_t *options, pid_t *attached_process, char **err_msg)
@@ -1481,6 +1548,13 @@ int lxc_attach(const char *name, const char *lxcpath,
 
 		*attached_process = attached_pid;
 
+		if (options->timeout > 0) {
+			ret = create_attach_timeout_thread(options->timeout, *attached_process);
+			if (ret) {
+				ERROR("Failed to create attach timeout thread for container.");
+				goto close_mainloop;
+			}
+		}
 		/* isulad: read error msg from pipe */
 		ssize_t size_read;
 		char errbuf[BUFSIZ + 1] = {0};
@@ -1510,6 +1584,11 @@ int lxc_attach(const char *name, const char *lxcpath,
 			}
 		}
 
+		if (g_attach_timeout_state == ATTACH_TIMEOUT && err_msg != NULL && *err_msg == NULL) {
+			*err_msg = strdup("Attach exceeded timeout");
+			if (!(*err_msg))
+				ERROR("Out of memory");
+		}
 	close_mainloop:
 		if (options->attach_flags & LXC_ATTACH_TERMINAL)
 			lxc_mainloop_close(&descr);
diff --git a/src/lxc/attach_options.h b/src/lxc/attach_options.h
index 71c1739d..5e279baf 100644
--- a/src/lxc/attach_options.h
+++ b/src/lxc/attach_options.h
@@ -137,6 +137,7 @@ typedef struct lxc_attach_options_t {
 	int log_fd;
 
 	char *init_fifo[3]; /* isulad: default fifos for the start */
+	unsigned int timeout;/* isulad: Seconds for waiting on a container to attach/exec before it is killed*/
 } lxc_attach_options_t;
 
 /*! Default attach options to use */
diff --git a/src/lxc/tools/arguments.h b/src/lxc/tools/arguments.h
index d03f8a42..2fc90ad9 100644
--- a/src/lxc/tools/arguments.h
+++ b/src/lxc/tools/arguments.h
@@ -69,6 +69,9 @@ struct lxc_arguments {
 	const char *exit_monitor_fifo; /* isulad: fifo used to monitor state of monitor process */
 	unsigned int start_timeout; /* isulad: Seconds for waiting on a container to start before it is killed*/
 
+	/* for lxc-attach */
+	unsigned int attach_timeout;
+
 	/* for lxc-console */
 	unsigned int ttynum;
 	char escape;
@@ -187,6 +190,7 @@ struct lxc_arguments {
 #define OPT_START_TIMEOUT OPT_USAGE - 12
 #define OPT_DISABLE_PTY OPT_USAGE - 13
 #define OPT_OPEN_STDIN OPT_USAGE - 14
+#define OPT_ATTACH_TIMEOUT OPT_USAGE - 15
 
 /* isulad add end*/
 
diff --git a/src/lxc/tools/lxc_attach.c b/src/lxc/tools/lxc_attach.c
index 674050de..2861ef4d 100644
--- a/src/lxc/tools/lxc_attach.c
+++ b/src/lxc/tools/lxc_attach.c
@@ -62,6 +62,7 @@ static char **extra_env;
 static ssize_t extra_env_size;
 static char **extra_keep;
 static ssize_t extra_keep_size;
+static unsigned int timeout = 0;
 
 static const struct option my_longopts[] = {
 	{"elevated-privileges", optional_argument, 0, 'e'},
@@ -78,6 +79,7 @@ static const struct option my_longopts[] = {
 	{"in-fifo", required_argument, 0, OPT_INPUT_FIFO}, /* isulad add terminal fifos*/
 	{"out-fifo", required_argument, 0, OPT_OUTPUT_FIFO},
 	{"err-fifo", required_argument, 0, OPT_STDERR_FIFO},
+	{"timeout", required_argument, 0, OPT_ATTACH_TIMEOUT},
 	LXC_COMMON_OPTIONS
 };
 
@@ -128,6 +130,7 @@ Options :\n\
                     multiple times.\n\
   -f, --rcfile=FILE\n\
                     Load configuration file FILE\n\
+        --timeout   Timeout in seconds (default: 0)\n\
 ",
 	.options      = my_longopts,
 	.parser       = my_parser,
@@ -205,6 +208,13 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg)
 	case OPT_STDERR_FIFO:
 		args->terminal_fifos[2] = arg;
 		break;
+	case OPT_ATTACH_TIMEOUT:
+		if(!is_non_negative_num(arg)) {
+			ERROR("Error attach timeout parameter:%s.\n", arg);
+			return -1;
+		}
+		args->attach_timeout = (unsigned int)atoi(arg);
+		break;
 	}
 
 	return 0;
@@ -478,6 +488,7 @@ int main(int argc, char *argv[])
 	attach_options.env_policy = env_policy;
 	attach_options.extra_env_vars = extra_env;
 	attach_options.extra_keep_env = extra_keep;
+	attach_options.timeout = my_args.attach_timeout;
 
 	if (my_args.argc > 0) {
 		command.program = my_args.argv[0];
diff --git a/src/lxc/tools/lxc_start.c b/src/lxc/tools/lxc_start.c
index 183fafcb..af63f581 100644
--- a/src/lxc/tools/lxc_start.c
+++ b/src/lxc/tools/lxc_start.c
@@ -49,6 +49,7 @@
 #include "config.h"
 #include "confile.h"
 #include "log.h"
+#include "utils.h"
 
 lxc_log_define(lxc_start, lxc);
 
@@ -113,18 +114,6 @@ Options :\n\
 	.pidfile      = NULL,
 };
 
-static bool is_non_negative_num(const char *s)
-{
-	if (!s || !strcmp(s, ""))
-		return false;
-	while(*s  != '\0') {
-		if(!isdigit(*s))
-			return false;
-		++s;
-	}
-	return true;
-}
-
 static int my_parser(struct lxc_arguments *args, int c, char *arg)
 {
 	switch (c) {
diff --git a/src/lxc/utils.c b/src/lxc/utils.c
index 480e6d0a..69eb3e52 100644
--- a/src/lxc/utils.c
+++ b/src/lxc/utils.c
@@ -2069,3 +2069,16 @@ out:
 	free(pid_info);
 	return alive;
 }
+
+bool is_non_negative_num(const char *s)
+{
+	if (!s || !strcmp(s, ""))
+		return false;
+	while(*s  != '\0') {
+		if(!isdigit(*s))
+			return false;
+		++s;
+	}
+	return true;
+}
+
diff --git a/src/lxc/utils.h b/src/lxc/utils.h
index 73ffdd97..20407af8 100644
--- a/src/lxc/utils.h
+++ b/src/lxc/utils.h
@@ -322,4 +322,6 @@ extern void lxc_write_error_message(int errfd, const char *format, ...);
 
 extern bool lxc_process_alive(pid_t pid, unsigned long long start_time);
 
+extern bool is_non_negative_num(const char *s);
+
 #endif /* __LXC_UTILS_H */
-- 
2.23.0

