From d6745a42729f4704a0d9913676bf6d8b03c21903 Mon Sep 17 00:00:00 2001
From: zhangxiaoyu <zhangxiaoyu58@huawei.com>
Date: Fri, 15 Jul 2022 17:06:09 +0800
Subject: [PATCH] refactor patch code of utils commands and so on

Signed-off-by: zhangxiaoyu <zhangxiaoyu58@huawei.com>
---
 src/lxc/cgroups/isulad_cgroup2_devices.c | 575 +++++++++++++++++++++++
 src/lxc/commands.c                       | 185 +++++++-
 src/lxc/commands.h                       |  10 +
 src/lxc/conf.h                           |  95 ++++
 src/lxc/isulad_utils.c                   | 319 +++++++++++++
 src/lxc/isulad_utils.h                   |  99 ++++
 src/lxc/lsm/lsm.c                        |  20 +
 src/lxc/lxc.h                            |  19 +
 src/lxc/lxccontainer.h                   | 194 ++++++++
 src/lxc/network.c                        |   8 +
 src/lxc/tools/lxc_ls.c                   |   8 +
 src/lxc/tools/lxc_start.c                | 109 ++++-
 src/lxc/utils.c                          | 173 +++++++
 src/lxc/utils.h                          |  11 +
 14 files changed, 1822 insertions(+), 3 deletions(-)
 create mode 100644 src/lxc/cgroups/isulad_cgroup2_devices.c
 create mode 100644 src/lxc/isulad_utils.c
 create mode 100644 src/lxc/isulad_utils.h

