From 0032e0ea93b38d9f869683ac08328ab1ca029f4d Mon Sep 17 00:00:00 2001
From: tanyifeng <tanyifeng1@huawei.com>
Date: Wed, 16 Jan 2019 14:38:38 +0800
Subject: [PATCH 039/131] print error message when container start failed

Signed-off-by: tanyifeng <tanyifeng1@huawei.com>
Signed-off-by: LiFeng <lifeng68@huawei.com>
---
 src/lxc/attach.c          |   6 +-
 src/lxc/cgroups/cgfsng.c  |  22 +++++--
 src/lxc/cgroups/cgroup.c  |   4 +-
 src/lxc/cgroups/cgroup.h  |   2 +
 src/lxc/conf.c            | 122 ++++++++++++++++++++++----------------
 src/lxc/conf.h            |   5 +-
 src/lxc/execute.c         |   3 +-
 src/lxc/lxccontainer.c    |  37 +++++++++++-
 src/lxc/start.c           |  14 +++--
 src/lxc/start.h           |   2 +-
 src/lxc/tools/lxc_start.c |   3 +
 11 files changed, 147 insertions(+), 73 deletions(-)

diff --git a/src/lxc/attach.c b/src/lxc/attach.c
index 4ccdd74b..b44ea746 100644
--- a/src/lxc/attach.c
+++ b/src/lxc/attach.c
@@ -1396,7 +1396,7 @@ int lxc_attach(const char *name, const char *lxcpath,
 
 		/* Setup resource limits */
 		if (!lxc_list_empty(&conf->limits)) {
-			ret = setup_resource_limits(&conf->limits, pid);
+			ret = setup_resource_limits(&conf->limits, pid, -1);
 			if (ret < 0)
 				goto on_error;
 		}
@@ -1650,8 +1650,8 @@ int lxc_attach_run_command(void *payload, int msg_fd)
 		}
 	}
 
-	/* isulad: write errorm messages */
-	lxc_write_error_message(msg_fd, "exec: \"%s\": %s", cmd->program, strerror(errno));
+	/* isulad: write error messages */
+	lxc_write_error_message(msg_fd, "exec: \"%s\": %s.", cmd->program, strerror(errno));
 
 	SYSERROR("Failed to exec \"%s\"", cmd->program);
 	return ret;
diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c
index bc1481d4..47b12a64 100644
--- a/src/lxc/cgroups/cgfsng.c
+++ b/src/lxc/cgroups/cgfsng.c
@@ -1236,7 +1236,7 @@ static int mkdir_eexist_on_last(const char *dir, mode_t mode)
 	return 0;
 }
 
