From 0015fbf989f5f1837f9588f8385b16dd38dbd29f Mon Sep 17 00:00:00 2001
From: haozi007 <liuhao27@huawei.com>
Date: Fri, 21 Jul 2023 17:35:52 +0800
Subject: [PATCH 3/3] [iSulad] adapt conf network storage and termianl

Signed-off-by: haozi007 <liuhao27@huawei.com>
---
 src/lxc/attach_options.h        |  26 +-
 src/lxc/cgroups/isulad_cgfsng.c | 114 +++---
 src/lxc/conf.c                  |   2 +-
 src/lxc/log.c                   |  58 +++
 src/lxc/network.c               |   8 +
 src/lxc/storage/dir.c           |   4 +
 src/lxc/storage/loop.c          |  41 +++
 src/lxc/storage/storage.c       |   7 +
 src/lxc/sync.h                  |   9 +
 src/lxc/terminal.c              | 610 ++++++++++++++++++++++++++++++++
 src/lxc/terminal.h              |  37 ++
 src/lxc/tools/lxc_ls.c          |   8 +
 src/lxc/utils.c                 | 143 ++++++++
 src/lxc/utils.h                 |   7 +
 src/tests/attach.c              |  11 +
 15 files changed, 1026 insertions(+), 59 deletions(-)

diff --git a/src/lxc/attach_options.h b/src/lxc/attach_options.h
index d09dfce..a4052fb 100644
--- a/src/lxc/attach_options.h
+++ b/src/lxc/attach_options.h
@@ -172,6 +172,28 @@ typedef struct lxc_attach_options_t {
 } lxc_attach_options_t;
 
 /*! Default attach options to use */