diff --git a/src/lxc/cgroups/isulad_cgroup2_devices.c b/src/lxc/cgroups/isulad_cgroup2_devices.c
new file mode 100644
index 0000000..05613c5
--- /dev/null
+++ b/src/lxc/cgroups/isulad_cgroup2_devices.c
@@ -0,0 +1,575 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+/* Parts of this taken from systemd's implementation. */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "cgroup2_devices.h"
+#include "config.h"
+#include "log.h"
+#include "macro.h"
+#include "memory_utils.h"
+
+#ifdef HAVE_STRUCT_BPF_CGROUP_DEV_CTX
+#include <linux/bpf.h>
+#include <linux/filter.h>
+
+#define BPF_LOG_BUF_SIZE (1 << 23) /* 8MB */
+#ifndef BPF_LOG_LEVEL1
+#define BPF_LOG_LEVEL1 1
+#endif
+
+#ifndef BPF_LOG_LEVEL2
+#define BPF_LOG_LEVEL2 2
+#endif
+
+#ifndef BPF_LOG_LEVEL
+#define BPF_LOG_LEVEL (BPF_LOG_LEVEL1 | BPF_LOG_LEVEL2)
+#endif
+
+lxc_log_define(cgroup2_devices, cgroup);
+
+static int bpf_program_add_instructions(struct bpf_program *prog,
+					const struct bpf_insn *instructions,
+					size_t count)
+{
+
+	struct bpf_insn *new_insn;
+
+	if (prog->kernel_fd >= 0)
+		return log_error_errno(-1, EBUSY, "Refusing to update bpf cgroup program that's already loaded");
+
+	new_insn = realloc(prog->instructions, sizeof(struct bpf_insn) * (count + prog->n_instructions));
+	if (!new_insn)
+		return log_error_errno(-1, ENOMEM, "Failed to reallocate bpf cgroup program");
+
+	prog->instructions = new_insn;
+	memset(prog->instructions + prog->n_instructions, 0,
+	       sizeof(struct bpf_insn) * count);
+	memcpy(prog->instructions + prog->n_instructions, instructions,
+	       sizeof(struct bpf_insn) * count);
+	prog->n_instructions += count;
+
+	return 0;
+}
+
+void bpf_program_free(struct bpf_program *prog)
+{
+	if (!prog)
+		return;
+
+	(void)bpf_program_cgroup_detach(prog);
+
+	if (prog->kernel_fd >= 0)
+		close(prog->kernel_fd);
+	free(prog->instructions);
+	free(prog->attached_path);
+	free(prog);
+}
+
+/* Memory load, dst_reg = *(uint *) (src_reg + off16) */
+#define BPF_LDX_MEM(SIZE, DST, SRC, OFF)                               \
+	((struct bpf_insn){.code = BPF_LDX | BPF_SIZE(SIZE) | BPF_MEM, \
+			   .dst_reg = DST,                             \
+			   .src_reg = SRC,                             \
+			   .off = OFF,                                 \
+			   .imm = 0})
+
+/* ALU ops on immediates, bpf_add|sub|...: dst_reg += imm32 */
+#define BPF_ALU32_IMM(OP, DST, IMM)                              \
+	((struct bpf_insn){.code = BPF_ALU | BPF_OP(OP) | BPF_K, \
+			   .dst_reg = DST,                       \
+			   .src_reg = 0,                         \
+			   .off = 0,                             \
+			   .imm = IMM})
+
+/* Short form of mov, dst_reg = src_reg */
+#define BPF_MOV64_IMM(DST, IMM)                                 \
+	((struct bpf_insn){.code = BPF_ALU64 | BPF_MOV | BPF_K, \
+			   .dst_reg = DST,                      \
+			   .src_reg = 0,                        \
+			   .off = 0,                            \
+			   .imm = IMM})
+
+#define BPF_MOV32_REG(DST, SRC)                               \
+	((struct bpf_insn){.code = BPF_ALU | BPF_MOV | BPF_X, \
+			   .dst_reg = DST,                    \
+			   .src_reg = SRC,                    \
+			   .off = 0,                          \
+			   .imm = 0})
+
+/* Conditional jumps against registers, if (dst_reg 'op' src_reg) goto pc + off16 */
+#define BPF_JMP_REG(OP, DST, SRC, OFF)                           \
+	((struct bpf_insn){.code = BPF_JMP | BPF_OP(OP) | BPF_X, \
+			   .dst_reg = DST,                       \
+			   .src_reg = SRC,                       \
+			   .off = OFF,                           \
+			   .imm = 0})
+
+/* Conditional jumps against immediates, if (dst_reg 'op' imm32) goto pc + off16 */
+#define BPF_JMP_IMM(OP, DST, IMM, OFF)                           \
+	((struct bpf_insn){.code = BPF_JMP | BPF_OP(OP) | BPF_K, \
+			   .dst_reg = DST,                       \
+			   .src_reg = 0,                         \
+			   .off = OFF,                           \
+			   .imm = IMM})
+
+/* Program exit */
+#define BPF_EXIT_INSN()                                \
+	((struct bpf_insn){.code = BPF_JMP | BPF_EXIT, \
+			   .dst_reg = 0,               \
+			   .src_reg = 0,               \
+			   .off = 0,                   \
+			   .imm = 0})
+
+static int bpf_access_mask(const char *acc, __u32 *mask)
+{
+	if (!acc)
+		return 0;
+
+	for (; *acc; acc++)
+		switch (*acc) {
+		case 'r':
+			*mask |= BPF_DEVCG_ACC_READ;
+			break;
+		case 'w':
+			*mask |= BPF_DEVCG_ACC_WRITE;
+			break;
+		case 'm':
+			*mask |= BPF_DEVCG_ACC_MKNOD;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+	return 0;
+}
+
+static int bpf_device_type(char type)
+{
+	switch (type) {
+	case 'a':
+		return 0;
+	case 'b':
+		return BPF_DEVCG_DEV_BLOCK;
+	case 'c':
+		return BPF_DEVCG_DEV_CHAR;
+	}
+
+	return -1;
+}
+
+static inline bool bpf_device_all_access(__u32 access_mask)
+{
+	return access_mask == (BPF_DEVCG_ACC_READ | BPF_DEVCG_ACC_WRITE | BPF_DEVCG_ACC_MKNOD);
+}
+
+struct bpf_program *bpf_program_new(uint32_t prog_type)
+{
+	__do_free struct bpf_program *prog = NULL;
+
+	prog = zalloc(sizeof(struct bpf_program));
+	if (!prog)
+		return ret_set_errno(NULL, ENOMEM);
+
+	prog->prog_type = prog_type;
+	prog->kernel_fd = -EBADF;
+	/*
+	 * By default a whitelist is used unless the user tells us otherwise.
+	 */
+	prog->device_list_type = LXC_BPF_DEVICE_CGROUP_WHITELIST;
+
+	return move_ptr(prog);
+}
+
+int bpf_program_init(struct bpf_program *prog)
+{
+	if (!prog)
+		return ret_set_errno(-1, EINVAL);
+
+	const struct bpf_insn pre_insn[] = {
+	    /* load device type to r2 */
+	    BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct bpf_cgroup_dev_ctx, access_type)),
+	    BPF_ALU32_IMM(BPF_AND, BPF_REG_2, 0xFFFF),
+
+	    /* load access type to r3 */
+	    BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct bpf_cgroup_dev_ctx, access_type)),
+	    BPF_ALU32_IMM(BPF_RSH, BPF_REG_3, 16),
+
+	    /* load major number to r4 */
+	    BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1, offsetof(struct bpf_cgroup_dev_ctx, major)),
+
+	    /* load minor number to r5 */
+	    BPF_LDX_MEM(BPF_W, BPF_REG_5, BPF_REG_1, offsetof(struct bpf_cgroup_dev_ctx, minor)),
+	};
+
+	return bpf_program_add_instructions(prog, pre_insn, ARRAY_SIZE(pre_insn));
+}
+
+int bpf_program_append_device(struct bpf_program *prog, struct device_item *device)
+{
+	int ret;
+	int jump_nr = 1;
+	__u32 access_mask = 0;
+	int device_type;
+	struct bpf_insn bpf_access_decision[2];
+	bool add_exist = false;
+
+	if (!prog || !device)
+		return ret_set_errno(-1, EINVAL);
+
+	/* This is a global rule so no need to append anything. */
+	if (device->global_rule > LXC_BPF_DEVICE_CGROUP_LOCAL_RULE) {
+		prog->device_list_type = device->global_rule;
+		return 0;
+	}
+
+	ret = bpf_access_mask(device->access, &access_mask);
+	if (ret < 0)
+		return log_error_errno(ret, -ret, "Invalid access mask specified %s", device->access);
+
+	if (!bpf_device_all_access(access_mask))
+		jump_nr += 3;
+
+	device_type = bpf_device_type(device->type);
+	if (device_type < 0)
+		return log_error_errno(-1, EINVAL, "Invalid bpf cgroup device type %c", device->type);
+
+	if (device_type > 0)
+		jump_nr++;
+
+	if (device->major >= 0)
+		jump_nr++;
+
+	if (device->minor >= 0)
+		jump_nr++;
+
+	if (device_type > 0) {
+		struct bpf_insn ins[] = {
+			BPF_JMP_IMM(BPF_JNE, BPF_REG_2, device_type, jump_nr--),
+		};
+
+		ret = bpf_program_add_instructions(prog, ins, ARRAY_SIZE(ins));
+		if (ret)
+			return log_error_errno(-1, errno, "Failed to add instructions to bpf cgroup program");
+		add_exist = true;
+	}
+
+	if (!bpf_device_all_access(access_mask)) {
+		struct bpf_insn ins[] = {
+			BPF_MOV32_REG(BPF_REG_1, BPF_REG_3),
+			BPF_ALU32_IMM(BPF_AND, BPF_REG_1, access_mask),
+			BPF_JMP_REG(BPF_JNE, BPF_REG_1, BPF_REG_3, jump_nr-2),
+		};
+
+		jump_nr -= 3;
+		ret = bpf_program_add_instructions(prog, ins, ARRAY_SIZE(ins));
+		if (ret)
+			return log_error_errno(-1, errno, "Failed to add instructions to bpf cgroup program");
+		add_exist = true;
+	}
+
+	if (device->major >= 0) {
+		struct bpf_insn ins[] = {
+			BPF_JMP_IMM(BPF_JNE, BPF_REG_4, device->major, jump_nr--),
+		};
+
+		ret = bpf_program_add_instructions(prog, ins, ARRAY_SIZE(ins));
+		if (ret)
+			return log_error_errno(-1, errno, "Failed to add instructions to bpf cgroup program");
+		add_exist = true;
+	}
+
+	if (device->minor >= 0) {
+		struct bpf_insn ins[] = {
+			BPF_JMP_IMM(BPF_JNE, BPF_REG_5, device->minor, jump_nr--),
+		};
+
+		ret = bpf_program_add_instructions(prog, ins, ARRAY_SIZE(ins));
+		if (ret)
+			return log_error_errno(-1, errno, "Failed to add instructions to bpf cgroup program");
+		add_exist = true;
+	}
+
+	if (add_exist) {
+		bpf_access_decision[0] = BPF_MOV64_IMM(BPF_REG_0, device->allow);
+		bpf_access_decision[1] = BPF_EXIT_INSN();
+		ret = bpf_program_add_instructions(prog, bpf_access_decision,
+					   ARRAY_SIZE(bpf_access_decision));
+		if (ret)
+			return log_error_errno(-1, errno, "Failed to add instructions to bpf cgroup program");
+	}
+
+	return 0;
+}
+
+int bpf_program_finalize(struct bpf_program *prog)
+{
+	struct bpf_insn ins[] = {
+	    BPF_MOV64_IMM(BPF_REG_0, prog->device_list_type),
+	    BPF_EXIT_INSN(),
+	};
+
+	if (!prog)
+		return ret_set_errno(-1, EINVAL);
+
+	TRACE("Implementing %s bpf device cgroup program",
+	      prog->device_list_type == LXC_BPF_DEVICE_CGROUP_BLACKLIST
+		  ? "blacklist"
+		  : "whitelist");
+	return bpf_program_add_instructions(prog, ins, ARRAY_SIZE(ins));
+}
+
+static int bpf_program_load_kernel(struct bpf_program *prog)
+{
+	__do_free char *log_buf = NULL;
+	__u32 log_level = 0;
+	__u32 log_size = 0;
+	union bpf_attr attr;
+	struct rlimit limit = {
+		.rlim_cur = RLIM_INFINITY,
+		.rlim_max = RLIM_INFINITY,
+	};
+
+	if (prog->kernel_fd >= 0) {
+		return 0;
+	}
+
+	if (lxc_log_get_level() <= LXC_LOG_LEVEL_DEBUG) {
+		log_buf = zalloc(BPF_LOG_BUF_SIZE);
+		if (!log_buf) {
+			WARN("Failed to allocate bpf log buffer");
+		} else {
+			log_level = BPF_LOG_LEVEL;
+			log_size = BPF_LOG_BUF_SIZE;
+		}
+	}
+
+	if (setrlimit(RLIMIT_MEMLOCK, &limit) < 0)
+		return log_error_errno(-1, errno, "Failed to set rlimit memlock to unlimited");
+
+	attr = (union bpf_attr){
+	    .prog_type	= prog->prog_type,
+	    .insns	= PTR_TO_UINT64(prog->instructions),
+	    .insn_cnt	= prog->n_instructions,
+	    .license	= PTR_TO_UINT64("GPL"),
+	    .log_buf	= PTR_TO_UINT64(log_buf),
+	    .log_level	= log_level,
+	    .log_size	= log_size,
+	};
+
+	prog->kernel_fd = bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
+	if (prog->kernel_fd < 0)
+		return log_error_errno(-1, errno, "Failed to load bpf program: %s", log_buf);
+
+	TRACE("Loaded bpf program: %s", log_buf ?: "(null)");
+	return 0;
+}
+
+int bpf_program_cgroup_attach(struct bpf_program *prog, int type,
+			      const char *path, uint32_t flags)
+{
+	__do_free char *copy = NULL;
+	__do_close int fd = -EBADF;
+	union bpf_attr attr;
+	int ret;
+
+	if (!prog)
+		return ret_set_errno(-1, EINVAL);
+
+	if (flags & ~(BPF_F_ALLOW_OVERRIDE | BPF_F_ALLOW_MULTI))
+		return log_error_errno(-1, EINVAL, "Invalid flags for bpf program");
+
+	if (prog->attached_path) {
+		if (prog->attached_type != type)
+			return log_error_errno(-1, EBUSY, "Wrong type for bpf program");
+
+		if (prog->attached_flags != flags)
+			return log_error_errno(-1, EBUSY, "Wrong flags for bpf program");
+
+		if (flags != BPF_F_ALLOW_OVERRIDE)
+			return true;
+	}
+
+	ret = bpf_program_load_kernel(prog);
+	if (ret < 0)
+		return log_error_errno(-1, ret, "Failed to load bpf program");
+
+	copy = strdup(path);
+	if (!copy)
+		return log_error_errno(-1, ENOMEM, "Failed to duplicate cgroup path %s", path);
+
+	fd = open(path, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
+	if (fd < 0)
+		return log_error_errno(-1, errno, "Failed to open cgroup path %s", path);
+
+	attr = (union bpf_attr){
+	    .attach_type	= type,
+	    .target_fd		= fd,
+	    .attach_bpf_fd	= prog->kernel_fd,
+	    .attach_flags	= flags,
+	};
+
+	ret = bpf(BPF_PROG_ATTACH, &attr, sizeof(attr));
+	if (ret < 0)
+		return log_error_errno(-1, errno, "Failed to attach bpf program");
+
+	free_move_ptr(prog->attached_path, copy);
+	prog->attached_type = type;
+	prog->attached_flags = flags;
+
+	TRACE("Loaded and attached bpf program to cgroup %s", prog->attached_path);
+	return 0;
+}
+
+int bpf_program_cgroup_detach(struct bpf_program *prog)
+{
+	int ret;
+	__do_close int fd = -EBADF;
+
+	if (!prog)
+		return 0;
+
+	if (!prog->attached_path)
+		return 0;
+
+	fd = open(prog->attached_path, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
+	if (fd < 0) {
+		if (errno != ENOENT)
+			return log_error_errno(-1, errno, "Failed to open attach cgroup %s",
+					       prog->attached_path);
+	} else {
+		union bpf_attr attr;
+
+		attr = (union bpf_attr){
+		    .attach_type	= prog->attached_type,
+		    .target_fd		= fd,
+		    .attach_bpf_fd	= prog->kernel_fd,
+		};
+
+		ret = bpf(BPF_PROG_DETACH, &attr, sizeof(attr));
+		if (ret < 0)
+			return log_error_errno(-1, errno, "Failed to detach bpf program from cgroup %s",
+					       prog->attached_path);
+	}
+
+	free(prog->attached_path);
+	prog->attached_path = NULL;
+
+	return 0;
+}
+
+void lxc_clear_cgroup2_devices(struct lxc_conf *conf)
+{
+	if (conf->cgroup2_devices) {
+		(void)bpf_program_cgroup_detach(conf->cgroup2_devices);
+		(void)bpf_program_free(conf->cgroup2_devices);
+	}
+}
+
+int bpf_list_add_device(struct lxc_conf *conf, struct device_item *device)
+{
+	__do_free struct lxc_list *list_elem = NULL;
+	__do_free struct device_item *new_device = NULL;
+	struct lxc_list *it;
+
+	lxc_list_for_each(it, &conf->devices) {
+		struct device_item *cur = it->elem;
+
+		if (cur->global_rule > LXC_BPF_DEVICE_CGROUP_LOCAL_RULE &&
+		    device->global_rule > LXC_BPF_DEVICE_CGROUP_LOCAL_RULE) {
+			TRACE("Switched from %s to %s",
+			      cur->global_rule == LXC_BPF_DEVICE_CGROUP_WHITELIST
+				  ? "whitelist"
+				  : "blacklist",
+			      device->global_rule == LXC_BPF_DEVICE_CGROUP_WHITELIST
+				  ? "whitelist"
+				  : "blacklist");
+			cur->global_rule = device->global_rule;
+			return 1;
+		}
+
+		if (cur->type != device->type)
+			continue;
+		if (cur->major != device->major)
+			continue;
+		if (cur->minor != device->minor)
+			continue;
+		if (strcmp(cur->access, device->access))
+			continue;
+
+		/*
+		 * The rule is switched from allow to deny or vica versa so
+		 * don't bother allocating just flip the existing one.
+		 */
+		if (cur->allow != device->allow) {
+			cur->allow = device->allow;
+			return log_trace(0, "Switched existing rule of bpf device program: type %c, major %d, minor %d, access %s, allow %d, global_rule %d",
+					 cur->type, cur->major, cur->minor,
+					 cur->access, cur->allow,
+					 cur->global_rule);
+		}
+
+		return log_trace(1, "Reusing existing rule of bpf device program: type %c, major %d, minor %d, access %s, allow %d, global_rule %d",
+				 cur->type, cur->major, cur->minor, cur->access,
+				 cur->allow, cur->global_rule);
+	}
+
+	list_elem = malloc(sizeof(*list_elem));
+	if (!list_elem)
+		return log_error_errno(-1, ENOMEM, "Failed to allocate new device list");
+
+	new_device = memdup(device, sizeof(struct device_item));
+	if (!new_device)
+		return log_error_errno(-1, ENOMEM, "Failed to allocate new device item");
+
+	lxc_list_add_elem(list_elem, move_ptr(new_device));
+	lxc_list_add_tail(&conf->devices, move_ptr(list_elem));
+
+	return 0;
+}
+
+bool bpf_devices_cgroup_supported(void)
+{
+	const struct bpf_insn dummy[] = {
+	    BPF_MOV64_IMM(BPF_REG_0, 1),
+	    BPF_EXIT_INSN(),
+	};
+
+	__do_bpf_program_free struct bpf_program *prog = NULL;
+	int ret;
+
+	if (geteuid() != 0)
+		return log_trace(false,
+				 "The bpf device cgroup requires real root");
+
+	prog = bpf_program_new(BPF_PROG_TYPE_CGROUP_DEVICE);
+	if (prog < 0)
+		return log_trace(false, "Failed to allocate new bpf device cgroup program");
+
+	ret = bpf_program_init(prog);
+	if (ret)
+		return log_error_errno(false, ENOMEM, "Failed to initialize bpf program");
+
+	ret = bpf_program_add_instructions(prog, dummy, ARRAY_SIZE(dummy));
+	if (ret < 0)
+		return log_trace(false, "Failed to add new instructions to bpf device cgroup program");
+
+	ret = bpf_program_load_kernel(prog);
+	if (ret < 0)
+		return log_trace(false, "Failed to load new bpf device cgroup program");
+
+	return log_trace(true, "The bpf device cgroup is supported");
+}
+#endif
diff --git a/src/lxc/commands.c b/src/lxc/commands.c
index b6ae101..c2a5665 100644
--- a/src/lxc/commands.c
+++ b/src/lxc/commands.c
@@ -86,6 +86,10 @@ static const char *lxc_cmd_str(lxc_cmd_t cmd)
 		[LXC_CMD_GET_INIT_PIDFD]        	= "get_init_pidfd",
 		[LXC_CMD_GET_LIMITING_CGROUP]		= "get_limiting_cgroup",
 		[LXC_CMD_GET_LIMITING_CGROUP2_FD]	= "get_limiting_cgroup2_fd",
+#ifdef HAVE_ISULAD
+		[LXC_CMD_SET_TERMINAL_FIFOS]  		= "set_terminal_fifos",
+		[LXC_CMD_SET_TERMINAL_WINCH]  		= "set_terminal_winch",
+#endif
 	};
 
 	if (cmd >= LXC_CMD_MAX)
@@ -117,7 +121,15 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
 	int ret;
 	struct lxc_cmd_rsp *rsp = &cmd->rsp;
 
+#ifdef HAVE_ISULAD
+	/*isulad: add timeout 1s to avoid long block due to [lxc monitor] error*/
+	ret = lxc_abstract_unix_recv_fds_timeout(sock, &fd_rsp, 1, rsp, sizeof(*rsp), 1000 * 1000);
+	if (ret < 0 && (errno == ECONNRESET || errno == EAGAIN || errno == EWOULDBLOCK)) {
+		errno = ECONNRESET; /*isulad set errno ECONNRESET when timeout */
+	}
+#else
 	ret = lxc_abstract_unix_recv_fds(sock, &fd_rsp, 1, rsp, sizeof(*rsp));
+#endif
 	if (ret < 0)
 		return log_warn_errno(-1,
 				      errno, "Failed to receive response for command \"%s\"",
@@ -592,8 +604,9 @@ static int lxc_cmd_get_cgroup_callback_do(int fd, struct lxc_cmd_req *req,
 		reqdata = NULL;
 	}
 
-	get_fn = (limiting_cgroup ? cgroup_ops->get_cgroup
-				  : cgroup_ops->get_limiting_cgroup);
+	// bugfix in newer version
+	get_fn = (limiting_cgroup ? cgroup_ops->get_limiting_cgroup
+				  : cgroup_ops->get_cgroup);
 
 	path = get_fn(cgroup_ops, reqdata);
 
@@ -1260,7 +1273,11 @@ int lxc_cmd_serve_state_clients(const char *name, const char *lxcpath,
 
 	ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
 	if (ret < 0)
+#ifdef HAVE_ISULAD
+		return log_warn_errno(-1, errno, "Failed to serve state clients");
+#else
 		return log_error_errno(-1, errno, "Failed to serve state clients");
+#endif
 
 	return 0;
 }
@@ -1475,6 +1492,123 @@ static int lxc_cmd_get_limiting_cgroup2_fd_callback(int fd,
 	return ret_errno(ENOSYS);
 }
 
+#ifdef HAVE_ISULAD
+/*
+ * isulad: lxc_cmd_set_terminal_fifos: Set the fifos used for the container as terminal input/output
+ *
+ * @hashed_sock_name: hashed socket name
+ *
+ * Returns 0 when success, else when fail.
+ */
+int lxc_cmd_set_terminal_fifos(const char *name, const char *lxcpath, const char *in_fifo,
+				const char *out_fifo, const char *err_fifo)
+{
+	int ret = 0, stopped = 0;
+	int len = 0;
+	char *tmp = NULL;
+	const char *split = "&&&&", *none_fifo_name = "none";
+	const char *cmd_in_fifo = in_fifo ? in_fifo : none_fifo_name;
+	const char *cmd_out_fifo = out_fifo ? out_fifo : none_fifo_name;
+	const char *cmd_err_fifo = err_fifo ? err_fifo : none_fifo_name;
+
+	if (len + strlen(cmd_in_fifo) + strlen(split) + strlen(cmd_out_fifo) +
+	     strlen(split) + strlen(cmd_err_fifo) == SIZE_MAX)
+		return -1;
+	len += strlen(cmd_in_fifo) + strlen(split) + strlen(cmd_out_fifo) + strlen(split) + strlen(cmd_err_fifo) + 1;
+	tmp = malloc(len);
+	if (tmp == NULL)
+		return -1;
+	ret = snprintf(tmp, len, "%s%s%s%s%s", cmd_in_fifo, split, cmd_out_fifo, split, cmd_err_fifo);
+	if (ret < 0 || ret >= len) {
+		ERROR("Failed to snprintf in fifo of command");
+		free(tmp);
+		return -1;
+	}
+
+	struct lxc_cmd_rr cmd = {
+		.req = {
+			.cmd = LXC_CMD_SET_TERMINAL_FIFOS,
+			.datalen = strlen(tmp)+1,
+			.data = tmp,
+		},
+	};
+
+	ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
+	if (ret < 0) {
+		ERROR("Failed to send command to container");
+		free(tmp);
+		return -1;
+	}
+
+	if (cmd.rsp.ret != 0) {
+		ERROR("Command response error:%d", cmd.rsp.ret);
+		free(tmp);
+		return -1;
+	}
+
+	free(tmp);
+	return 0;
+}
+
+static int lxc_cmd_set_terminal_fifos_callback(int fd, struct lxc_cmd_req *req,
+					struct lxc_handler *handler, struct lxc_epoll_descr *descr)
+{
+	struct lxc_cmd_rsp rsp;
+	memset(&rsp, 0, sizeof(rsp));
+
+	rsp.ret = lxc_terminal_add_fifos(handler->conf, req->data);;
+
+	return lxc_cmd_rsp_send(fd, &rsp);
+}
+
+struct lxc_cmd_set_terminal_winch_request {
+	unsigned int height;
+	unsigned int width;
+};
+
+int lxc_cmd_set_terminal_winch(const char *name, const char *lxcpath, unsigned int height, unsigned int width)
+{
+	int ret = 0, stopped = 0;
+	struct lxc_cmd_set_terminal_winch_request data = { 0 };
+
+	data.height = height;
+	data.width = width;
+
+	struct lxc_cmd_rr cmd = {
+		.req = {
+			.cmd = LXC_CMD_SET_TERMINAL_WINCH,
+			.datalen = sizeof(struct lxc_cmd_set_terminal_winch_request),
+			.data = &data,
+		},
+	};
+
+	ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
+	if (ret < 0) {
+		ERROR("Failed to send command to container");
+		return -1;
+	}
+
+	if (cmd.rsp.ret != 0) {
+		ERROR("Command response error:%d", cmd.rsp.ret);
+		return -1;
+	}
+	return 0;
+}
+
+static int lxc_cmd_set_terminal_winch_callback(int fd, struct lxc_cmd_req *req,
+					struct lxc_handler *handler, struct lxc_epoll_descr *descr)
+{
+	struct lxc_cmd_rsp rsp;
+	struct lxc_cmd_set_terminal_winch_request *data = (struct lxc_cmd_set_terminal_winch_request *)(req->data);
+	memset(&rsp, 0, sizeof(rsp));
+
+	rsp.ret = lxc_set_terminal_winsz(&handler->conf->console, data->height, data->width);;
+
+	return lxc_cmd_rsp_send(fd, &rsp);
+
+}
+#endif
+
 static int lxc_cmd_process(int fd, struct lxc_cmd_req *req,
 			   struct lxc_handler *handler,
 			   struct lxc_epoll_descr *descr)
@@ -1504,10 +1638,18 @@ static int lxc_cmd_process(int fd, struct lxc_cmd_req *req,
 		[LXC_CMD_GET_INIT_PIDFD]                = lxc_cmd_get_init_pidfd_callback,
 		[LXC_CMD_GET_LIMITING_CGROUP]           = lxc_cmd_get_limiting_cgroup_callback,
 		[LXC_CMD_GET_LIMITING_CGROUP2_FD]       = lxc_cmd_get_limiting_cgroup2_fd_callback,
+#ifdef HAVE_ISULAD
+		[LXC_CMD_SET_TERMINAL_FIFOS]  			= lxc_cmd_set_terminal_fifos_callback,
+		[LXC_CMD_SET_TERMINAL_WINCH]  			= lxc_cmd_set_terminal_winch_callback,
+#endif
 	};
 
 	if (req->cmd >= LXC_CMD_MAX)
+#ifdef HAVE_ISULAD
+		return log_error_errno(-1, ENOENT, "Undefined command id %d", req->cmd);
+#else
 		return log_trace_errno(-1, EINVAL, "Invalid command id %d", req->cmd);
+#endif
 
 	return cb[req->cmd](fd, req, handler, descr);
 }
@@ -1646,6 +1788,44 @@ static int lxc_cmd_accept(int fd, uint32_t events, void *data,
 	return ret;
 }
 
+#ifdef HAVE_ISULAD
+int lxc_cmd_init(const char *name, const char *lxcpath, const char *suffix)
+{
+	__do_close int fd = -EBADF;
+	int ret;
+	char path[LXC_AUDS_ADDR_LEN] = {0};
+	__do_free char *runtime_sock_dir = NULL;
+
+	runtime_sock_dir = generate_named_unix_sock_dir(name);
+	if (runtime_sock_dir == NULL)
+		return -1;
+
+	if (mkdir_p(runtime_sock_dir, 0700) < 0)
+		return log_error_errno(-1, errno, "Failed to create container runtime unix sock directory %s", path);
+
+	if (generate_named_unix_sock_path(name, suffix, path, sizeof(path)) != 0)
+		return -1;
+
+	fd = lxc_named_unix_open(path, SOCK_STREAM, 0);
+	if (fd < 0) {
+		if (errno == EADDRINUSE) {
+			WARN("Container \"%s\" appears to be already running", name);
+			(void)unlink(path);
+
+			fd = lxc_named_unix_open(path, SOCK_STREAM, 0);
+			if (fd < 0)
+				return log_error_errno(-1, errno, "Failed to create command socket %s", path);
+		} else
+			return log_error_errno(-1, errno, "Failed to create command socket %s", path);
+	}
+
+	ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
+	if (ret < 0)
+		return log_error_errno(-1, errno, "Failed to set FD_CLOEXEC on command socket file descriptor");
+
+	return log_trace(move_fd(fd), "Created unix socket \"%s\"", path);
+}
+#else
 int lxc_cmd_init(const char *name, const char *lxcpath, const char *suffix)
 {
 	__do_close int fd = -EBADF;
@@ -1670,6 +1850,7 @@ int lxc_cmd_init(const char *name, const char *lxcpath, const char *suffix)
 
 	return log_trace(move_fd(fd), "Created abstract unix socket \"%s\"", &path[1]);
 }
+#endif
 
 int lxc_cmd_mainloop_add(const char *name, struct lxc_epoll_descr *descr,
 			 struct lxc_handler *handler)
diff --git a/src/lxc/commands.h b/src/lxc/commands.h
index 3624a14..f6371fd 100644
--- a/src/lxc/commands.h
+++ b/src/lxc/commands.h
@@ -40,6 +40,10 @@ typedef enum {
 	LXC_CMD_GET_INIT_PIDFD,
 	LXC_CMD_GET_LIMITING_CGROUP,
 	LXC_CMD_GET_LIMITING_CGROUP2_FD,
+#ifdef HAVE_ISULAD
+	LXC_CMD_SET_TERMINAL_FIFOS,
+	LXC_CMD_SET_TERMINAL_WINCH,
+#endif
 	LXC_CMD_MAX,
 } lxc_cmd_t;
 
@@ -136,4 +140,10 @@ extern char *lxc_cmd_get_limiting_cgroup_path(const char *name,
 					      const char *subsystem);
 extern int lxc_cmd_get_limiting_cgroup2_fd(const char *name, const char *lxcpath);
 
+#ifdef HAVE_ISULAD
+extern int lxc_cmd_set_terminal_fifos(const char *name, const char *lxcpath,
+				const char *in_fifo, const char *out_fifo, const char *err_fifo);
+extern int lxc_cmd_set_terminal_winch(const char *name, const char *lxcpath, unsigned int height, unsigned int width);
+#endif
+
 #endif /* __commands_h */
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index b72afba..0478eb1 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -23,6 +23,10 @@
 #include "start.h"
 #include "terminal.h"
 
+#ifdef HAVE_ISULAD
+#include "oci_runtime_hooks.h"
+#endif
+
 #if HAVE_SYS_RESOURCE_H
 #include <sys/resource.h>
 #endif
@@ -146,6 +150,8 @@ struct lxc_tty_info {
  * @mountflags : the portion of @options that are flags
  * @data       : the portion of @options that are not flags
  * @managed    : whether it is managed by LXC
+ * @maskedpaths: A list of paths to be msked over inside the container
+ * @ropaths    : A list of paths to be remounted with readonly inside the container
  */
 struct lxc_rootfs {
 	char *path;
@@ -155,6 +161,14 @@ struct lxc_rootfs {
 	unsigned long mountflags;
 	char *data;
 	bool managed;
+#ifdef HAVE_ISULAD
+	/* isulad: maskedpaths */
+	struct lxc_list maskedpaths;
+	/* isulad: ropaths */
+	struct lxc_list ropaths;
+	/* isulad: errfd */
+	int errfd;
+#endif
 };
 
 /*
@@ -203,6 +217,11 @@ enum lxchooks {
 	LXCHOOK_CLONE,
 	LXCHOOK_DESTROY,
 	LXCHOOK_START_HOST,
+#ifdef HAVE_ISULAD
+	OCI_HOOK_PRESTART,
+	OCI_HOOK_POSTSTART,
+	OCI_HOOK_POSTSTOP,
+#endif
 	NUM_LXC_HOOKS
 };
 
@@ -233,6 +252,27 @@ struct device_item {
 	int global_rule;
 };
 
+#ifdef HAVE_ISULAD
+/*
+ * iSulad: Defines a structure to store the devices which will
+ * be attached in container
+ * @name       : the target device name in container
+ * @type       : the type of target device "c" or "b"
+ * @mode       : file mode for the device
+ * @maj        : major number for the device
+ * @min        : minor number for the device
+ */
+struct lxc_populate_devs {
+	char *name;
+	char *type;
+	mode_t file_mode;
+	int maj;
+	int min;
+	uid_t uid;
+	gid_t gid;
+};
+#endif
+
 struct lxc_conf {
 	/* Pointer to the name of the container. Do not free! */
 	const char *name;
@@ -401,6 +441,40 @@ struct lxc_conf {
 		/* Absolute path (in the container) to the shared mount point */
 		char *path_cont;
 	} shmount;
+
+#ifdef HAVE_ISULAD
+	/* support oci hook */
+	oci_runtime_spec_hooks *ocihooks;
+
+	/* init args used to repalce init_cmd */
+	char **init_argv;
+	size_t init_argc;
+
+	gid_t *init_groups;
+	size_t init_groups_len;
+
+	/* populate devices */
+	struct lxc_list populate_devs;
+	mode_t umask;  // umask value
+
+	char *container_info_file;
+
+  /* exit fifo fd*/
+	int exit_fd;
+
+  /* record error messages */
+	char *errmsg;
+
+  /* pipdfd for get error message of child or grandchild process */
+	int errpipe[2];
+
+  /* systemd value */
+	char *systemd;
+
+  /* Linux Security Modules SELinux context for device mount */
+	char *lsm_se_mount_context;
+#endif
+
 };
 
 extern int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
@@ -439,7 +513,11 @@ 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);
+#ifdef HAVE_ISULAD
+extern int setup_resource_limits(struct lxc_list *limits, pid_t pid, int errfd);
+#else
 extern int setup_resource_limits(struct lxc_list *limits, pid_t pid);
+#endif
 extern int find_unmapped_nsid(const struct lxc_conf *conf, enum idtype idtype);
 extern int mapped_hostid(unsigned id, const struct lxc_conf *conf,
 			 enum idtype idtype);
@@ -447,8 +525,14 @@ extern int userns_exec_1(const struct lxc_conf *conf, int (*fn)(void *),
 			 void *data, const char *fn_name);
 extern int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *),
 			    void *data, const char *fn_name);