-static bool create_path_for_hierarchy(struct hierarchy *h, char *cgname)
+static bool create_path_for_hierarchy(struct hierarchy *h, char *cgname, int errfd)
 {
 	int ret;
 
@@ -1244,8 +1244,8 @@ static bool create_path_for_hierarchy(struct hierarchy *h, char *cgname)
 
 	if (file_exists(h->container_full_path)) { // it must not already exist
 		ERROR("Cgroup path \"%s\" already exist.", h->container_full_path);
-		//lxc_write_error_message(errfd, "%s:%d: Cgroup path \"%s\" already exist.",
-		//	__FILE__, __LINE__, h->fullcgpath);
+		lxc_write_error_message(errfd, "%s:%d: Cgroup path \"%s\" already exist.",
+			__FILE__, __LINE__, h->container_full_path);
 		return false;
 	}
 
@@ -1288,7 +1288,7 @@ __cgfsng_ops static bool cgfsng_payload_create(struct cgroup_ops *ops,
 	}
 
 	for (i = 0; ops->hierarchies[i]; i++) {
-		if (!create_path_for_hierarchy(ops->hierarchies[i], container_cgroup)) {
+		if (!create_path_for_hierarchy(ops->hierarchies[i], container_cgroup, ops->errfd)) {
 			SYSERROR("Failed to create %s", ops->hierarchies[i]->container_full_path);
 			return false;
 		}
@@ -2203,6 +2203,11 @@ static int cg_legacy_set_data(struct cgroup_ops *ops, const char *filename,
 
 	fullpath = must_make_path(h->container_full_path, filename, NULL);
 	ret = lxc_write_to_file(fullpath, value, strlen(value), false, 0666);
+	if (ret) {
+		lxc_write_error_message(ops->errfd,
+			"%s:%d: setting cgroup config for ready process caused \"failed to write %s to %s: %s\".",
+			__FILE__, __LINE__, value, fullpath, strerror(errno));
+	}
 	free(fullpath);
 	return ret;
 }
@@ -2294,9 +2299,15 @@ static bool __cg_legacy_setup_limits(struct cgroup_ops *ops,
 			}
 			if (setvalue > readvalue) {
 				ERROR("The maximum allowed cpu-shares is %s", value);
+				lxc_write_error_message(ops->errfd,
+					"%s:%d: setting cgroup config for ready process caused \"The maximum allowed cpu-shares is %s\".",
+					__FILE__, __LINE__, value);
 				goto out;
 			} else if (setvalue < readvalue) {
 				ERROR("The minimum allowed cpu-shares is %s", value);
+				lxc_write_error_message(ops->errfd,
+					"%s:%d: setting cgroup config for ready process caused \"The minimum allowed cpu-shares is %s\".",
+					__FILE__, __LINE__, value);
 				goto out;
 			}
 		}
@@ -2699,7 +2710,7 @@ __cgfsng_ops static bool cgfsng_data_init(struct cgroup_ops *ops, struct lxc_han
 	return true;
 }
 
-struct cgroup_ops *cgfsng_ops_init(void)
+struct cgroup_ops *cgfsng_ops_init(int errfd)
 {
 	struct cgroup_ops *cgfsng_ops;
 
@@ -2715,6 +2726,7 @@ struct cgroup_ops *cgfsng_ops_init(void)
 		return NULL;
 	}
 
+	cgfsng_ops->errfd = errfd;
 	cgfsng_ops->data_init = cgfsng_data_init;
 	cgfsng_ops->destroy = cgfsng_payload_destroy;
 	cgfsng_ops->payload_create = cgfsng_payload_create;
diff --git a/src/lxc/cgroups/cgroup.c b/src/lxc/cgroups/cgroup.c
index 8e7aef96..7442c310 100644
--- a/src/lxc/cgroups/cgroup.c
+++ b/src/lxc/cgroups/cgroup.c
@@ -38,13 +38,13 @@
 
 lxc_log_define(cgroup, lxc);
 
-extern struct cgroup_ops *cgfsng_ops_init(void);
+extern struct cgroup_ops *cgfsng_ops_init(int errfd);
 
 struct cgroup_ops *cgroup_init(struct lxc_handler *handler)
 {
 	struct cgroup_ops *cgroup_ops;
 
-	cgroup_ops = cgfsng_ops_init();
+	cgroup_ops = cgfsng_ops_init(handler->conf->errpipe[1]);
 	if (!cgroup_ops) {
 		ERROR("Failed to initialize cgroup driver");
 		return NULL;
diff --git a/src/lxc/cgroups/cgroup.h b/src/lxc/cgroups/cgroup.h
index fa4871ed..b6116f68 100644
--- a/src/lxc/cgroups/cgroup.h
+++ b/src/lxc/cgroups/cgroup.h
@@ -92,6 +92,8 @@ struct cgroup_ops {
 	char **cgroup_use;
 	char *cgroup_pattern;
 	char *container_cgroup;
+	/* isulad: errfd */
+	int errfd;
 
 	/* @hierarchies
 	 * - A NULL-terminated array of struct hierarchy, one per legacy
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 88cebfd5..8fa63f7c 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -2414,6 +2414,8 @@ static int mount_entry_create_dir_file(const struct mntent *mntent,
 		ret = mkdir_p(path, 0755);
 		if (ret < 0 && errno != EEXIST) {
 			SYSERROR("Failed to create directory \"%s\"", path);
+			lxc_write_error_message(rootfs->errfd, "%s:%d: mkdir %s: %s.",
+				__FILE__, __LINE__, path, strerror(errno));
 			return -1;
 		}
 	}
@@ -2435,12 +2437,17 @@ static int mount_entry_create_dir_file(const struct mntent *mntent,
 	free(p1);
 	if (ret < 0 && errno != EEXIST) {
 		SYSERROR("Failed to create directory \"%s\"", path);
+		lxc_write_error_message(rootfs->errfd, "%s:%d: mkdir %s: %s.",
+				__FILE__, __LINE__, p2, strerror(errno));
 		return -1;
 	}
 
 	ret = mknod(path, S_IFREG | 0000, 0);
-	if (ret < 0 && errno != EEXIST)
+	if (ret < 0 && errno != EEXIST) {
+		lxc_write_error_message(rootfs->errfd, "%s:%d: open %s: %s.",
+				__FILE__, __LINE__, path, strerror(errno));
 		return -errno;
+	}
 
 	return 0;
 }
@@ -2550,7 +2557,9 @@ static inline int mount_entry_on_generic(struct mntent *mntent,
 	if (rootfs_path) {
 		rpath = follow_symlink_in_scope(path, rootfs_path);
 		if (!rpath) {
-			ERROR("Failed to get real path for '%s'", path);
+			ERROR("Failed to get real path of '%s' in scope '%s'.", path, rootfs_path);
+			lxc_write_error_message(rootfs->errfd, "%s:%d: failed to get real path of '%s' in scope '%s'.",
+				__FILE__, __LINE__, path, rootfs_path);
 			return -1;
 		}
 		dest = rpath;
@@ -2558,6 +2567,8 @@ static inline int mount_entry_on_generic(struct mntent *mntent,
 		ret = check_mount_destination(rootfs_path, dest);
 		if (ret) {
 			ERROR("Mount destination is invalid: '%s'", dest);
+			lxc_write_error_message(rootfs->errfd, "%s:%d: mount destination is invalid: '%s'.",
+				__FILE__, __LINE__, dest);
 			free(rpath);
 			return -1;
 		}
@@ -2587,6 +2598,10 @@ static inline int mount_entry_on_generic(struct mntent *mntent,
 		ret = mount_entry(mntent->mnt_fsname, dest, mntent->mnt_type, mntflags,
 				  pflags, mntdata, optional, dev, relative, rootfs_path);
 	}
+	if (ret < 0) {
+		lxc_write_error_message(rootfs->errfd, "%s:%d: failed to mount %s as type %s.",
+				__FILE__, __LINE__, mntent->mnt_fsname, mntent->mnt_type);
+	}
 
 	free(mntdata);
 	free(rpath);
@@ -2949,7 +2964,7 @@ static int parse_resource(const char *res)
 	return resid;
 }
 
-int setup_resource_limits(struct lxc_list *limits, pid_t pid)
+int setup_resource_limits(struct lxc_list *limits, pid_t pid, int errfd)
 {
 	int resid;
 	struct lxc_list *it;
@@ -2966,7 +2981,10 @@ int setup_resource_limits(struct lxc_list *limits, pid_t pid)
 
 #if HAVE_PRLIMIT || HAVE_PRLIMIT64
 		if (prlimit(pid, resid, &lim->limit, NULL) != 0) {
-			SYSERROR("Failed to set limit %s", lim->resource);
+			SYSERROR("Failed to set limit %s %lu %lu.", lim->resource, lim->limit.rlim_cur, lim->limit.rlim_max);
+			lxc_write_error_message(errfd, "%s:%d: Failed to set limit %s %lu %lu: %s.",
+					__FILE__, __LINE__, lim->resource,
+					lim->limit.rlim_cur, lim->limit.rlim_max, strerror(errno));
 			return -1;
 		}
 
@@ -3989,6 +4007,8 @@ int lxc_setup(struct lxc_handler *handler)
 	ret = lxc_setup_rootfs_prepare_root(lxc_conf, name, lxcpath);
 	if (ret < 0) {
 		ERROR("Failed to setup rootfs");
+		lxc_write_error_message(lxc_conf->errpipe[1], "%s:%d: failed to setup rootfs %s.",
+				__FILE__, __LINE__, lxc_conf->rootfs.path);
 		return -1;
 	}
 
@@ -3996,31 +4016,31 @@ int lxc_setup(struct lxc_handler *handler)
 		ret = setup_utsname(lxc_conf->utsname);
 		if (ret < 0) {
 			ERROR("Failed to setup the utsname %s", name);
-			return -1;
+			goto on_error;
 		}
 	}
 
 	ret = lxc_setup_keyring();
 	if (ret < 0)
-		return -1;
+		goto on_error;
 
 	ret = lxc_setup_network_in_child_namespaces(lxc_conf, &lxc_conf->network);
 	if (ret < 0) {
 		ERROR("Failed to setup network");
-		return -1;
+		goto on_error;
 	}
 
 	ret = lxc_network_send_name_and_ifindex_to_parent(handler);
 	if (ret < 0) {
 		ERROR("Failed to send network device names and ifindices to parent");
-		return -1;
+		goto on_error;
 	}
 
 	if (lxc_conf->autodev > 0) {
 		ret = mount_autodev(name, &lxc_conf->rootfs, lxcpath);
 		if (ret < 0) {
 			ERROR("Failed to mount \"/dev\"");
-			return -1;
+			goto on_error;
 		}
 	}
 
@@ -4030,13 +4050,14 @@ int lxc_setup(struct lxc_handler *handler)
 	ret = lxc_mount_auto_mounts(lxc_conf, lxc_conf->auto_mounts & ~LXC_AUTO_CGROUP_MASK, handler);
 	if (ret < 0) {
 		ERROR("Failed to setup first automatic mounts");
-		return -1;
+		goto on_error;
 	}
 
+	lxc_conf->rootfs.errfd = lxc_conf->errpipe[1];
 	ret = setup_mount(lxc_conf, &lxc_conf->rootfs, lxc_conf->fstab, name, lxcpath);
 	if (ret < 0) {
 		ERROR("Failed to setup mounts");
-		return -1;
+		goto on_error;
 	}
 
 	if (lxc_conf->is_execute) {
@@ -4047,13 +4068,13 @@ int lxc_setup(struct lxc_handler *handler)
 			ret = snprintf(path, PATH_MAX, SBINDIR "/init.lxc.static");
 			if (ret < 0 || ret >= PATH_MAX) {
 				ERROR("Path to init.lxc.static too long");
-				return -1;
+				goto on_error;
 			}
 
 			fd = open(path, O_PATH | O_CLOEXEC);
 			if (fd < 0) {
 				SYSERROR("Unable to open lxc.init.static");
-				return -1;
+				goto on_error;
 			}
 
 			((struct execute_args *)handler->data)->init_fd = fd;
@@ -4062,7 +4083,7 @@ int lxc_setup(struct lxc_handler *handler)
 			ret = lxc_execute_bind_init(handler);
 			if (ret < 0) {
 				ERROR("Failed to bind-mount the lxc init system");
-				return -1;
+				goto on_error;
 			}
 		}
 	}
@@ -4074,7 +4095,7 @@ int lxc_setup(struct lxc_handler *handler)
 	ret = lxc_mount_auto_mounts(lxc_conf, lxc_conf->auto_mounts & LXC_AUTO_CGROUP_MASK, handler);
 	if (ret < 0) {
 		ERROR("Failed to setup remaining automatic mounts");
-		return -1;
+		goto on_error;
 	}
 
 	/*isulad: move mount entries here, before we do lxc_fill_autodev and populate devices  */
@@ -4083,27 +4104,27 @@ int lxc_setup(struct lxc_handler *handler)
 					  &lxc_conf->mount_list, name, lxcpath);
 		if (ret < 0) {
 			ERROR("Failed to setup mount entries");
-			return -1;
+			goto on_error;
 		}
 	}
 
 	ret = run_lxc_hooks(name, "mount", lxc_conf, NULL);
 	if (ret < 0) {
 		ERROR("Failed to run mount hooks");
-		return -1;
+		goto on_error;
 	}
 
 	if (lxc_conf->autodev > 0) {
 		ret = run_lxc_hooks(name, "autodev", lxc_conf, NULL);
 		if (ret < 0) {
 			ERROR("Failed to run autodev hooks");
-			return -1;
+			goto on_error;
 		}
 
 		ret = lxc_fill_autodev(&lxc_conf->rootfs);
 		if (ret < 0) {
 			ERROR("Failed to populate \"/dev\"");
-			return -1;
+			goto on_error;
 		}
 	}
 
@@ -4111,64 +4132,64 @@ int lxc_setup(struct lxc_handler *handler)
 	if (!lxc_list_empty(&lxc_conf->populate_devs)) {
 		if (setup_populate_devs(&lxc_conf->rootfs, &lxc_conf->populate_devs)) {
 			ERROR("Failed to setup devices in the container");
-			return -1;;
+			goto on_error;
 		}
 	}
 
 	/* Make sure any start hooks are in the container */
 	if (!verify_start_hooks(lxc_conf)) {
 		ERROR("Failed to verify start hooks");
-		return -1;
+		goto on_error;
 	}
 
 	ret = lxc_setup_console(&lxc_conf->rootfs, &lxc_conf->console,
 				lxc_conf->ttys.dir);
 	if (ret < 0) {
 		ERROR("Failed to setup console");
-		return -1;
+		goto on_error;
 	}
 
 	ret = lxc_setup_dev_symlinks(&lxc_conf->rootfs);
 	if (ret < 0) {
 		ERROR("Failed to setup \"/dev\" symlinks");
-		return -1;
+		goto on_error;
 	}
 
 	ret = lxc_create_tmp_proc_mount(lxc_conf);
 	if (ret < 0) {
 		ERROR("Failed to \"/proc\" LSMs");
-		return -1;
+		goto on_error;
 	}
 
 	ret = lxc_setup_rootfs_switch_root(&lxc_conf->rootfs);
 	if (ret < 0) {
 		ERROR("Failed to pivot root into rootfs");
-		return -1;
+		goto on_error;
 	}
 
 	/* isulad: remount rootfs readonly if necessary */
 	if (setup_rootfs_mountopts(&lxc_conf->rootfs)) {
 		ERROR("failed to set rootfs for '%s'", name);
-		return -1;
+		goto on_error;
 	}
 
 	if (lxc_conf->rootfs.path) {
 		ret = lxc_setup_devpts(lxc_conf);
 		if (ret < 0) {
 			ERROR("Failed to setup new devpts instance");
-			return -1;
+			goto on_error;
 		}
 	}
 
 	ret = lxc_create_ttys(handler);
 	if (ret < 0)
-		return -1;
+		goto on_error;
 
 	//isulad: setup rootfs masked paths
 	if (!lxc_list_empty(&lxc_conf->rootfs.maskedpaths)) {
 		if (setup_rootfs_maskedpaths(&lxc_conf->rootfs.maskedpaths)) {
 			ERROR("failed to setup maskedpaths");
-			return -1;
+			goto on_error;
 		}
 	}
 
@@ -4176,7 +4197,7 @@ int lxc_setup(struct lxc_handler *handler)
 	if (!lxc_list_empty(&lxc_conf->rootfs.ropaths)) {
 		if (setup_rootfs_ropaths(&lxc_conf->rootfs.ropaths)) {
 			ERROR("failed to setup readonlypaths");
-			return -1;
+			goto on_error;
 		}
 	}
 
@@ -4186,7 +4207,7 @@ int lxc_setup(struct lxc_handler *handler)
 	ret = setup_personality(lxc_conf->personality);
 	if (ret < 0) {
 		ERROR("Failed to set personality");
-		return -1;
+		goto on_error;
 	}
 
 	/* Set sysctl value to a path under /proc/sys as determined from the
@@ -4197,7 +4218,7 @@ int lxc_setup(struct lxc_handler *handler)
 		ret = setup_sysctl_parameters(&lxc_conf->sysctls);
 		if (ret < 0) {
 			ERROR("Failed to setup sysctl parameters");
-			return -1;
+			goto on_error;
 		}
 	}
 
@@ -4206,21 +4227,24 @@ int lxc_setup(struct lxc_handler *handler)
 			ERROR("Container requests lxc.cap.drop and "
 			      "lxc.cap.keep: either use lxc.cap.drop or "
 			      "lxc.cap.keep, not both");
-			return -1;
+			goto on_error;
 		}
 
 		if (dropcaps_except(&lxc_conf->keepcaps)) {
 			ERROR("Failed to keep capabilities");
-			return -1;
+			goto on_error;
 		}
 	} else if (setup_caps(&lxc_conf->caps)) {
 		ERROR("Failed to drop capabilities");
-		return -1;
+		goto on_error;
 	}
 
 	NOTICE("The container \"%s\" is set up", name);
 
 	return 0;
+on_error:
+	lxc_write_error_message(lxc_conf->errpipe[1], "Failed to setup lxc, please check the config file.");
+	return -1;
 }
 
 /* isulad drop caps for container*/
@@ -4555,11 +4579,9 @@ void* wait_ocihook_timeout(void *arg)
 			__FILE__, __LINE__, lxchook_names[conf->which],
 			(double)conf->timeout);
 
-		if (conf->errfd >= 0) {
-			lxc_write_error_message(conf->errfd, "%s:%d: running %s hook caused \"hook ran past specified timeout of %.1fs\"",
-				__FILE__, __LINE__, lxchook_names[conf->which],
-				(double)conf->timeout);
-		}
+		lxc_write_error_message(conf->errfd, "%s:%d: running %s hook caused \"hook ran past specified timeout of %.1fs\".",
+			__FILE__, __LINE__, lxchook_names[conf->which],
+			(double)conf->timeout);
 
 		if (kill(conf->pid, SIGKILL) && errno != ESRCH) {
 			ERROR("Send kill signal failed");
@@ -4640,22 +4662,18 @@ static int run_ocihook_buffer(struct oci_hook_conf *oconf, char *inmsg)
 		goto print_hook;
 	} else if (WIFEXITED(ret) && WEXITSTATUS(ret) != 0) {
 		ERROR("Script exited with status %d. output:%s", WEXITSTATUS(ret), output);
-		if (conf->errfd >= 0) {
-			lxc_write_error_message(conf->errfd, "%s:%d: running %s hook caused \"error running hook: exit status %d, output:%s\"",
-				__FILE__, __LINE__,
-				(conf->which >= NUM_LXC_HOOKS) ? "invalid type" : lxchook_names[conf->which],
-				WEXITSTATUS(ret), output);
-		}
+		lxc_write_error_message(conf->errfd, "%s:%d: running %s hook caused \"error running hook: exit status %d, output:%s\".",
+			__FILE__, __LINE__,
+			(conf->which >= NUM_LXC_HOOKS) ? "invalid type" : lxchook_names[conf->which],
+			WEXITSTATUS(ret), output);
 
 		goto print_hook;
 	} else if (WIFSIGNALED(ret)) {
 		ERROR("Script terminated by signal %d.", WTERMSIG(ret));
-		if (conf->errfd >= 0) {
-			lxc_write_error_message(conf->errfd, "%s:%d: running %s hook caused \"error running hook: Script terminated by signal %d\"",
-				__FILE__, __LINE__,
-				(conf->which >= NUM_LXC_HOOKS) ? "invalid type" : lxchook_names[conf->which],
-				WTERMSIG(ret));
-		}
+		lxc_write_error_message(conf->errfd, "%s:%d: running %s hook caused \"error running hook: Script terminated by signal %d\".",
+			__FILE__, __LINE__,
+			(conf->which >= NUM_LXC_HOOKS) ? "invalid type" : lxchook_names[conf->which],
+			WTERMSIG(ret));
 
 		goto print_hook;
 	}
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index b92c48e1..88f5b417 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -175,6 +175,8 @@ struct lxc_rootfs {
 	struct lxc_list maskedpaths;
 	/* isulad: ropaths */
 	struct lxc_list ropaths;
+	/* isulad: errfd */
+	int errfd;
 };
 
 /*
@@ -462,7 +464,7 @@ extern int lxc_setup_rootfs_prepare_root(struct lxc_conf *conf,
 					 const char *name, const char *lxcpath);
 extern int lxc_setup(struct lxc_handler *handler);
 extern int lxc_setup_parent(struct lxc_handler *handler);
-extern int setup_resource_limits(struct lxc_list *limits, pid_t pid);
+extern int setup_resource_limits(struct lxc_list *limits, pid_t pid, int errfd);
 extern int find_unmapped_nsid(struct lxc_conf *conf, enum idtype idtype);
 extern int mapped_hostid(unsigned id, struct lxc_conf *conf,
 			 enum idtype idtype);
@@ -499,6 +501,7 @@ int lxc_clear_populate_devices(struct lxc_conf *c);
 int lxc_clear_rootfs_masked_paths(struct lxc_conf *c);
 int lxc_clear_rootfs_ro_paths(struct lxc_conf *c);
 int lxc_drop_caps(struct lxc_conf *conf);
+void lxc_close_error_pipe(int *errpipe);
 
 /* isulad add end */
 
diff --git a/src/lxc/execute.c b/src/lxc/execute.c
index d388e633..3fc46c6e 100644
--- a/src/lxc/execute.c
+++ b/src/lxc/execute.c
@@ -40,7 +40,7 @@
 
 lxc_log_define(execute, start);
 
-static int execute_start(struct lxc_handler *handler, void* data)
+static int execute_start(struct lxc_handler *handler, void* data, int fd)
 {
 	int argc_add, j;
 	char **argv;
@@ -91,6 +91,7 @@ static int execute_start(struct lxc_handler *handler, void* data)
 	else
 		execvp(argv[0], argv);
 	SYSERROR("Failed to exec %s", argv[0]);
+	lxc_write_error_message(fd, "Failed to exec: \"%s\": %s.", argv[0], strerror(errno));
 
 	free(argv);
 out1:
diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index e99c41cb..d6418510 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -916,7 +916,9 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
 		NULL,
 	};
 	char **init_cmd = NULL;
-	int keepfds[4] = {-1, -1, -1, -1};
+	int keepfds[] = {-1, -1, -1, -1, -1};
+	ssize_t size_read;
+	char errbuf[BUFSIZ + 1] = {0};
 
 	/* container does exist */
 	if (!c)
@@ -962,7 +964,7 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
 			argv = init_cmd = split_init_cmd(conf->init_cmd);
 	}
 
-    /* isulad: use init argv as init cmd */
+	/* isulad: use init argv as init cmd */
 	if (!argv) {
 		argv = init_cmd = use_init_args(conf->init_argv, conf->init_argc);
 	}
@@ -986,10 +988,19 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
 		char title[2048];
 		pid_t pid;
 
+		//isulad: pipdfd for get error message of child or grandchild process.
+		if (pipe2(conf->errpipe, O_CLOEXEC) != 0) {
+			SYSERROR("Failed to init errpipe");
+			free_init_cmd(init_cmd);
+			lxc_free_handler(handler);
+			return false;
+		}
+
 		pid = fork();
 		if (pid < 0) {
 			free_init_cmd(init_cmd);
 			lxc_free_handler(handler);
+			lxc_close_error_pipe(conf->errpipe);
 			return false;
 		}
 
@@ -999,11 +1010,23 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
 			 * the PID file, child will do the free and unlink.
 			 */
 			c->pidfile = NULL;
+			close(conf->errpipe[1]);
+			conf->errpipe[1] = -1;
 
 			/* Wait for container to tell us whether it started
 			 * successfully.
 			 */
 			started = wait_on_daemonized_start(handler, pid);
+			if (!started) {
+				size_read = read(conf->errpipe[0], errbuf, BUFSIZ);
+				if (size_read > 0) {
+					conf->errmsg = strdup(errbuf);
+					if (!conf->errmsg)
+						ERROR("Out of memory");
+				}
+			}
+			close(conf->errpipe[0]);
+			conf->errpipe[0] = -1;
 
 			free_init_cmd(init_cmd);
 			lxc_free_handler(handler);
@@ -1039,6 +1062,7 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
 		if (pid != 0) {
 			free_init_cmd(init_cmd);
 			lxc_free_handler(handler);
+			lxc_close_error_pipe(conf->errpipe);
 			_exit(EXIT_SUCCESS);
 		}
 
@@ -1050,10 +1074,12 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
 			SYSERROR("Failed to change to \"/\" directory");
 			_exit(EXIT_FAILURE);
 		}
