From df2061c420b0ca9af3f3248a249458e64d399c12 Mon Sep 17 00:00:00 2001
From: LiFeng <lifeng68@huawei.com>
Date: Mon, 14 Jan 2019 04:29:40 -0500
Subject: [PATCH 021/131] lxc-attch: add error message

Signed-off-by: LiFeng <lifeng68@huawei.com>
---
 src/lxc/attach.c           | 49 ++++++++++++++++++++++++++++++++++----
 src/lxc/attach.h           |  4 ++--
 src/lxc/attach_options.h   |  6 ++---
 src/lxc/conf.c             | 27 +++++++++++++++++----
 src/lxc/conf.h             |  3 +++
 src/lxc/lxccontainer.c     |  4 ++--
 src/lxc/tools/lxc_attach.c |  8 +++----
 src/lxc/tools/lxc_ls.c     |  4 ++--
 src/lxc/utils.c            | 21 ++++++++++++++++
 src/lxc/utils.h            |  1 +
 10 files changed, 105 insertions(+), 22 deletions(-)

diff --git a/src/lxc/attach.c b/src/lxc/attach.c
index 1886bdef..570b9d0e 100644
--- a/src/lxc/attach.c
+++ b/src/lxc/attach.c
@@ -757,10 +757,15 @@ static int attach_child_main(struct attach_clone_payload *payload)
 	gid_t ns_root_gid = 0;
 	lxc_attach_options_t* options = payload->options;
 	struct lxc_proc_context_info* init_ctx = payload->init_ctx;
+	int msg_fd = -1;
 	bool needs_lsm = (options->namespaces & CLONE_NEWNS) &&
 			 (options->attach_flags & LXC_ATTACH_LSM) &&
 			 init_ctx->lsm_label;
 
+	/*isulad: record errpipe fd*/
+	msg_fd = init_ctx->container->lxc_conf->errpipe[1];
+	init_ctx->container->lxc_conf->errpipe[1] = -1;
+
 	/* A description of the purpose of this functionality is provided in the
 	 * lxc-attach(1) manual page. We have to remount here and not in the
 	 * parent process, otherwise /proc may not properly reflect the new pid
@@ -980,7 +985,7 @@ static int attach_child_main(struct attach_clone_payload *payload)
 		goto on_error;
 
 	/* We're done, so we can now do whatever the user intended us to do. */
-	_exit(payload->exec_function(payload->exec_payload));
+	_exit(payload->exec_function(payload->exec_payload, msg_fd));
 
 on_error:
 	lxc_put_attach_clone_payload(payload);
@@ -1085,7 +1090,7 @@ static inline void lxc_attach_terminal_close_log(struct lxc_terminal *terminal)
 
 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)