+#ifdef HAVE_ISULAD
+// isulad modify
+extern int parse_mntopts(const char *mntopts, unsigned long *mntflags,
+			unsigned long *pflags, char **mntdata);
+#else
 extern int parse_mntopts(const char *mntopts, unsigned long *mntflags,
 			 char **mntdata);
+#endif
 extern int parse_propagationopts(const char *mntopts, unsigned long *pflags);
 extern void tmp_proc_unmount(struct lxc_conf *lxc_conf);
 extern void turn_into_dependent_mounts(void);
@@ -480,4 +564,15 @@ static inline int chown_mapped_root(const char *path, const struct lxc_conf *con
 	return userns_exec_mapped_root(path, -EBADF, conf);
 }
 
+#ifdef HAVE_ISULAD
+// isulad add
+int lxc_clear_init_args(struct lxc_conf *lxc_conf);
+int lxc_clear_init_groups(struct lxc_conf *lxc_conf);
+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);
+int run_oci_hooks(const char *name, const char *hookname, struct lxc_conf *conf, const char *lxcpath);
+void lxc_close_error_pipe(int *errpipe);
+#endif
 #endif /* __LXC_CONF_H */
diff --git a/src/lxc/isulad_utils.c b/src/lxc/isulad_utils.c
new file mode 100644
index 0000000..15d9323
--- /dev/null
+++ b/src/lxc/isulad_utils.c
@@ -0,0 +1,319 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+/******************************************************************************
+ * Copyright (c) Huawei Technologies Co., Ltd. 2020. Allrights reserved
+ * Description: isulad utils
+ * Author: lifeng
+ * Create: 2020-04-11
+******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <ctype.h>
+
+#include "isulad_utils.h"
+#include "log.h"
+#include "path.h"
+#include "file_utils.h"
+
+lxc_log_define(isulad_utils, lxc);
+
+void *lxc_common_calloc_s(size_t size)
+{
+	if (size == 0 || size > SIZE_MAX) {
+		return NULL;
+	}
+
+	return calloc((size_t)1, size);
+}
+
+int lxc_mem_realloc(void **newptr, size_t newsize, void *oldptr, size_t oldsize)
+{
+	void *tmp = NULL;
+
+	if (newsize == 0) {
+		goto err_out;
+	}
+
+	tmp = lxc_common_calloc_s(newsize);
+	if (tmp == NULL) {
+		ERROR("Failed to malloc memory");
+		goto err_out;
+	}
+
+	if (oldptr != NULL) {
+		memcpy(tmp, oldptr, (newsize < oldsize) ? newsize : oldsize);
+
+		memset(oldptr, 0, oldsize);
+
+		free(oldptr);
+	}
+
+	*newptr = tmp;
+	return 0;
+
+err_out:
+	return -1;
+}
+
+char *safe_strdup(const char *src)
+{
+	char *dst = NULL;
+
+	if (src == NULL) {
+		return NULL;
+	}
+
+	dst = strdup(src);
+	if (dst == NULL) {
+		abort();
+	}
+
+	return dst;
+}
+
+int lxc_open(const char *filename, int flags, mode_t mode)
+{
+	char rpath[PATH_MAX] = {0x00};
+
+	if (cleanpath(filename, rpath, sizeof(rpath)) == NULL) {
+		return -1;
+	}
+	if (mode) {
+		return open(rpath, (int)((unsigned int)flags | O_CLOEXEC), mode);
+	} else {
+		return open(rpath, (int)((unsigned int)flags | O_CLOEXEC));
+	}
+}
+
+FILE *lxc_fopen(const char *filename, const char *mode)
+{
+	char rpath[PATH_MAX] = {0x00};
+
+	if (cleanpath(filename, rpath, sizeof(rpath)) == NULL) {
+		return NULL;
+	}
+
+	return fopen_cloexec(rpath, mode);
+}
+
+/* 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);
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+	ret = vsnprintf(errbuf, BUFSIZ, format, argp);
+#pragma GCC diagnostic pop
+	va_end(argp);
+	if (ret < 0 || ret >= BUFSIZ)
+		SYSERROR("Failed to call vsnprintf");
+	sret = write(errfd, errbuf, strlen(errbuf));
+	if (sret < 0)
+		SYSERROR("Write errbuf failed");
+}
+
+/* isulad: read file to buffer */
+int lxc_file2str(const char *filename, char ret[], int cap)
+{
+    int fd, num_read;
+
+    if ((fd = lxc_open(filename, O_RDONLY | O_CLOEXEC, 0)) == -1)
+        return -1;
+    if ((num_read = read(fd, ret, cap - 1)) <= 0)
+        num_read = -1;
+    else
+        ret[num_read] = 0;
+    close(fd);
+
+    return num_read;
+}
+
+/* isuald: lxc_stat2proc() makes sure it can handle arbitrary executable file basenames
+ * for `cmd', i.e. those with embedded whitespace or embedded ')'s.
+ * Such names confuse %s (see scanf(3)), so the string is split and %39c
+ * is used instead. (except for embedded ')' "(%[^)]c)" would work.
+ */
+static proc_t *lxc_stat2proc(const char *S)
+{
+    int num;
+    proc_t *P = NULL;
+    char *tmp = NULL;
+
+    if (!S)
+        return NULL;
+
+    tmp = strrchr(S, ')');  /* split into "PID (cmd" and "<rest>" */
+    if (!tmp)
+        return NULL;
+    *tmp = '\0';            /* replace trailing ')' with NUL */
+
+    P = malloc(sizeof(proc_t));
+    if (P == NULL)
+        return NULL;
+    (void)memset(P, 0x00, sizeof(proc_t));
+
+    /* parse these two strings separately, skipping the leading "(". */
+    num = sscanf(S, "%d (%15c", &P->pid, P->cmd);   /* comm[16] in kernel */
+    if (num != 2) {
+        ERROR("Call sscanf error: %s", errno ? strerror(errno) : "");
+        free(P);
+        return NULL;
+    }
+    num = sscanf(tmp + 2,           /* skip space after ')' too */
+                 "%c "
+                 "%d %d %d %d %d "
+                 "%lu %lu %lu %lu %lu "
+                 "%Lu %Lu %Lu %Lu "  /* utime stime cutime cstime */
+                 "%ld %ld %ld %ld "
+                 "%Lu "  /* start_time */
+                 "%lu "
+                 "%ld "
+                 "%lu %lu %lu %lu %lu %lu "
+                 "%*s %*s %*s %*s " /* discard, no RT signals & Linux 2.1 used hex */
+                 "%lu %lu %lu "
+                 "%d %d "
+                 "%lu %lu",
+                 &P->state,
+                 &P->ppid, &P->pgrp, &P->session, &P->tty, &P->tpgid,
+                 &P->flags, &P->min_flt, &P->cmin_flt, &P->maj_flt, &P->cmaj_flt,
+                 &P->utime, &P->stime, &P->cutime, &P->cstime,
+                 &P->priority, &P->nice, &P->timeout, &P->it_real_value,
+                 &P->start_time,
+                 &P->vsize,
+                 &P->rss,
+                 &P->rss_rlim, &P->start_code, &P->end_code, &P->start_stack, &P->kstk_esp,
+                 &P->kstk_eip,
+                 &P->wchan, &P->nswap, &P->cnswap,
+                 &P->exit_signal, &P->processor,  /* 2.2.1 ends with "exit_signal" */
+                 &P->rtprio, &P->sched  /* both added to 2.5.18 */
+                );
+    if (num != 35) {
+        ERROR("Call sscanf error: %s", errno ? strerror(errno) : "");
+        free(P);
+        return NULL;
+    }
+    if (P->tty == 0)
+        P->tty = -1;  /* the old notty val, update elsewhere bef. moving to 0 */
+    return P;
+}
+
+/* isulad: get starttime of process pid */
+unsigned long long lxc_get_process_startat(pid_t pid)
+{
+    int sret = 0;
+    unsigned long long startat = 0;
+    proc_t *pid_info = NULL;
+    char filename[PATH_MAX] = {0};
+    char sbuf[1024] = {0}; /* bufs for stat */
+
+    sret = snprintf(filename, sizeof(filename), "/proc/%d/stat", pid);
+    if (sret < 0 || sret >= sizeof(filename)) {
+        ERROR("Failed to sprintf filename");
+        goto out;
+    }
+
+    if ((lxc_file2str(filename, sbuf, sizeof(sbuf))) == -1) {
+        SYSERROR("Failed to read pidfile %s", filename);
+        goto out;
+    }
+
+    pid_info = lxc_stat2proc(sbuf);
+    if (!pid_info) {
+        ERROR("Failed to get proc stat info");
+        goto out;
+    }
+
+    startat = pid_info->start_time;
+out:
+    free(pid_info);
+    return startat;
+}
+
+// isulad: set env home in container
+int lxc_setup_env_home(uid_t uid)
+{
+	char *homedir = "/"; // default home dir is /
+	struct passwd pw, *pwbufp = NULL;
+	char buf[BUFSIZ];
+	int ret;
+
+	ret = getpwuid_r(uid, &pw, buf, sizeof(buf), &pwbufp);
+	if ((ret == 0) && (pwbufp != NULL) && (pwbufp->pw_uid == uid)) {
+		homedir = pwbufp->pw_dir;
+		goto set_env;
+	}
+
+	WARN("User invalid, can not find user '%u'", uid);
+
+set_env:
+	// if we didn't configure HOME, set it based on uid
+	if (setenv("HOME", homedir, 0) < 0) {
+		SYSERROR("Unable to set env 'HOME'");
+		return -1;
+	}
+
+	NOTICE("Setted env 'HOME' to %s", homedir);
+	return 0;
+}
+
+bool lxc_process_alive(pid_t pid, unsigned long long start_time)
+{
+	int sret = 0;
+	bool alive = true;
+	proc_t *pid_info = NULL;
+	char filename[PATH_MAX] = {0};
+	char sbuf[1024] = {0}; /* bufs for stat */
+
+	sret = kill(pid, 0);
+	if (sret < 0 && errno == ESRCH)
+		return false;
+
+	sret = snprintf(filename, sizeof(filename), "/proc/%d/stat", pid);
+	if (sret < 0 || sret >= sizeof(filename)) {
+		ERROR("Failed to sprintf filename");
+		goto out;
+	}
+
+	if ((lxc_file2str(filename, sbuf, sizeof(sbuf))) == -1) {
+		ERROR("Failed to read pidfile %s", filename);
+		alive = false;
+		goto out;
+	}
+
+	pid_info = lxc_stat2proc(sbuf);
+	if (!pid_info) {
+		ERROR("Failed to get proc stat info");
+		alive = false;
+		goto out;
+	}
+
+	if (start_time != pid_info->start_time)
+		alive = false;
+out:
+	free(pid_info);
+	return alive;
+}
+
+bool is_non_negative_num(const char *s)
+{
+	if (!s || !strcmp(s, ""))
+		return false;
+	while(*s  != '\0') {
+		if(!isdigit(*s))
+			return false;
+		++s;
+	}
+	return true;
+}
diff --git a/src/lxc/isulad_utils.h b/src/lxc/isulad_utils.h
new file mode 100644
index 0000000..345f511
--- /dev/null
+++ b/src/lxc/isulad_utils.h
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+/******************************************************************************
+ * Copyright (c) Huawei Technologies Co., Ltd. 2020. Allrights reserved
+ * Description: isulad utils
+ * Author: lifeng
+ * Create: 2020-04-11
+******************************************************************************/
+#ifndef __iSULAD_UTILS_H
+#define __iSULAD_UTILS_H
+
+#include <stdio.h>
+#include <stdbool.h>
+
+/* isulad: replace space with SPACE_MAGIC_STR */
+#define SPACE_MAGIC_STR "[#)"
+
+/* isulad:
+ ld cutime, cstime, priority, nice, timeout, it_real_value, rss,
+ c  state,
+ d  ppid, pgrp, session, tty, tpgid,
+ s  signal, blocked, sigignore, sigcatch,
+ lu flags, min_flt, cmin_flt, maj_flt, cmaj_flt, utime, stime,
+ lu rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip,
+ lu start_time, vsize, wchan, nswap, cnswap,
+*/
+
+/* Basic data structure which holds all information we can get about a process.
+ * (unless otherwise specified, fields are read from /proc/#/stat)
+ *
+ * Most of it comes from task_struct in linux/sched.h
+ */
+typedef struct proc_t {
+    // 1st 16 bytes
+    int pid;        /* process id */
+    int ppid;       /* pid of parent process */
+
+    char state;     /* single-char code for process state (S=sleeping) */
+
+    unsigned long long
+    utime,      /* user-mode CPU time accumulated by process */
+    stime,      /* kernel-mode CPU time accumulated by process */
+    // and so on...
+    cutime,     /* cumulative utime of process and reaped children */
+    cstime,     /* cumulative stime of process and reaped children */
+    start_time; /* start time of process -- seconds since 1-1-70 */
+
+    long
+    priority,   /* kernel scheduling priority */
+    timeout,    /* ? */
+    nice,       /* standard unix nice level of process */
+    rss,        /* resident set size from /proc/#/stat (pages) */
+    it_real_value;  /* ? */
+    unsigned long
+    rtprio,     /* real-time priority */
+    sched,      /* scheduling class */
+    vsize,      /* number of pages of virtual memory ... */
+    rss_rlim,   /* resident set size limit? */
+    flags,      /* kernel flags for the process */
+    min_flt,    /* number of minor page faults since process start */
+    maj_flt,    /* number of major page faults since process start */
+    cmin_flt,   /* cumulative min_flt of process and child processes */
+    cmaj_flt,   /* cumulative maj_flt of process and child processes */
+    nswap,      /* ? */
+    cnswap,     /* cumulative nswap ? */
+    start_code, /* address of beginning of code segment */
+    end_code,   /* address of end of code segment */
+    start_stack,    /* address of the bottom of stack for the process */
+    kstk_esp,   /* kernel stack pointer */
+    kstk_eip,   /* kernel instruction pointer */
+    wchan;      /* address of kernel wait channel proc is sleeping in */
+
+    char cmd[16];   /* basename of executable file in call to exec(2) */
+    int
+    pgrp,       /* process group id */
+    session,    /* session id */
+    tty,        /* full device number of controlling terminal */
+    tpgid,      /* terminal process group id */
+    exit_signal,    /* might not be SIGCHLD */
+    processor;      /* current (or most recent?) CPU */
+} proc_t;
+
+extern int lxc_mem_realloc(void **newptr, size_t newsize, void *oldptr, size_t oldsize);
+extern void *lxc_common_calloc_s(size_t size);
+extern char *safe_strdup(const char *src);
+
+extern int lxc_open(const char *filename, int flags, mode_t mode);
+extern FILE *lxc_fopen(const char *filename, const char *mode);
+
+extern void lxc_write_error_message(int errfd, const char *format, ...);
+extern int lxc_file2str(const char *filename, char ret[], int cap);
+extern int unsigned long long lxc_get_process_startat(pid_t pid);
+// set env home in container
+extern int lxc_setup_env_home(uid_t uid);
+
+extern bool lxc_process_alive(pid_t pid, unsigned long long start_time);
+
+extern bool is_non_negative_num(const char *s);
+
+#endif
diff --git a/src/lxc/lsm/lsm.c b/src/lxc/lsm/lsm.c
index 553e0c9..2f87dd6 100644
--- a/src/lxc/lsm/lsm.c
+++ b/src/lxc/lsm/lsm.c
@@ -168,6 +168,26 @@ int lsm_process_label_set(const char *label, struct lxc_conf *conf,
 	return drv->process_label_set(label, conf, on_exec);
 }
 