-
+		close(conf->errpipe[0]);
+		conf->errpipe[0] = -1;
 		keepfds[0] = handler->conf->maincmd_fd;
 		keepfds[1] = handler->state_socket_pair[0];
 		keepfds[2] = handler->state_socket_pair[1];
+		keepfds[4] = conf->errpipe[1];
 		ret = lxc_check_inherited(conf, true, keepfds,
 					  sizeof(keepfds) / sizeof(keepfds[0]));
 		if (ret < 0)
@@ -1088,6 +1114,7 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
 		if (w < 0 || (size_t)w >= sizeof(pidstr)) {
 			free_init_cmd(init_cmd);
 			lxc_free_handler(handler);
+			lxc_close_error_pipe(conf->errpipe);
 
 			SYSERROR("Failed to write monitor pid to \"%s\"", c->pidfile);
 
@@ -1101,6 +1128,7 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
 		if (ret < 0) {
 			free_init_cmd(init_cmd);
 			lxc_free_handler(handler);
+			lxc_close_error_pipe(conf->errpipe);
 
 			SYSERROR("Failed to write monitor pid to \"%s\"", c->pidfile);
 
@@ -1159,6 +1187,9 @@ reboot:
 	if (conf->exit_fd >= 0) {
 		keepfds[3] = conf->exit_fd;
 	}
+	/* isulad: keep errpipe fd */
+	if (c->daemonize)
+		keepfds[4] = conf->errpipe[1];
 	ret = lxc_check_inherited(conf, c->daemonize, keepfds,
 				  sizeof(keepfds) / sizeof(keepfds[0]));
 	if (ret < 0) {
diff --git a/src/lxc/start.c b/src/lxc/start.c
index ec61b322..3e6854fa 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -892,6 +892,7 @@ int lxc_init(const char *name, struct lxc_handler *handler)
 	ret = lxc_terminal_setup(conf);
 	if (ret < 0) {
 		ERROR("Failed to create console");
+		lxc_write_error_message(conf->errpipe[1], "Failed to create console for container \"%s\".", name);
 		goto out_restore_sigmask;
 	}
 	TRACE("Created console");
@@ -1390,6 +1391,8 @@ static int do_start(void *data)
 		struct stat st;
 		if (stat(handler->conf->init_cwd, &st) < 0 && mkdir_p(handler->conf->init_cwd, 0755) < 0) {
 			SYSERROR("Try to create directory \"%s\" as workdir failed", handler->conf->init_cwd);
+			lxc_write_error_message(handler->conf->errpipe[1], "%s:%d: Failed to create workdir: %s.",
+					__FILE__, __LINE__, strerror(errno));
 			goto out_warn_father;
 		}
 		if (chdir(handler->conf->init_cwd)) {
@@ -1489,7 +1492,7 @@ static int do_start(void *data)
 	/* After this call, we are in error because this ops should not return
 	 * as it execs.
 	 */
-	handler->ops->start(handler, handler->data);
+	handler->ops->start(handler, handler->data, handler->daemonize ? handler->conf->errpipe[1] : -1);
 
 out_warn_father:
 	/* We want the parent to know something went wrong, so we return a
@@ -1898,7 +1901,7 @@ static int lxc_spawn(struct lxc_handler *handler)
 		goto out_delete_net;
 
 	if (!lxc_list_empty(&conf->limits)) {
-		ret = setup_resource_limits(&conf->limits, handler->pid);
+		ret = setup_resource_limits(&conf->limits, handler->pid, conf->errpipe[1]);
 		if (ret < 0) {
 			ERROR("Failed to setup resource limits");
 			goto out_delete_net;
@@ -1960,7 +1963,7 @@ static int lxc_spawn(struct lxc_handler *handler)
 	}
 
 	if (START_TIMEOUT == global_timeout_state) {
-		//lxc_write_error_message(conf->errpipe[1], "Starting the container \"%s\" timeout.", name);
+		lxc_write_error_message(conf->errpipe[1], "Starting the container \"%s\" timeout.", name);
 		ERROR("Starting the container \"%s\" timeout.", name);
 		goto out_delete_net;
 	}
@@ -2008,7 +2011,7 @@ static int lxc_spawn(struct lxc_handler *handler)
 	}
 
 	if (START_TIMEOUT == global_timeout_state) {
-		//lxc_write_error_message(conf->errpipe[1], "Starting the container \"%s\" timeout.", name);
+		lxc_write_error_message(conf->errpipe[1], "Starting the container \"%s\" timeout.", name);
 		ERROR("Starting the container \"%s\" timeout.", name);
 		goto out_abort;
 	}
@@ -2232,7 +2235,7 @@ struct start_args {
 	char *const *argv;
 };
 
-static int start(struct lxc_handler *handler, void* data)
+static int start(struct lxc_handler *handler, void* data, int fd)
 {
 	struct start_args *arg = data;
 
@@ -2240,6 +2243,7 @@ static int start(struct lxc_handler *handler, void* data)
 
 	execvp(arg->argv[0], arg->argv);
 	SYSERROR("Failed to exec \"%s\"", arg->argv[0]);
+	lxc_write_error_message(fd, "exec: \"%s\": %s.", arg->argv[0], strerror(errno));
 	return 0;
 }
 
diff --git a/src/lxc/start.h b/src/lxc/start.h
index 1d84325b..ab72e6e0 100644
--- a/src/lxc/start.h
+++ b/src/lxc/start.h
@@ -145,7 +145,7 @@ struct execute_args {
 };
 
 struct lxc_operations {
-	int (*start)(struct lxc_handler *, void *);
+	int (*start)(struct lxc_handler *, void *, int);
 	int (*post_start)(struct lxc_handler *, void *);
 };
 
diff --git a/src/lxc/tools/lxc_start.c b/src/lxc/tools/lxc_start.c
index f37f8a6a..ec487018 100644
--- a/src/lxc/tools/lxc_start.c
+++ b/src/lxc/tools/lxc_start.c
@@ -392,6 +392,9 @@ int main(int argc, char *argv[])
 	else
 		err = c->start(c, 0, args) ? EXIT_SUCCESS : EXIT_FAILURE;
 	if (err) {
+		if (c->lxc_conf->errmsg)
+			fprintf(stderr, "%s:%s:%s:%d starting container process caused \"%s\"", c->name,
+			__FILE__, __func__, __LINE__, c->lxc_conf->errmsg);
 		ERROR("The container failed to start");
 
 		if (my_args.daemonize)
-- 
2.23.0