+	       lxc_attach_options_t *options, pid_t *attached_process, char **err_msg)
 {
 	int i, ret, status;
 	int ipc_sockets[2];
@@ -1268,6 +1273,15 @@ int lxc_attach(const char *name, const char *lxcpath,
 		return -1;
 	}
 
+
+	/* isulad: pipdfd for get error message of child or grandchild process. */
+	if (pipe2(conf->errpipe, O_CLOEXEC) != 0) {
+		SYSERROR("Failed to init errpipe");
+		free(cwd);
+		lxc_proc_put_context_info(init_ctx);
+		return -1;
+	}
+
 	/* Create intermediate subprocess, two reasons:
 	 *       1. We can't setns() in the child itself, since we want to make
 	 *          sure we are properly attached to the pidns.
@@ -1291,6 +1305,11 @@ int lxc_attach(const char *name, const char *lxcpath,
 		/* close unneeded file descriptors */
 		close(ipc_sockets[1]);
 		free(cwd);
+
+		/* isulad: close errpipe */
+		close(conf->errpipe[1]);
+		conf->errpipe[1] = -1;
+
 		lxc_proc_close_ns_fd(init_ctx);
 		if (options->attach_flags & LXC_ATTACH_TERMINAL)
 			lxc_attach_terminal_close_slave(&terminal);
@@ -1399,6 +1418,19 @@ int lxc_attach(const char *name, const char *lxcpath,
 
 		*attached_process = attached_pid;
 
+		/* isulad: read error msg from pipe */
+		ssize_t size_read;
+		char errbuf[BUFSIZ + 1] = {0};
+
+		size_read = read(conf->errpipe[0], errbuf, BUFSIZ);
+		if (size_read > 0) {
+			if (err_msg)
+				*err_msg = strdup(errbuf);
+			if (!(*err_msg))
+				ERROR("Out of memory");
+			goto close_mainloop;
+		}
+
 		/* Now shut down communication with child, we're done. */
 		shutdown(ipc_sockets[0], SHUT_RDWR);
 		close(ipc_sockets[0]);
@@ -1439,7 +1471,11 @@ int lxc_attach(const char *name, const char *lxcpath,
 
 	/* close unneeded file descriptors */
 	close(ipc_sockets[0]);
-	ipc_sockets[0] = -EBADF;
+	ipc_sockets[0] = -EBADF;\
+
+	/* isulad: close errpipe */
+	close(conf->errpipe[0]);
+	conf->errpipe[0] = -1;
 
 	if (options->attach_flags & LXC_ATTACH_TERMINAL) {
 		lxc_attach_terminal_close_master(&terminal);
@@ -1539,7 +1575,7 @@ int lxc_attach(const char *name, const char *lxcpath,
 	_exit(0);
 }
 
-int lxc_attach_run_command(void *payload)
+int lxc_attach_run_command(void *payload, int msg_fd)
 {
 	int ret = -1;
 	lxc_attach_command_t *cmd = payload;
@@ -1556,11 +1592,14 @@ int lxc_attach_run_command(void *payload)
 		}
 	}
 
+	/* isulad: write errorm messages */
+	lxc_write_error_message(msg_fd, "exec: \"%s\": %s", cmd->program, strerror(errno));
+
 	SYSERROR("Failed to exec \"%s\"", cmd->program);
 	return ret;
 }
 
-int lxc_attach_run_shell(void* payload)
+int lxc_attach_run_shell(void* payload, int msg_fd)
 {
 	uid_t uid;
 	struct passwd pwent;
diff --git a/src/lxc/attach.h b/src/lxc/attach.h
index 4bf9578e..e62b98bc 100644
--- a/src/lxc/attach.h
+++ b/src/lxc/attach.h
@@ -42,7 +42,7 @@ struct lxc_proc_context_info {
 };
 
 extern 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);
+	       lxc_attach_exec_t exec_function, void *exec_payload,
+	       lxc_attach_options_t *options, pid_t *attached_process, char **err_msg);
 
 #endif /* __LXC_ATTACH_H */
diff --git a/src/lxc/attach_options.h b/src/lxc/attach_options.h
index 081618cd..7b0a8cb3 100644
--- a/src/lxc/attach_options.h
+++ b/src/lxc/attach_options.h
@@ -71,7 +71,7 @@ enum {
  *
  * \return Function should return \c 0 on success, and any other value to denote failure.
  */
-typedef int (*lxc_attach_exec_t)(void* payload);
+typedef int (*lxc_attach_exec_t)(void* payload, int msg_fd);
 
 /*!
  * LXC attach options for \ref lxc_container \c attach().
@@ -173,7 +173,7 @@ typedef struct lxc_attach_command_t {
  *
  * \return \c -1 on error, exit code of lxc_attach_command_t program on success.
  */
-extern int lxc_attach_run_command(void* payload);
+extern int lxc_attach_run_command(void* payload, int msg_fd);
 
 /*!
  * \brief Run a shell command in the container.
@@ -182,7 +182,7 @@ extern int lxc_attach_run_command(void* payload);
  *
  * \return Exit code of shell.
  */
-extern int lxc_attach_run_shell(void* payload);
+extern int lxc_attach_run_shell(void* payload, int msg_fd);
 
 #ifdef  __cplusplus
 }
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 537f956c..8d8230fb 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -2803,10 +2803,6 @@ struct lxc_conf *lxc_conf_init(void)
 	new->console.slave = -1;
 	new->console.name[0] = '\0';
 	memset(&new->console.ringbuf, 0, sizeof(struct lxc_ringbuf));
-	/* isulad init console fifos */
-	new->console.init_fifo[0] = NULL;
-	new->console.init_fifo[1] = NULL;
-	lxc_list_init(&new->console.fifos);
 	new->maincmd_fd = -1;
 	new->nbd_idx = -1;
 	new->rootfs.mount = strdup(default_rootfs_mount);
@@ -2851,6 +2847,14 @@ struct lxc_conf *lxc_conf_init(void)
 	lxc_list_init(&new->rootfs.maskedpaths);
 	lxc_list_init(&new->rootfs.ropaths);
 	new->exit_fd = -1;
+	/* isulad init console fifos */
+	new->console.init_fifo[0] = NULL;
+	new->console.init_fifo[1] = NULL;
+	lxc_list_init(&new->console.fifos);
+
+	new->errmsg = NULL;
+	new->errpipe[0] = -1;
+	new->errpipe[1] = -1;
 	/* isulad add end */
 
 	return new;
@@ -4280,6 +4284,19 @@ int lxc_clear_rootfs_ro_paths(struct lxc_conf *c)
 	return 0;
 }
 
+/*isulad: close error pipe */
+void lxc_close_error_pipe(int *errpipe)
+{
+	if (errpipe[0] >= 0) {
+		close(errpipe[0]);
+		errpipe[0] = -1;
+	}
+	if (errpipe[1] >= 0) {
+		close(errpipe[1]);
+		errpipe[1] = -1;
+	}
+}
+
 void lxc_conf_free(struct lxc_conf *conf)
 {
 	if (!conf)
@@ -4333,6 +4350,8 @@ void lxc_conf_free(struct lxc_conf *conf)
 	free(conf->container_info_file);
 	if (conf->exit_fd != -1)
 		close(conf->exit_fd);
+	free(conf->errmsg);
+	lxc_close_error_pipe(conf->errpipe);
 	/* isulad add end */
 	free(conf);
 }
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index 79278128..db474e11 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -413,6 +413,9 @@ struct lxc_conf {
 	char *container_info_file;
 
 	int exit_fd; /* exit fifo fd*/
+
+	char *errmsg; /* record error messages */
+	int errpipe[2];//pipdfd for get error message of child or grandchild process.
 	/* isulad add end */
 };
 
diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index 8029f339..31f4819e 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -4063,7 +4063,7 @@ static int lxcapi_attach(struct lxc_container *c, lxc_attach_exec_t exec_functio
 
 	current_config = c->lxc_conf;
 
-	ret = lxc_attach(c->name, c->config_path, exec_function, exec_payload, options, attached_process);
+	ret = lxc_attach(c->name, c->config_path, exec_function, exec_payload, options, attached_process, &c->lxc_conf->errmsg);
 	current_config = NULL;
 	return ret;
 }
@@ -4080,7 +4080,7 @@ static int do_lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options
 	command.program = (char*)program;
 	command.argv = (char**)argv;
 
-	r = lxc_attach(c->name, c->config_path, lxc_attach_run_command, &command, options, &pid);
+	r = lxc_attach(c->name, c->config_path, lxc_attach_run_command, &command, options, &pid, NULL);
 	if (r < 0) {
 		ERROR("ups");
 		return r;
diff --git a/src/lxc/tools/lxc_attach.c b/src/lxc/tools/lxc_attach.c
index 6d0ffe57..a590fd12 100644
--- a/src/lxc/tools/lxc_attach.c
+++ b/src/lxc/tools/lxc_attach.c
@@ -295,8 +295,8 @@ static int do_attach_foreground(struct lxc_container *c, lxc_attach_command_t *c
 		wexit = ExitSignalOffset + signal;
 	}
 out:
-	//if (c->lxc_conf->errmsg)
-	//	*errmsg = strdup(c->lxc_conf->errmsg);
+	if (c->lxc_conf->errmsg)
+		*errmsg = strdup(c->lxc_conf->errmsg);
 	return wexit;
 }
 
@@ -376,8 +376,8 @@ static int do_attach_background(struct lxc_container *c, lxc_attach_command_t *c
 	else
 		ret = c->attach(c, lxc_attach_run_shell, NULL, attach_options, &pid);
 	if (ret < 0) {
-		//if (c->lxc_conf->errmsg)
-		//	lxc_write_error_message(msgpipe[1], "%s", c->lxc_conf->errmsg);
+		if (c->lxc_conf->errmsg)
+			lxc_write_error_message(msgpipe[1], "%s", c->lxc_conf->errmsg);
 		close(msgpipe[1]);
 		msgpipe[1] = -1;
 		ret = -1;
diff --git a/src/lxc/tools/lxc_ls.c b/src/lxc/tools/lxc_ls.c
index cb3eb1e5..e261c7bf 100644
--- a/src/lxc/tools/lxc_ls.c
+++ b/src/lxc/tools/lxc_ls.c
@@ -122,7 +122,7 @@ struct wrapargs {
 /*
  * Takes struct wrapargs as argument.
  */
-static int ls_get_wrapper(void *wrap);
+static int ls_get_wrapper(void *wrap, int msgfd);
 
 /*
  * To calculate swap usage we should not simply check memory.usage_in_bytes and
@@ -1023,7 +1023,7 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg)
 	return 0;
 }
 
-static int ls_get_wrapper(void *wrap)
+static int ls_get_wrapper(void *wrap, int msgfd)
 {
 	int ret = -1;
 	size_t len = 0;
diff --git a/src/lxc/utils.c b/src/lxc/utils.c
index 74e74a15..8ec9f461 100644
--- a/src/lxc/utils.c
+++ b/src/lxc/utils.c
@@ -1971,3 +1971,24 @@ out:
 	return startat;
 }
 
+/* isulad: write error message */
+void lxc_write_error_message(int errfd, const char *format, ...)
+{
+	int ret;
+	char errbuf[BUFSIZ + 1] = {0};
+	ssize_t sret;
+	va_list argp;
+
+	if (errfd <= 0)
+		return;
+
+	va_start(argp, format);
+	ret = vsnprintf(errbuf, BUFSIZ, format, argp);
+	va_end(argp);
+	if (ret < 0)
+		SYSERROR("Failed to call vsnprintf");
+	sret = write(errfd, errbuf, strlen(errbuf));
+	if (sret < 0)
+		SYSERROR("Write errbuf failed");
+}
+
diff --git a/src/lxc/utils.h b/src/lxc/utils.h
index 364bf672..3d56fd93 100644
--- a/src/lxc/utils.h
+++ b/src/lxc/utils.h
@@ -314,5 +314,6 @@ extern int lxc_setup_env_home(uid_t uid);
 
 extern int fd_nonblock(int fd);
 extern int unsigned long long lxc_get_process_startat(pid_t pid);
+extern void lxc_write_error_message(int errfd, const char *format, ...);
 
 #endif /* __LXC_UTILS_H */
-- 
2.23.0