+#ifdef HAVE_ISULAD
+int lsm_file_label_set(const char *path, const char *label)
+{
+	if (!drv) {
+		ERROR("LSM driver not inited");
+		return -1;
+	}
+	return drv->file_label_set(path, label);
+}
+
+int lsm_relabel(const char *path, const char *label, bool share)
+{
+	if (!drv) {
+		ERROR("LSM driver not inited");
+		return -1;
+	}
+	return drv->relabel(path, label, share);
+}
+#endif
+
 int lsm_process_prepare(struct lxc_conf *conf, const char *lxcpath)
 {
 	if (!drv) {
diff --git a/src/lxc/lxc.h b/src/lxc/lxc.h
index 630eff0..fb57083 100644
--- a/src/lxc/lxc.h
+++ b/src/lxc/lxc.h
@@ -32,8 +32,14 @@ struct lxc_handler;
  * @daemonize    : whether or not the container is daemonized
  * Returns 0 on success, < 0 otherwise
  */
+#ifdef HAVE_ISULAD
+extern int lxc_start(char *const argv[], struct lxc_handler *handler,
+		     const char *lxcpath, bool daemonize, int *error_num,
+		     unsigned int start_timeout);
+#else
 extern int lxc_start(char *const argv[], struct lxc_handler *handler,
 		     const char *lxcpath, bool daemonize, int *error_num);
+#endif
 
 /*
  * Start the specified command inside an application container
@@ -44,9 +50,15 @@ extern int lxc_start(char *const argv[], struct lxc_handler *handler,
  * @daemonize    : whether or not the container is daemonized
  * Returns 0 on success, < 0 otherwise
  */
+#ifdef HAVE_ISULAD
+extern int lxc_execute(const char *name, char *const argv[], int quiet,
+		       struct lxc_handler *handler, const char *lxcpath,
+		       bool daemonize, int *error_num, unsigned int start_timeout);
+#else
 extern int lxc_execute(const char *name, char *const argv[], int quiet,
 		       struct lxc_handler *handler, const char *lxcpath,
 		       bool daemonize, int *error_num);
+#endif
 
 /*
  * Close the fd associated with the monitoring
@@ -83,6 +95,13 @@ extern lxc_state_t lxc_state(const char *name, const char *lxcpath);
  */
 extern struct lxc_container *lxc_container_new(const char *name, const char *configpath);
 
+#ifdef HAVE_ISULAD
+/*
+ * Create a new container without loading config.
+ */
+extern struct lxc_container *lxc_container_without_config_new(const char *name, const char *configpath);
+#endif
+
 /*
  * Returns 1 on success, 0 on failure.
  */
diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h
index b4ec1d6..3680ade 100644
--- a/src/lxc/lxccontainer.h
+++ b/src/lxc/lxccontainer.h
@@ -26,6 +26,10 @@ extern "C" {
 #define LXC_CREATE_MAXFLAGS       (1 << 1) /*!< Number of \c LXC_CREATE* flags */
 #define LXC_MOUNT_API_V1		   1
 
+#ifdef HAVE_ISULAD
+#define LXC_IMAGE_OCI_KEY "lxc.imagetype.oci"
+#endif
+
 struct bdev_specs;
 
 struct lxc_snapshot;
@@ -40,6 +44,41 @@ struct lxc_mount {
 	int version;
 };
 
+#ifdef HAVE_ISULAD
+struct lxc_blkio_metrics {
+	uint64_t read;
+	uint64_t write;
+	uint64_t total;
+};
+
+struct lxc_container_metrics {
+    /* State of container */
+    const char *state;
+    /* The process ID of the init container */
+    pid_t init;
+    /* Current pids */
+    uint64_t pids_current;
+    /* CPU usage */
+    uint64_t cpu_use_nanos;
+    uint64_t cpu_use_user;
+    uint64_t cpu_use_sys;
+    /* BlkIO usage */
+    struct lxc_blkio_metrics io_service_bytes;
+    struct lxc_blkio_metrics io_serviced;
+    /* Memory usage */
+    uint64_t mem_used;
+    uint64_t mem_limit;
+    /* Kernel Memory usage */
+    uint64_t kmem_used;
+    uint64_t kmem_limit;
+    /* Cache usage */
+    uint64_t cache;
+    uint64_t cache_total;
+    /* total inactive file */
+    uint64_t inactive_file_total;
+};
+#endif
+
 /*!
  * An LXC container.
  *
@@ -107,6 +146,38 @@ struct lxc_container {
 	/*! Full path to configuration file */
 	char *config_path;
 
+#ifdef HAVE_ISULAD
+	/*! isulad:
+	 * \private
+	 * exit FIFO File to open used monitor the state of lxc monitor process.
+	 */
+	char *exit_fifo;
+	/*! Whether container wishes to create pty or pipes for console log */
+	bool disable_pty;
+
+	/*! Whether container wishes to keep stdin active */
+	bool open_stdin;
+
+	/*!
+	 * \private
+	 * isulad: support oci hook from json file
+	 * full path of json file
+	 * */
+	char *ocihookfile;
+
+	/*! isulad:
+	 * \private
+	 * start_timeout.
+	 */
+	unsigned int start_timeout;
+
+	/*! isulad:
+	 * \private
+	 *  image_type_oci
+	 */
+	bool image_type_oci;
+#endif
+
 	/*!
 	 * \brief Determine if \c /var/lib/lxc/$name/config exists.
 	 *
@@ -865,6 +936,115 @@ struct lxc_container {
 	 * \return pidfd of init process of the container.
 	 */
 	int (*init_pidfd)(struct lxc_container *c);
+
+#ifdef HAVE_ISULAD
+	/*! isulad add
+	 * \brief An API call to set the path of info file
+	 *
+	 * \param c Container.
+	 * \param info_file Value of the path of info file.
+	 *
+	 * \return \c true on success, else \c false.
+	 */
+	bool (*set_container_info_file) (struct lxc_container *c, const char *info_file);
+
+	/*! isulad add
+	 * \brief An API call to change the path of the console default fifos
+	 *
+	 * \param c Container.
+	 * \param path Value of the console path.
+	 *
+	 * \return \c true on success, else \c false.
+	 */
+	bool (*set_terminal_init_fifos)(struct lxc_container *c, const char *in, const char *out, const char *err);
+
+	/*! isulad add
+	 * \brief An API call to add the path of terminal fifos
+	 *
+	 * \param c Container.
+	 * \param path Value of the console path..
+	 *
+	 * \return \c true on success, else \c false.
+	 */
+	bool (*add_terminal_fifos)(struct lxc_container *c, const char *in, const char *out, const char *err);
+
+	bool (*set_terminal_winch)(struct lxc_container *c, unsigned int height, unsigned int width);
+
+	bool (*set_exec_terminal_winch)(struct lxc_container *c, const char *suffix, unsigned int height, unsigned int width);
+
+	/*!
+	 * \brief Change whether the container wants to create pty or pipes
+	 * from the console log.
+	 *
+	 * \param c Container.
+	 * \param state Value for the disable pty bit (0 or 1).
+	 *
+	 * \return \c true on success, else \c false.
+	 */
+	bool (*want_disable_pty)(struct lxc_container *c, bool state);
+
+	/*!
+	 * \brief Change whether the container wants to keep stdin active
+	 * for parent process of container
+	 *
+	 * \param c Container.
+	 * \param state Value for the open_stdin bit (0 or 1).
+	 *
+	 * \return \c true on success, else \c false.
+	 */
+	bool (*want_open_stdin)(struct lxc_container *c, bool state);
+
+	/*! isulad add
+	 * \brief An API call to clean resources of container
+	 *
+	 * \param c Container.
+	 * \param pid Value of container process.
+	 *
+	 * \return \c true on success, else \c false.
+	 */
+	bool (*clean_container_resource) (struct lxc_container *c, pid_t pid);
+
+	/*! isulad add
+	 * \brief An API call to get container pids
+	 *
+	 * \param c Container.
+	 * \param pids Value of container pids.
+	 * \param pids_len Value of container pids len.
+	 * \param pid Value of container pid.
+	 * \return \c true on success, else \c false.
+	 */
+	bool (*get_container_pids)(struct lxc_container *c,pid_t **pids,size_t *pids_len);
+
+	/*! isulad add
+	 * \brief An API call to set start timeout
+	 *
+	 * \param c Container.
+	 * \param start_timeout Value of start timeout.
+	 *
+	 * \return \c true on success, else \c false.
+	 */
+	bool (*set_start_timeout)(struct lxc_container *c, unsigned int start_timeout);
+
+	/*! isulad add
+	 * \brief An API call to set oci type
+	 *
+	 * \param c Container.
+	 * \param image_type_oci image oci type.
+	 *
+	 * \return \c true on success, else \c false.
+	 */
+	bool (*set_oci_type)(struct lxc_container *c, bool image_type_oci);
+	
+	/*! isulad add
+	 * \brief An API call to set start timeout
+	 *
+	 * \param c Container.
+	 * \param start_timeout Value of start timeout.
+	 *
+	 * \return \c true on success, else \c false.
+	 */
+	bool (*get_container_metrics)(struct lxc_container *c, struct lxc_container_metrics *metrics);
+#endif
 };
 
 /*!
@@ -998,6 +1178,20 @@ struct lxc_console_log {
  */
 struct lxc_container *lxc_container_new(const char *name, const char *configpath);
 
+#ifdef HAVE_ISULAD
+/*!
+ * \brief Create a new container without loading config.
+ *
+ * \param name Name to use for container.
+ * \param configpath Full path to configuration file to use.
+ *
+ * \return Newly-allocated container, or \c NULL on error.
+ *
+ * \note This function can only used for listing container.
+ */
+struct lxc_container *lxc_container_without_config_new(const char *name, const char *configpath);
+#endif
+
 /*!
  * \brief Add a reference to the specified container.
  *
diff --git a/src/lxc/network.c b/src/lxc/network.c
index bca0440..56efa4b 100644
--- a/src/lxc/network.c
+++ b/src/lxc/network.c
@@ -3441,9 +3441,17 @@ 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
+		if (netdev->name[0] != '\0') {
+			err = lxc_netdev_up(netdev->name);
+			if (err)
+				return log_error_errno(-1, -err, "Failed to set network device \"%s\" up", netdev->name);
+		}
+#else
 		err = lxc_netdev_up(netdev->name);
 		if (err)
 			return log_error_errno(-1, -err, "Failed to set network device \"%s\" up", netdev->name);
+#endif
 
 		/* the network is up, make the loopback up too */
 		err = lxc_netdev_up("lo");
diff --git a/src/lxc/tools/lxc_ls.c b/src/lxc/tools/lxc_ls.c
index 0abcd7a..7c0b69c 100644
--- a/src/lxc/tools/lxc_ls.c
+++ b/src/lxc/tools/lxc_ls.c
@@ -106,7 +106,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
@@ -1005,7 +1009,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/tools/lxc_start.c b/src/lxc/tools/lxc_start.c
index 459b867..3ef5961 100644
--- a/src/lxc/tools/lxc_start.c
+++ b/src/lxc/tools/lxc_start.c
@@ -28,6 +28,11 @@
 #include "confile.h"
 #include "log.h"
 
+#ifdef HAVE_ISULAD
+#include <ctype.h>
+#include "isulad_utils.h"
+#endif
+
 lxc_log_define(lxc_start, lxc);
 
 static int my_parser(struct lxc_arguments *args, int c, char *arg);
@@ -48,6 +53,16 @@ static const struct option my_longopts[] = {
 	{"share-ipc", required_argument, 0, OPT_SHARE_IPC},
 	{"share-uts", required_argument, 0, OPT_SHARE_UTS},
 	{"share-pid", required_argument, 0, OPT_SHARE_PID},
+#ifdef HAVE_ISULAD
+	{"in-fifo", required_argument, 0, OPT_INPUT_FIFO},
+	{"out-fifo", required_argument, 0, OPT_OUTPUT_FIFO},
+	{"err-fifo", required_argument, 0, OPT_STDERR_FIFO},
+	{"container-pidfile", required_argument, 0, OPT_CONTAINER_INFO},
+	{"exit-fifo", required_argument, 0, OPT_EXIT_FIFO},
+	{"start-timeout", required_argument, 0, OPT_START_TIMEOUT},
+	{"disable-pty", no_argument, 0, OPT_DISABLE_PTY},
+	{"open-stdin", no_argument, 0, OPT_OPEN_STDIN},
+#endif
 	LXC_COMMON_OPTIONS
 };
 
@@ -70,7 +85,20 @@ Options :\n\
                          Note: --daemon implies --close-all-fds\n\
   -s, --define KEY=VAL   Assign VAL to configuration variable KEY\n\
       --share-[net|ipc|uts|pid]=NAME Share a namespace with another container or pid\n\
-",
+"
+#ifdef HAVE_ISULAD
+"\
+      --in-fifo           Stdin fifo path\n\
+      --out-fifo          Stdout fifo path\n\
+      --err-fifo          Stderr fifo path\n\
+      --container-pidfile File path for container pid\n\
+      --exit-fifo         Fifo path to save exit code\n\
+      --start-timeout     Timeout for start container\n\
+      --disable-pty       Disable pty for attach\n\
+      --open-stdin        Open stdin for attach\n\
+"
+#endif
+,
 	.options      = my_longopts,
 	.parser       = my_parser,
 	.checker      = NULL,
@@ -118,6 +146,38 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg)
 	case OPT_SHARE_PID:
 		args->share_ns[LXC_NS_PID] = arg;
 		break;
+
+#ifdef HAVE_ISULAD
+	case OPT_CONTAINER_INFO:
+		args->container_info = arg;
+		break;
+	case OPT_INPUT_FIFO:
+		args->terminal_fifos[0] = arg;
+		break;
+	case OPT_OUTPUT_FIFO:
+		args->terminal_fifos[1] = arg;
+		break;
+	case OPT_STDERR_FIFO:
+		args->terminal_fifos[2] = arg;
+		break;
+	case OPT_EXIT_FIFO:
+		args->exit_monitor_fifo = arg;
+		break;
+	case OPT_DISABLE_PTY:
+		args->disable_pty = 1;
+		break;
+	case OPT_OPEN_STDIN:
+		args->open_stdin = 1;
+		break;
+	case OPT_START_TIMEOUT:
+		if(!is_non_negative_num(arg)) {
+			fprintf(stderr, "Error start timeout parameter:%s.\n", arg);
+			return -1;
+		}
+		args->start_timeout = (unsigned int)atoi(arg);
+		break;
+#endif
+
 	}
 	return 0;
 }