+
+#ifdef HAVE_ISULAD
+#define LXC_ATTACH_OPTIONS_DEFAULT					\
+	{                                               		\
+		.attach_flags	= LXC_ATTACH_DEFAULT,   		\
+		.namespaces	= -1,					\
+		.personality	= LXC_ATTACH_DETECT_PERSONALITY,	\
+		.initial_cwd	= NULL,					\
+		.uid		= (uid_t)-1,            		\
+		.gid		= (gid_t)-1,            		\
+		.env_policy	= LXC_ATTACH_KEEP_ENV,  		\
+		.extra_env_vars = NULL,                 		\
+		.extra_keep_env = NULL,                 		\
+		.stdin_fd	= 0,                    		\
+		.stdout_fd	= 1,                    		\
+		.stderr_fd	= 2,                    		\
+		.log_fd		= -EBADF,               		\
+		.lsm_label	= NULL,					\
+		.groups		= {},					\
+		.init_fifo =   {NULL, NULL, NULL},  \
+	}
+#else
 #define LXC_ATTACH_OPTIONS_DEFAULT					\
 	{                                               		\
 		.attach_flags	= LXC_ATTACH_DEFAULT,   		\
@@ -189,10 +211,8 @@ typedef struct lxc_attach_options_t {
 		.log_fd		= -EBADF,               		\
 		.lsm_label	= NULL,					\
 		.groups		= {},					\
-#ifdef HAVE_ISULAD
-		/* .init_fifo = */  	{NULL, NULL, NULL},  \
-#endif
 	}
+#endif
 
 /*!
  * Representation of a command to run in a container.
diff --git a/src/lxc/cgroups/isulad_cgfsng.c b/src/lxc/cgroups/isulad_cgfsng.c
index dcaa229..38ad677 100644
--- a/src/lxc/cgroups/isulad_cgfsng.c
+++ b/src/lxc/cgroups/isulad_cgfsng.c
@@ -385,11 +385,11 @@ static struct hierarchy *add_hierarchy(struct hierarchy ***h, char **clist, char
 
 	new = zalloc(sizeof(*new));
 	new->controllers = clist;
-	new->mountpoint = mountpoint;
-	new->container_base_path = container_base_path;
-	new->version = type;
-	new->cgfd_con = -EBADF;
-	new->cgfd_mon = -EBADF;
+	new->at_mnt = mountpoint;
+	new->at_base = container_base_path;
+	new->fs_type = type;
+	new->dfd_con = -EBADF;
+	new->dfd_mon = -EBADF;
 
 	newentry = append_null_to_list((void ***)h);
 	(*h)[newentry] = new;
@@ -586,8 +586,8 @@ static void lxc_cgfsng_print_hierarchies(struct cgroup_ops *ops)
 		int j;
 		char **cit;
 
-		TRACE("  %d: base_cgroup: %s", i, (*it)->container_base_path ? (*it)->container_base_path : "(null)");
-		TRACE("      mountpoint:  %s", (*it)->mountpoint ? (*it)->mountpoint : "(null)");
+		TRACE("  %d: base_cgroup: %s", i, (*it)->at_base ? (*it)->at_base : "(null)");
+		TRACE("      at_mnt:  %s", (*it)->at_mnt ? (*it)->at_mnt : "(null)");
 		TRACE("      controllers:");
 		for (j = 0, cit = (*it)->controllers; cit && *cit; cit++, j++)
 			TRACE("      %d: %s", j, *cit);
@@ -628,17 +628,21 @@ static int isulad_cgroup_tree_remove(struct hierarchy **hierarchies,
 		struct hierarchy *h = hierarchies[i];
 		int ret;
 
-		if (!h->container_full_path) {
-			h->container_full_path = must_make_path(h->mountpoint, h->container_base_path, container_cgroup, NULL);
+		if (!h->path_con) {
+			h->path_con = must_make_path(h->at_mnt, h->at_base, container_cgroup, NULL);
 		}
 
-		ret = lxc_rm_rf(h->container_full_path);
+		ret = lxc_rm_rf(h->path_con);
 		if (ret < 0) {
-			SYSERROR("Failed to destroy \"%s\"", h->container_full_path);
+			if (errno == ENOENT) {
+				WARN("Destroy path: \"%s\" do not exist", h->path_con);
+				return 0;
+			}
+			SYSERROR("Failed to destroy \"%s\"", h->path_con);
 			return -1;
 		}
 
-		free_disarm(h->container_full_path);
+		free_disarm(h->path_con);
 	}
 
 	return 0;
@@ -842,7 +846,7 @@ static bool isulad_cg_legacy_handle_cpuset_hierarchy(struct hierarchy *h, char *
 	if (slash != NULL) {
 		while (slash) {
 			*slash = '\0';
-			cgpath = must_make_path(h->mountpoint, h->container_base_path, cgname, NULL);
+			cgpath = must_make_path(h->at_mnt, h->at_base, cgname, NULL);
 			sub_mk_success = build_sub_cpuset_cgroup_dir(cgpath);
 			free(cgpath);
 			*slash = '/';
@@ -853,7 +857,7 @@ static bool isulad_cg_legacy_handle_cpuset_hierarchy(struct hierarchy *h, char *
 		}
 	}
 
-	cgpath = must_make_path(h->mountpoint, h->container_base_path, cgname, NULL);
+	cgpath = must_make_path(h->at_mnt, h->at_base, cgname, NULL);
 	sub_mk_success = build_sub_cpuset_cgroup_dir(cgpath);
 	free(cgpath);
 	if (!sub_mk_success) {
@@ -902,7 +906,7 @@ static bool create_path_for_hierarchy(struct hierarchy *h, char *cgname, int err
 	int ret;
 	__do_free char *path = NULL;
 
-	path = must_make_path(h->mountpoint, h->container_base_path, cgname, NULL);
+	path = must_make_path(h->at_mnt, h->at_base, cgname, NULL);
 
 	if (file_exists(path)) { // it must not already exist
 		ERROR("Cgroup path \"%s\" already exist.", path);
@@ -926,8 +930,8 @@ static bool create_path_for_hierarchy(struct hierarchy *h, char *cgname, int err
 	if (h->cgfd_con < 0)
 		return log_error_errno(false, errno, "Failed to open %s", path);
 
-	if (h->container_full_path == NULL) {
-		h->container_full_path = move_ptr(path);
+	if (h->path_con == NULL) {
+		h->path_con = move_ptr(path);
 	}
 
 	return true;
@@ -961,7 +965,7 @@ __cgfsng_ops static inline bool isulad_cgfsng_payload_create(struct cgroup_ops *
 
 	for (i = 0; ops->hierarchies[i]; i++) {
 		if (!create_path_for_hierarchy(ops->hierarchies[i], container_cgroup, ops->errfd)) {
-			SYSERROR("Failed to create %s", ops->hierarchies[i]->container_full_path);
+			SYSERROR("Failed to create %s", ops->hierarchies[i]->path_con);
 			return false;
 		}
 	}
@@ -1008,7 +1012,7 @@ __cgfsng_ops static bool isulad_cgfsng_payload_enter(struct cgroup_ops *ops,
 		int retry_count = 0;
 		int max_retry = 10;
 
-		fullpath = must_make_path(ops->hierarchies[i]->container_full_path,
+		fullpath = must_make_path(ops->hierarchies[i]->path_con,
 		                          "cgroup.procs", NULL);
 retry:
 		ret = lxc_write_to_file(fullpath, pidstr, len, false, 0666);
@@ -1016,7 +1020,7 @@ retry:
 			if (retry_count < max_retry) {
 				SYSERROR("Failed to enter cgroup \"%s\" with retry count:%d", fullpath, retry_count);
 				(void)isulad_cg_legacy_handle_cpuset_hierarchy(ops->hierarchies[i], ops->container_cgroup);
-				(void)isulad_mkdir_eexist_on_last(ops->hierarchies[i]->container_full_path, 0755);
+				(void)isulad_mkdir_eexist_on_last(ops->hierarchies[i]->path_con, 0755);
 				usleep(100 * 1000); /* 100 millisecond */
 				retry_count++;
 				goto retry;
@@ -1097,12 +1101,12 @@ static int chown_cgroup_wrapper(void *data)
 		 * files (which systemd in wily insists on doing).
 		 */
 
-		if (arg->hierarchies[i]->version == CGROUP_SUPER_MAGIC)
+		if (arg->hierarchies[i]->fs_type == CGROUP_SUPER_MAGIC)
 			(void)fchowmodat(dirfd, "tasks", destuid, nsgid, 0664);
 
 		(void)fchowmodat(dirfd, "cgroup.procs", destuid, nsgid, 0664);
 
-		if (arg->hierarchies[i]->version != CGROUP2_SUPER_MAGIC)
+		if (arg->hierarchies[i]->fs_type != CGROUP2_SUPER_MAGIC)
 			continue;
 
 		for (char **p = arg->hierarchies[i]->cgroup2_chown; p && *p; p++)
@@ -1207,7 +1211,7 @@ static int cg_legacy_mount_controllers(int type, struct hierarchy *h,
 		INFO("Remounted %s read-only", controllerpath);
 	}
 
-	sourcepath = must_make_path(h->mountpoint, h->container_base_path,
+	sourcepath = must_make_path(h->at_mnt, h->at_base,
 				    container_cgroup, NULL);
 	if (type == LXC_AUTO_CGROUP_RO)
 		flags |= MS_RDONLY;
@@ -1253,7 +1257,7 @@ static int __cg_mount_direct(int type, struct hierarchy *h,
 	 if (type == LXC_AUTO_CGROUP_RO || type == LXC_AUTO_CGROUP_FULL_RO)
 		 flags |= MS_RDONLY;
 
-	 if (h->version != CGROUP2_SUPER_MAGIC) {
+	 if (h->fs_type != CGROUP2_SUPER_MAGIC) {
 		 controllers = lxc_string_join(",", (const char **)h->controllers, false);
 		 if (!controllers)
 			 return -ENOMEM;
@@ -1349,7 +1353,7 @@ __cgfsng_ops static bool isulad_cgfsng_mount(struct cgroup_ops *ops,
 		char *controllerpath = NULL;
 		char *path2 = NULL;
 		struct hierarchy *h = ops->hierarchies[i];
-		char *controller = strrchr(h->mountpoint, '/');
+		char *controller = strrchr(h->at_mnt, '/');
 
 		if (!controller)
 			continue;
@@ -1401,7 +1405,7 @@ __cgfsng_ops static bool isulad_cgfsng_mount(struct cgroup_ops *ops,
 		}
 
 		// isulad: ignore ops->container_cgroup so we will not see directory lxc after /sys/fs/cgroup/xxx in container,
-		// isulad: ignore h->container_base_path so we will not see subgroup of /sys/fs/cgroup/xxx/subgroup in container
+		// isulad: ignore h->at_base so we will not see subgroup of /sys/fs/cgroup/xxx/subgroup in container
 		path2 = must_make_path(controllerpath, NULL);
 		ret = mkdir_p(path2, 0755);
 		if (ret < 0) {
@@ -1513,8 +1517,8 @@ __cgfsng_ops static bool isulad_cgfsng_escape(const struct cgroup_ops *ops,
 		int ret;
 
 		fullpath =
-		    must_make_path(ops->hierarchies[i]->mountpoint,
-				   ops->hierarchies[i]->container_base_path,
+		    must_make_path(ops->hierarchies[i]->at_mnt,
+				   ops->hierarchies[i]->at_base,
 				   "cgroup.procs", NULL);
 		ret = lxc_write_to_file(fullpath, "0", 2, false, 0666);
 		if (ret != 0)
@@ -1569,7 +1573,7 @@ static bool cg_legacy_freeze(struct cgroup_ops *ops)
 	if (!h)
 		return ret_set_errno(-1, ENOENT);
 
-	return lxc_write_openat(h->container_full_path, "freezer.state",
+	return lxc_write_openat(h->path_con, "freezer.state",
 				"FROZEN", STRLITERALLEN("FROZEN"));
 }
 
@@ -1619,13 +1623,13 @@ static int cg_unified_freeze(struct cgroup_ops *ops, int timeout)
 	if (!h)
 		return ret_set_errno(-1, ENOENT);
 
-	if (!h->container_full_path)
+	if (!h->path_con)
 		return ret_set_errno(-1, EEXIST);
 
 	if (timeout != 0) {
 		__do_free char *events_file = NULL;
 
-		events_file = must_make_path(h->container_full_path, "cgroup.events", NULL);
+		events_file = must_make_path(h->path_con, "cgroup.events", NULL);
 		fd = open(events_file, O_RDONLY | O_CLOEXEC);
 		if (fd < 0)
 			return log_error_errno(-1, errno, "Failed to open cgroup.events file");
@@ -1642,7 +1646,7 @@ static int cg_unified_freeze(struct cgroup_ops *ops, int timeout)
 			return log_error_errno(-1, errno, "Failed to add cgroup.events fd handler to mainloop");
 	}
 
-	ret = lxc_write_openat(h->container_full_path, "cgroup.freeze", "1", 1);
+	ret = lxc_write_openat(h->path_con, "cgroup.freeze", "1", 1);
 	if (ret < 0)
 		return log_error_errno(-1, errno, "Failed to open cgroup.freeze file");
 
@@ -1671,7 +1675,7 @@ static int cg_legacy_unfreeze(struct cgroup_ops *ops)
 	if (!h)
 		return ret_set_errno(-1, ENOENT);
 
-	return lxc_write_openat(h->container_full_path, "freezer.state",
+	return lxc_write_openat(h->path_con, "freezer.state",
 				"THAWED", STRLITERALLEN("THAWED"));
 }
 
@@ -1687,13 +1691,13 @@ static int cg_unified_unfreeze(struct cgroup_ops *ops, int timeout)
 	if (!h)
 		return ret_set_errno(-1, ENOENT);
 
-	if (!h->container_full_path)
+	if (!h->path_con)
 		return ret_set_errno(-1, EEXIST);
 
 	if (timeout != 0) {
 		__do_free char *events_file = NULL;
 
-		events_file = must_make_path(h->container_full_path, "cgroup.events", NULL);
+		events_file = must_make_path(h->path_con, "cgroup.events", NULL);
 		fd = open(events_file, O_RDONLY | O_CLOEXEC);
 		if (fd < 0)
 			return log_error_errno(-1, errno, "Failed to open cgroup.events file");
@@ -1710,7 +1714,7 @@ static int cg_unified_unfreeze(struct cgroup_ops *ops, int timeout)
 			return log_error_errno(-1, errno, "Failed to add cgroup.events fd handler to mainloop");
 	}
 
-	ret = lxc_write_openat(h->container_full_path, "cgroup.freeze", "0", 1);
+	ret = lxc_write_openat(h->path_con, "cgroup.freeze", "0", 1);
 	if (ret < 0)
 		return log_error_errno(-1, errno, "Failed to open cgroup.freeze file");
 
@@ -1741,11 +1745,11 @@ __cgfsng_ops static const char *isulad_cgfsng_get_cgroup(struct cgroup_ops *ops,
 		return log_warn_errno(NULL, ENOENT, "Failed to find hierarchy for controller \"%s\"",
 				      controller ? controller : "(null)");
 
-	if (!h->container_full_path)
-		h->container_full_path = must_make_path(h->mountpoint, h->container_base_path, ops->container_cgroup, NULL);
+	if (!h->path_con)
+		h->path_con = must_make_path(h->at_mnt, h->at_base, ops->container_cgroup, NULL);
 
-	return h->container_full_path
-		   ? h->container_full_path + strlen(h->mountpoint)
+	return h->path_con
+		   ? h->path_con + strlen(h->at_mnt)
 		   : NULL;
 }
 
@@ -1759,10 +1763,10 @@ __cgfsng_ops static const char *isulad_cgfsng_get_cgroup_full_path(struct cgroup
 		return log_warn_errno(NULL, ENOENT, "Failed to find hierarchy for controller \"%s\"",
 				      controller ? controller : "(null)");
 
-	if (!h->container_full_path)
-		h->container_full_path = must_make_path(h->mountpoint, h->container_base_path, ops->container_cgroup, NULL);
+	if (!h->path_con)
+		h->path_con = must_make_path(h->at_mnt, h->at_base, ops->container_cgroup, NULL);
 
-	return h->container_full_path;
+	return h->path_con;
 }
 
 /* Given a cgroup path returned from lxc_cmd_get_cgroup_path, build a full path,
@@ -1772,7 +1776,7 @@ static inline char *build_full_cgpath_from_monitorpath(struct hierarchy *h,
 						       const char *inpath,
 						       const char *filename)
 {
-	return must_make_path(h->mountpoint, inpath, filename, NULL);
+	return must_make_path(h->at_mnt, inpath, filename, NULL);
 }
 
 static int cgroup_attach_leaf(const struct lxc_conf *conf, int unified_fd, pid_t pid)
@@ -2004,7 +2008,7 @@ static int __cg_unified_attach(const struct hierarchy *h,
 	if (!cgroup)
 		return 0;
 
-	path = must_make_path(h->mountpoint, cgroup, NULL);
+	path = must_make_path(h->at_mnt, cgroup, NULL);
 
 	unified_fd = open(path, O_PATH | O_DIRECTORY | O_CLOEXEC);
 	if (unified_fd < 0)
@@ -2062,7 +2066,7 @@ __cgfsng_ops static bool isulad_cgfsng_attach(struct cgroup_ops *ops,
 		__do_free char *fullpath = NULL, *path = NULL;
 		struct hierarchy *h = ops->hierarchies[i];
 
-		if (h->version == CGROUP2_SUPER_MAGIC) {
+		if (h->fs_type == CGROUP2_SUPER_MAGIC) {
 			ret = __cg_unified_attach(h, conf, name, lxcpath, pid,
 						  h->controllers[0]);
 			if (ret < 0)
@@ -2410,7 +2414,7 @@ static int isulad_cg_legacy_get_data(struct cgroup_ops *ops, const char *filenam
 		return -ENOENT;
 	}
 
-	fullpath = must_make_path(h->container_full_path, filename, NULL);
+	fullpath = must_make_path(h->path_con, filename, NULL);
 	ret = lxc_read_from_file(fullpath, value, len);
 	free(fullpath);
 	free(controller);
@@ -2456,7 +2460,7 @@ static int isulad_cg_legacy_set_data(struct cgroup_ops *ops, const char *filenam
 		return -ENOENT;
 	}
 
-	fullpath = must_make_path(h->container_full_path, filename, NULL);
+	fullpath = must_make_path(h->path_con, filename, NULL);
 
 retry:
 	ret = lxc_write_to_file(fullpath, value, strlen(value), false, 0666);
@@ -2464,7 +2468,7 @@ retry:
 		if (retry_count < max_retry) {
 			SYSERROR("setting cgroup config for ready process caused \"failed to write %s to %s\".", value, fullpath);
 			(void)isulad_cg_legacy_handle_cpuset_hierarchy(h, container_cgroup);
-			(void)isulad_mkdir_eexist_on_last(h->container_full_path, 0755);
+			(void)isulad_mkdir_eexist_on_last(h->path_con, 0755);
 			usleep(100 * 1000); /* 100 millisecond */
 			retry_count++;
 			goto retry;
@@ -2651,7 +2655,7 @@ __cgfsng_ops static bool isulad_cgfsng_setup_limits(struct cgroup_ops *ops,
 			if (setvalue <= 0)
 				cgvalue = "max";
 
-			ret = lxc_write_openat(h->container_full_path,
+			ret = lxc_write_openat(h->path_con,
 					       cg->subsystem, cgvalue,
 					       strlen(cgvalue));
 			if (ret < 0)
@@ -2659,12 +2663,12 @@ __cgfsng_ops static bool isulad_cgfsng_setup_limits(struct cgroup_ops *ops,
 						       cg->subsystem, cgvalue);
 		} else {
 			if (strcmp(cg->subsystem, "io.weight") == 0 || strcmp(cg->subsystem, "io.bfq.weight") == 0) {
-				path = must_make_path(h->container_full_path, cg->subsystem, NULL);
+				path = must_make_path(h->path_con, cg->subsystem, NULL);
 				if (!file_exists(path)) {
 					continue;
 				}
 			}
-			ret = lxc_write_openat(h->container_full_path,
+			ret = lxc_write_openat(h->path_con,
 					       cg->subsystem, cg->value,
 					       strlen(cg->value));
 			if (ret < 0)
@@ -2703,7 +2707,7 @@ __cgfsng_ops bool isulad_cgfsng_devices_activate(struct cgroup_ops *ops,
 
 	unified = ops->unified;
 	if (!unified || !unified->bpf_device_controller ||
-	    !unified->container_full_path || lxc_list_empty(&conf->devices))
+	    !unified->path_con || lxc_list_empty(&conf->devices))
 		return true;
 
 	devices = bpf_program_new(BPF_PROG_TYPE_CGROUP_DEVICE);
@@ -2740,7 +2744,7 @@ __cgfsng_ops bool isulad_cgfsng_devices_activate(struct cgroup_ops *ops,
 		return log_error_errno(false, ENOMEM, "Failed to finalize bpf program");
 
 	ret = bpf_program_cgroup_attach(devices, BPF_CGROUP_DEVICE,
-					unified->container_full_path,
+					unified->path_con,
 					BPF_F_ALLOW_MULTI);
 	if (ret)
 		return log_error_errno(false, ENOMEM, "Failed to attach bpf program");
@@ -2794,7 +2798,7 @@ bool __cgfsng_delegate_controllers(struct cgroup_ops *ops, const char *cgroup)
 	if (parts_len > 0)
 		parts_len--;
 
-	base_path = must_make_path(unified->mountpoint, unified->container_base_path, NULL);
+	base_path = must_make_path(unified->at_mnt, unified->at_base, NULL);
 	for (ssize_t i = -1; i < parts_len; i++) {
 		int ret;
 		__do_free char *target = NULL;
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 23783db..a0e0375 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -4796,7 +4796,7 @@ int lxc_setup(struct lxc_handler *handler)
 
 #ifdef HAVE_ISULAD
 	/* Ask father to run oci prestart hooks and wait for him to finish. */
-	if (lxc_sync_barrier_parent(handler, LXC_SYNC_OCI_PRESTART_HOOK)) {
+	if (lxc_sync_wait_parent(handler, LXC_SYNC_OCI_PRESTART_HOOK)) {
 		return log_error(-1, "Failed to sync parent to start host hook");
 	}
 #endif
diff --git a/src/lxc/log.c b/src/lxc/log.c
index cdd11ff..167725a 100644
--- a/src/lxc/log.c
+++ b/src/lxc/log.c
@@ -53,6 +53,39 @@ static char *log_vmname = NULL;
 
 lxc_log_define(log, lxc);
 
+#ifdef HAVE_ISULAD
+// iSulad gather log by fifo, so lxc should support log driver of fifo
+static inline const char *isulad_get_fifo_path(const char *file)
+{
+#define ISULAD_FIFO_PREFIX "fifo:"
+
+	if (strncmp(file, ISULAD_FIFO_PREFIX, strlen(ISULAD_FIFO_PREFIX)) == 0) {
+		return (file + strlen(ISULAD_FIFO_PREFIX));
+	}
+	return NULL;
+}
+
+static int isulad_open_fifo(const char *file_path)
+{
+#define LOG_FIFO_SIZE (1024 * 1024)
+	int fd;
+
+	fd = lxc_unpriv(open(file_path, O_RDWR | O_NONBLOCK | O_CLOEXEC));
+	if (fd == -1) {
+		fprintf(stderr, "Open fifo %s failed: %s\n", file_path, strerror(errno));
+		return -1;
+	}
+
+	if (fcntl(fd, F_SETPIPE_SZ, LOG_FIFO_SIZE) == -1) {
+		printf("Set fifo buffer size failed: %s", strerror(errno));
+		close(fd);
+		return -1;
+	}
+
+	return fd;
+}
+#endif
+
 static int lxc_log_priority_to_syslog(int priority)
 {
 	switch (priority) {
@@ -334,6 +367,13 @@ static int log_append_logfile(const struct lxc_log_appender *appender,
 
 	log_container_name = lxc_log_get_container_name();
 
+#ifdef HAVE_ISULAD
+	/* use isulad log format */
+	if (log_container_name != NULL && strlen(log_container_name) > 15) {
+		log_container_name = log_container_name + (strlen(log_container_name) - 15);
+	}
+#endif
+
 	if (fd_to_use < 0)
 		fd_to_use = lxc_log_fd;
 
@@ -349,9 +389,13 @@ static int log_append_logfile(const struct lxc_log_appender *appender,
 	 * instead of strnprintf().
 	 */
 	n = snprintf(buffer, sizeof(buffer),
+#ifdef HAVE_ISULAD
+			 "%15s %s %-8s %s - %s:%s:%d -",
+#else
 		     "%s%s%s %s %-8s %s - %s:%s:%d - ",
 		     log_prefix,
 		     log_container_name ? " " : "",
+#endif
 		     log_container_name ? log_container_name : "",
 		     date_time,
 		     lxc_log_priority_to_string(event->priority),
@@ -619,6 +663,13 @@ static int __lxc_log_set_file(const char *fname, int create_dirs)
 		return ret_errno(EINVAL);
 	}
 
+#ifdef HAVE_ISULAD
+	fname = isulad_get_fifo_path(fname);
+	if (fname == NULL) {
+		return ret_errno(EINVAL);
+	}
+#endif
+
 #if USE_CONFIGPATH_LOGS
 	/* We don't build_dir for the default if the default is i.e.
 	 * /var/lib/lxc/$container/$container.log.
@@ -628,7 +679,11 @@ static int __lxc_log_set_file(const char *fname, int create_dirs)
 	if (build_dir(fname))
 		return log_error_errno(-errno, errno, "Failed to create dir for log file \"%s\"", fname);
 
+#ifdef HAVE_ISULAD
+	lxc_log_fd = isulad_open_fifo(fname);
+#else
 	lxc_log_fd = log_open(fname);
+#endif
 	if (lxc_log_fd < 0)
 		return lxc_log_fd;
 
@@ -724,6 +779,9 @@ int lxc_log_init(struct lxc_log *log)
 
 	if (lxc_log_fd >= 0) {
 		lxc_log_category_lxc.appender = &log_appender_logfile;
+#ifdef HAVE_ISULAD
+	if (!lxc_quiet_specified && !log->quiet)
+#endif
 		lxc_log_category_lxc.appender->next = &log_appender_stderr;
 	}
 
diff --git a/src/lxc/network.c b/src/lxc/network.c
index e1ee57e..c8d0402 100644
--- a/src/lxc/network.c
+++ b/src/lxc/network.c
@@ -3875,10 +3875,18 @@ static int lxc_network_setup_in_child_namespaces_common(struct lxc_netdev *netde
 
 	/* set the network device up */
 	if (netdev->flags & IFF_UP) {
+#ifdef HAVE_ISULAD
+		// iSulad do not set net dev name, just want to setup loop dev
+		if (netdev->name[0] != '\0') {
+#endif
 		err = lxc_netdev_up(netdev->name);
 		if (err)
 			return log_error_errno(-1, -err, "Failed to set network device \"%s\" up", netdev->name);
 
+#ifdef HAVE_ISULAD
+		}
+#endif
+
 		/* the network is up, make the loopback up too */
 		err = lxc_netdev_up("lo");
 		if (err)
diff --git a/src/lxc/storage/dir.c b/src/lxc/storage/dir.c
index bdf4e3f..09e08ad 100644
--- a/src/lxc/storage/dir.c
+++ b/src/lxc/storage/dir.c
@@ -94,6 +94,9 @@ int dir_create(struct lxc_storage *bdev, const char *dest, const char *n,
 
 int dir_destroy(struct lxc_storage *orig)
 {
+#ifdef HAVE_ISULAD
+	// isulad: do not destroy rootfs for directory, it should be managed by caller
+#else
 	int ret;
 	const char *src;
 
@@ -102,6 +105,7 @@ int dir_destroy(struct lxc_storage *orig)
 	ret = lxc_rmdir_onedev(src, NULL);
 	if (ret < 0)
 		return log_error_errno(ret, errno, "Failed to delete \"%s\"", src);
+#endif
 
 	return 0;
 }
diff --git a/src/lxc/storage/loop.c b/src/lxc/storage/loop.c
index 870b84c..17c11d5 100644
--- a/src/lxc/storage/loop.c
+++ b/src/lxc/storage/loop.c
@@ -19,6 +19,9 @@
 #include "storage.h"
 #include "storage_utils.h"
 #include "utils.h"
+#ifdef HAVE_ISULAD
+#include "lxclock.h"
+#endif
 
 lxc_log_define(loop, lxc);
 
@@ -216,6 +219,10 @@ int loop_mount(struct lxc_storage *bdev)
 	int ret, loopfd;
 	char loname[PATH_MAX];
 	const char *src;
+#ifdef HAVE_ISULAD
+	struct lxc_lock *l = NULL;
+	ret = -1;
+#endif
 
 	if (strcmp(bdev->type, "loop"))
 		return -22;
@@ -223,13 +230,32 @@ int loop_mount(struct lxc_storage *bdev)
 	if (!bdev->src || !bdev->dest)
 		return -22;
 
+#ifdef HAVE_ISULAD
+	/* isulad: do lock before mount, so we can avoid use loop which is used by
+	 * other starting contianers */
+	l = lxc_newlock("mount_lock", "mount_lock");
+	if (!l) {
+		SYSERROR("create file lock error when mount fs");
+		return -1;
+	}
+
+	if (lxclock(l, 0) != 0) {
+		SYSERROR("try to lock failed when mount fs");
+		goto out;
+	}
+#endif
+
 	/* skip prefix */
 	src = lxc_storage_get_path(bdev->src, bdev->type);
 
 	loopfd = lxc_prepare_loop_dev(src, loname, LO_FLAGS_AUTOCLEAR);
 	if (loopfd < 0) {
 		ERROR("Failed to prepare loop device for loop file \"%s\"", src);
+#ifdef HAVE_ISULAD
+		goto out;
+#else
 		return -1;
+#endif
 	}
 	DEBUG("Prepared loop device \"%s\"", loname);
 
@@ -238,14 +264,29 @@ int loop_mount(struct lxc_storage *bdev)
 		ERROR("Failed to mount rootfs \"%s\" on \"%s\" via loop device \"%s\"",
 		      bdev->src, bdev->dest, loname);
 		close(loopfd);
+#ifdef HAVE_ISULAD
+		goto out;
+#else
 		return -1;
+#endif
 	}
 
 	bdev->lofd = loopfd;
 	DEBUG("Mounted rootfs \"%s\" on \"%s\" via loop device \"%s\"",
 	      bdev->src, bdev->dest, loname);
 
+#ifdef HAVE_ISULAD
+	ret = 0;
+out:
+	if (lxcunlock(l) != 0) {
+		SYSERROR("try to unlock failed when mount fs");
+		ret = -1;
+	}
+	lxc_putlock(l);
+	return ret;
+#else
 	return 0;
+#endif
 }
 
 int loop_umount(struct lxc_storage *bdev)
diff --git a/src/lxc/storage/storage.c b/src/lxc/storage/storage.c
index c840c68..39756d0 100644
--- a/src/lxc/storage/storage.c
+++ b/src/lxc/storage/storage.c
@@ -587,8 +587,15 @@ bool storage_destroy(struct lxc_conf *conf)
 	int destroy_rv = 0;
 
 	r = storage_init(conf);
+#ifdef HAVE_ISULAD
+	if (r == NULL) {
+		WARN("%s 's storage init failed, the storage may be deleted already", conf->name);
+		return true;
+	}
+#else
 	if (!r)
 		return ret;
+#endif
 
 	destroy_rv = r->ops->destroy(r);
 	if (destroy_rv == 0)
diff --git a/src/lxc/sync.h b/src/lxc/sync.h
index 6703eda..ef03e1e 100644
--- a/src/lxc/sync.h
+++ b/src/lxc/sync.h
@@ -20,11 +20,20 @@ enum /* start */ {
 	START_SYNC_CONFIGURE		=  1,
 	START_SYNC_POST_CONFIGURE	=  2,
 	START_SYNC_IDMAPPED_MOUNTS	=  3,
+#ifdef HAVE_ISULAD
+	LXC_SYNC_OCI_PRESTART_HOOK = 4,
+	START_SYNC_CGROUP_LIMITS	=  5,
+	START_SYNC_FDS			=  6,
+	START_SYNC_READY_START		=  7,
+	START_SYNC_RESTART		=  8,
+	START_SYNC_POST_RESTART		=  9,
+#else
 	START_SYNC_CGROUP_LIMITS	=  4,
 	START_SYNC_FDS			=  5,
 	START_SYNC_READY_START		=  6,
 	START_SYNC_RESTART		=  7,
 	START_SYNC_POST_RESTART		=  8,
+#endif
 };
 
 enum /* attach */ {
diff --git a/src/lxc/terminal.c b/src/lxc/terminal.c
index a1dcc2d..8da00a9 100644
--- a/src/lxc/terminal.c
+++ b/src/lxc/terminal.c
@@ -28,6 +28,10 @@
 #include "syscall_wrappers.h"
 #include "terminal.h"
 #include "utils.h"
+#ifdef HAVE_ISULAD
+#include "logger_json_file.h"
+#include "include/strlcpy.h"
+#endif
 
 #if HAVE_OPENPTY
 #include <pty.h>
@@ -193,6 +197,69 @@ static int lxc_terminal_truncate_log_file(struct lxc_terminal *terminal)
 	return lxc_unpriv(ftruncate(terminal->log_fd, 0));
 }
 
+#ifdef HAVE_ISULAD
+// change windows size API for iSulad
+int lxc_set_terminal_winsz(struct lxc_terminal *terminal, unsigned int height, unsigned int width)
+{
+	int ret = 0;
+	struct winsize wsz;
+
+	if (terminal->ptmx < 0) {
+		return 0;
+	}
+
+	ret = ioctl(terminal->ptmx, TIOCGWINSZ, &wsz);
+	if (ret < 0) {
+		WARN("Failed to get window size");
+		return -1;
+	}
+	wsz.ws_col = width;
+	wsz.ws_row = height;
+
+	ret = ioctl(terminal->ptmx, TIOCSWINSZ, &wsz);
+	if (ret < 0)
+		WARN("Failed to set window size");
+	else
+		DEBUG("Set window size to %d columns and %d rows", wsz.ws_col,
+		      wsz.ws_row);
+	return ret;
+}
+
+/*
+ * isulad: support mult-logfiles
+ * */
+static int lxc_terminal_rename_old_log_file(struct lxc_terminal *terminal)
+{
+	int ret;
+	unsigned int i;
+	char tmp[PATH_MAX] = {0};
+	char *rename_fname = NULL;
+
+	for (i = terminal->log_rotate - 1; i > 1; i--) {
+		ret = snprintf(tmp, PATH_MAX, "%s.%u", terminal->log_path, i);
+		if (ret < 0 || ret >= PATH_MAX) {
+			free(rename_fname);
+			return -EFBIG;
+		}
+		free(rename_fname);
+		rename_fname = safe_strdup(tmp);
+		ret = snprintf(tmp, PATH_MAX, "%s.%u", terminal->log_path, (i - 1));
+		if (ret < 0 || ret >= PATH_MAX) {
+			free(rename_fname);
+			return -EFBIG;
+		}
+		ret = lxc_unpriv(rename(tmp, rename_fname));
+		if (ret < 0 && errno != ENOENT) {
+			free(rename_fname);
+			return ret;
+		}
+	}
+
+	free(rename_fname);
+	return 0;
+}
+#endif
+
 static int lxc_terminal_rotate_log_file(struct lxc_terminal *terminal)
 {
 	__do_free char *tmp = NULL;
@@ -206,6 +273,15 @@ static int lxc_terminal_rotate_log_file(struct lxc_terminal *terminal)
 	if (terminal->log_fd < 0)
 		return -EBADF;
 
+#ifdef HAVE_ISULAD
+	/* isuald: rotate old log file first */
+	ret = lxc_terminal_rename_old_log_file(terminal);
+	if(ret != 0) {
+		ERROR("Rename old log file failed");
+		return ret;
+	}
+#endif
+
 	len = strlen(terminal->log_path) + sizeof(".1");
 	tmp = must_realloc(NULL, len);
 
@@ -222,6 +298,92 @@ static int lxc_terminal_rotate_log_file(struct lxc_terminal *terminal)
 	return lxc_terminal_create_log_file(terminal);
 }
 
+#ifdef HAVE_ISULAD
+static int do_isulad_io(int fd, struct lxc_terminal *terminal)
+{
+	char buf[LXC_TERMINAL_BUFFER_SIZE];
+	int r, w, w_log, w_rbuf;
+
+	w = r = lxc_read_nointr(fd, buf, sizeof(buf));
+	if (r <= 0) {
+		if (lxc_terminal_is_fifo(fd, &terminal->fifos)) {
+			// delete failure fifo, and continue io loop
+			lxc_terminal_delete_fifo(fd, &terminal->fifos);
+		} else if (fd == terminal->pipes[1][0]) {
+			// disable stdout of container
+			terminal->pipes[1][0] = -EBADF;
+		} else if (fd == terminal->pipes[2][0]) {
+			// disable stderr of container
+			terminal->pipes[2][0] = -EBADF;
+		} else if (fd == terminal->pipes[0][1]) {
+			terminal->pipes[0][1] = -EBADF;
+			TRACE("closed stdin pipe of container stdin");
+		} else {
+			// other fd should break io loop
+			return -1;
+		}
+		return 0;
+	}
+
+	w_rbuf = w_log = 0;
+	if (lxc_terminal_is_fifo(fd, &terminal->fifos)) {
+		if (terminal->ptx > 0)
+			w = lxc_write_nointr(terminal->ptx, buf, r);
+		if (terminal->pipes[0][1] > 0)
+			w = lxc_write_nointr(terminal->pipes[0][1], buf, r);
+		if (w != r)
+			WARN("Short write on ptx/pipe r:%d != w:%d", r, w);
+	}
+
+	if (fd == terminal->pipes[1][0] || fd == terminal->pipes[2][0]) {
+		/* write to peer first */
+		if (terminal->peer >= 0)
+			w = lxc_write_nointr(terminal->peer, buf, r);
+
+		/* isulad: forward data to fifos */
+		lxc_forward_data_to_fifo(&terminal->fifos, fd == terminal->pipes[2][0], buf, r);
+
+		/* write to terminal ringbuffer */
+		if (terminal->buffer_size > 0)
+			w_rbuf = lxc_ringbuf_write(&terminal->ringbuf, buf, r);
+
+		/* write to terminal log */
+		if (terminal->log_fd >= 0) {
+			if (fd == terminal->pipes[1][0])
+				w_log = isulad_lxc_terminal_write_log_file(terminal, "stdout", buf, r);
+			else
+				w_log = isulad_lxc_terminal_write_log_file(terminal, "stderr", buf, r);
+		}
+
+		if (w != r)
+			WARN("Short write on peer r:%d != w:%d", r, w);
+	}
+
+	if (w_rbuf < 0) {
+		errno = -w_rbuf;
+		SYSTRACE("Failed to write %d bytes to terminal ringbuffer", r);
+	}
+
+	if (w_log < 0)
+		TRACE("Failed to write %d bytes to terminal log", r);
+
+	return 0;
+}
+
+static int isulad_io_handler(int fd, uint32_t events, void *data,
+				       struct lxc_async_descr *descr)
+{
+	struct lxc_terminal *terminal = data;
+	int ret;
+
+	ret = do_isulad_io(fd, data);
+	if (ret < 0)
+		return log_info(LXC_MAINLOOP_CLOSE,
+				"Terminal client on fd %d has exited", fd);
+
+	return LXC_MAINLOOP_CONTINUE;
+}
+#else
 static int lxc_terminal_write_log_file(struct lxc_terminal *terminal, char *buf,
 				       int bytes_read)
 {
@@ -327,6 +489,7 @@ static int lxc_terminal_write_log_file(struct lxc_terminal *terminal, char *buf,
 	bytes_read -= ret;
 	return bytes_read;
 }
+#endif
 
 static int lxc_terminal_ptx_io(struct lxc_terminal *terminal)
 {
@@ -342,13 +505,22 @@ static int lxc_terminal_ptx_io(struct lxc_terminal *terminal)
 	if (terminal->peer >= 0)
 		w = lxc_write_nointr(terminal->peer, buf, r);
 
+#ifdef HAVE_ISULAD
+	/* isulad: forward data to fifos */
+	lxc_forward_data_to_fifo(&terminal->fifos, fd == terminal->pipes[2][0], buf, r);
+#endif
+
 	/* write to terminal ringbuffer */
 	if (terminal->buffer_size > 0)
 		w_rbuf = lxc_ringbuf_write(&terminal->ringbuf, buf, r);
 
 	/* write to terminal log */
 	if (terminal->log_fd >= 0)
+#ifdef HAVE_ISULAD
+		w_log = isulad_lxc_terminal_write_log_file(terminal, "stdout", buf, r); // isulad: distinguishes between stderr and stdout
+#else
 		w_log = lxc_terminal_write_log_file(terminal, buf, r);
+#endif
 
 	if (w != r)
 		WARN("Short write on terminal r:%d != w:%d", r, w);
@@ -368,12 +540,30 @@ static int lxc_terminal_peer_io(struct lxc_terminal *terminal)
 {
 	char buf[LXC_TERMINAL_BUFFER_SIZE];
 	int r, w;
+#ifdef HAVE_ISULAD
+	int w_pipe;
+#endif
 
 	w = r = lxc_read_nointr(terminal->peer, buf, sizeof(buf));
 	if (r <= 0)
+#ifdef HAVE_ISULAD
+		return 0; // isulad: do not close mainloop when peer close
+#else
 		return -1;
+#endif
 
+#ifdef HAVE_ISULAD
+	if (terminal->ptx > 0)
+		w = lxc_write_nointr(terminal->ptx, buf, r);
+	// isulad: write peer data into stdin of container
+	if (terminal->pipes[0][1] > 0) {
+		w_pipe = lxc_write_nointr(terminal->pipes[0][1], buf, r);
+		if (w_pipe != r)
+			WARN("Short write on pipe r:%d != w_pipe:%d", r, w_pipe);
+	}
+else
 	w = lxc_write_nointr(terminal->ptx, buf, r);
+#endif
 	if (w != r)
 		WARN("Short write on terminal r:%d != w:%d", r, w);
 
@@ -442,6 +632,124 @@ static int lxc_terminal_mainloop_add_peer(struct lxc_terminal *terminal)
 	return 0;
 }
 
+#ifdef HAVE_ISULAD
+/* isulad add pipes to mainloop
+*  if disable-pty setted, we use pipes to connect with isulad
+*  isulad                          lxc monitor                       container
+*  stdin/out/err   <--fifo-->       pipe[3]        <--pipe-->      stdin/out/err
+*/
+static int lxc_terminal_mainloop_add_pipes(struct lxc_terminal *terminal)
+{
+	int ret = 0;
+
+	// parent read data from fifo, and send to stdin of container
+	if (terminal->pipes[0][1] > 0) {
+		ret = lxc_mainloop_add_handler(terminal->descr, terminal->pipes[0][1],
+		                               isulad_io_handler,
+									   default_cleanup_handler, terminal, "isulad_io_handler_pipe_in");
+		if (ret) {
+			ERROR("pipe fd %d not added to mainloop", terminal->pipes[0][1]);
+			return -1;
+		}
+	}
+	// parent read data from stdout of container, and send to fifo
+	if (terminal->pipes[1][0] > 0) {
+		ret = lxc_mainloop_add_handler(terminal->descr, terminal->pipes[1][0],
+		                               isulad_io_handler,
+									   default_cleanup_handler, terminal, "isulad_io_handler_pipe_out");
+		if (ret) {
+			ERROR("pipe fd %d not added to mainloop", terminal->pipes[1][0]);
+			return -1;
+		}
+	}
+	// parent read data from stderr of container, and send to fifo
+	if (terminal->pipes[2][0] > 0) {
+		ret = lxc_mainloop_add_handler(terminal->descr, terminal->pipes[2][0],
+		                               isulad_io_handler,
+									   default_cleanup_handler, terminal, "isulad_io_handler_pipe_err");
+		if (ret) {
+			ERROR("pipe fd %d not added to mainloop", terminal->pipes[2][0]);
+			return -1;
+		}
+	}
+	return ret;
+}
+
+/* isulad add fifo to mainloop
+*  if disable-pty is false, we use pipes to connect with isulad
+*  isulad                          lxc monitor                       container
+*  stdin/out/err   <--fifo-->       pty             <------>      stdin/out/err
+*/
+static int lxc_terminal_mainloop_add_fifo(struct lxc_terminal *terminal)
+{
+	int ret = 0;
+	struct lxc_list *it = NULL;
+	struct lxc_list *next = NULL;
+	struct lxc_fifos_fd *elem = NULL;
+
+	lxc_list_for_each_safe(it, &terminal->fifos, next) {
+		elem = it->elem;
+		if (elem->in_fd >= 0) {
+			ret = lxc_mainloop_add_handler(terminal->descr, elem->in_fd,
+			                               isulad_io_handler,
+										   default_cleanup_handler, terminal, "isulad_io_handler_fifos");
+			if (ret) {
+				ERROR("console fifo %s not added to mainloop", elem->in_fifo);
+				return -1;
+			}
+		}
+	}
+	return ret;
+}
+
+int lxc_terminal_mainloop_add(struct lxc_async_descr *descr,
+			      struct lxc_terminal *terminal)
+{
+	int ret;
+
+	/* We cache the descr so that we can add an fd to it when someone
+	 * does attach to it in lxc_terminal_allocate().
+	 */
+	terminal->descr = descr;
+
+	ret = lxc_terminal_mainloop_add_peer(terminal);
+	if (ret < 0) {
+		ERROR("Failed to add handler for terminal peer to mainloop");
+		return -1;
+	}
+
+	/* isulad add pipes to mainloop */
+	ret = lxc_terminal_mainloop_add_pipes(terminal);
+	if (ret < 0) {
+		ERROR("Failed to add handler for terminal fifos to mainloop");
+		return -1;
+	}
+
+	/* isulad add fifo to mainloop */
+	ret = lxc_terminal_mainloop_add_fifo(terminal);
+	if (ret < 0) {
+		ERROR("Failed to add handler for terminal fifos to mainloop");
+		return -1;
+	}
+
+	// iSulad change: should support pipe replace to pty, this check will cause isulad fifo filed
+	if (terminal->ptx < 0) {
+		INFO("Terminal is not initialized");
+		return 0;
+	}
+
+	ret = lxc_mainloop_add_handler(descr, terminal->ptx,
+				       lxc_terminal_ptx_io_handler,
+				       default_cleanup_handler,
+				       terminal, "lxc_terminal_ptx_io_handler");
+	if (ret < 0) {
+		ERROR("Failed to add handler for terminal ptx fd %d to mainloop", terminal->ptx);
+		return -1;
+	}
+
+	return 0;
+}
+#else
 int lxc_terminal_mainloop_add(struct lxc_async_descr *descr,
 			      struct lxc_terminal *terminal)
 {
@@ -468,6 +776,7 @@ int lxc_terminal_mainloop_add(struct lxc_async_descr *descr,
 
 	return lxc_terminal_mainloop_add_peer(terminal);
 }
+#endif
 
 int lxc_setup_tios(int fd, struct termios *oldtios)
 {
@@ -686,8 +995,27 @@ static int lxc_terminal_peer_default(struct lxc_terminal *terminal)
 
 	if (terminal->path)
 		path = terminal->path;
+#ifdef HAVE_ISULAD
+	/* isulad: if no console was given, try current controlling terminal, there
+	 * won't be one if we were started as a daemon (-d)
+	 */
+	if (!path && !access("/dev/tty", F_OK)) {
+		int fd;
+		fd = open("/dev/tty", O_RDWR);
+		if (fd >= 0) {
+			close(fd);
+			path = "/dev/tty";
+		}
+	}
+
+	if (!path) {
+		DEBUG("Not have a controlling terminal");
+		return 0;
+	}
+#else
 	else
 		path = "/dev/tty";
+#endif
 
 	terminal->peer = lxc_unpriv(open(path, O_RDWR | O_CLOEXEC));
 	if (terminal->peer < 0) {
@@ -803,6 +1131,35 @@ void lxc_terminal_delete(struct lxc_terminal *terminal)
 	if (terminal->log_fd >= 0)
 		close(terminal->log_fd);
 	terminal->log_fd = -1;
+
+#ifdef HAVE_ISULAD
+	if (is_syslog(terminal->log_driver)) {
+		closelog();
+		free(terminal->log_driver);
+	}
+	/* isulad: close all pipes */
+	if (terminal->pipes[0][0] >= 0)
+		close(terminal->pipes[0][0]);
+	terminal->pipes[0][0] = -1;
+	if (terminal->pipes[0][1] >= 0)
+		close(terminal->pipes[0][1]);
+	terminal->pipes[0][1] = -1;
+	if (terminal->pipes[1][0] >= 0)
+		close(terminal->pipes[1][0]);
+	terminal->pipes[1][0] = -1;
+	if (terminal->pipes[1][1] >= 0)
+		close(terminal->pipes[1][1]);
+	terminal->pipes[1][1] = -1;
+	if (terminal->pipes[2][0] >= 0)
+		close(terminal->pipes[2][0]);
+	terminal->pipes[2][0] = -1;
+	if (terminal->pipes[2][1] >= 0)
+		close(terminal->pipes[2][1]);
+	terminal->pipes[2][1] = -1;
+
+	/* isulad: delete all fifos */
+	lxc_terminal_delete_fifo(-1, &terminal->fifos);
+#endif
 }
 
 /**
@@ -895,6 +1252,176 @@ static int lxc_terminal_map_ids(struct lxc_conf *c, struct lxc_terminal *termina
 	return 0;
 }
 
+#ifdef HAVE_ISULAD
+/* isulad: fd_nonblock */
+static int fd_nonblock(int fd)
+{
+	int flags;
+
+	flags = fcntl(fd, F_GETFL);
+
+	return fcntl(fd, F_SETFL, (int)((unsigned int)flags | O_NONBLOCK));
+}
+
+static int terminal_fifo_open(const char *fifo_path, int flags)
+{
+	int fd = -1;
+
+	fd = lxc_open(fifo_path, flags, 0);
+	if (fd < 0) {
+		WARN("Failed to open fifo %s to send message: %s.", fifo_path,
+		     strerror(errno));
+		return -1;
+	}
+
+	return fd;
+}
+
+static bool fifo_exists(const char *path)
+{
+	struct stat sb;
+	int ret;
+
+	ret = stat(path, &sb);
+	if (ret < 0)
+		// could be something other than eexist, just say no
+		return false;
+	return S_ISFIFO(sb.st_mode);
+}
+
+/* isulad: set terminal fifos */
+static int lxc_terminal_set_fifo(struct lxc_terminal *console, const char *in, const char *out, const char *err, int *input_fd)
+{
+	int fifofd_in = -1, fifofd_out = -1, fifofd_err = -1;
+	struct lxc_fifos_fd *fifo_elem = NULL;
+
+	if ((in && !fifo_exists(in)) || (out && !fifo_exists(out)) || (err && !fifo_exists(err))) {
+		ERROR("File %s or %s or %s does not refer to a FIFO", in, out, err);
+		return -1;
+	}
+
+	if (in) {
+		fifofd_in = terminal_fifo_open(in, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
+		if (fifofd_in < 0) {
+			SYSERROR("Failed to open FIFO: %s", in);
+			return -1;
+		}
+	}
+
+	if (out) {
+		fifofd_out = terminal_fifo_open(out, O_WRONLY | O_NONBLOCK | O_CLOEXEC);
+		if (fifofd_out < 0) {
+			SYSERROR("Failed to open FIFO: %s", out);
+			if (fifofd_in >= 0)
+				close(fifofd_in);
+			return -1;
+		}
+	}
+
+	if (err) {
+		fifofd_err = terminal_fifo_open(err, O_WRONLY | O_NONBLOCK | O_CLOEXEC);
+		if (fifofd_err < 0) {
+			SYSERROR("Failed to open FIFO: %s", err);
+			if (fifofd_in >= 0)
+				close(fifofd_in);
+			if (fifofd_out >= 0)
+				close(fifofd_out);
+			return -1;
+		}
+	}
+
+	fifo_elem = malloc(sizeof(*fifo_elem));
+	if (fifo_elem == NULL) {
+		if (fifofd_in >= 0)
+			close(fifofd_in);
+		if (fifofd_out >= 0)
+			close(fifofd_out);
+		if (fifofd_err >= 0)
+			close(fifofd_err);
+		return -1;
+	}
+	memset(fifo_elem, 0, sizeof(*fifo_elem));
+
+	fifo_elem->in_fifo = safe_strdup(in ? in : "");
+	fifo_elem->out_fifo = safe_strdup(out ? out : "");
+	fifo_elem->err_fifo = safe_strdup(err ? err : "");
+	fifo_elem->in_fd = fifofd_in;
+	fifo_elem->out_fd = fifofd_out;
+	fifo_elem->err_fd = fifofd_err;
+	lxc_list_add_elem(&fifo_elem->node, fifo_elem);
+	lxc_list_add_tail(&console->fifos, &fifo_elem->node);
+
+	if (input_fd)
+		*input_fd = fifofd_in;
+
+	return 0;
+}
+
+/* isulad: add default fifos */
+static int lxc_terminal_fifo_default(struct lxc_terminal *terminal)
+{
+	if (terminal->init_fifo[0] || terminal->init_fifo[1] || terminal->init_fifo[2])
+		return lxc_terminal_set_fifo(terminal, terminal->init_fifo[0], terminal->init_fifo[1], terminal->init_fifo[2], NULL);
+	return 0;
+}
+
+/* isulad: add fifos dynamic*/
+int lxc_terminal_add_fifos(struct lxc_conf *conf, const char *fifonames)
+{
+	int ret = 0;
+	struct lxc_terminal *terminal = &conf->console;
+	int fifofd_in = -1;
+	char *tmp = NULL, *saveptr = NULL, *in = NULL, *out = NULL, *err = NULL;
+	const char *none_fifo_name = "none";
+
+	tmp = safe_strdup(fifonames);
+
+	in = strtok_r(tmp, "&&&&", &saveptr);
+	if (!in) {
+		ret = -1;
+		goto free_out;
+	}
+	if (strcmp(in, none_fifo_name) == 0)
+		in = NULL;
+
+	out = strtok_r(NULL, "&&&&",  &saveptr);
+	if (!out) {
+		ret = -1;
+		goto free_out;
+	}
+	if (strcmp(out, none_fifo_name) == 0)
+		out = NULL;
+
+	err = strtok_r(NULL, "&&&&",  &saveptr);
+	if (!err) {
+		ret = -1;
+		goto free_out;
+	}
+	if (strcmp(err, none_fifo_name) == 0)
+		err = NULL;
+
+	ret = lxc_terminal_set_fifo(terminal, in, out, err, &fifofd_in);
+	if (ret < 0) {
+		ERROR("Faild to set fifos to console config");
+		ret = -1;
+		goto free_out;
+	}
+
+	if (lxc_mainloop_add_handler(terminal->descr, fifofd_in,
+	                             lxc_terminal_io_cb, terminal)) {
+		ERROR("console fifo not added to mainloop");
+		lxc_terminal_delete_fifo(fifofd_in, &terminal->fifos);
+		ret = -1;
+		goto free_out;
+	}
+
+free_out:
+	if (tmp)
+		free(tmp);
+	return ret;
+}
+#endif
+
 static int lxc_terminal_create_foreign(struct lxc_conf *conf, struct lxc_terminal *terminal)
 {
 	int ret;
@@ -923,6 +1450,15 @@ static int lxc_terminal_create_foreign(struct lxc_conf *conf, struct lxc_termina
 		goto err;
 	}
 
+#ifdef HAVE_ISULAD
+	/* isulad: make ptmx NONBLOCK */
+	ret = fd_nonblock(terminal->ptx);
+	if (ret < 0) {
+		SYSERROR("Failed to set O_NONBLOCK flag on terminal ptx");
+		goto err;
+	}
+#endif
+
 	ret = fd_cloexec(terminal->pty, true);
 	if (ret < 0) {
 		SYSERROR("Failed to set FD_CLOEXEC flag on terminal pty");
@@ -1095,8 +1631,42 @@ static int lxc_terminal_create_native(const char *name, const char *lxcpath,
 int lxc_terminal_create(const char *name, const char *lxcpath,
 			struct lxc_conf *conf, struct lxc_terminal *terminal)
 {
+#ifndef HAVE_ISULAD
 	if (!lxc_terminal_create_native(name, lxcpath, terminal))
 		return 0;
+#else
+	/* isulad: open default fifos */
+	ret = lxc_terminal_fifo_default(terminal);
+	if (ret < 0) {
+		ERROR("Failed to allocate fifo terminal");
+		lxc_terminal_delete(terminal);
+		return -ENODEV;
+	}
+
+	if (terminal->disable_pty) {
+		/* isulad: create 3 pipes */
+		/* for stdin */
+		if (pipe2(terminal->pipes[0], O_CLOEXEC)) {
+			ERROR("Failed to create stdin pipe");
+			lxc_terminal_delete(terminal);
+			return -ENODEV;
+		}
+
+		/* for stdout */
+		if (pipe2(terminal->pipes[1], O_CLOEXEC)) {
+			ERROR("Failed to create stdout pipe");
+			lxc_terminal_delete(terminal);
+			return -ENODEV;
+		}
+		/* for stderr */
+		if (pipe2(terminal->pipes[2], O_CLOEXEC)) {
+			ERROR("Failed to create stderr pipe");
+			lxc_terminal_delete(terminal);
+			return -ENODEV;
+		}
+		return 0;
+	}
+#endif
 
 	return lxc_terminal_create_foreign(conf, terminal);
 }
@@ -1113,6 +1683,19 @@ int lxc_terminal_setup(struct lxc_conf *conf)
 	if (ret < 0)
 		goto err;
 
+#ifdef HAVE_ISULAD
+	if (is_syslog(terminal->log_driver)) {
+		if (terminal->log_syslog_tag == NULL) {
+				terminal->log_syslog_tag = malloc(16 * sizeof(char));
+				(void)strlcpy(terminal->log_syslog_tag, conf->name, 16);
+		}
+		if (terminal->log_syslog_facility <= 0) {
+				terminal->log_syslog_facility = LOG_DAEMON;
+		}
+		openlog(terminal->log_syslog_tag, LOG_PID, terminal->log_syslog_facility);
+	}
+#endif
+
 	ret = lxc_terminal_create_log_file(terminal);
 	if (ret < 0)
 		goto err;
@@ -1356,7 +1939,11 @@ int lxc_terminal_prepare_login(int fd)
 	if (ret < 0)
 		return -1;
 
+#ifdef HAVE_ISULAD
+	ret = set_stdfds(fd);
+#else
 	ret = lxc_terminal_set_stdfds(fd);
+#endif
 	if (ret < 0)
 		return -1;
 
@@ -1384,6 +1971,19 @@ void lxc_terminal_init(struct lxc_terminal *terminal)
 	terminal->peer = -EBADF;
 	terminal->log_fd = -EBADF;
 	lxc_terminal_info_init(&terminal->proxy);
+
+#ifdef HAVE_ISULAD
+	terminal->init_fifo[0] = NULL;
+	terminal->init_fifo[1] = NULL;
+	terminal->init_fifo[2] = NULL;
+	terminal->pipes[0][0] = -1;
+	terminal->pipes[0][1] = -1;
+	terminal->pipes[1][0] = -1;
+	terminal->pipes[1][1] = -1;
+	terminal->pipes[2][0] = -1;
+	terminal->pipes[2][1] = -1;
+	lxc_list_init(&terminal->fifos);
+#endif
 }
 
 void lxc_terminal_conf_free(struct lxc_terminal *terminal)
@@ -1393,4 +1993,14 @@ void lxc_terminal_conf_free(struct lxc_terminal *terminal)
 	if (terminal->buffer_size > 0 && terminal->ringbuf.addr)
 		lxc_ringbuf_release(&terminal->ringbuf);
 	lxc_terminal_signal_fini(terminal);
+
+#ifdef HAVE_ISULAD
+	/*isulad: free console fifos */
+	free(terminal->init_fifo[0]);
+	free(terminal->init_fifo[1]);
+	free(terminal->init_fifo[2]);
+	lxc_terminal_delete_fifo(-1, &terminal->fifos);
+	free(terminal->log_driver);
+	free(terminal->log_syslog_tag);
+#endif
 }
diff --git a/src/lxc/terminal.h b/src/lxc/terminal.h
index d8e0f5c..886b8f6 100644
--- a/src/lxc/terminal.h
+++ b/src/lxc/terminal.h
@@ -85,6 +85,17 @@ struct lxc_terminal {
 
 		/* whether the log file will be rotated */
 		unsigned int log_rotate;
+
+#ifdef HAVE_ISULAD
+		/* driver of log, support file and syslog */
+		char *log_driver;
+
+		/* syslog tag for every log */
+		char *log_syslog_tag;
+
+		/* syslog facility */
+		int log_syslog_facility;
+#endif
 	};
 
 	struct /* lxc_terminal_ringbuf */ {
@@ -94,8 +105,29 @@ struct lxc_terminal {
 		/* the in-memory ringbuffer */
 		struct lxc_ringbuf ringbuf;
 	};
+
+#ifdef HAVE_ISULAD
+	char *init_fifo[3]; /* isulad: default fifos for the start */
+	struct lxc_list fifos; /* isulad: fifos used to forward teminal */
+	bool disable_pty;
+	bool open_stdin;
+	int pipes[3][2]; /* isulad: pipes for dup to container fds of stdin,stdout,stderr on daemonize mode*/
+#endif
 };
 
+#ifdef HAVE_ISULAD
+/* isulad: fifo struct */
+struct lxc_fifos_fd {
+	char *in_fifo;
+	char *out_fifo;
+	char *err_fifo;
+	int in_fd;
+	int out_fd;
+	int err_fd;
+	struct lxc_list node;
+};
+#endif
+
 /**
  * lxc_terminal_allocate: allocate the console or a tty
  *
@@ -265,4 +297,9 @@ static inline bool wants_console(const struct lxc_terminal *terminal)
 	return !terminal->path || !strequal(terminal->path, "none");
 }
 
+#ifdef HAVE_ISULAD
+__hidden extern int lxc_terminal_add_fifos(struct lxc_conf *conf, const char *fifonames);
+__hidden extern int lxc_set_terminal_winsz(struct lxc_terminal *terminal, unsigned int height, unsigned int width);
+#endif
+
 #endif /* __LXC_TERMINAL_H */
diff --git a/src/lxc/tools/lxc_ls.c b/src/lxc/tools/lxc_ls.c
index 23bee59..86a453d 100644
--- a/src/lxc/tools/lxc_ls.c
+++ b/src/lxc/tools/lxc_ls.c
@@ -104,7 +104,11 @@ struct wrapargs {
 /*
  * Takes struct wrapargs as argument.
  */
+#ifdef HAVE_ISULAD
+static int ls_get_wrapper(void *wrap, int msgfd);
+#else
 static int ls_get_wrapper(void *wrap);
+#endif
 
 /*
  * To calculate swap usage we should not simply check memory.usage_in_bytes and
@@ -999,7 +1003,11 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg)
 	return 0;
 }
 
+#ifdef HAVE_ISULAD
+static int ls_get_wrapper(void *wrap, int msgfd);
+#else
 static int ls_get_wrapper(void *wrap)
+#endif
 {
 	int ret = -1;
 	size_t len = 0;
diff --git a/src/lxc/utils.c b/src/lxc/utils.c
index d3d82e2..25cb0d1 100644
--- a/src/lxc/utils.c
+++ b/src/lxc/utils.c
@@ -1021,7 +1021,11 @@ static int open_if_safe(int dirfd, const char *nextpath)
  *
  * Return an open fd for the path, or <0 on error.
  */
+#ifdef HAVE_ISULAD
+int open_without_symlink(const char *target, const char *prefix_skip)
+#else
 static int open_without_symlink(const char *target, const char *prefix_skip)
+#endif
 {
 	int curlen = 0, dirfd, fulllen, i;
 	char *dup;
@@ -1151,6 +1155,65 @@ int safe_mount_beneath_at(int beneath_fd, const char *src, const char *dst, cons
 	return __safe_mount_beneath_at(beneath_fd, src, dst, fstype, flags, data);
 }
 
+#ifdef HAVE_ISULAD
+static int format_mount_label(const char *data, const char *mount_label, char **mnt_opts)
+{
+	int ret = 0;
+
+	if (mount_label != NULL) {
+		if (data != NULL) {
+			ret = asprintf(mnt_opts, "%s,context=\"%s\"", data, mount_label);
+		} else {
+			ret = asprintf(mnt_opts, "context=\"%s\"", mount_label);
+		}
+
+		return ret < 0 ? -1 : 0;
+	}
+
+	*mnt_opts = data != NULL ? strdup(data) : NULL;
+	return 0;
+}
+
+static int receive_mount_options(const char *data, const char *mount_label,
+    const char *fstype, char **mnt_opts)
+{
+	// SELinux kernels don't support labeling of /proc or /sys
+	if (fstype != NULL && (strcmp(fstype, "proc") == 0 || strcmp(fstype, "sysfs") == 0)) {
+		return format_mount_label(data, NULL, mnt_opts);
+	}
+
+	return format_mount_label(data, mount_label, mnt_opts);
+}
+
+static int relabel_bind_mount_source(const char *src, const char *fstype, const char *data, const char *mount_label)
+{
+	__do_free_string_list char **parts = NULL;
+	ssize_t parts_len;
+	ssize_t i;
+
+	if (data == NULL) {
+		return lsm_relabel(src, mount_label, false);
+	}
+
+	parts = lxc_string_split(data, ',');
+	if (parts == NULL) {
+		return -1;
+	}
+
+	parts_len = lxc_array_len((void **)parts);
+	for (i = 0; i < parts_len; i++) {
+		if (strcmp(parts[i], "z") == 0) {
+			return lsm_relabel(src, mount_label, true);
+		} else if (strcmp(parts[i], "Z") == 0) {
+			return lsm_relabel(src, mount_label, false);
+		}
+	}
+
+	return lsm_relabel(src, mount_label, false);
+}
+
+#endif
+
 /*
  * Safely mount a path into a container, ensuring that the mount target
  * is under the container's @rootfs.  (If @rootfs is NULL, then the container
@@ -1159,14 +1222,22 @@ int safe_mount_beneath_at(int beneath_fd, const char *src, const char *dst, cons
  * CAVEAT: This function must not be used for other purposes than container
  * setup before executing the container's init
  */
+#ifdef HAVE_ISULAD
+int safe_mount(const char *src, const char *dest, const char *fstype,
+		unsigned long flags, const void *data, const char *rootfs, const char *mount_label)
+#else
 int safe_mount(const char *src, const char *dest, const char *fstype,
 		unsigned long flags, const void *data, const char *rootfs)
+#endif
 {
 	int destfd, ret, saved_errno;
 	/* Only needs enough for /proc/self/fd/<fd>. */
 	char srcbuf[50], destbuf[50];
 	int srcfd = -1;
 	const char *mntsrc = src;
+#ifdef HAVE_ISULAD
+  __do_free char *mnt_opts = NULL;
+#endif
 
 	if (!rootfs)
 		rootfs = "";
@@ -1209,8 +1280,23 @@ int safe_mount(const char *src, const char *dest, const char *fstype,
 		return -EINVAL;
 	}
 
+#ifdef HAVE_ISULAD
+	if (receive_mount_options(data, mount_label, fstype, &mnt_opts) != 0) {
+		ERROR("Failed to receive mount options");
+		return -EINVAL;
+	}
+
+	ret = mount(mntsrc, destbuf, fstype, flags, mnt_opts);
+	saved_errno = errno;
+	if (ret < 0 && fstype != NULL && strcmp(fstype, "mqueue") == 0) {
+		INFO("older kernels don't support labeling of /dev/mqueue, retry without selinux context");
+		ret = mount(mntsrc, destbuf, fstype, flags, data);
+		saved_errno = errno;
+	}
+#else
 	ret = mount(mntsrc, destbuf, fstype, flags, data);
 	saved_errno = errno;
+#endif
 	if (srcfd != -1)
 		close(srcfd);
 
@@ -1221,6 +1307,18 @@ int safe_mount(const char *src, const char *dest, const char *fstype,
 		return ret;
 	}
 
+#ifdef HAVE_ISULAD
+	if (fstype != NULL && strcmp(fstype, "mqueue") == 0 && lsm_file_label_set(dest, mount_label) != 0) {
+		ERROR("Failed to set file label on %s", dest);
+		return -EINVAL;
+	}
+
+	if (fstype != NULL && strcmp(fstype, "bind") == 0 &&
+		    relabel_bind_mount_source(src, fstype, (const char *)data, mount_label) != 0) {
+		ERROR("Failed to reabel %s with %s", src, mount_label);
+		return -EINVAL;
+	}
+#endif
 	return 0;
 }
 
@@ -1442,6 +1540,11 @@ static int lxc_get_unused_loop_dev(char *name_loop)
 {
 	int loop_nr, ret;
 	int fd_ctl = -1, fd_tmp = -1;
+#ifdef HAVE_ISULAD
+	// isulad: retry and try mknod
+	int max_retry = 200;
+	bool try_mknod = true;
+#endif
 
 	fd_ctl = open("/dev/loop-control", O_RDWR | O_CLOEXEC);
 	if (fd_ctl < 0) {
@@ -1459,6 +1562,39 @@ static int lxc_get_unused_loop_dev(char *name_loop)
 	if (ret < 0)
 		goto on_error;
 
+#ifdef HAVE_ISULAD
+	while (max_retry > 0) {
+		max_retry--;
+		fd_tmp = open(name_loop, O_RDWR | O_CLOEXEC);
+		if (fd_tmp > 0) {
+			goto on_error;
+		}
+		/* Success of LOOP_CTL_GET_FREE doesn't mean /dev/loop$i is ready,
+		* we try to make node by ourself to avoid wait. */
+		if (try_mknod) {
+			/* Do not check result of mknod because LOOP_CTL_GET_FREE
+			* alse do mknod, so this mknod may fail as node already
+			* exist. If we can open the node without error, we can
+			* say that it's be created successfully.
+			*
+			* note: 7 is the major device number of loopback devices
+			*	 in kernel.
+			*/
+			mknod(name_loop, S_IFBLK | 0640, makedev(7, loop_nr));
+			try_mknod = false;
+			continue;
+		}
+		/* we need to wait some time to make sure it's ready for open if
+		* it can't open even if we have already try to make node by ourself. */
+		if (max_retry > 1) {
+			usleep(5000); /* 5 millisecond */
+			continue;
+		}
+		SYSERROR("Failed to open loop \"%s\"", name_loop);
+		// try more once for android
+		break;
+	}
+#endif
 	fd_tmp = open(name_loop, O_RDWR | O_CLOEXEC);
 	if (fd_tmp < 0) {
 		/* on Android loop devices are moved under /dev/block, give it a shot */
@@ -1678,6 +1814,7 @@ uint64_t lxc_find_next_power2(uint64_t n)
 	return n;
 }
 
+#ifndef HAVE_ISULAD
 static int process_dead(/* takes */ int status_fd)
 {
 	__do_close int dupfd = -EBADF;
@@ -1715,15 +1852,20 @@ static int process_dead(/* takes */ int status_fd)
 
 	return ret;
 }
+#endif
 
 int lxc_set_death_signal(int signal, pid_t parent, int parent_status_fd)
 {
 	int ret;
+#ifndef HAVE_ISULAD
 	pid_t ppid;
+#endif
 
 	ret = prctl(PR_SET_PDEATHSIG, prctl_arg(signal), prctl_arg(0),
 		    prctl_arg(0), prctl_arg(0));
 
+#ifndef HAVE_ISULAD
+	// isulad: delete this check, ppid will not be 0 if we shared host pid
 	/* verify that we haven't been orphaned in the meantime */
 	ppid = (pid_t)syscall(SYS_getppid);
 	if (ppid == 0) { /* parent outside our pidns */
@@ -1735,6 +1877,7 @@ int lxc_set_death_signal(int signal, pid_t parent, int parent_status_fd)
 	} else if (ppid != parent) {
 		return raise(SIGKILL);
 	}
+#endif
 
 	if (ret < 0)
 		return -1;
diff --git a/src/lxc/utils.h b/src/lxc/utils.h
index 87feeed..0d326c0 100644
--- a/src/lxc/utils.h
+++ b/src/lxc/utils.h
@@ -140,8 +140,15 @@ __hidden extern char *on_path(const char *cmd, const char *rootfs);
 __hidden extern char *choose_init(const char *rootfs);
 __hidden extern bool switch_to_ns(pid_t pid, const char *ns);
 __hidden extern char *get_template_path(const char *t);
+#ifdef HAVE_ISULAD
+__hidden extern int open_without_symlink(const char *target, const char *prefix_skip);
+__hidden extern int safe_mount(const char *src, const char *dest, const char *fstype,
+		      unsigned long flags, const void *data,
+		      const char *rootfs, const char *mount_label);
+#else
 __hidden extern int safe_mount(const char *src, const char *dest, const char *fstype,
 			       unsigned long flags, const void *data, const char *rootfs);
+#endif
 __hidden extern int open_devnull(void);
 __hidden extern int set_stdfds(int fd);
 __hidden extern int null_stdfds(void);
diff --git a/src/tests/attach.c b/src/tests/attach.c
index b695df3..a6698f5 100644
--- a/src/tests/attach.c
+++ b/src/tests/attach.c
@@ -31,6 +31,9 @@
 #include "lxctest.h"
 #include "utils.h"
 #include "lsm/lsm.h"
+#ifdef HAVE_ISULAD
+#include "config.h"
+#endif
 
 #include <lxc/lxccontainer.h>
 
@@ -80,7 +83,11 @@ static void test_attach_lsm_set_config(struct lxc_container *ct)
 	ct->save_config(ct, NULL);
 }
 
+#ifdef HAVE_ISULAD
+static int test_attach_lsm_func_func(void* payload, int fd)
+#else
 static int test_attach_lsm_func_func(void* payload)
+#endif
 {
 	TSTOUT("%s", lsm_ops->process_label_get(lsm_ops, syscall(SYS_getpid)));
 	return 0;
@@ -191,7 +198,11 @@ static int  test_attach_lsm_func(struct lxc_container *ct) { return 0; }
 static int  test_attach_lsm_cmd(struct lxc_container *ct) { return 0; }
 #endif /* HAVE_APPARMOR || HAVE_SELINUX */
 
+#ifdef HAVE_ISULAD
+static int test_attach_func_func(void* payload, int fd)
+#else
 static int test_attach_func_func(void* payload)
+#endif
 {
 	TSTOUT("%d", (int)syscall(SYS_getpid));
 	return 0;
-- 
2.25.1