@@ -163,6 +223,9 @@ int main(int argc, char *argv[])
 		"/sbin/init",
 		NULL,
 	};
+#ifdef HAVE_ISULAD
+	char *container_info_file = NULL;
+#endif
 
 	lxc_list_init(&defines);
 
@@ -283,6 +346,42 @@ int main(int argc, char *argv[])
 			goto out;
 		}
 
+#ifdef HAVE_ISULAD
+	/* isulad: container info file used to store pid and ppid info of container*/
+	if (my_args.container_info != NULL) {
+		if (ensure_path(&container_info_file, my_args.container_info) < 0) {
+			ERROR("Failed to ensure container's piddile '%s'", my_args.container_info);
+			goto out;
+		}
+		if (!c->set_container_info_file(c, container_info_file)) {
+			ERROR("Failed to set container's piddile '%s'", container_info_file);
+			goto out;
+		}
+	}
+
+	if (my_args.terminal_fifos[0] || my_args.terminal_fifos[1] || my_args.terminal_fifos[2]) {
+		c->set_terminal_init_fifos(c, my_args.terminal_fifos[0], my_args.terminal_fifos[1], my_args.terminal_fifos[2]);
+	}
+
+	/* isulad: fifo used to monitor state of monitor process */
+	if (my_args.exit_monitor_fifo != NULL) {
+		c->exit_fifo = safe_strdup(my_args.exit_monitor_fifo);
+	}
+
+	if (my_args.disable_pty) {
+		c->want_disable_pty(c, true);
+	}
+
+	if (my_args.open_stdin) {
+		c->want_open_stdin(c, true);
+	}
+
+	/* isulad: add start timeout */
+	if(my_args.start_timeout) {
+		c->set_start_timeout(c, my_args.start_timeout);
+	}
+#endif
+
 	if (my_args.console)
 		if (!c->set_config_item(c, "lxc.console.path", my_args.console))
 			goto out;
@@ -305,6 +404,11 @@ int main(int argc, char *argv[])
 	else
 		err = c->start(c, 0, args) ? EXIT_SUCCESS : EXIT_FAILURE;
 	if (err) {
+#ifdef HAVE_ISULAD
+		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);
+#endif
 		ERROR("The container failed to start");
 
 		if (my_args.daemonize)
@@ -320,5 +424,8 @@ int main(int argc, char *argv[])
 
 out:
 	lxc_container_put(c);
+#ifdef HAVE_ISULAD
+	free(container_info_file);
+#endif
 	exit(err);
 }
diff --git a/src/lxc/utils.c b/src/lxc/utils.c
index 88d0f85..ab351d8 100644
--- a/src/lxc/utils.c
+++ b/src/lxc/utils.c
@@ -27,6 +27,9 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <unistd.h>
+#ifdef HAVE_ISULAD
+#include <sys/sysmacros.h>
+#endif
 
 #include "config.h"
 #include "log.h"
@@ -71,6 +74,9 @@ static int _recursive_rmdir(const char *dirname, dev_t pdev,
 	int ret;
 	struct dirent *direntp;
 	char pathname[PATH_MAX];
+#ifdef HAVE_ISULAD
+	int saved_errno = 0;
+#endif
 
 	dir = opendir(dirname);
 	if (!dir)
@@ -133,6 +139,11 @@ static int _recursive_rmdir(const char *dirname, dev_t pdev,
 		} else {
 			ret = unlink(pathname);
 			if (ret < 0) {
+#ifdef HAVE_ISULAD
+				if (saved_errno == 0) {
+					saved_errno = errno;
+				}
+#endif
 				__do_close int fd = -EBADF;
 
 				fd = open(pathname, O_RDONLY | O_CLOEXEC | O_NONBLOCK);
@@ -158,10 +169,18 @@ static int _recursive_rmdir(const char *dirname, dev_t pdev,
 	}
 
 	if (rmdir(dirname) < 0 && !btrfs_try_remove_subvol(dirname) && !hadexclude) {
+#ifdef HAVE_ISULAD
+		if (saved_errno == 0) {
+			saved_errno = errno;
+		}
+#endif
 		SYSERROR("Failed to delete \"%s\"", dirname);
 		failed = 1;
 	}
 
+#ifdef HAVE_ISULAD
+	errno = saved_errno;
+#endif
 	return failed ? -1 : 0;
 }
 
@@ -1008,7 +1027,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;
@@ -1079,6 +1102,65 @@ out:
 	return dirfd;
 }
 
+#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
@@ -1087,14 +1169,22 @@ out:
  * 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 = "";
@@ -1137,8 +1227,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);
 
@@ -1149,6 +1254,19 @@ 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;
 }
 
@@ -1215,7 +1333,11 @@ domount:
 	if (!strcmp(rootfs, ""))
 		ret = mount("proc", path, "proc", 0, NULL);
 	else
+#ifdef HAVE_ISULAD
+		ret = safe_mount("proc", path, "proc", 0, NULL, rootfs, NULL);
+#else
 		ret = safe_mount("proc", path, "proc", 0, NULL, rootfs);
+#endif
 	if (ret < 0)
 		return -1;
 
@@ -1425,6 +1547,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) {
@@ -1442,8 +1569,37 @@ static int lxc_get_unused_loop_dev(char *name_loop)
 	if (ret < 0 || ret >= LO_NAME_SIZE)
 		goto on_error;
 
+#ifdef HAVE_ISULAD
+retry:
+#endif
 	fd_tmp = open(name_loop, O_RDWR | O_CLOEXEC);
 	if (fd_tmp < 0) {
+#ifdef HAVE_ISULAD
+		/* 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;
+			goto retry;
+		}
+		/* 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 > 0) {
+			max_retry--;
+			usleep(5000); /* 5 millisecond */
+			goto retry;
+		}
+		SYSERROR("Failed to open loop \"%s\"", name_loop);
+		goto on_error;
+#else
 		/* on Android loop devices are moved under /dev/block, give it a shot */
 		ret = snprintf(name_loop, LO_NAME_SIZE, "/dev/block/loop%d", loop_nr);
                 if (ret < 0 || ret >= LO_NAME_SIZE)
@@ -1452,6 +1608,7 @@ static int lxc_get_unused_loop_dev(char *name_loop)
 		fd_tmp = open(name_loop, O_RDWR | O_CLOEXEC);
 		if (fd_tmp < 0)
 			SYSERROR("Failed to open loop \"%s\"", name_loop);
+#endif
 	}
 
 on_error:
@@ -1661,6 +1818,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;
@@ -1698,15 +1856,19 @@ 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
 	/* verify that we haven't been orphaned in the meantime */
 	ppid = (pid_t)syscall(SYS_getppid);
 	if (ppid == 0) { /* parent outside our pidns */
@@ -1718,6 +1880,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;
@@ -1755,8 +1918,18 @@ int lxc_rm_rf(const char *dirname)
 	struct dirent *direntp;
 
 	dir = opendir(dirname);
+#ifdef HAVE_ISULAD
+	if (!dir) {
+		if (errno == ENOENT) {
+			WARN("Destroy path: \"%s\" do not exist", dirname);
+			return 0;
+		}
+		return log_error_errno(-1, errno, "Failed to open dir \"%s\"", dirname);
+	}
+#else
 	if (!dir)
 		return log_error_errno(-1, errno, "Failed to open dir \"%s\"", dirname);
+#endif
 
 	while ((direntp = readdir(dir))) {
 		__do_free char *pathname = NULL;
diff --git a/src/lxc/utils.h b/src/lxc/utils.h
index cf2c042..917a086 100644
--- a/src/lxc/utils.h
+++ b/src/lxc/utils.h
@@ -28,6 +28,10 @@
 #include "process_utils.h"
 #include "string_utils.h"
 
+#ifdef HAVE_ISULAD
+#include "isulad_utils.h"
+#endif
+
 /* returns 1 on success, 0 if there were any failures */
 extern int lxc_rmdir_onedev(const char *path, const char *exclude);
 extern int get_u16(unsigned short *val, const char *arg, int base);
@@ -145,9 +149,16 @@ extern bool cgns_supported(void);
 extern char *choose_init(const char *rootfs);
 extern bool switch_to_ns(pid_t pid, const char *ns);
 extern char *get_template_path(const char *t);
+#ifdef HAVE_ISULAD
+extern int open_without_symlink(const char *target, const char *prefix_skip);
+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
 extern int safe_mount(const char *src, const char *dest, const char *fstype,
 		      unsigned long flags, const void *data,
 		      const char *rootfs);
+#endif
 extern int lxc_mount_proc_if_needed(const char *rootfs);
 extern int open_devnull(void);
 extern int set_stdfds(int fd);
-- 
2.25.1

